1/*! DataTables 1.13.4
vendor: 46,563 bytes, lines 1-1387
1 2 * ©2008-2023 SpryMedia Ltd - datatables.net/license 3 */ 4 5/** 6 * @summary DataTables 7 * @description Paginate, search and order HTML tables 8 * @version 1.13.4 9 * @author SpryMedia Ltd 10 * @contact www.datatables.net 11 * @copyright SpryMedia Ltd. 12 * 13 * This source file is free software, available under the following license: 14 * MIT license - http://datatables.net/license 15 * 16 * This source file is distributed in the hope that it will be useful, but 17 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 18 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. 19 * 20 * For details please refer to: http://www.datatables.net 21 */ 22 23/*jslint evil: true, undef: true, browser: true */ 24/*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,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/ 25 26(function( factory ) { 27 "use strict"; 28 29 if ( typeof define === 'function' && define.amd ) { 30 // AMD 31 define( ['jquery'], function ( $ ) { 32 return factory( $, window, document ); 33 } ); 34 } 35 else if ( typeof exports === 'object' ) { 36 // CommonJS 37 // jQuery's factory checks for a global window - if it isn't present then it 38 // returns a factory function that expects the window object 39 var jq = require('jquery'); 40 41 if (typeof window !== 'undefined') { 42 module.exports = function (root, $) { 43 if ( ! root ) { 44 // CommonJS environments without a window global must pass a 45 // root. This will give an error otherwise 46 root = window; 47 } 48 49 if ( ! $ ) { 50 $ = jq( root ); 51 } 52 53 return factory( $, root, root.document ); 54 }; 55 } 56 else { 57 return factory( jq, window, window.document ); 58 } 59 } 60 else { 61 // Browser 62 window.DataTable = factory( jQuery, window, document ); 63 } 64} 65(function( $, window, document, undefined ) { 66 "use strict"; 67 68 69 var DataTable = function ( selector, options ) 70 { 71 // Check if called with a window or jQuery object for DOM less applications 72 // This is for backwards compatibility 73 if (DataTable.factory(selector, options)) { 74 return DataTable; 75 } 76 77 // When creating with `new`, create a new DataTable, returning the API instance 78 if (this instanceof DataTable) { 79 return $(selector).DataTable(options); 80 } 81 else { 82 // Argument switching 83 options = selector; 84 } 85 86 /** 87 * Perform a jQuery selector action on the table's TR elements (from the tbody) and 88 * return the resulting jQuery object. 89 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on 90 * @param {object} [oOpts] Optional parameters for modifying the rows to be included 91 * @param {string} [oOpts.filter=none] Select TR elements that meet the current filter 92 * criterion ("applied") or all TR elements (i.e. no filter). 93 * @param {string} [oOpts.order=current] Order of the TR elements in the processed array. 94 * Can be either 'current', whereby the current sorting of the table is used, or 95 * 'original' whereby the original order the data was read into the table is used. 96 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page 97 * ("current") or not ("all"). If 'current' is given, then order is assumed to be 98 * 'current' and filter is 'applied', regardless of what they might be given as. 99 * @returns {object} jQuery object, filtered by the given selector. 100 * @dtopt API 101 * @deprecated Since v1.10 102 * 103 * @example 104 * $(document).ready(function() { 105 * var oTable = $('#example').dataTable(); 106 * 107 * // Highlight every second row 108 * oTable.$('tr:odd').css('backgroundColor', 'blue'); 109 * } ); 110 * 111 * @example 112 * $(document).ready(function() { 113 * var oTable = $('#example').dataTable(); 114 * 115 * // Filter to rows with 'Webkit' in them, add a background colour and then 116 * // remove the filter, thus highlighting the 'Webkit' rows only. 117 * oTable.fnFilter('Webkit'); 118 * oTable.$('tr', {"search": "applied"}).css('backgroundColor', 'blue'); 119 * oTable.fnFilter(''); 120 * } ); 121 */ 122 this.$ = function ( sSelector, oOpts ) 123 { 124 return this.api(true).$( sSelector, oOpts ); 125 }; 126 127 128 /** 129 * Almost identical to $ in operation, but in this case returns the data for the matched 130 * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes 131 * rather than any descendants, so the data can be obtained for the row/cell. If matching 132 * rows are found, the data returned is the original data array/object that was used to 133 * create the row (or a generated array if from a DOM source). 134 * 135 * This method is often useful in-combination with $ where both functions are given the 136 * same parameters and the array indexes will match identically. 137 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on 138 * @param {object} [oOpts] Optional parameters for modifying the rows to be included 139 * @param {string} [oOpts.filter=none] Select elements that meet the current filter 140 * criterion ("applied") or all elements (i.e. no filter). 141 * @param {string} [oOpts.order=current] Order of the data in the processed array. 142 * Can be either 'current', whereby the current sorting of the table is used, or 143 * 'original' whereby the original order the data was read into the table is used. 144 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page 145 * ("current") or not ("all"). If 'current' is given, then order is assumed to be 146 * 'current' and filter is 'applied', regardless of what they might be given as. 147 * @returns {array} Data for the matched elements. If any elements, as a result of the 148 * selector, were not TR, TD or TH elements in the DataTable, they will have a null 149 * entry in the array. 150 * @dtopt API 151 * @deprecated Since v1.10 152 * 153 * @example 154 * $(document).ready(function() { 155 * var oTable = $('#example').dataTable(); 156 * 157 * // Get the data from the first row in the table 158 * var data = oTable._('tr:first'); 159 * 160 * // Do something useful with the data 161 * alert( "First cell is: "+data[0] ); 162 * } ); 163 * 164 * @example 165 * $(document).ready(function() { 166 * var oTable = $('#example').dataTable(); 167 * 168 * // Filter to 'Webkit' and get all data for 169 * oTable.fnFilter('Webkit'); 170 * var data = oTable._('tr', {"search": "applied"}); 171 * 172 * // Do something with the data 173 * alert( data.length+" rows matched the search" ); 174 * } ); 175 */ 176 this._ = function ( sSelector, oOpts ) 177 { 178 return this.api(true).rows( sSelector, oOpts ).data(); 179 }; 180 181 182 /** 183 * Create a DataTables Api instance, with the currently selected tables for 184 * the Api's context. 185 * @param {boolean} [traditional=false] Set the API instance's context to be 186 * only the table referred to by the `DataTable.ext.iApiIndex` option, as was 187 * used in the API presented by DataTables 1.9- (i.e. the traditional mode), 188 * or if all tables captured in the jQuery object should be used. 189 * @return {DataTables.Api} 190 */ 191 this.api = function ( traditional ) 192 { 193 return traditional ? 194 new _Api( 195 _fnSettingsFromNode( this[ _ext.iApiIndex ] ) 196 ) : 197 new _Api( this ); 198 }; 199 200 201 /** 202 * Add a single new row or multiple rows of data to the table. Please note 203 * that this is suitable for client-side processing only - if you are using 204 * server-side processing (i.e. "bServerSide": true), then to add data, you 205 * must add it to the data source, i.e. the server-side, through an Ajax call. 206 * @param {array|object} data The data to be added to the table. This can be: 207 * <ul> 208 * <li>1D array of data - add a single row with the data provided</li> 209 * <li>2D array of arrays - add multiple rows in a single call</li> 210 * <li>object - data object when using <i>mData</i></li> 211 * <li>array of objects - multiple data objects when using <i>mData</i></li> 212 * </ul> 213 * @param {bool} [redraw=true] redraw the table or not 214 * @returns {array} An array of integers, representing the list of indexes in 215 * <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to 216 * the table. 217 * @dtopt API 218 * @deprecated Since v1.10 219 * 220 * @example 221 * // Global var for counter 222 * var giCount = 2; 223 * 224 * $(document).ready(function() { 225 * $('#example').dataTable(); 226 * } ); 227 * 228 * function fnClickAddRow() { 229 * $('#example').dataTable().fnAddData( [ 230 * giCount+".1", 231 * giCount+".2", 232 * giCount+".3", 233 * giCount+".4" ] 234 * ); 235 * 236 * giCount++; 237 * } 238 */ 239 this.fnAddData = function( data, redraw ) 240 { 241 var api = this.api( true ); 242 243 /* Check if we want to add multiple rows or not */ 244 var rows = Array.isArray(data) && ( Array.isArray(data[0]) || $.isPlainObject(data[0]) ) ? 245 api.rows.add( data ) : 246 api.row.add( data ); 247 248 if ( redraw === undefined || redraw ) { 249 api.draw(); 250 } 251 252 return rows.flatten().toArray(); 253 }; 254 255 256 /** 257 * This function will make DataTables recalculate the column sizes, based on the data 258 * contained in the table and the sizes applied to the columns (in the DOM, CSS or 259 * through the sWidth parameter). This can be useful when the width of the table's 260 * parent element changes (for example a window resize). 261 * @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to 262 * @dtopt API 263 * @deprecated Since v1.10 264 * 265 * @example 266 * $(document).ready(function() { 267 * var oTable = $('#example').dataTable( { 268 * "sScrollY": "200px", 269 * "bPaginate": false 270 * } ); 271 * 272 * $(window).on('resize', function () { 273 * oTable.fnAdjustColumnSizing(); 274 * } ); 275 * } ); 276 */ 277 this.fnAdjustColumnSizing = function ( bRedraw ) 278 { 279 var api = this.api( true ).columns.adjust(); 280 var settings = api.settings()[0]; 281 var scroll = settings.oScroll; 282 283 if ( bRedraw === undefined || bRedraw ) { 284 api.draw( false ); 285 } 286 else if ( scroll.sX !== "" || scroll.sY !== "" ) { 287 /* If not redrawing, but scrolling, we want to apply the new column sizes anyway */ 288 _fnScrollDraw( settings ); 289 } 290 }; 291 292 293 /** 294 * Quickly and simply clear a table 295 * @param {bool} [bRedraw=true] redraw the table or not 296 * @dtopt API 297 * @deprecated Since v1.10 298 * 299 * @example 300 * $(document).ready(function() { 301 * var oTable = $('#example').dataTable(); 302 * 303 * // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...) 304 * oTable.fnClearTable(); 305 * } ); 306 */ 307 this.fnClearTable = function( bRedraw ) 308 { 309 var api = this.api( true ).clear(); 310 311 if ( bRedraw === undefined || bRedraw ) { 312 api.draw(); 313 } 314 }; 315 316 317 /** 318 * The exact opposite of 'opening' a row, this function will close any rows which 319 * are currently 'open'. 320 * @param {node} nTr the table row to 'close' 321 * @returns {int} 0 on success, or 1 if failed (can't find the row) 322 * @dtopt API 323 * @deprecated Since v1.10 324 * 325 * @example 326 * $(document).ready(function() { 327 * var oTable; 328 * 329 * // 'open' an information row when a row is clicked on 330 * $('#example tbody tr').click( function () { 331 * if ( oTable.fnIsOpen(this) ) { 332 * oTable.fnClose( this ); 333 * } else { 334 * oTable.fnOpen( this, "Temporary row opened", "info_row" ); 335 * } 336 * } ); 337 * 338 * oTable = $('#example').dataTable(); 339 * } ); 340 */ 341 this.fnClose = function( nTr ) 342 { 343 this.api( true ).row( nTr ).child.hide(); 344 }; 345 346 347 /** 348 * Remove a row for the table 349 * @param {mixed} target The index of the row from aoData to be deleted, or 350 * the TR element you want to delete 351 * @param {function|null} [callBack] Callback function 352 * @param {bool} [redraw=true] Redraw the table or not 353 * @returns {array} The row that was deleted 354 * @dtopt API 355 * @deprecated Since v1.10 356 * 357 * @example 358 * $(document).ready(function() { 359 * var oTable = $('#example').dataTable(); 360 * 361 * // Immediately remove the first row 362 * oTable.fnDeleteRow( 0 ); 363 * } ); 364 */ 365 this.fnDeleteRow = function( target, callback, redraw ) 366 { 367 var api = this.api( true ); 368 var rows = api.rows( target ); 369 var settings = rows.settings()[0]; 370 var data = settings.aoData[ rows[0][0] ]; 371 372 rows.remove(); 373 374 if ( callback ) { 375 callback.call( this, settings, data ); 376 } 377 378 if ( redraw === undefined || redraw ) { 379 api.draw(); 380 } 381 382 return data; 383 }; 384 385 386 /** 387 * Restore the table to it's original state in the DOM by removing all of DataTables 388 * enhancements, alterations to the DOM structure of the table and event listeners. 389 * @param {boolean} [remove=false] Completely remove the table from the DOM 390 * @dtopt API 391 * @deprecated Since v1.10 392 * 393 * @example 394 * $(document).ready(function() { 395 * // This example is fairly pointless in reality, but shows how fnDestroy can be used 396 * var oTable = $('#example').dataTable(); 397 * oTable.fnDestroy(); 398 * } ); 399 */ 400 this.fnDestroy = function ( remove ) 401 { 402 this.api( true ).destroy( remove ); 403 }; 404 405 406 /** 407 * Redraw the table 408 * @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw. 409 * @dtopt API 410 * @deprecated Since v1.10 411 * 412 * @example 413 * $(document).ready(function() { 414 * var oTable = $('#example').dataTable(); 415 * 416 * // Re-draw the table - you wouldn't want to do it here, but it's an example :-) 417 * oTable.fnDraw(); 418 * } ); 419 */ 420 this.fnDraw = function( complete ) 421 { 422 // Note that this isn't an exact match to the old call to _fnDraw - it takes 423 // into account the new data, but can hold position. 424 this.api( true ).draw( complete ); 425 }; 426 427 428 /** 429 * Filter the input based on data 430 * @param {string} sInput String to filter the table on 431 * @param {int|null} [iColumn] Column to limit filtering to 432 * @param {bool} [bRegex=false] Treat as regular expression or not 433 * @param {bool} [bSmart=true] Perform smart filtering or not 434 * @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es) 435 * @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false) 436 * @dtopt API 437 * @deprecated Since v1.10 438 * 439 * @example 440 * $(document).ready(function() { 441 * var oTable = $('#example').dataTable(); 442 * 443 * // Sometime later - filter... 444 * oTable.fnFilter( 'test string' ); 445 * } ); 446 */ 447 this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive ) 448 { 449 var api = this.api( true ); 450 451 if ( iColumn === null || iColumn === undefined ) { 452 api.search( sInput, bRegex, bSmart, bCaseInsensitive ); 453 } 454 else { 455 api.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive ); 456 } 457 458 api.draw(); 459 }; 460 461 462 /** 463 * Get the data for the whole table, an individual row or an individual cell based on the 464 * provided parameters. 465 * @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as 466 * a TR node then the data source for the whole row will be returned. If given as a 467 * TD/TH cell node then iCol will be automatically calculated and the data for the 468 * cell returned. If given as an integer, then this is treated as the aoData internal 469 * data index for the row (see fnGetPosition) and the data for that row used. 470 * @param {int} [col] Optional column index that you want the data of. 471 * @returns {array|object|string} If mRow is undefined, then the data for all rows is 472 * returned. If mRow is defined, just data for that row, and is iCol is 473 * defined, only data for the designated cell is returned. 474 * @dtopt API 475 * @deprecated Since v1.10 476 * 477 * @example 478 * // Row data 479 * $(document).ready(function() { 480 * oTable = $('#example').dataTable(); 481 * 482 * oTable.$('tr').click( function () { 483 * var data = oTable.fnGetData( this ); 484 * // ... do something with the array / object of data for the row 485 * } ); 486 * } ); 487 * 488 * @example 489 * // Individual cell data 490 * $(document).ready(function() { 491 * oTable = $('#example').dataTable(); 492 * 493 * oTable.$('td').click( function () { 494 * var sData = oTable.fnGetData( this ); 495 * alert( 'The cell clicked on had the value of '+sData ); 496 * } ); 497 * } ); 498 */ 499 this.fnGetData = function( src, col ) 500 { 501 var api = this.api( true ); 502 503 if ( src !== undefined ) { 504 var type = src.nodeName ? src.nodeName.toLowerCase() : ''; 505 506 return col !== undefined || type == 'td' || type == 'th' ? 507 api.cell( src, col ).data() : 508 api.row( src ).data() || null; 509 } 510 511 return api.data().toArray(); 512 }; 513 514 515 /** 516 * Get an array of the TR nodes that are used in the table's body. Note that you will 517 * typically want to use the '$' API method in preference to this as it is more 518 * flexible. 519 * @param {int} [iRow] Optional row index for the TR element you want 520 * @returns {array|node} If iRow is undefined, returns an array of all TR elements 521 * in the table's body, or iRow is defined, just the TR element requested. 522 * @dtopt API 523 * @deprecated Since v1.10 524 * 525 * @example 526 * $(document).ready(function() { 527 * var oTable = $('#example').dataTable(); 528 * 529 * // Get the nodes from the table 530 * var nNodes = oTable.fnGetNodes( ); 531 * } ); 532 */ 533 this.fnGetNodes = function( iRow ) 534 { 535 var api = this.api( true ); 536 537 return iRow !== undefined ? 538 api.row( iRow ).node() : 539 api.rows().nodes().flatten().toArray(); 540 }; 541 542 543 /** 544 * Get the array indexes of a particular cell from it's DOM element 545 * and column index including hidden columns 546 * @param {node} node this can either be a TR, TD or TH in the table's body 547 * @returns {int} If nNode is given as a TR, then a single index is returned, or 548 * if given as a cell, an array of [row index, column index (visible), 549 * column index (all)] is given. 550 * @dtopt API 551 * @deprecated Since v1.10 552 * 553 * @example 554 * $(document).ready(function() { 555 * $('#example tbody td').click( function () { 556 * // Get the position of the current data from the node 557 * var aPos = oTable.fnGetPosition( this ); 558 * 559 * // Get the data array for this row 560 * var aData = oTable.fnGetData( aPos[0] ); 561 * 562 * // Update the data array and return the value 563 * aData[ aPos[1] ] = 'clicked'; 564 * this.innerHTML = 'clicked'; 565 * } ); 566 * 567 * // Init DataTables 568 * oTable = $('#example').dataTable(); 569 * } ); 570 */ 571 this.fnGetPosition = function( node ) 572 { 573 var api = this.api( true ); 574 var nodeName = node.nodeName.toUpperCase(); 575 576 if ( nodeName == 'TR' ) { 577 return api.row( node ).index(); 578 } 579 else if ( nodeName == 'TD' || nodeName == 'TH' ) { 580 var cell = api.cell( node ).index(); 581 582 return [ 583 cell.row, 584 cell.columnVisible, 585 cell.column 586 ]; 587 } 588 return null; 589 }; 590 591 592 /** 593 * Check to see if a row is 'open' or not. 594 * @param {node} nTr the table row to check 595 * @returns {boolean} true if the row is currently open, false otherwise 596 * @dtopt API 597 * @deprecated Since v1.10 598 * 599 * @example 600 * $(document).ready(function() { 601 * var oTable; 602 * 603 * // 'open' an information row when a row is clicked on 604 * $('#example tbody tr').click( function () { 605 * if ( oTable.fnIsOpen(this) ) { 606 * oTable.fnClose( this ); 607 * } else { 608 * oTable.fnOpen( this, "Temporary row opened", "info_row" ); 609 * } 610 * } ); 611 * 612 * oTable = $('#example').dataTable(); 613 * } ); 614 */ 615 this.fnIsOpen = function( nTr ) 616 { 617 return this.api( true ).row( nTr ).child.isShown(); 618 }; 619 620 621 /** 622 * This function will place a new row directly after a row which is currently 623 * on display on the page, with the HTML contents that is passed into the 624 * function. This can be used, for example, to ask for confirmation that a 625 * particular record should be deleted. 626 * @param {node} nTr The table row to 'open' 627 * @param {string|node|jQuery} mHtml The HTML to put into the row 628 * @param {string} sClass Class to give the new TD cell 629 * @returns {node} The row opened. Note that if the table row passed in as the 630 * first parameter, is not found in the table, this method will silently 631 * return. 632 * @dtopt API 633 * @deprecated Since v1.10 634 * 635 * @example 636 * $(document).ready(function() { 637 * var oTable; 638 * 639 * // 'open' an information row when a row is clicked on 640 * $('#example tbody tr').click( function () { 641 * if ( oTable.fnIsOpen(this) ) { 642 * oTable.fnClose( this ); 643 * } else { 644 * oTable.fnOpen( this, "Temporary row opened", "info_row" ); 645 * } 646 * } ); 647 * 648 * oTable = $('#example').dataTable(); 649 * } ); 650 */ 651 this.fnOpen = function( nTr, mHtml, sClass ) 652 { 653 return this.api( true ) 654 .row( nTr ) 655 .child( mHtml, sClass ) 656 .show() 657 .child()[0]; 658 }; 659 660 661 /** 662 * Change the pagination - provides the internal logic for pagination in a simple API 663 * function. With this function you can have a DataTables table go to the next, 664 * previous, first or last pages. 665 * @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last" 666 * or page number to jump to (integer), note that page 0 is the first page. 667 * @param {bool} [bRedraw=true] Redraw the table or not 668 * @dtopt API 669 * @deprecated Since v1.10 670 * 671 * @example 672 * $(document).ready(function() { 673 * var oTable = $('#example').dataTable(); 674 * oTable.fnPageChange( 'next' ); 675 * } ); 676 */ 677 this.fnPageChange = function ( mAction, bRedraw ) 678 { 679 var api = this.api( true ).page( mAction ); 680 681 if ( bRedraw === undefined || bRedraw ) { 682 api.draw(false); 683 } 684 }; 685 686 687 /** 688 * Show a particular column 689 * @param {int} iCol The column whose display should be changed 690 * @param {bool} bShow Show (true) or hide (false) the column 691 * @param {bool} [bRedraw=true] Redraw the table or not 692 * @dtopt API 693 * @deprecated Since v1.10 694 * 695 * @example 696 * $(document).ready(function() { 697 * var oTable = $('#example').dataTable(); 698 * 699 * // Hide the second column after initialisation 700 * oTable.fnSetColumnVis( 1, false ); 701 * } ); 702 */ 703 this.fnSetColumnVis = function ( iCol, bShow, bRedraw ) 704 { 705 var api = this.api( true ).column( iCol ).visible( bShow ); 706 707 if ( bRedraw === undefined || bRedraw ) { 708 api.columns.adjust().draw(); 709 } 710 }; 711 712 713 /** 714 * Get the settings for a particular table for external manipulation 715 * @returns {object} DataTables settings object. See 716 * {@link DataTable.models.oSettings} 717 * @dtopt API 718 * @deprecated Since v1.10 719 * 720 * @example 721 * $(document).ready(function() { 722 * var oTable = $('#example').dataTable(); 723 * var oSettings = oTable.fnSettings(); 724 * 725 * // Show an example parameter from the settings 726 * alert( oSettings._iDisplayStart ); 727 * } ); 728 */ 729 this.fnSettings = function() 730 { 731 return _fnSettingsFromNode( this[_ext.iApiIndex] ); 732 }; 733 734 735 /** 736 * Sort the table by a particular column 737 * @param {int} iCol the data index to sort on. Note that this will not match the 738 * 'display index' if you have hidden data entries 739 * @dtopt API 740 * @deprecated Since v1.10 741 * 742 * @example 743 * $(document).ready(function() { 744 * var oTable = $('#example').dataTable(); 745 * 746 * // Sort immediately with columns 0 and 1 747 * oTable.fnSort( [ [0,'asc'], [1,'asc'] ] ); 748 * } ); 749 */ 750 this.fnSort = function( aaSort ) 751 { 752 this.api( true ).order( aaSort ).draw(); 753 }; 754 755 756 /** 757 * Attach a sort listener to an element for a given column 758 * @param {node} nNode the element to attach the sort listener to 759 * @param {int} iColumn the column that a click on this node will sort on 760 * @param {function} [fnCallback] callback function when sort is run 761 * @dtopt API 762 * @deprecated Since v1.10 763 * 764 * @example 765 * $(document).ready(function() { 766 * var oTable = $('#example').dataTable(); 767 * 768 * // Sort on column 1, when 'sorter' is clicked on 769 * oTable.fnSortListener( document.getElementById('sorter'), 1 ); 770 * } ); 771 */ 772 this.fnSortListener = function( nNode, iColumn, fnCallback ) 773 { 774 this.api( true ).order.listener( nNode, iColumn, fnCallback ); 775 }; 776 777 778 /** 779 * Update a table cell or row - this method will accept either a single value to 780 * update the cell with, an array of values with one element for each column or 781 * an object in the same format as the original data source. The function is 782 * self-referencing in order to make the multi column updates easier. 783 * @param {object|array|string} mData Data to update the cell/row with 784 * @param {node|int} mRow TR element you want to update or the aoData index 785 * @param {int} [iColumn] The column to update, give as null or undefined to 786 * update a whole row. 787 * @param {bool} [bRedraw=true] Redraw the table or not 788 * @param {bool} [bAction=true] Perform pre-draw actions or not 789 * @returns {int} 0 on success, 1 on error 790 * @dtopt API 791 * @deprecated Since v1.10 792 * 793 * @example 794 * $(document).ready(function() { 795 * var oTable = $('#example').dataTable(); 796 * oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell 797 * oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row 798 * } ); 799 */ 800 this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction ) 801 { 802 var api = this.api( true ); 803 804 if ( iColumn === undefined || iColumn === null ) { 805 api.row( mRow ).data( mData ); 806 } 807 else { 808 api.cell( mRow, iColumn ).data( mData ); 809 } 810 811 if ( bAction === undefined || bAction ) { 812 api.columns.adjust(); 813 } 814 815 if ( bRedraw === undefined || bRedraw ) { 816 api.draw(); 817 } 818 return 0; 819 }; 820 821 822 /** 823 * Provide a common method for plug-ins to check the version of DataTables being used, in order 824 * to ensure compatibility. 825 * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the 826 * formats "X" and "X.Y" are also acceptable. 827 * @returns {boolean} true if this version of DataTables is greater or equal to the required 828 * version, or false if this version of DataTales is not suitable 829 * @method 830 * @dtopt API 831 * @deprecated Since v1.10 832 * 833 * @example 834 * $(document).ready(function() { 835 * var oTable = $('#example').dataTable(); 836 * alert( oTable.fnVersionCheck( '1.9.0' ) ); 837 * } ); 838 */ 839 this.fnVersionCheck = _ext.fnVersionCheck; 840 841 842 var _that = this; 843 var emptyInit = options === undefined; 844 var len = this.length; 845 846 if ( emptyInit ) { 847 options = {}; 848 } 849 850 this.oApi = this.internal = _ext.internal; 851 852 // Extend with old style plug-in API methods 853 for ( var fn in DataTable.ext.internal ) { 854 if ( fn ) { 855 this[fn] = _fnExternApiFunc(fn); 856 } 857 } 858 859 this.each(function() { 860 // For each initialisation we want to give it a clean initialisation 861 // object that can be bashed around 862 var o = {}; 863 var oInit = len > 1 ? // optimisation for single table case 864 _fnExtend( o, options, true ) : 865 options; 866 867 /*global oInit,_that,emptyInit*/ 868 var i=0, iLen, j, jLen, k, kLen; 869 var sId = this.getAttribute( 'id' ); 870 var bInitHandedOff = false; 871 var defaults = DataTable.defaults; 872 var $this = $(this); 873 874 875 /* Sanity check */ 876 if ( this.nodeName.toLowerCase() != 'table' ) 877 { 878 _fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 ); 879 return; 880 } 881 882 /* Backwards compatibility for the defaults */ 883 _fnCompatOpts( defaults ); 884 _fnCompatCols( defaults.column ); 885 886 /* Convert the camel-case defaults to Hungarian */ 887 _fnCamelToHungarian( defaults, defaults, true ); 888 _fnCamelToHungarian( defaults.column, defaults.column, true ); 889 890 /* Setting up the initialisation object */ 891 _fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ), true ); 892 893 894 895 /* Check to see if we are re-initialising a table */ 896 var allSettings = DataTable.settings; 897 for ( i=0, iLen=allSettings.length ; i<iLen ; i++ ) 898 { 899 var s = allSettings[i]; 900 901 /* Base check on table node */ 902 if ( 903 s.nTable == this || 904 (s.nTHead && s.nTHead.parentNode == this) || 905 (s.nTFoot && s.nTFoot.parentNode == this) 906 ) { 907 var bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve; 908 var bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy; 909 910 if ( emptyInit || bRetrieve ) 911 { 912 return s.oInstance; 913 } 914 else if ( bDestroy ) 915 { 916 s.oInstance.fnDestroy(); 917 break; 918 } 919 else 920 { 921 _fnLog( s, 0, 'Cannot reinitialise DataTable', 3 ); 922 return; 923 } 924 } 925 926 /* If the element we are initialising has the same ID as a table which was previously 927 * initialised, but the table nodes don't match (from before) then we destroy the old 928 * instance by simply deleting it. This is under the assumption that the table has been 929 * destroyed by other methods. Anyone using non-id selectors will need to do this manually 930 */ 931 if ( s.sTableId == this.id ) 932 { 933 allSettings.splice( i, 1 ); 934 break; 935 } 936 } 937 938 /* Ensure the table has an ID - required for accessibility */ 939 if ( sId === null || sId === "" ) 940 { 941 sId = "DataTables_Table_"+(DataTable.ext._unique++); 942 this.id = sId; 943 } 944 945 /* Create the settings object for this table and set some of the default parameters */ 946 var oSettings = $.extend( true, {}, DataTable.models.oSettings, { 947 "sDestroyWidth": $this[0].style.width, 948 "sInstance": sId, 949 "sTableId": sId 950 } ); 951 oSettings.nTable = this; 952 oSettings.oApi = _that.internal; 953 oSettings.oInit = oInit; 954 955 allSettings.push( oSettings ); 956 957 // Need to add the instance after the instance after the settings object has been added 958 // to the settings array, so we can self reference the table instance if more than one 959 oSettings.oInstance = (_that.length===1) ? _that : $this.dataTable(); 960 961 // Backwards compatibility, before we apply all the defaults 962 _fnCompatOpts( oInit ); 963 _fnLanguageCompat( oInit.oLanguage ); 964 965 // If the length menu is given, but the init display length is not, use the length menu 966 if ( oInit.aLengthMenu && ! oInit.iDisplayLength ) 967 { 968 oInit.iDisplayLength = Array.isArray( oInit.aLengthMenu[0] ) ? 969 oInit.aLengthMenu[0][0] : oInit.aLengthMenu[0]; 970 } 971 972 // Apply the defaults and init options to make a single init object will all 973 // options defined from defaults and instance options. 974 oInit = _fnExtend( $.extend( true, {}, defaults ), oInit ); 975 976 977 // Map the initialisation options onto the settings object 978 _fnMap( oSettings.oFeatures, oInit, [ 979 "bPaginate", 980 "bLengthChange", 981 "bFilter", 982 "bSort", 983 "bSortMulti", 984 "bInfo", 985 "bProcessing", 986 "bAutoWidth", 987 "bSortClasses", 988 "bServerSide", 989 "bDeferRender" 990 ] ); 991 _fnMap( oSettings, oInit, [ 992 "asStripeClasses", 993 "ajax", 994 "fnServerData", 995 "fnFormatNumber", 996 "sServerMethod", 997 "aaSorting", 998 "aaSortingFixed", 999 "aLengthMenu", 1000 "sPaginationType", 1001 "sAjaxSource", 1002 "sAjaxDataProp", 1003 "iStateDuration", 1004 "sDom", 1005 "bSortCellsTop", 1006 "iTabIndex", 1007 "fnStateLoadCallback", 1008 "fnStateSaveCallback", 1009 "renderer", 1010 "searchDelay", 1011 "rowId", 1012 [ "iCookieDuration", "iStateDuration" ], // backwards compat 1013 [ "oSearch", "oPreviousSearch" ], 1014 [ "aoSearchCols", "aoPreSearchCols" ], 1015 [ "iDisplayLength", "_iDisplayLength" ] 1016 ] ); 1017 _fnMap( oSettings.oScroll, oInit, [ 1018 [ "sScrollX", "sX" ], 1019 [ "sScrollXInner", "sXInner" ], 1020 [ "sScrollY", "sY" ], 1021 [ "bScrollCollapse", "bCollapse" ] 1022 ] ); 1023 _fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" ); 1024 1025 /* Callback functions which are array driven */ 1026 _fnCallbackReg( oSettings, 'aoDrawCallback', oInit.fnDrawCallback, 'user' ); 1027 _fnCallbackReg( oSettings, 'aoServerParams', oInit.fnServerParams, 'user' ); 1028 _fnCallbackReg( oSettings, 'aoStateSaveParams', oInit.fnStateSaveParams, 'user' ); 1029 _fnCallbackReg( oSettings, 'aoStateLoadParams', oInit.fnStateLoadParams, 'user' ); 1030 _fnCallbackReg( oSettings, 'aoStateLoaded', oInit.fnStateLoaded, 'user' ); 1031 _fnCallbackReg( oSettings, 'aoRowCallback', oInit.fnRowCallback, 'user' ); 1032 _fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow, 'user' ); 1033 _fnCallbackReg( oSettings, 'aoHeaderCallback', oInit.fnHeaderCallback, 'user' ); 1034 _fnCallbackReg( oSettings, 'aoFooterCallback', oInit.fnFooterCallback, 'user' ); 1035 _fnCallbackReg( oSettings, 'aoInitComplete', oInit.fnInitComplete, 'user' ); 1036 _fnCallbackReg( oSettings, 'aoPreDrawCallback', oInit.fnPreDrawCallback, 'user' ); 1037 1038 oSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId ); 1039 1040 /* Browser support detection */ 1041 _fnBrowserDetect( oSettings ); 1042 1043 var oClasses = oSettings.oClasses; 1044 1045 $.extend( oClasses, DataTable.ext.classes, oInit.oClasses ); 1046 $this.addClass( oClasses.sTable ); 1047 1048 1049 if ( oSettings.iInitDisplayStart === undefined ) 1050 { 1051 /* Display start point, taking into account the save saving */ 1052 oSettings.iInitDisplayStart = oInit.iDisplayStart; 1053 oSettings._iDisplayStart = oInit.iDisplayStart; 1054 } 1055 1056 if ( oInit.iDeferLoading !== null ) 1057 { 1058 oSettings.bDeferLoading = true; 1059 var tmp = Array.isArray( oInit.iDeferLoading ); 1060 oSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading; 1061 oSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading; 1062 } 1063 1064 /* Language definitions */ 1065 var oLanguage = oSettings.oLanguage; 1066 $.extend( true, oLanguage, oInit.oLanguage ); 1067 1068 if ( oLanguage.sUrl ) 1069 { 1070 /* Get the language definitions from a file - because this Ajax call makes the language 1071 * get async to the remainder of this function we use bInitHandedOff to indicate that 1072 * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor 1073 */ 1074 $.ajax( { 1075 dataType: 'json', 1076 url: oLanguage.sUrl, 1077 success: function ( json ) { 1078 _fnCamelToHungarian( defaults.oLanguage, json ); 1079 _fnLanguageCompat( json ); 1080 $.extend( true, oLanguage, json, oSettings.oInit.oLanguage ); 1081 1082 _fnCallbackFire( oSettings, null, 'i18n', [oSettings]); 1083 _fnInitialise( oSettings ); 1084 }, 1085 error: function () { 1086 // Error occurred loading language file, continue on as best we can 1087 _fnInitialise( oSettings ); 1088 } 1089 } ); 1090 bInitHandedOff = true; 1091 } 1092 else { 1093 _fnCallbackFire( oSettings, null, 'i18n', [oSettings]); 1094 } 1095 1096 /* 1097 * Stripes 1098 */ 1099 if ( oInit.asStripeClasses === null ) 1100 { 1101 oSettings.asStripeClasses =[ 1102 oClasses.sStripeOdd, 1103 oClasses.sStripeEven 1104 ]; 1105 } 1106 1107 /* Remove row stripe classes if they are already on the table row */ 1108 var stripeClasses = oSettings.asStripeClasses; 1109 var rowOne = $this.children('tbody').find('tr').eq(0); 1110 if ( $.inArray( true, $.map( stripeClasses, function(el, i) { 1111 return rowOne.hasClass(el); 1112 } ) ) !== -1 ) { 1113 $('tbody tr', this).removeClass( stripeClasses.join(' ') ); 1114 oSettings.asDestroyStripes = stripeClasses.slice(); 1115 } 1116 1117 /* 1118 * Columns 1119 * See if we should load columns automatically or use defined ones 1120 */ 1121 var anThs = []; 1122 var aoColumnsInit; 1123 var nThead = this.getElementsByTagName('thead'); 1124 if ( nThead.length !== 0 ) 1125 { 1126 _fnDetectHeader( oSettings.aoHeader, nThead[0] ); 1127 anThs = _fnGetUniqueThs( oSettings ); 1128 } 1129 1130 /* If not given a column array, generate one with nulls */ 1131 if ( oInit.aoColumns === null ) 1132 { 1133 aoColumnsInit = []; 1134 for ( i=0, iLen=anThs.length ; i<iLen ; i++ ) 1135 { 1136 aoColumnsInit.push( null ); 1137 } 1138 } 1139 else 1140 { 1141 aoColumnsInit = oInit.aoColumns; 1142 } 1143 1144 /* Add the columns */ 1145 for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ ) 1146 { 1147 _fnAddColumn( oSettings, anThs ? anThs[i] : null ); 1148 } 1149 1150 /* Apply the column definitions */ 1151 _fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) { 1152 _fnColumnOptions( oSettings, iCol, oDef ); 1153 } ); 1154 1155 /* HTML5 attribute detection - build an mData object automatically if the 1156 * attributes are found 1157 */ 1158 if ( rowOne.length ) { 1159 var a = function ( cell, name ) { 1160 return cell.getAttribute( 'data-'+name ) !== null ? name : null; 1161 }; 1162 1163 $( rowOne[0] ).children('th, td').each( function (i, cell) { 1164 var col = oSettings.aoColumns[i]; 1165 1166 if (! col) { 1167 _fnLog( oSettings, 0, 'Incorrect column count', 18 ); 1168 } 1169 1170 if ( col.mData === i ) { 1171 var sort = a( cell, 'sort' ) || a( cell, 'order' ); 1172 var filter = a( cell, 'filter' ) || a( cell, 'search' ); 1173 1174 if ( sort !== null || filter !== null ) { 1175 col.mData = { 1176 _: i+'.display', 1177 sort: sort !== null ? i+'.@data-'+sort : undefined, 1178 type: sort !== null ? i+'.@data-'+sort : undefined, 1179 filter: filter !== null ? i+'.@data-'+filter : undefined 1180 }; 1181 col._isArrayHost = true; 1182 1183 _fnColumnOptions( oSettings, i ); 1184 } 1185 } 1186 } ); 1187 } 1188 1189 var features = oSettings.oFeatures; 1190 var loadedInit = function () { 1191 /* 1192 * Sorting 1193 * @todo For modularisation (1.11) this needs to do into a sort start up handler 1194 */ 1195 1196 // If aaSorting is not defined, then we use the first indicator in asSorting 1197 // in case that has been altered, so the default sort reflects that option 1198 if ( oInit.aaSorting === undefined ) { 1199 var sorting = oSettings.aaSorting; 1200 for ( i=0, iLen=sorting.length ; i<iLen ; i++ ) { 1201 sorting[i][1] = oSettings.aoColumns[ i ].asSorting[0]; 1202 } 1203 } 1204 1205 /* Do a first pass on the sorting classes (allows any size changes to be taken into 1206 * account, and also will apply sorting disabled classes if disabled 1207 */ 1208 _fnSortingClasses( oSettings ); 1209 1210 if ( features.bSort ) { 1211 _fnCallbackReg( oSettings, 'aoDrawCallback', function () { 1212 if ( oSettings.bSorted ) { 1213 var aSort = _fnSortFlatten( oSettings ); 1214 var sortedColumns = {}; 1215 1216 $.each( aSort, function (i, val) { 1217 sortedColumns[ val.src ] = val.dir; 1218 } ); 1219 1220 _fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] ); 1221 _fnSortAria( oSettings ); 1222 } 1223 } ); 1224 } 1225 1226 _fnCallbackReg( oSettings, 'aoDrawCallback', function () { 1227 if ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) { 1228 _fnSortingClasses( oSettings ); 1229 } 1230 }, 'sc' ); 1231 1232 1233 /* 1234 * Final init 1235 * Cache the header, body and footer as required, creating them if needed 1236 */ 1237 1238 // Work around for Webkit bug 83867 - store the caption-side before removing from doc 1239 var captions = $this.children('caption').each( function () { 1240 this._captionSide = $(this).css('caption-side'); 1241 } ); 1242 1243 var thead = $this.children('thead'); 1244 if ( thead.length === 0 ) { 1245 thead = $('<thead/>').appendTo($this); 1246 } 1247 oSettings.nTHead = thead[0]; 1248 1249 var tbody = $this.children('tbody'); 1250 if ( tbody.length === 0 ) { 1251 tbody = $('<tbody/>').insertAfter(thead); 1252 } 1253 oSettings.nTBody = tbody[0]; 1254 1255 var tfoot = $this.children('tfoot'); 1256 if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") ) { 1257 // If we are a scrolling table, and no footer has been given, then we need to create 1258 // a tfoot element for the caption element to be appended to 1259 tfoot = $('<tfoot/>').appendTo($this); 1260 } 1261 1262 if ( tfoot.length === 0 || tfoot.children().length === 0 ) { 1263 $this.addClass( oClasses.sNoFooter ); 1264 } 1265 else if ( tfoot.length > 0 ) { 1266 oSettings.nTFoot = tfoot[0]; 1267 _fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot ); 1268 } 1269 1270 /* Check if there is data passing into the constructor */ 1271 if ( oInit.aaData ) { 1272 for ( i=0 ; i<oInit.aaData.length ; i++ ) { 1273 _fnAddData( oSettings, oInit.aaData[ i ] ); 1274 } 1275 } 1276 else if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' ) { 1277 /* Grab the data from the page - only do this when deferred loading or no Ajax 1278 * source since there is no point in reading the DOM data if we are then going 1279 * to replace it with Ajax data 1280 */ 1281 _fnAddTr( oSettings, $(oSettings.nTBody).children('tr') ); 1282 } 1283 1284 /* Copy the data index array */ 1285 oSettings.aiDisplay = oSettings.aiDisplayMaster.slice(); 1286 1287 /* Initialisation complete - table can be drawn */ 1288 oSettings.bInitialised = true; 1289 1290 /* Check if we need to initialise the table (it might not have been handed off to the 1291 * language processor) 1292 */ 1293 if ( bInitHandedOff === false ) { 1294 _fnInitialise( oSettings ); 1295 } 1296 }; 1297 1298 /* Must be done after everything which can be overridden by the state saving! */ 1299 _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' ); 1300 1301 if ( oInit.bStateSave ) 1302 { 1303 features.bStateSave = true; 1304 _fnLoadState( oSettings, oInit, loadedInit ); 1305 } 1306 else { 1307 loadedInit(); 1308 } 1309 1310 } ); 1311 _that = null; 1312 return this; 1313 }; 1314 1315 1316 /* 1317 * It is useful to have variables which are scoped locally so only the 1318 * DataTables functions can access them and they don't leak into global space. 1319 * At the same time these functions are often useful over multiple files in the 1320 * core and API, so we list, or at least document, all variables which are used 1321 * by DataTables as private variables here. This also ensures that there is no 1322 * clashing of variable names and that they can easily referenced for reuse. 1323 */ 1324 1325 1326 // Defined else where 1327 // _selector_run 1328 // _selector_opts 1329 // _selector_first 1330 // _selector_row_indexes 1331 1332 var _ext; // DataTable.ext 1333 var _Api; // DataTable.Api 1334 var _api_register; // DataTable.Api.register 1335 var _api_registerPlural; // DataTable.Api.registerPlural 1336 1337 var _re_dic = {}; 1338 var _re_new_lines = /[\r\n\u2028]/g; 1339 var _re_html = /<.*?>/g; 1340 1341 // This is not strict ISO8601 - Date.parse() is quite lax, although 1342 // implementations differ between browsers. 1343 var _re_date = /^\d{2,4}[\.\/\-]\d{1,2}[\.\/\-]\d{1,2}([T ]{1}\d{1,2}[:\.]\d{2}([\.:]\d{2})?)?$/; 1344 1345 // Escape regular expression special characters 1346 var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' ); 1347 1348 // http://en.wikipedia.org/wiki/Foreign_exchange_market 1349 // - \u20BD - Russian ruble. 1350 // - \u20a9 - South Korean Won 1351 // - \u20BA - Turkish Lira 1352 // - \u20B9 - Indian Rupee 1353 // - R - Brazil (R$) and South Africa 1354 // - fr - Swiss Franc 1355 // - kr - Swedish krona, Norwegian krone and Danish krone 1356 // - \u2009 is thin space and \u202F is narrow no-break space, both used in many 1357 // - É - Bitcoin 1358 // - Î - Ethereum 1359 // standards as thousands separators. 1360 var _re_formatted_numeric = /['\u00A0,$£â¬Â¥%\u2009\u202F\u20BD\u20a9\u20BArfkÉÎ]/gi; 1361 1362 1363 var _empty = function ( d ) { 1364 return !d || d === true || d === '-' ? true : false; 1365 }; 1366 1367 1368 var _intVal = function ( s ) { 1369 var integer = parseInt( s, 10 ); 1370 return !isNaN(integer) && isFinite(s) ? integer : null; 1371 }; 1372 1373 // Convert from a formatted number with characters other than `.` as the 1374 // decimal place, to a Javascript number 1375 var _numToDecimal = function ( num, decimalPoint ) { 1376 // Cache created regular expressions for speed as this function is called often 1377 if ( ! _re_dic[ decimalPoint ] ) { 1378 _re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' ); 1379 } 1380 return typeof num === 'string' && decimalPoint !== '.' ? 1381 num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) : 1382 num; 1383 }; 1384 1385 1386 var _isNumber = function ( d, decimalPoint, formatted ) { 1387
vendor: 2,585 bytes, lines 1387-1521
1387let type = typeof d; 1388 var strType = type === 'string'; 1389 1390 if ( type === 'number' || type === 'bigint') { 1391 return true; 1392 } 1393 1394 // If empty return immediately so there must be a number if it is a 1395 // formatted string (this stops the string "k", or "kr", etc being detected 1396 // as a formatted number for currency 1397 if ( _empty( d ) ) { 1398 return true; 1399 } 1400 1401 if ( decimalPoint && strType ) { 1402 d = _numToDecimal( d, decimalPoint ); 1403 } 1404 1405 if ( formatted && strType ) { 1406 d = d.replace( _re_formatted_numeric, '' ); 1407 } 1408 1409 return !isNaN( parseFloat(d) ) && isFinite( d ); 1410 }; 1411 1412 1413 // A string without HTML in it can be considered to be HTML still 1414 var _isHtml = function ( d ) { 1415 return _empty( d ) || typeof d === 'string'; 1416 }; 1417 1418 1419 var _htmlNumeric = function ( d, decimalPoint, formatted ) { 1420 if ( _empty( d ) ) { 1421 return true; 1422 } 1423 1424 var html = _isHtml( d ); 1425 return ! html ? 1426 null : 1427 _isNumber( _stripHtml( d ), decimalPoint, formatted ) ? 1428 true : 1429 null; 1430 }; 1431 1432 1433 var _pluck = function ( a, prop, prop2 ) { 1434 var out = []; 1435 var i=0, ien=a.length; 1436 1437 // Could have the test in the loop for slightly smaller code, but speed 1438 // is essential here 1439 if ( prop2 !== undefined ) { 1440 for ( ; i<ien ; i++ ) { 1441 if ( a[i] && a[i][ prop ] ) { 1442 out.push( a[i][ prop ][ prop2 ] ); 1443 } 1444 } 1445 } 1446 else { 1447 for ( ; i<ien ; i++ ) { 1448 if ( a[i] ) { 1449 out.push( a[i][ prop ] ); 1450 } 1451 } 1452 } 1453 1454 return out; 1455 }; 1456 1457 1458 // Basically the same as _pluck, but rather than looping over `a` we use `order` 1459 // as the indexes to pick from `a` 1460 var _pluck_order = function ( a, order, prop, prop2 ) 1461 { 1462 var out = []; 1463 var i=0, ien=order.length; 1464 1465 // Could have the test in the loop for slightly smaller code, but speed 1466 // is essential here 1467 if ( prop2 !== undefined ) { 1468 for ( ; i<ien ; i++ ) { 1469 if ( a[ order[i] ][ prop ] ) { 1470 out.push( a[ order[i] ][ prop ][ prop2 ] ); 1471 } 1472 } 1473 } 1474 else { 1475 for ( ; i<ien ; i++ ) { 1476 out.push( a[ order[i] ][ prop ] ); 1477 } 1478 } 1479 1480 return out; 1481 }; 1482 1483 1484 var _range = function ( len, start ) 1485 { 1486 var out = []; 1487 var end; 1488 1489 if ( start === undefined ) { 1490 start = 0; 1491 end = len; 1492 } 1493 else { 1494 end = start; 1495 start = len; 1496 } 1497 1498 for ( var i=start ; i<end ; i++ ) { 1499 out.push( i ); 1500 } 1501 1502 return out; 1503 }; 1504 1505 1506 var _removeEmpty = function ( a ) 1507 { 1508 var out = []; 1509 1510 for ( var i=0, ien=a.length ; i<ien ; i++ ) { 1511 if ( a[i] ) { // careful - will remove all falsy values! 1512 out.push( a[i] ); 1513 } 1514 } 1515 1516 return out; 1517 }; 1518 1519 1520 var _stripHtml = function ( d ) { 1521 return d.replace( _re_html, '' );
vendor: 10,574 bytes, lines 1521-1895
1521 1522 }; 1523 1524 1525 /** 1526 * Determine if all values in the array are unique. This means we can short 1527 * cut the _unique method at the cost of a single loop. A sorted array is used 1528 * to easily check the values. 1529 * 1530 * @param {array} src Source array 1531 * @return {boolean} true if all unique, false otherwise 1532 * @ignore 1533 */ 1534 var _areAllUnique = function ( src ) { 1535 if ( src.length < 2 ) { 1536 return true; 1537 } 1538 1539 var sorted = src.slice().sort(); 1540 var last = sorted[0]; 1541 1542 for ( var i=1, ien=sorted.length ; i<ien ; i++ ) { 1543 if ( sorted[i] === last ) { 1544 return false; 1545 } 1546 1547 last = sorted[i]; 1548 } 1549 1550 return true; 1551 }; 1552 1553 1554 /** 1555 * Find the unique elements in a source array. 1556 * 1557 * @param {array} src Source array 1558 * @return {array} Array of unique items 1559 * @ignore 1560 */ 1561 var _unique = function ( src ) 1562 { 1563 if ( _areAllUnique( src ) ) { 1564 return src.slice(); 1565 } 1566 1567 // A faster unique method is to use object keys to identify used values, 1568 // but this doesn't work with arrays or objects, which we must also 1569 // consider. See jsperf.com/compare-array-unique-versions/4 for more 1570 // information. 1571 var 1572 out = [], 1573 val, 1574 i, ien=src.length, 1575 j, k=0; 1576 1577 again: for ( i=0 ; i<ien ; i++ ) { 1578 val = src[i]; 1579 1580 for ( j=0 ; j<k ; j++ ) { 1581 if ( out[j] === val ) { 1582 continue again; 1583 } 1584 } 1585 1586 out.push( val ); 1587 k++; 1588 } 1589 1590 return out; 1591 }; 1592 1593 // Surprisingly this is faster than [].concat.apply 1594 // https://jsperf.com/flatten-an-array-loop-vs-reduce/2 1595 var _flatten = function (out, val) { 1596 if (Array.isArray(val)) { 1597 for (var i=0 ; i<val.length ; i++) { 1598 _flatten(out, val[i]); 1599 } 1600 } 1601 else { 1602 out.push(val); 1603 } 1604 1605 return out; 1606 } 1607 1608 var _includes = function (search, start) { 1609 if (start === undefined) { 1610 start = 0; 1611 } 1612 1613 return this.indexOf(search, start) !== -1; 1614 }; 1615 1616 // Array.isArray polyfill. 1617 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray 1618 if (! Array.isArray) { 1619 Array.isArray = function(arg) { 1620 return Object.prototype.toString.call(arg) === '[object Array]'; 1621 }; 1622 } 1623 1624 if (! Array.prototype.includes) { 1625 Array.prototype.includes = _includes; 1626 } 1627 1628 // .trim() polyfill 1629 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/trim 1630 if (!String.prototype.trim) { 1631 String.prototype.trim = function () { 1632 return this.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ''); 1633 }; 1634 } 1635 1636 if (! String.prototype.includes) { 1637 String.prototype.includes = _includes; 1638 } 1639 1640 /** 1641 * DataTables utility methods 1642 * 1643 * This namespace provides helper methods that DataTables uses internally to 1644 * create a DataTable, but which are not exclusively used only for DataTables. 1645 * These methods can be used by extension authors to save the duplication of 1646 * code. 1647 * 1648 * @namespace 1649 */ 1650 DataTable.util = { 1651 /** 1652 * Throttle the calls to a function. Arguments and context are maintained 1653 * for the throttled function. 1654 * 1655 * @param {function} fn Function to be called 1656 * @param {integer} freq Call frequency in mS 1657 * @return {function} Wrapped function 1658 */ 1659 throttle: function ( fn, freq ) { 1660 var 1661 frequency = freq !== undefined ? freq : 200, 1662 last, 1663 timer; 1664 1665 return function () { 1666 var 1667 that = this, 1668 now = +new Date(), 1669 args = arguments; 1670 1671 if ( last && now < last + frequency ) { 1672 clearTimeout( timer ); 1673 1674 timer = setTimeout( function () { 1675 last = undefined; 1676 fn.apply( that, args ); 1677 }, frequency ); 1678 } 1679 else { 1680 last = now; 1681 fn.apply( that, args ); 1682 } 1683 }; 1684 }, 1685 1686 1687 /** 1688 * Escape a string such that it can be used in a regular expression 1689 * 1690 * @param {string} val string to escape 1691 * @returns {string} escaped string 1692 */ 1693 escapeRegex: function ( val ) { 1694 return val.replace( _re_escape_regex, '\\$1' ); 1695 }, 1696 1697 /** 1698 * Create a function that will write to a nested object or array 1699 * @param {*} source JSON notation string 1700 * @returns Write function 1701 */ 1702 set: function ( source ) { 1703 if ( $.isPlainObject( source ) ) { 1704 /* Unlike get, only the underscore (global) option is used for for 1705 * setting data since we don't know the type here. This is why an object 1706 * option is not documented for `mData` (which is read/write), but it is 1707 * for `mRender` which is read only. 1708 */ 1709 return DataTable.util.set( source._ ); 1710 } 1711 else if ( source === null ) { 1712 // Nothing to do when the data source is null 1713 return function () {}; 1714 } 1715 else if ( typeof source === 'function' ) { 1716 return function (data, val, meta) { 1717 source( data, 'set', val, meta ); 1718 }; 1719 } 1720 else if ( typeof source === 'string' && (source.indexOf('.') !== -1 || 1721 source.indexOf('[') !== -1 || source.indexOf('(') !== -1) ) 1722 { 1723 // Like the get, we need to get data from a nested object 1724 var setData = function (data, val, src) { 1725 var a = _fnSplitObjNotation( src ), b; 1726 var aLast = a[a.length-1]; 1727 var arrayNotation, funcNotation, o, innerSrc; 1728 1729 for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ ) { 1730 // Protect against prototype pollution 1731 if (a[i] === '__proto__' || a[i] === 'constructor') { 1732 throw new Error('Cannot set prototype values'); 1733 } 1734 1735 // Check if we are dealing with an array notation request 1736 arrayNotation = a[i].match(__reArray); 1737 funcNotation = a[i].match(__reFn); 1738 1739 if ( arrayNotation ) { 1740 a[i] = a[i].replace(__reArray, ''); 1741 data[ a[i] ] = []; 1742 1743 // Get the remainder of the nested object to set so we can recurse 1744 b = a.slice(); 1745 b.splice( 0, i+1 ); 1746 innerSrc = b.join('.'); 1747 1748 // Traverse each entry in the array setting the properties requested 1749 if ( Array.isArray( val ) ) { 1750 for ( var j=0, jLen=val.length ; j<jLen ; j++ ) { 1751 o = {}; 1752 setData( o, val[j], innerSrc ); 1753 data[ a[i] ].push( o ); 1754 } 1755 } 1756 else { 1757 // We've been asked to save data to an array, but it 1758 // isn't array data to be saved. Best that can be done 1759 // is to just save the value. 1760 data[ a[i] ] = val; 1761 } 1762 1763 // The inner call to setData has already traversed through the remainder 1764 // of the source and has set the data, thus we can exit here 1765 return; 1766 } 1767 else if ( funcNotation ) { 1768 // Function call 1769 a[i] = a[i].replace(__reFn, ''); 1770 data = data[ a[i] ]( val ); 1771 } 1772 1773 // If the nested object doesn't currently exist - since we are 1774 // trying to set the value - create it 1775 if ( data[ a[i] ] === null || data[ a[i] ] === undefined ) { 1776 data[ a[i] ] = {}; 1777 } 1778 data = data[ a[i] ]; 1779 } 1780 1781 // Last item in the input - i.e, the actual set 1782 if ( aLast.match(__reFn ) ) { 1783 // Function call 1784 data = data[ aLast.replace(__reFn, '') ]( val ); 1785 } 1786 else { 1787 // If array notation is used, we just want to strip it and use the property name 1788 // and assign the value. If it isn't used, then we get the result we want anyway 1789 data[ aLast.replace(__reArray, '') ] = val; 1790 } 1791 }; 1792 1793 return function (data, val) { // meta is also passed in, but not used 1794 return setData( data, val, source ); 1795 }; 1796 } 1797 else { 1798 // Array or flat object mapping 1799 return function (data, val) { // meta is also passed in, but not used 1800 data[source] = val; 1801 }; 1802 } 1803 }, 1804 1805 /** 1806 * Create a function that will read nested objects from arrays, based on JSON notation 1807 * @param {*} source JSON notation string 1808 * @returns Value read 1809 */ 1810 get: function ( source ) { 1811 if ( $.isPlainObject( source ) ) { 1812 // Build an object of get functions, and wrap them in a single call 1813 var o = {}; 1814 $.each( source, function (key, val) { 1815 if ( val ) { 1816 o[key] = DataTable.util.get( val ); 1817 } 1818 } ); 1819 1820 return function (data, type, row, meta) { 1821 var t = o[type] || o._; 1822 return t !== undefined ? 1823 t(data, type, row, meta) : 1824 data; 1825 }; 1826 } 1827 else if ( source === null ) { 1828 // Give an empty string for rendering / sorting etc 1829 return function (data) { // type, row and meta also passed, but not used 1830 return data; 1831 }; 1832 } 1833 else if ( typeof source === 'function' ) { 1834 return function (data, type, row, meta) { 1835 return source( data, type, row, meta ); 1836 }; 1837 } 1838 else if ( typeof source === 'string' && (source.indexOf('.') !== -1 || 1839 source.indexOf('[') !== -1 || source.indexOf('(') !== -1) ) 1840 { 1841 /* If there is a . in the source string then the data source is in a 1842 * nested object so we loop over the data for each level to get the next 1843 * level down. On each loop we test for undefined, and if found immediately 1844 * return. This allows entire objects to be missing and sDefaultContent to 1845 * be used if defined, rather than throwing an error 1846 */ 1847 var fetchData = function (data, type, src) { 1848 var arrayNotation, funcNotation, out, innerSrc; 1849 1850 if ( src !== "" ) { 1851 var a = _fnSplitObjNotation( src ); 1852 1853 for ( var i=0, iLen=a.length ; i<iLen ; i++ ) { 1854 // Check if we are dealing with special notation 1855 arrayNotation = a[i].match(__reArray); 1856 funcNotation = a[i].match(__reFn); 1857 1858 if ( arrayNotation ) { 1859 // Array notation 1860 a[i] = a[i].replace(__reArray, ''); 1861 1862 // Condition allows simply [] to be passed in 1863 if ( a[i] !== "" ) { 1864 data = data[ a[i] ]; 1865 } 1866 out = []; 1867 1868 // Get the remainder of the nested object to get 1869 a.splice( 0, i+1 ); 1870 innerSrc = a.join('.'); 1871 1872 // Traverse each entry in the array getting the properties requested 1873 if ( Array.isArray( data ) ) { 1874 for ( var j=0, jLen=data.length ; j<jLen ; j++ ) { 1875 out.push( fetchData( data[j], type, innerSrc ) ); 1876 } 1877 } 1878 1879 // If a string is given in between the array notation indicators, that 1880 // is used to join the strings together, otherwise an array is returned 1881 var join = arrayNotation[0].substring(1, arrayNotation[0].length-1); 1882 data = (join==="") ? out : out.join(join); 1883 1884 // The inner call to fetchData has already traversed through the remainder 1885 // of the source requested, so we exit from the loop 1886 break; 1887 } 1888 else if ( funcNotation ) { 1889 // Function call 1890 a[i] = a[i].replace(__reFn, ''); 1891 data = data[ a[i] ](); 1892 continue; 1893 } 1894 1895 if (
1895 data === null
vendor: 60,603 bytes, lines 1895-4066
1895 || data[ a[i] ] === undefined ) { 1896 return undefined; 1897 } 1898 1899 data = data[ a[i] ]; 1900 } 1901 } 1902 1903 return data; 1904 }; 1905 1906 return function (data, type) { // row and meta also passed, but not used 1907 return fetchData( data, type, source ); 1908 }; 1909 } 1910 else { 1911 // Array or flat object mapping 1912 return function (data, type) { // row and meta also passed, but not used 1913 return data[source]; 1914 }; 1915 } 1916 } 1917 }; 1918 1919 1920 1921 /** 1922 * Create a mapping object that allows camel case parameters to be looked up 1923 * for their Hungarian counterparts. The mapping is stored in a private 1924 * parameter called `_hungarianMap` which can be accessed on the source object. 1925 * @param {object} o 1926 * @memberof DataTable#oApi 1927 */ 1928 function _fnHungarianMap ( o ) 1929 { 1930 var 1931 hungarian = 'a aa ai ao as b fn i m o s ', 1932 match, 1933 newKey, 1934 map = {}; 1935 1936 $.each( o, function (key, val) { 1937 match = key.match(/^([^A-Z]+?)([A-Z])/); 1938 1939 if ( match && hungarian.indexOf(match[1]+' ') !== -1 ) 1940 { 1941 newKey = key.replace( match[0], match[2].toLowerCase() ); 1942 map[ newKey ] = key; 1943 1944 if ( match[1] === 'o' ) 1945 { 1946 _fnHungarianMap( o[key] ); 1947 } 1948 } 1949 } ); 1950 1951 o._hungarianMap = map; 1952 } 1953 1954 1955 /** 1956 * Convert from camel case parameters to Hungarian, based on a Hungarian map 1957 * created by _fnHungarianMap. 1958 * @param {object} src The model object which holds all parameters that can be 1959 * mapped. 1960 * @param {object} user The object to convert from camel case to Hungarian. 1961 * @param {boolean} force When set to `true`, properties which already have a 1962 * Hungarian value in the `user` object will be overwritten. Otherwise they 1963 * won't be. 1964 * @memberof DataTable#oApi 1965 */ 1966 function _fnCamelToHungarian ( src, user, force ) 1967 { 1968 if ( ! src._hungarianMap ) { 1969 _fnHungarianMap( src ); 1970 } 1971 1972 var hungarianKey; 1973 1974 $.each( user, function (key, val) { 1975 hungarianKey = src._hungarianMap[ key ]; 1976 1977 if ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) ) 1978 { 1979 // For objects, we need to buzz down into the object to copy parameters 1980 if ( hungarianKey.charAt(0) === 'o' ) 1981 { 1982 // Copy the camelCase options over to the hungarian 1983 if ( ! user[ hungarianKey ] ) { 1984 user[ hungarianKey ] = {}; 1985 } 1986 $.extend( true, user[hungarianKey], user[key] ); 1987 1988 _fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force ); 1989 } 1990 else { 1991 user[hungarianKey] = user[ key ]; 1992 } 1993 } 1994 } ); 1995 } 1996 1997 1998 /** 1999 * Language compatibility - when certain options are given, and others aren't, we 2000 * need to duplicate the values over, in order to provide backwards compatibility 2001 * with older language files. 2002 * @param {object} oSettings dataTables settings object 2003 * @memberof DataTable#oApi 2004 */ 2005 function _fnLanguageCompat( lang ) 2006 { 2007 // Note the use of the Hungarian notation for the parameters in this method as 2008 // this is called after the mapping of camelCase to Hungarian 2009 var defaults = DataTable.defaults.oLanguage; 2010 2011 // Default mapping 2012 var defaultDecimal = defaults.sDecimal; 2013 if ( defaultDecimal ) { 2014 _addNumericSort( defaultDecimal ); 2015 } 2016 2017 if ( lang ) { 2018 var zeroRecords = lang.sZeroRecords; 2019 2020 // Backwards compatibility - if there is no sEmptyTable given, then use the same as 2021 // sZeroRecords - assuming that is given. 2022 if ( ! lang.sEmptyTable && zeroRecords && 2023 defaults.sEmptyTable === "No data available in table" ) 2024 { 2025 _fnMap( lang, lang, 'sZeroRecords', 'sEmptyTable' ); 2026 } 2027 2028 // Likewise with loading records 2029 if ( ! lang.sLoadingRecords && zeroRecords && 2030 defaults.sLoadingRecords === "Loading..." ) 2031 { 2032 _fnMap( lang, lang, 'sZeroRecords', 'sLoadingRecords' ); 2033 } 2034 2035 // Old parameter name of the thousands separator mapped onto the new 2036 if ( lang.sInfoThousands ) { 2037 lang.sThousands = lang.sInfoThousands; 2038 } 2039 2040 var decimal = lang.sDecimal; 2041 if ( decimal && defaultDecimal !== decimal ) { 2042 _addNumericSort( decimal ); 2043 } 2044 } 2045 } 2046 2047 2048 /** 2049 * Map one parameter onto another 2050 * @param {object} o Object to map 2051 * @param {*} knew The new parameter name 2052 * @param {*} old The old parameter name 2053 */ 2054 var _fnCompatMap = function ( o, knew, old ) { 2055 if ( o[ knew ] !== undefined ) { 2056 o[ old ] = o[ knew ]; 2057 } 2058 }; 2059 2060 2061 /** 2062 * Provide backwards compatibility for the main DT options. Note that the new 2063 * options are mapped onto the old parameters, so this is an external interface 2064 * change only. 2065 * @param {object} init Object to map 2066 */ 2067 function _fnCompatOpts ( init ) 2068 { 2069 _fnCompatMap( init, 'ordering', 'bSort' ); 2070 _fnCompatMap( init, 'orderMulti', 'bSortMulti' ); 2071 _fnCompatMap( init, 'orderClasses', 'bSortClasses' ); 2072 _fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' ); 2073 _fnCompatMap( init, 'order', 'aaSorting' ); 2074 _fnCompatMap( init, 'orderFixed', 'aaSortingFixed' ); 2075 _fnCompatMap( init, 'paging', 'bPaginate' ); 2076 _fnCompatMap( init, 'pagingType', 'sPaginationType' ); 2077 _fnCompatMap( init, 'pageLength', 'iDisplayLength' ); 2078 _fnCompatMap( init, 'searching', 'bFilter' ); 2079 2080 // Boolean initialisation of x-scrolling 2081 if ( typeof init.sScrollX === 'boolean' ) { 2082 init.sScrollX = init.sScrollX ? '100%' : ''; 2083 } 2084 if ( typeof init.scrollX === 'boolean' ) { 2085 init.scrollX = init.scrollX ? '100%' : ''; 2086 } 2087 2088 // Column search objects are in an array, so it needs to be converted 2089 // element by element 2090 var searchCols = init.aoSearchCols; 2091 2092 if ( searchCols ) { 2093 for ( var i=0, ien=searchCols.length ; i<ien ; i++ ) { 2094 if ( searchCols[i] ) { 2095 _fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] ); 2096 } 2097 } 2098 } 2099 } 2100 2101 2102 /** 2103 * Provide backwards compatibility for column options. Note that the new options 2104 * are mapped onto the old parameters, so this is an external interface change 2105 * only. 2106 * @param {object} init Object to map 2107 */ 2108 function _fnCompatCols ( init ) 2109 { 2110 _fnCompatMap( init, 'orderable', 'bSortable' ); 2111 _fnCompatMap( init, 'orderData', 'aDataSort' ); 2112 _fnCompatMap( init, 'orderSequence', 'asSorting' ); 2113 _fnCompatMap( init, 'orderDataType', 'sortDataType' ); 2114 2115 // orderData can be given as an integer 2116 var dataSort = init.aDataSort; 2117 if ( typeof dataSort === 'number' && ! Array.isArray( dataSort ) ) { 2118 init.aDataSort = [ dataSort ]; 2119 } 2120 } 2121 2122 2123 /** 2124 * Browser feature detection for capabilities, quirks 2125 * @param {object} settings dataTables settings object 2126 * @memberof DataTable#oApi 2127 */ 2128 function _fnBrowserDetect( settings ) 2129 { 2130 // We don't need to do this every time DataTables is constructed, the values 2131 // calculated are specific to the browser and OS configuration which we 2132 // don't expect to change between initialisations 2133 if ( ! DataTable.__browser ) { 2134 var browser = {}; 2135 DataTable.__browser = browser; 2136 2137 // Scrolling feature / quirks detection 2138 var n = $('<div/>') 2139 .css( { 2140 position: 'fixed', 2141 top: 0, 2142 left: $(window).scrollLeft()*-1, // allow for scrolling 2143 height: 1, 2144 width: 1, 2145 overflow: 'hidden' 2146 } ) 2147 .append( 2148 $('<div/>') 2149 .css( { 2150 position: 'absolute', 2151 top: 1, 2152 left: 1, 2153 width: 100, 2154 overflow: 'scroll' 2155 } ) 2156 .append( 2157 $('<div/>') 2158 .css( { 2159 width: '100%', 2160 height: 10 2161 } ) 2162 ) 2163 ) 2164 .appendTo( 'body' ); 2165 2166 var outer = n.children(); 2167 var inner = outer.children(); 2168 2169 // Numbers below, in order, are: 2170 // inner.offsetWidth, inner.clientWidth, outer.offsetWidth, outer.clientWidth 2171 // 2172 // IE6 XP: 100 100 100 83 2173 // IE7 Vista: 100 100 100 83 2174 // IE 8+ Windows: 83 83 100 83 2175 // Evergreen Windows: 83 83 100 83 2176 // Evergreen Mac with scrollbars: 85 85 100 85 2177 // Evergreen Mac without scrollbars: 100 100 100 100 2178 2179 // Get scrollbar width 2180 browser.barWidth = outer[0].offsetWidth - outer[0].clientWidth; 2181 2182 // IE6/7 will oversize a width 100% element inside a scrolling element, to 2183 // include the width of the scrollbar, while other browsers ensure the inner 2184 // element is contained without forcing scrolling 2185 browser.bScrollOversize = inner[0].offsetWidth === 100 && outer[0].clientWidth !== 100; 2186 2187 // In rtl text layout, some browsers (most, but not all) will place the 2188 // scrollbar on the left, rather than the right. 2189 browser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1; 2190 2191 // IE8- don't provide height and width for getBoundingClientRect 2192 browser.bBounding = n[0].getBoundingClientRect().width ? true : false; 2193 2194 n.remove(); 2195 } 2196 2197 $.extend( settings.oBrowser, DataTable.__browser ); 2198 settings.oScroll.iBarWidth = DataTable.__browser.barWidth; 2199 } 2200 2201 2202 /** 2203 * Array.prototype reduce[Right] method, used for browsers which don't support 2204 * JS 1.6. Done this way to reduce code size, since we iterate either way 2205 * @param {object} settings dataTables settings object 2206 * @memberof DataTable#oApi 2207 */ 2208 function _fnReduce ( that, fn, init, start, end, inc ) 2209 { 2210 var 2211 i = start, 2212 value, 2213 isSet = false; 2214 2215 if ( init !== undefined ) { 2216 value = init; 2217 isSet = true; 2218 } 2219 2220 while ( i !== end ) { 2221 if ( ! that.hasOwnProperty(i) ) { 2222 continue; 2223 } 2224 2225 value = isSet ? 2226 fn( value, that[i], i, that ) : 2227 that[i]; 2228 2229 isSet = true; 2230 i += inc; 2231 } 2232 2233 return value; 2234 } 2235 2236 /** 2237 * Add a column to the list used for the table with default values 2238 * @param {object} oSettings dataTables settings object 2239 * @param {node} nTh The th element for this column 2240 * @memberof DataTable#oApi 2241 */ 2242 function _fnAddColumn( oSettings, nTh ) 2243 { 2244 // Add column to aoColumns array 2245 var oDefaults = DataTable.defaults.column; 2246 var iCol = oSettings.aoColumns.length; 2247 var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, { 2248 "nTh": nTh ? nTh : document.createElement('th'), 2249 "sTitle": oDefaults.sTitle ? oDefaults.sTitle : nTh ? nTh.innerHTML : '', 2250 "aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol], 2251 "mData": oDefaults.mData ? oDefaults.mData : iCol, 2252 idx: iCol 2253 } ); 2254 oSettings.aoColumns.push( oCol ); 2255 2256 // Add search object for column specific search. Note that the `searchCols[ iCol ]` 2257 // passed into extend can be undefined. This allows the user to give a default 2258 // with only some of the parameters defined, and also not give a default 2259 var searchCols = oSettings.aoPreSearchCols; 2260 searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] ); 2261 2262 // Use the default column options function to initialise classes etc 2263 _fnColumnOptions( oSettings, iCol, $(nTh).data() ); 2264 } 2265 2266 2267 /** 2268 * Apply options for a column 2269 * @param {object} oSettings dataTables settings object 2270 * @param {int} iCol column index to consider 2271 * @param {object} oOptions object with sType, bVisible and bSearchable etc 2272 * @memberof DataTable#oApi 2273 */ 2274 function _fnColumnOptions( oSettings, iCol, oOptions ) 2275 { 2276 var oCol = oSettings.aoColumns[ iCol ]; 2277 var oClasses = oSettings.oClasses; 2278 var th = $(oCol.nTh); 2279 2280 // Try to get width information from the DOM. We can't get it from CSS 2281 // as we'd need to parse the CSS stylesheet. `width` option can override 2282 if ( ! oCol.sWidthOrig ) { 2283 // Width attribute 2284 oCol.sWidthOrig = th.attr('width') || null; 2285 2286 // Style attribute 2287 var t = (th.attr('style') || '').match(/width:\s*(\d+[pxem%]+)/); 2288 if ( t ) { 2289 oCol.sWidthOrig = t[1]; 2290 } 2291 } 2292 2293 /* User specified column options */ 2294 if ( oOptions !== undefined && oOptions !== null ) 2295 { 2296 // Backwards compatibility 2297 _fnCompatCols( oOptions ); 2298 2299 // Map camel case parameters to their Hungarian counterparts 2300 _fnCamelToHungarian( DataTable.defaults.column, oOptions, true ); 2301 2302 /* Backwards compatibility for mDataProp */ 2303 if ( oOptions.mDataProp !== undefined && !oOptions.mData ) 2304 { 2305 oOptions.mData = oOptions.mDataProp; 2306 } 2307 2308 if ( oOptions.sType ) 2309 { 2310 oCol._sManualType = oOptions.sType; 2311 } 2312 2313 // `class` is a reserved word in Javascript, so we need to provide 2314 // the ability to use a valid name for the camel case input 2315 if ( oOptions.className && ! oOptions.sClass ) 2316 { 2317 oOptions.sClass = oOptions.className; 2318 } 2319 if ( oOptions.sClass ) { 2320 th.addClass( oOptions.sClass ); 2321 } 2322 2323 var origClass = oCol.sClass; 2324 2325 $.extend( oCol, oOptions ); 2326 _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" ); 2327 2328 // Merge class from previously defined classes with this one, rather than just 2329 // overwriting it in the extend above 2330 if (origClass !== oCol.sClass) { 2331 oCol.sClass = origClass + ' ' + oCol.sClass; 2332 } 2333 2334 /* iDataSort to be applied (backwards compatibility), but aDataSort will take 2335 * priority if defined 2336 */ 2337 if ( oOptions.iDataSort !== undefined ) 2338 { 2339 oCol.aDataSort = [ oOptions.iDataSort ]; 2340 } 2341 _fnMap( oCol, oOptions, "aDataSort" ); 2342 } 2343 2344 /* Cache the data get and set functions for speed */ 2345 var mDataSrc = oCol.mData; 2346 var mData = _fnGetObjectDataFn( mDataSrc ); 2347 var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null; 2348 2349 var attrTest = function( src ) { 2350 return typeof src === 'string' && src.indexOf('@') !== -1; 2351 }; 2352 oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && ( 2353 attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter) 2354 ); 2355 oCol._setter = null; 2356 2357 oCol.fnGetData = function (rowData, type, meta) { 2358 var innerData = mData( rowData, type, undefined, meta ); 2359 2360 return mRender && type ? 2361 mRender( innerData, type, rowData, meta ) : 2362 innerData; 2363 }; 2364 oCol.fnSetData = function ( rowData, val, meta ) { 2365 return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta ); 2366 }; 2367 2368 // Indicate if DataTables should read DOM data as an object or array 2369 // Used in _fnGetRowElements 2370 if ( typeof mDataSrc !== 'number' && ! oCol._isArrayHost ) { 2371 oSettings._rowReadObject = true; 2372 } 2373 2374 /* Feature sorting overrides column specific when off */ 2375 if ( !oSettings.oFeatures.bSort ) 2376 { 2377 oCol.bSortable = false; 2378 th.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called 2379 } 2380 2381 /* Check that the class assignment is correct for sorting */ 2382 var bAsc = $.inArray('asc', oCol.asSorting) !== -1; 2383 var bDesc = $.inArray('desc', oCol.asSorting) !== -1; 2384 if ( !oCol.bSortable || (!bAsc && !bDesc) ) 2385 { 2386 oCol.sSortingClass = oClasses.sSortableNone; 2387 oCol.sSortingClassJUI = ""; 2388 } 2389 else if ( bAsc && !bDesc ) 2390 { 2391 oCol.sSortingClass = oClasses.sSortableAsc; 2392 oCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed; 2393 } 2394 else if ( !bAsc && bDesc ) 2395 { 2396 oCol.sSortingClass = oClasses.sSortableDesc; 2397 oCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed; 2398 } 2399 else 2400 { 2401 oCol.sSortingClass = oClasses.sSortable; 2402 oCol.sSortingClassJUI = oClasses.sSortJUI; 2403 } 2404 } 2405 2406 2407 /** 2408 * Adjust the table column widths for new data. Note: you would probably want to 2409 * do a redraw after calling this function! 2410 * @param {object} settings dataTables settings object 2411 * @memberof DataTable#oApi 2412 */ 2413 function _fnAdjustColumnSizing ( settings ) 2414 { 2415 /* Not interested in doing column width calculation if auto-width is disabled */ 2416 if ( settings.oFeatures.bAutoWidth !== false ) 2417 { 2418 var columns = settings.aoColumns; 2419 2420 _fnCalculateColumnWidths( settings ); 2421 for ( var i=0 , iLen=columns.length ; i<iLen ; i++ ) 2422 { 2423 columns[i].nTh.style.width = columns[i].sWidth; 2424 } 2425 } 2426 2427 var scroll = settings.oScroll; 2428 if ( scroll.sY !== '' || scroll.sX !== '') 2429 { 2430 _fnScrollDraw( settings ); 2431 } 2432 2433 _fnCallbackFire( settings, null, 'column-sizing', [settings] ); 2434 } 2435 2436 2437 /** 2438 * Convert the index of a visible column to the index in the data array (take account 2439 * of hidden columns) 2440 * @param {object} oSettings dataTables settings object 2441 * @param {int} iMatch Visible column index to lookup 2442 * @returns {int} i the data index 2443 * @memberof DataTable#oApi 2444 */ 2445 function _fnVisibleToColumnIndex( oSettings, iMatch ) 2446 { 2447 var aiVis = _fnGetColumns( oSettings, 'bVisible' ); 2448 2449 return typeof aiVis[iMatch] === 'number' ? 2450 aiVis[iMatch] : 2451 null; 2452 } 2453 2454 2455 /** 2456 * Convert the index of an index in the data array and convert it to the visible 2457 * column index (take account of hidden columns) 2458 * @param {int} iMatch Column index to lookup 2459 * @param {object} oSettings dataTables settings object 2460 * @returns {int} i the data index 2461 * @memberof DataTable#oApi 2462 */ 2463 function _fnColumnIndexToVisible( oSettings, iMatch ) 2464 { 2465 var aiVis = _fnGetColumns( oSettings, 'bVisible' ); 2466 var iPos = $.inArray( iMatch, aiVis ); 2467 2468 return iPos !== -1 ? iPos : null; 2469 } 2470 2471 2472 /** 2473 * Get the number of visible columns 2474 * @param {object} oSettings dataTables settings object 2475 * @returns {int} i the number of visible columns 2476 * @memberof DataTable#oApi 2477 */ 2478 function _fnVisbleColumns( oSettings ) 2479 { 2480 var vis = 0; 2481 2482 // No reduce in IE8, use a loop for now 2483 $.each( oSettings.aoColumns, function ( i, col ) { 2484 if ( col.bVisible && $(col.nTh).css('display') !== 'none' ) { 2485 vis++; 2486 } 2487 } ); 2488 2489 return vis; 2490 } 2491 2492 2493 /** 2494 * Get an array of column indexes that match a given property 2495 * @param {object} oSettings dataTables settings object 2496 * @param {string} sParam Parameter in aoColumns to look for - typically 2497 * bVisible or bSearchable 2498 * @returns {array} Array of indexes with matched properties 2499 * @memberof DataTable#oApi 2500 */ 2501 function _fnGetColumns( oSettings, sParam ) 2502 { 2503 var a = []; 2504 2505 $.map( oSettings.aoColumns, function(val, i) { 2506 if ( val[sParam] ) { 2507 a.push( i ); 2508 } 2509 } ); 2510 2511 return a; 2512 } 2513 2514 2515 /** 2516 * Calculate the 'type' of a column 2517 * @param {object} settings dataTables settings object 2518 * @memberof DataTable#oApi 2519 */ 2520 function _fnColumnTypes ( settings ) 2521 { 2522 var columns = settings.aoColumns; 2523 var data = settings.aoData; 2524 var types = DataTable.ext.type.detect; 2525 var i, ien, j, jen, k, ken; 2526 var col, cell, detectedType, cache; 2527 2528 // For each column, spin over the 2529 for ( i=0, ien=columns.length ; i<ien ; i++ ) { 2530 col = columns[i]; 2531 cache = []; 2532 2533 if ( ! col.sType && col._sManualType ) { 2534 col.sType = col._sManualType; 2535 } 2536 else if ( ! col.sType ) { 2537 for ( j=0, jen=types.length ; j<jen ; j++ ) { 2538 for ( k=0, ken=data.length ; k<ken ; k++ ) { 2539 // Use a cache array so we only need to get the type data 2540 // from the formatter once (when using multiple detectors) 2541 if ( cache[k] === undefined ) { 2542 cache[k] = _fnGetCellData( settings, k, i, 'type' ); 2543 } 2544 2545 detectedType = types[j]( cache[k], settings ); 2546 2547 // If null, then this type can't apply to this column, so 2548 // rather than testing all cells, break out. There is an 2549 // exception for the last type which is `html`. We need to 2550 // scan all rows since it is possible to mix string and HTML 2551 // types 2552 if ( ! detectedType && j !== types.length-1 ) { 2553 break; 2554 } 2555 2556 // Only a single match is needed for html type since it is 2557 // bottom of the pile and very similar to string - but it 2558 // must not be empty 2559 if ( detectedType === 'html' && ! _empty(cache[k]) ) { 2560 break; 2561 } 2562 } 2563 2564 // Type is valid for all data points in the column - use this 2565 // type 2566 if ( detectedType ) { 2567 col.sType = detectedType; 2568 break; 2569 } 2570 } 2571 2572 // Fall back - if no type was detected, always use string 2573 if ( ! col.sType ) { 2574 col.sType = 'string'; 2575 } 2576 } 2577 } 2578 } 2579 2580 2581 /** 2582 * Take the column definitions and static columns arrays and calculate how 2583 * they relate to column indexes. The callback function will then apply the 2584 * definition found for a column to a suitable configuration object. 2585 * @param {object} oSettings dataTables settings object 2586 * @param {array} aoColDefs The aoColumnDefs array that is to be applied 2587 * @param {array} aoCols The aoColumns array that defines columns individually 2588 * @param {function} fn Callback function - takes two parameters, the calculated 2589 * column index and the definition for that column. 2590 * @memberof DataTable#oApi 2591 */ 2592 function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn ) 2593 { 2594 var i, iLen, j, jLen, k, kLen, def; 2595 var columns = oSettings.aoColumns; 2596 2597 // Column definitions with aTargets 2598 if ( aoColDefs ) 2599 { 2600 /* Loop over the definitions array - loop in reverse so first instance has priority */ 2601 for ( i=aoColDefs.length-1 ; i>=0 ; i-- ) 2602 { 2603 def = aoColDefs[i]; 2604 2605 /* Each definition can target multiple columns, as it is an array */ 2606 var aTargets = def.target !== undefined 2607 ? def.target 2608 : def.targets !== undefined 2609 ? def.targets 2610 : def.aTargets; 2611 2612 if ( ! Array.isArray( aTargets ) ) 2613 { 2614 aTargets = [ aTargets ]; 2615 } 2616 2617 for ( j=0, jLen=aTargets.length ; j<jLen ; j++ ) 2618 { 2619 if ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 ) 2620 { 2621 /* Add columns that we don't yet know about */ 2622 while( columns.length <= aTargets[j] ) 2623 { 2624 _fnAddColumn( oSettings ); 2625 } 2626 2627 /* Integer, basic index */ 2628 fn( aTargets[j], def ); 2629 } 2630 else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 ) 2631 { 2632 /* Negative integer, right to left column counting */ 2633 fn( columns.length+aTargets[j], def ); 2634 } 2635 else if ( typeof aTargets[j] === 'string' ) 2636 { 2637 /* Class name matching on TH element */ 2638 for ( k=0, kLen=columns.length ; k<kLen ; k++ ) 2639 { 2640 if ( aTargets[j] == "_all" || 2641 $(columns[k].nTh).hasClass( aTargets[j] ) ) 2642 { 2643 fn( k, def ); 2644 } 2645 } 2646 } 2647 } 2648 } 2649 } 2650 2651 // Statically defined columns array 2652 if ( aoCols ) 2653 { 2654 for ( i=0, iLen=aoCols.length ; i<iLen ; i++ ) 2655 { 2656 fn( i, aoCols[i] ); 2657 } 2658 } 2659 } 2660 2661 /** 2662 * Add a data array to the table, creating DOM node etc. This is the parallel to 2663 * _fnGatherData, but for adding rows from a Javascript source, rather than a 2664 * DOM source. 2665 * @param {object} oSettings dataTables settings object 2666 * @param {array} aData data array to be added 2667 * @param {node} [nTr] TR element to add to the table - optional. If not given, 2668 * DataTables will create a row automatically 2669 * @param {array} [anTds] Array of TD|TH elements for the row - must be given 2670 * if nTr is. 2671 * @returns {int} >=0 if successful (index of new aoData entry), -1 if failed 2672 * @memberof DataTable#oApi 2673 */ 2674 function _fnAddData ( oSettings, aDataIn, nTr, anTds ) 2675 { 2676 /* Create the object for storing information about this new row */ 2677 var iRow = oSettings.aoData.length; 2678 var oData = $.extend( true, {}, DataTable.models.oRow, { 2679 src: nTr ? 'dom' : 'data', 2680 idx: iRow 2681 } ); 2682 2683 oData._aData = aDataIn; 2684 oSettings.aoData.push( oData ); 2685 2686 /* Create the cells */ 2687 var nTd, sThisType; 2688 var columns = oSettings.aoColumns; 2689 2690 // Invalidate the column types as the new data needs to be revalidated 2691 for ( var i=0, iLen=columns.length ; i<iLen ; i++ ) 2692 { 2693 columns[i].sType = null; 2694 } 2695 2696 /* Add to the display array */ 2697 oSettings.aiDisplayMaster.push( iRow ); 2698 2699 var id = oSettings.rowIdFn( aDataIn ); 2700 if ( id !== undefined ) { 2701 oSettings.aIds[ id ] = oData; 2702 } 2703 2704 /* Create the DOM information, or register it if already present */ 2705 if ( nTr || ! oSettings.oFeatures.bDeferRender ) 2706 { 2707 _fnCreateTr( oSettings, iRow, nTr, anTds ); 2708 } 2709 2710 return iRow; 2711 } 2712 2713 2714 /** 2715 * Add one or more TR elements to the table. Generally we'd expect to 2716 * use this for reading data from a DOM sourced table, but it could be 2717 * used for an TR element. Note that if a TR is given, it is used (i.e. 2718 * it is not cloned). 2719 * @param {object} settings dataTables settings object 2720 * @param {array|node|jQuery} trs The TR element(s) to add to the table 2721 * @returns {array} Array of indexes for the added rows 2722 * @memberof DataTable#oApi 2723 */ 2724 function _fnAddTr( settings, trs ) 2725 { 2726 var row; 2727 2728 // Allow an individual node to be passed in 2729 if ( ! (trs instanceof $) ) { 2730 trs = $(trs); 2731 } 2732 2733 return trs.map( function (i, el) { 2734 row = _fnGetRowElements( settings, el ); 2735 return _fnAddData( settings, row.data, el, row.cells ); 2736 } ); 2737 } 2738 2739 2740 /** 2741 * Take a TR element and convert it to an index in aoData 2742 * @param {object} oSettings dataTables settings object 2743 * @param {node} n the TR element to find 2744 * @returns {int} index if the node is found, null if not 2745 * @memberof DataTable#oApi 2746 */ 2747 function _fnNodeToDataIndex( oSettings, n ) 2748 { 2749 return (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null; 2750 } 2751 2752 2753 /** 2754 * Take a TD element and convert it into a column data index (not the visible index) 2755 * @param {object} oSettings dataTables settings object 2756 * @param {int} iRow The row number the TD/TH can be found in 2757 * @param {node} n The TD/TH element to find 2758 * @returns {int} index if the node is found, -1 if not 2759 * @memberof DataTable#oApi 2760 */ 2761 function _fnNodeToColumnIndex( oSettings, iRow, n ) 2762 { 2763 return $.inArray( n, oSettings.aoData[ iRow ].anCells ); 2764 } 2765 2766 2767 /** 2768 * Get the data for a given cell from the internal cache, taking into account data mapping 2769 * @param {object} settings dataTables settings object 2770 * @param {int} rowIdx aoData row id 2771 * @param {int} colIdx Column index 2772 * @param {string} type data get type ('display', 'type' 'filter|search' 'sort|order') 2773 * @returns {*} Cell data 2774 * @memberof DataTable#oApi 2775 */ 2776 function _fnGetCellData( settings, rowIdx, colIdx, type ) 2777 { 2778 if (type === 'search') { 2779 type = 'filter'; 2780 } 2781 else if (type === 'order') { 2782 type = 'sort'; 2783 } 2784 2785 var draw = settings.iDraw; 2786 var col = settings.aoColumns[colIdx]; 2787 var rowData = settings.aoData[rowIdx]._aData; 2788 var defaultContent = col.sDefaultContent; 2789 var cellData = col.fnGetData( rowData, type, { 2790 settings: settings, 2791 row: rowIdx, 2792 col: colIdx 2793 } ); 2794 2795 if ( cellData === undefined ) { 2796 if ( settings.iDrawError != draw && defaultContent === null ) { 2797 _fnLog( settings, 0, "Requested unknown parameter "+ 2798 (typeof col.mData=='function' ? '{function}' : "'"+col.mData+"'")+ 2799 " for row "+rowIdx+", column "+colIdx, 4 ); 2800 settings.iDrawError = draw; 2801 } 2802 return defaultContent; 2803 } 2804 2805 // When the data source is null and a specific data type is requested (i.e. 2806 // not the original data), we can use default column data 2807 if ( (cellData === rowData || cellData === null) && defaultContent !== null && type !== undefined ) { 2808 cellData = defaultContent; 2809 } 2810 else if ( typeof cellData === 'function' ) { 2811 // If the data source is a function, then we run it and use the return, 2812 // executing in the scope of the data object (for instances) 2813 return cellData.call( rowData ); 2814 } 2815 2816 if ( cellData === null && type === 'display' ) { 2817 return ''; 2818 } 2819 2820 if ( type === 'filter' ) { 2821 var fomatters = DataTable.ext.type.search; 2822 2823 if ( fomatters[ col.sType ] ) { 2824 cellData = fomatters[ col.sType ]( cellData ); 2825 } 2826 } 2827 2828 return cellData; 2829 } 2830 2831 2832 /** 2833 * Set the value for a specific cell, into the internal data cache 2834 * @param {object} settings dataTables settings object 2835 * @param {int} rowIdx aoData row id 2836 * @param {int} colIdx Column index 2837 * @param {*} val Value to set 2838 * @memberof DataTable#oApi 2839 */ 2840 function _fnSetCellData( settings, rowIdx, colIdx, val ) 2841 { 2842 var col = settings.aoColumns[colIdx]; 2843 var rowData = settings.aoData[rowIdx]._aData; 2844 2845 col.fnSetData( rowData, val, { 2846 settings: settings, 2847 row: rowIdx, 2848 col: colIdx 2849 } ); 2850 } 2851 2852 2853 // Private variable that is used to match action syntax in the data property object 2854 var __reArray = /\[.*?\]$/; 2855 var __reFn = /\(\)$/; 2856 2857 /** 2858 * Split string on periods, taking into account escaped periods 2859 * @param {string} str String to split 2860 * @return {array} Split string 2861 */ 2862 function _fnSplitObjNotation( str ) 2863 { 2864 return $.map( str.match(/(\\.|[^\.])+/g) || [''], function ( s ) { 2865 return s.replace(/\\\./g, '.'); 2866 } ); 2867 } 2868 2869 2870 /** 2871 * Return a function that can be used to get data from a source object, taking 2872 * into account the ability to use nested objects as a source 2873 * @param {string|int|function} mSource The data source for the object 2874 * @returns {function} Data get function 2875 * @memberof DataTable#oApi 2876 */ 2877 var _fnGetObjectDataFn = DataTable.util.get; 2878 2879 2880 /** 2881 * Return a function that can be used to set data from a source object, taking 2882 * into account the ability to use nested objects as a source 2883 * @param {string|int|function} mSource The data source for the object 2884 * @returns {function} Data set function 2885 * @memberof DataTable#oApi 2886 */ 2887 var _fnSetObjectDataFn = DataTable.util.set; 2888 2889 2890 /** 2891 * Return an array with the full table data 2892 * @param {object} oSettings dataTables settings object 2893 * @returns array {array} aData Master data array 2894 * @memberof DataTable#oApi 2895 */ 2896 function _fnGetDataMaster ( settings ) 2897 { 2898 return _pluck( settings.aoData, '_aData' ); 2899 } 2900 2901 2902 /** 2903 * Nuke the table 2904 * @param {object} oSettings dataTables settings object 2905 * @memberof DataTable#oApi 2906 */ 2907 function _fnClearTable( settings ) 2908 { 2909 settings.aoData.length = 0; 2910 settings.aiDisplayMaster.length = 0; 2911 settings.aiDisplay.length = 0; 2912 settings.aIds = {}; 2913 } 2914 2915 2916 /** 2917 * Take an array of integers (index array) and remove a target integer (value - not 2918 * the key!) 2919 * @param {array} a Index array to target 2920 * @param {int} iTarget value to find 2921 * @memberof DataTable#oApi 2922 */ 2923 function _fnDeleteIndex( a, iTarget, splice ) 2924 { 2925 var iTargetIndex = -1; 2926 2927 for ( var i=0, iLen=a.length ; i<iLen ; i++ ) 2928 { 2929 if ( a[i] == iTarget ) 2930 { 2931 iTargetIndex = i; 2932 } 2933 else if ( a[i] > iTarget ) 2934 { 2935 a[i]--; 2936 } 2937 } 2938 2939 if ( iTargetIndex != -1 && splice === undefined ) 2940 { 2941 a.splice( iTargetIndex, 1 ); 2942 } 2943 } 2944 2945 2946 /** 2947 * Mark cached data as invalid such that a re-read of the data will occur when 2948 * the cached data is next requested. Also update from the data source object. 2949 * 2950 * @param {object} settings DataTables settings object 2951 * @param {int} rowIdx Row index to invalidate 2952 * @param {string} [src] Source to invalidate from: undefined, 'auto', 'dom' 2953 * or 'data' 2954 * @param {int} [colIdx] Column index to invalidate. If undefined the whole 2955 * row will be invalidated 2956 * @memberof DataTable#oApi 2957 * 2958 * @todo For the modularisation of v1.11 this will need to become a callback, so 2959 * the sort and filter methods can subscribe to it. That will required 2960 * initialisation options for sorting, which is why it is not already baked in 2961 */ 2962 function _fnInvalidate( settings, rowIdx, src, colIdx ) 2963 { 2964 var row = settings.aoData[ rowIdx ]; 2965 var i, ien; 2966 var cellWrite = function ( cell, col ) { 2967 // This is very frustrating, but in IE if you just write directly 2968 // to innerHTML, and elements that are overwritten are GC'ed, 2969 // even if there is a reference to them elsewhere 2970 while ( cell.childNodes.length ) { 2971 cell.removeChild( cell.firstChild ); 2972 } 2973 2974 cell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' ); 2975 }; 2976 2977 // Are we reading last data from DOM or the data object? 2978 if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) { 2979 // Read the data from the DOM 2980 row._aData = _fnGetRowElements( 2981 settings, row, colIdx, colIdx === undefined ? undefined : row._aData 2982 ) 2983 .data; 2984 } 2985 else { 2986 // Reading from data object, update the DOM 2987 var cells = row.anCells; 2988 2989 if ( cells ) { 2990 if ( colIdx !== undefined ) { 2991 cellWrite( cells[colIdx], colIdx ); 2992 } 2993 else { 2994 for ( i=0, ien=cells.length ; i<ien ; i++ ) { 2995 cellWrite( cells[i], i ); 2996 } 2997 } 2998 } 2999 } 3000 3001 // For both row and cell invalidation, the cached data for sorting and 3002 // filtering is nulled out 3003 row._aSortData = null; 3004 row._aFilterData = null; 3005 3006 // Invalidate the type for a specific column (if given) or all columns since 3007 // the data might have changed 3008 var cols = settings.aoColumns; 3009 if ( colIdx !== undefined ) { 3010 cols[ colIdx ].sType = null; 3011 } 3012 else { 3013 for ( i=0, ien=cols.length ; i<ien ; i++ ) { 3014 cols[i].sType = null; 3015 } 3016 3017 // Update DataTables special `DT_*` attributes for the row 3018 _fnRowAttributes( settings, row ); 3019 } 3020 } 3021 3022 3023 /** 3024 * Build a data source object from an HTML row, reading the contents of the 3025 * cells that are in the row. 3026 * 3027 * @param {object} settings DataTables settings object 3028 * @param {node|object} TR element from which to read data or existing row 3029 * object from which to re-read the data from the cells 3030 * @param {int} [colIdx] Optional column index 3031 * @param {array|object} [d] Data source object. If `colIdx` is given then this 3032 * parameter should also be given and will be used to write the data into. 3033 * Only the column in question will be written 3034 * @returns {object} Object with two parameters: `data` the data read, in 3035 * document order, and `cells` and array of nodes (they can be useful to the 3036 * caller, so rather than needing a second traversal to get them, just return 3037 * them from here). 3038 * @memberof DataTable#oApi 3039 */ 3040 function _fnGetRowElements( settings, row, colIdx, d ) 3041 { 3042 var 3043 tds = [], 3044 td = row.firstChild, 3045 name, col, o, i=0, contents, 3046 columns = settings.aoColumns, 3047 objectRead = settings._rowReadObject; 3048 3049 // Allow the data object to be passed in, or construct 3050 d = d !== undefined ? 3051 d : 3052 objectRead ? 3053 {} : 3054 []; 3055 3056 var attr = function ( str, td ) { 3057 if ( typeof str === 'string' ) { 3058 var idx = str.indexOf('@'); 3059 3060 if ( idx !== -1 ) { 3061 var attr = str.substring( idx+1 ); 3062 var setter = _fnSetObjectDataFn( str ); 3063 setter( d, td.getAttribute( attr ) ); 3064 } 3065 } 3066 }; 3067 3068 // Read data from a cell and store into the data object 3069 var cellProcess = function ( cell ) { 3070 if ( colIdx === undefined || colIdx === i ) { 3071 col = columns[i]; 3072 contents = (cell.innerHTML).trim(); 3073 3074 if ( col && col._bAttrSrc ) { 3075 var setter = _fnSetObjectDataFn( col.mData._ ); 3076 setter( d, contents ); 3077 3078 attr( col.mData.sort, cell ); 3079 attr( col.mData.type, cell ); 3080 attr( col.mData.filter, cell ); 3081 } 3082 else { 3083 // Depending on the `data` option for the columns the data can 3084 // be read to either an object or an array. 3085 if ( objectRead ) { 3086 if ( ! col._setter ) { 3087 // Cache the setter function 3088 col._setter = _fnSetObjectDataFn( col.mData ); 3089 } 3090 col._setter( d, contents ); 3091 } 3092 else { 3093 d[i] = contents; 3094 } 3095 } 3096 } 3097 3098 i++; 3099 }; 3100 3101 if ( td ) { 3102 // `tr` element was passed in 3103 while ( td ) { 3104 name = td.nodeName.toUpperCase(); 3105 3106 if ( name == "TD" || name == "TH" ) { 3107 cellProcess( td ); 3108 tds.push( td ); 3109 } 3110 3111 td = td.nextSibling; 3112 } 3113 } 3114 else { 3115 // Existing row object passed in 3116 tds = row.anCells; 3117 3118 for ( var j=0, jen=tds.length ; j<jen ; j++ ) { 3119 cellProcess( tds[j] ); 3120 } 3121 } 3122 3123 // Read the ID from the DOM if present 3124 var rowNode = row.firstChild ? row : row.nTr; 3125 3126 if ( rowNode ) { 3127 var id = rowNode.getAttribute( 'id' ); 3128 3129 if ( id ) { 3130 _fnSetObjectDataFn( settings.rowId )( d, id ); 3131 } 3132 } 3133 3134 return { 3135 data: d, 3136 cells: tds 3137 }; 3138 } 3139 /** 3140 * Create a new TR element (and it's TD children) for a row 3141 * @param {object} oSettings dataTables settings object 3142 * @param {int} iRow Row to consider 3143 * @param {node} [nTrIn] TR element to add to the table - optional. If not given, 3144 * DataTables will create a row automatically 3145 * @param {array} [anTds] Array of TD|TH elements for the row - must be given 3146 * if nTr is. 3147 * @memberof DataTable#oApi 3148 */ 3149 function _fnCreateTr ( oSettings, iRow, nTrIn, anTds ) 3150 { 3151 var 3152 row = oSettings.aoData[iRow], 3153 rowData = row._aData, 3154 cells = [], 3155 nTr, nTd, oCol, 3156 i, iLen, create; 3157 3158 if ( row.nTr === null ) 3159 { 3160 nTr = nTrIn || document.createElement('tr'); 3161 3162 row.nTr = nTr; 3163 row.anCells = cells; 3164 3165 /* Use a private property on the node to allow reserve mapping from the node 3166 * to the aoData array for fast look up 3167 */ 3168 nTr._DT_RowIndex = iRow; 3169 3170 /* Special parameters can be given by the data source to be used on the row */ 3171 _fnRowAttributes( oSettings, row ); 3172 3173 /* Process each column */ 3174 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ ) 3175 { 3176 oCol = oSettings.aoColumns[i]; 3177 create = nTrIn ? false : true; 3178 3179 nTd = create ? document.createElement( oCol.sCellType ) : anTds[i]; 3180 3181 if (! nTd) { 3182 _fnLog( oSettings, 0, 'Incorrect column count', 18 ); 3183 } 3184 3185 nTd._DT_CellIndex = { 3186 row: iRow, 3187 column: i 3188 }; 3189 3190 cells.push( nTd ); 3191 3192 // Need to create the HTML if new, or if a rendering function is defined 3193 if ( create || ((oCol.mRender || oCol.mData !== i) && 3194 (!$.isPlainObject(oCol.mData) || oCol.mData._ !== i+'.display') 3195 )) { 3196 nTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' ); 3197 } 3198 3199 /* Add user defined class */ 3200 if ( oCol.sClass ) 3201 { 3202 nTd.className += ' '+oCol.sClass; 3203 } 3204 3205 // Visibility - add or remove as required 3206 if ( oCol.bVisible && ! nTrIn ) 3207 { 3208 nTr.appendChild( nTd ); 3209 } 3210 else if ( ! oCol.bVisible && nTrIn ) 3211 { 3212 nTd.parentNode.removeChild( nTd ); 3213 } 3214 3215 if ( oCol.fnCreatedCell ) 3216 { 3217 oCol.fnCreatedCell.call( oSettings.oInstance, 3218 nTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i 3219 ); 3220 } 3221 } 3222 3223 _fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [nTr, rowData, iRow, cells] ); 3224 } 3225 } 3226 3227 3228 /** 3229 * Add attributes to a row based on the special `DT_*` parameters in a data 3230 * source object. 3231 * @param {object} settings DataTables settings object 3232 * @param {object} DataTables row object for the row to be modified 3233 * @memberof DataTable#oApi 3234 */ 3235 function _fnRowAttributes( settings, row ) 3236 { 3237 var tr = row.nTr; 3238 var data = row._aData; 3239 3240 if ( tr ) { 3241 var id = settings.rowIdFn( data ); 3242 3243 if ( id ) { 3244 tr.id = id; 3245 } 3246 3247 if ( data.DT_RowClass ) { 3248 // Remove any classes added by DT_RowClass before 3249 var a = data.DT_RowClass.split(' '); 3250 row.__rowc = row.__rowc ? 3251 _unique( row.__rowc.concat( a ) ) : 3252 a; 3253 3254 $(tr) 3255 .removeClass( row.__rowc.join(' ') ) 3256 .addClass( data.DT_RowClass ); 3257 } 3258 3259 if ( data.DT_RowAttr ) { 3260 $(tr).attr( data.DT_RowAttr ); 3261 } 3262 3263 if ( data.DT_RowData ) { 3264 $(tr).data( data.DT_RowData ); 3265 } 3266 } 3267 } 3268 3269 3270 /** 3271 * Create the HTML header for the table 3272 * @param {object} oSettings dataTables settings object 3273 * @memberof DataTable#oApi 3274 */ 3275 function _fnBuildHead( oSettings ) 3276 { 3277 var i, ien, cell, row, column; 3278 var thead = oSettings.nTHead; 3279 var tfoot = oSettings.nTFoot; 3280 var createHeader = $('th, td', thead).length === 0; 3281 var classes = oSettings.oClasses; 3282 var columns = oSettings.aoColumns; 3283 3284 if ( createHeader ) { 3285 row = $('<tr/>').appendTo( thead ); 3286 } 3287 3288 for ( i=0, ien=columns.length ; i<ien ; i++ ) { 3289 column = columns[i]; 3290 cell = $( column.nTh ).addClass( column.sClass ); 3291 3292 if ( createHeader ) { 3293 cell.appendTo( row ); 3294 } 3295 3296 // 1.11 move into sorting 3297 if ( oSettings.oFeatures.bSort ) { 3298 cell.addClass( column.sSortingClass ); 3299 3300 if ( column.bSortable !== false ) { 3301 cell 3302 .attr( 'tabindex', oSettings.iTabIndex ) 3303 .attr( 'aria-controls', oSettings.sTableId ); 3304 3305 _fnSortAttachListener( oSettings, column.nTh, i ); 3306 } 3307 } 3308 3309 if ( column.sTitle != cell[0].innerHTML ) { 3310 cell.html( column.sTitle ); 3311 } 3312 3313 _fnRenderer( oSettings, 'header' )( 3314 oSettings, cell, column, classes 3315 ); 3316 } 3317 3318 if ( createHeader ) { 3319 _fnDetectHeader( oSettings.aoHeader, thead ); 3320 } 3321 3322 /* Deal with the footer - add classes if required */ 3323 $(thead).children('tr').children('th, td').addClass( classes.sHeaderTH ); 3324 $(tfoot).children('tr').children('th, td').addClass( classes.sFooterTH ); 3325 3326 // Cache the footer cells. Note that we only take the cells from the first 3327 // row in the footer. If there is more than one row the user wants to 3328 // interact with, they need to use the table().foot() method. Note also this 3329 // allows cells to be used for multiple columns using colspan 3330 if ( tfoot !== null ) { 3331 var cells = oSettings.aoFooter[0]; 3332 3333 for ( i=0, ien=cells.length ; i<ien ; i++ ) { 3334 column = columns[i]; 3335 3336 if (column) { 3337 column.nTf = cells[i].cell; 3338 3339 if ( column.sClass ) { 3340 $(column.nTf).addClass( column.sClass ); 3341 } 3342 } 3343 else { 3344 _fnLog( oSettings, 0, 'Incorrect column count', 18 ); 3345 } 3346 } 3347 } 3348 } 3349 3350 3351 /** 3352 * Draw the header (or footer) element based on the column visibility states. The 3353 * methodology here is to use the layout array from _fnDetectHeader, modified for 3354 * the instantaneous column visibility, to construct the new layout. The grid is 3355 * traversed over cell at a time in a rows x columns grid fashion, although each 3356 * cell insert can cover multiple elements in the grid - which is tracks using the 3357 * aApplied array. Cell inserts in the grid will only occur where there isn't 3358 * already a cell in that position. 3359 * @param {object} oSettings dataTables settings object 3360 * @param array {objects} aoSource Layout array from _fnDetectHeader 3361 * @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc, 3362 * @memberof DataTable#oApi 3363 */ 3364 function _fnDrawHead( oSettings, aoSource, bIncludeHidden ) 3365 { 3366 var i, iLen, j, jLen, k, kLen, n, nLocalTr; 3367 var aoLocal = []; 3368 var aApplied = []; 3369 var iColumns = oSettings.aoColumns.length; 3370 var iRowspan, iColspan; 3371 3372 if ( ! aoSource ) 3373 { 3374 return; 3375 } 3376 3377 if ( bIncludeHidden === undefined ) 3378 { 3379 bIncludeHidden = false; 3380 } 3381 3382 /* Make a copy of the master layout array, but without the visible columns in it */ 3383 for ( i=0, iLen=aoSource.length ; i<iLen ; i++ ) 3384 { 3385 aoLocal[i] = aoSource[i].slice(); 3386 aoLocal[i].nTr = aoSource[i].nTr; 3387 3388 /* Remove any columns which are currently hidden */ 3389 for ( j=iColumns-1 ; j>=0 ; j-- ) 3390 { 3391 if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden ) 3392 { 3393 aoLocal[i].splice( j, 1 ); 3394 } 3395 } 3396 3397 /* Prep the applied array - it needs an element for each row */ 3398 aApplied.push( [] ); 3399 } 3400 3401 for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ ) 3402 { 3403 nLocalTr = aoLocal[i].nTr; 3404 3405 /* All cells are going to be replaced, so empty out the row */ 3406 if ( nLocalTr ) 3407 { 3408 while( (n = nLocalTr.firstChild) ) 3409 { 3410 nLocalTr.removeChild( n ); 3411 } 3412 } 3413 3414 for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ ) 3415 { 3416 iRowspan = 1; 3417 iColspan = 1; 3418 3419 /* Check to see if there is already a cell (row/colspan) covering our target 3420 * insert point. If there is, then there is nothing to do. 3421 */ 3422 if ( aApplied[i][j] === undefined ) 3423 { 3424 nLocalTr.appendChild( aoLocal[i][j].cell ); 3425 aApplied[i][j] = 1; 3426 3427 /* Expand the cell to cover as many rows as needed */ 3428 while ( aoLocal[i+iRowspan] !== undefined && 3429 aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell ) 3430 { 3431 aApplied[i+iRowspan][j] = 1; 3432 iRowspan++; 3433 } 3434 3435 /* Expand the cell to cover as many columns as needed */ 3436 while ( aoLocal[i][j+iColspan] !== undefined && 3437 aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell ) 3438 { 3439 /* Must update the applied array over the rows for the columns */ 3440 for ( k=0 ; k<iRowspan ; k++ ) 3441 { 3442 aApplied[i+k][j+iColspan] = 1; 3443 } 3444 iColspan++; 3445 } 3446 3447 /* Do the actual expansion in the DOM */ 3448 $(aoLocal[i][j].cell) 3449 .attr('rowspan', iRowspan) 3450 .attr('colspan', iColspan); 3451 } 3452 } 3453 } 3454 } 3455 3456 3457 /** 3458 * Insert the required TR nodes into the table for display 3459 * @param {object} oSettings dataTables settings object 3460 * @param ajaxComplete true after ajax call to complete rendering 3461 * @memberof DataTable#oApi 3462 */ 3463 function _fnDraw( oSettings, ajaxComplete ) 3464 { 3465 // Allow for state saving and a custom start position 3466 _fnStart( oSettings ); 3467 3468 /* Provide a pre-callback function which can be used to cancel the draw is false is returned */ 3469 var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] ); 3470 if ( $.inArray( false, aPreDraw ) !== -1 ) 3471 { 3472 _fnProcessingDisplay( oSettings, false ); 3473 return; 3474 } 3475 3476 var anRows = []; 3477 var iRowCount = 0; 3478 var asStripeClasses = oSettings.asStripeClasses; 3479 var iStripes = asStripeClasses.length; 3480 var oLang = oSettings.oLanguage; 3481 var bServerSide = _fnDataSource( oSettings ) == 'ssp'; 3482 var aiDisplay = oSettings.aiDisplay; 3483 var iDisplayStart = oSettings._iDisplayStart; 3484 var iDisplayEnd = oSettings.fnDisplayEnd(); 3485 3486 oSettings.bDrawing = true; 3487 3488 /* Server-side processing draw intercept */ 3489 if ( oSettings.bDeferLoading ) 3490 { 3491 oSettings.bDeferLoading = false; 3492 oSettings.iDraw++; 3493 _fnProcessingDisplay( oSettings, false ); 3494 } 3495 else if ( !bServerSide ) 3496 { 3497 oSettings.iDraw++; 3498 } 3499 else if ( !oSettings.bDestroying && !ajaxComplete) 3500 { 3501 _fnAjaxUpdate( oSettings ); 3502 return; 3503 } 3504 3505 if ( aiDisplay.length !== 0 ) 3506 { 3507 var iStart = bServerSide ? 0 : iDisplayStart; 3508 var iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd; 3509 3510 for ( var j=iStart ; j<iEnd ; j++ ) 3511 { 3512 var iDataIndex = aiDisplay[j]; 3513 var aoData = oSettings.aoData[ iDataIndex ]; 3514 if ( aoData.nTr === null ) 3515 { 3516 _fnCreateTr( oSettings, iDataIndex ); 3517 } 3518 3519 var nRow = aoData.nTr; 3520 3521 /* Remove the old striping classes and then add the new one */ 3522 if ( iStripes !== 0 ) 3523 { 3524 var sStripe = asStripeClasses[ iRowCount % iStripes ]; 3525 if ( aoData._sRowStripe != sStripe ) 3526 { 3527 $(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe ); 3528 aoData._sRowStripe = sStripe; 3529 } 3530 } 3531 3532 // Row callback functions - might want to manipulate the row 3533 // iRowCount and j are not currently documented. Are they at all 3534 // useful? 3535 _fnCallbackFire( oSettings, 'aoRowCallback', null, 3536 [nRow, aoData._aData, iRowCount, j, iDataIndex] ); 3537 3538 anRows.push( nRow ); 3539 iRowCount++; 3540 } 3541 } 3542 else 3543 { 3544 /* Table is empty - create a row with an empty message in it */ 3545 var sZero = oLang.sZeroRecords; 3546 if ( oSettings.iDraw == 1 && _fnDataSource( oSettings ) == 'ajax' ) 3547 { 3548 sZero = oLang.sLoadingRecords; 3549 } 3550 else if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 ) 3551 { 3552 sZero = oLang.sEmptyTable; 3553 } 3554 3555 anRows[ 0 ] = $( '<tr/>', { 'class': iStripes ? asStripeClasses[0] : '' } ) 3556 .append( $('<td />', { 3557 'valign': 'top', 3558 'colSpan': _fnVisbleColumns( oSettings ), 3559 'class': oSettings.oClasses.sRowEmpty 3560 } ).html( sZero ) )[0]; 3561 } 3562 3563 /* Header and footer callbacks */ 3564 _fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0], 3565 _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] ); 3566 3567 _fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0], 3568 _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] ); 3569 3570 var body = $(oSettings.nTBody); 3571 3572 body.children().detach(); 3573 body.append( $(anRows) ); 3574 3575 /* Call all required callback functions for the end of a draw */ 3576 _fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] ); 3577 3578 /* Draw is complete, sorting and filtering must be as well */ 3579 oSettings.bSorted = false; 3580 oSettings.bFiltered = false; 3581 oSettings.bDrawing = false; 3582 } 3583 3584 3585 /** 3586 * Redraw the table - taking account of the various features which are enabled 3587 * @param {object} oSettings dataTables settings object 3588 * @param {boolean} [holdPosition] Keep the current paging position. By default 3589 * the paging is reset to the first page 3590 * @memberof DataTable#oApi 3591 */ 3592 function _fnReDraw( settings, holdPosition ) 3593 { 3594 var 3595 features = settings.oFeatures, 3596 sort = features.bSort, 3597 filter = features.bFilter; 3598 3599 if ( sort ) { 3600 _fnSort( settings ); 3601 } 3602 3603 if ( filter ) { 3604 _fnFilterComplete( settings, settings.oPreviousSearch ); 3605 } 3606 else { 3607 // No filtering, so we want to just use the display master 3608 settings.aiDisplay = settings.aiDisplayMaster.slice(); 3609 } 3610 3611 if ( holdPosition !== true ) { 3612 settings._iDisplayStart = 0; 3613 } 3614 3615 // Let any modules know about the draw hold position state (used by 3616 // scrolling internally) 3617 settings._drawHold = holdPosition; 3618 3619 _fnDraw( settings ); 3620 3621 settings._drawHold = false; 3622 } 3623 3624 3625 /** 3626 * Add the options to the page HTML for the table 3627 * @param {object} oSettings dataTables settings object 3628 * @memberof DataTable#oApi 3629 */ 3630 function _fnAddOptionsHtml ( oSettings ) 3631 { 3632 var classes = oSettings.oClasses; 3633 var table = $(oSettings.nTable); 3634 var holding = $('<div/>').insertBefore( table ); // Holding element for speed 3635 var features = oSettings.oFeatures; 3636 3637 // All DataTables are wrapped in a div 3638 var insert = $('<div/>', { 3639 id: oSettings.sTableId+'_wrapper', 3640 'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter) 3641 } ); 3642 3643 oSettings.nHolding = holding[0]; 3644 oSettings.nTableWrapper = insert[0]; 3645 oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling; 3646 3647 /* Loop over the user set positioning and place the elements as needed */ 3648 var aDom = oSettings.sDom.split(''); 3649 var featureNode, cOption, nNewNode, cNext, sAttr, j; 3650 for ( var i=0 ; i<aDom.length ; i++ ) 3651 { 3652 featureNode = null; 3653 cOption = aDom[i]; 3654 3655 if ( cOption == '<' ) 3656 { 3657 /* New container div */ 3658 nNewNode = $('<div/>')[0]; 3659 3660 /* Check to see if we should append an id and/or a class name to the container */ 3661 cNext = aDom[i+1]; 3662 if ( cNext == "'" || cNext == '"' ) 3663 { 3664 sAttr = ""; 3665 j = 2; 3666 while ( aDom[i+j] != cNext ) 3667 { 3668 sAttr += aDom[i+j]; 3669 j++; 3670 } 3671 3672 /* Replace jQuery UI constants @todo depreciated */ 3673 if ( sAttr == "H" ) 3674 { 3675 sAttr = classes.sJUIHeader; 3676 } 3677 else if ( sAttr == "F" ) 3678 { 3679 sAttr = classes.sJUIFooter; 3680 } 3681 3682 /* The attribute can be in the format of "#id.class", "#id" or "class" This logic 3683 * breaks the string into parts and applies them as needed 3684 */ 3685 if ( sAttr.indexOf('.') != -1 ) 3686 { 3687 var aSplit = sAttr.split('.'); 3688 nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1); 3689 nNewNode.className = aSplit[1]; 3690 } 3691 else if ( sAttr.charAt(0) == "#" ) 3692 { 3693 nNewNode.id = sAttr.substr(1, sAttr.length-1); 3694 } 3695 else 3696 { 3697 nNewNode.className = sAttr; 3698 } 3699 3700 i += j; /* Move along the position array */ 3701 } 3702 3703 insert.append( nNewNode ); 3704 insert = $(nNewNode); 3705 } 3706 else if ( cOption == '>' ) 3707 { 3708 /* End container div */ 3709 insert = insert.parent(); 3710 } 3711 // @todo Move options into their own plugins? 3712 else if ( cOption == 'l' && features.bPaginate && features.bLengthChange ) 3713 { 3714 /* Length */ 3715 featureNode = _fnFeatureHtmlLength( oSettings ); 3716 } 3717 else if ( cOption == 'f' && features.bFilter ) 3718 { 3719 /* Filter */ 3720 featureNode = _fnFeatureHtmlFilter( oSettings ); 3721 } 3722 else if ( cOption == 'r' && features.bProcessing ) 3723 { 3724 /* pRocessing */ 3725 featureNode = _fnFeatureHtmlProcessing( oSettings ); 3726 } 3727 else if ( cOption == 't' ) 3728 { 3729 /* Table */ 3730 featureNode = _fnFeatureHtmlTable( oSettings ); 3731 } 3732 else if ( cOption == 'i' && features.bInfo ) 3733 { 3734 /* Info */ 3735 featureNode = _fnFeatureHtmlInfo( oSettings ); 3736 } 3737 else if ( cOption == 'p' && features.bPaginate ) 3738 { 3739 /* Pagination */ 3740 featureNode = _fnFeatureHtmlPaginate( oSettings ); 3741 } 3742 else if ( DataTable.ext.feature.length !== 0 ) 3743 { 3744 /* Plug-in features */ 3745 var aoFeatures = DataTable.ext.feature; 3746 for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ ) 3747 { 3748 if ( cOption == aoFeatures[k].cFeature ) 3749 { 3750 featureNode = aoFeatures[k].fnInit( oSettings ); 3751 break; 3752 } 3753 } 3754 } 3755 3756 /* Add to the 2D features array */ 3757 if ( featureNode ) 3758 { 3759 var aanFeatures = oSettings.aanFeatures; 3760 3761 if ( ! aanFeatures[cOption] ) 3762 { 3763 aanFeatures[cOption] = []; 3764 } 3765 3766 aanFeatures[cOption].push( featureNode ); 3767 insert.append( featureNode ); 3768 } 3769 } 3770 3771 /* Built our DOM structure - replace the holding div with what we want */ 3772 holding.replaceWith( insert ); 3773 oSettings.nHolding = null; 3774 } 3775 3776 3777 /** 3778 * Use the DOM source to create up an array of header cells. The idea here is to 3779 * create a layout grid (array) of rows x columns, which contains a reference 3780 * to the cell that that point in the grid (regardless of col/rowspan), such that 3781 * any column / row could be removed and the new grid constructed 3782 * @param array {object} aLayout Array to store the calculated layout in 3783 * @param {node} nThead The header/footer element for the table 3784 * @memberof DataTable#oApi 3785 */ 3786 function _fnDetectHeader ( aLayout, nThead ) 3787 { 3788 var nTrs = $(nThead).children('tr'); 3789 var nTr, nCell; 3790 var i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan; 3791 var bUnique; 3792 var fnShiftCol = function ( a, i, j ) { 3793 var k = a[i]; 3794 while ( k[j] ) { 3795 j++; 3796 } 3797 return j; 3798 }; 3799 3800 aLayout.splice( 0, aLayout.length ); 3801 3802 /* We know how many rows there are in the layout - so prep it */ 3803 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ ) 3804 { 3805 aLayout.push( [] ); 3806 } 3807 3808 /* Calculate a layout array */ 3809 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ ) 3810 { 3811 nTr = nTrs[i]; 3812 iColumn = 0; 3813 3814 /* For every cell in the row... */ 3815 nCell = nTr.firstChild; 3816 while ( nCell ) { 3817 if ( nCell.nodeName.toUpperCase() == "TD" || 3818 nCell.nodeName.toUpperCase() == "TH" ) 3819 { 3820 /* Get the col and rowspan attributes from the DOM and sanitise them */ 3821 iColspan = nCell.getAttribute('colspan') * 1; 3822 iRowspan = nCell.getAttribute('rowspan') * 1; 3823 iColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan; 3824 iRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan; 3825 3826 /* There might be colspan cells already in this row, so shift our target 3827 * accordingly 3828 */ 3829 iColShifted = fnShiftCol( aLayout, i, iColumn ); 3830 3831 /* Cache calculation for unique columns */ 3832 bUnique = iColspan === 1 ? true : false; 3833 3834 /* If there is col / rowspan, copy the information into the layout grid */ 3835 for ( l=0 ; l<iColspan ; l++ ) 3836 { 3837 for ( k=0 ; k<iRowspan ; k++ ) 3838 { 3839 aLayout[i+k][iColShifted+l] = { 3840 "cell": nCell, 3841 "unique": bUnique 3842 }; 3843 aLayout[i+k].nTr = nTr; 3844 } 3845 } 3846 } 3847 nCell = nCell.nextSibling; 3848 } 3849 } 3850 } 3851 3852 3853 /** 3854 * Get an array of unique th elements, one for each column 3855 * @param {object} oSettings dataTables settings object 3856 * @param {node} nHeader automatically detect the layout from this node - optional 3857 * @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional 3858 * @returns array {node} aReturn list of unique th's 3859 * @memberof DataTable#oApi 3860 */ 3861 function _fnGetUniqueThs ( oSettings, nHeader, aLayout ) 3862 { 3863 var aReturn = []; 3864 if ( !aLayout ) 3865 { 3866 aLayout = oSettings.aoHeader; 3867 if ( nHeader ) 3868 { 3869 aLayout = []; 3870 _fnDetectHeader( aLayout, nHeader ); 3871 } 3872 } 3873 3874 for ( var i=0, iLen=aLayout.length ; i<iLen ; i++ ) 3875 { 3876 for ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ ) 3877 { 3878 if ( aLayout[i][j].unique && 3879 (!aReturn[j] || !oSettings.bSortCellsTop) ) 3880 { 3881 aReturn[j] = aLayout[i][j].cell; 3882 } 3883 } 3884 } 3885 3886 return aReturn; 3887 } 3888 3889 /** 3890 * Set the start position for draw 3891 * @param {object} oSettings dataTables settings object 3892 */ 3893 function _fnStart( oSettings ) 3894 { 3895 var bServerSide = _fnDataSource( oSettings ) == 'ssp'; 3896 var iInitDisplayStart = oSettings.iInitDisplayStart; 3897 3898 // Check and see if we have an initial draw position from state saving 3899 if ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 ) 3900 { 3901 oSettings._iDisplayStart = bServerSide ? 3902 iInitDisplayStart : 3903 iInitDisplayStart >= oSettings.fnRecordsDisplay() ? 3904 0 : 3905 iInitDisplayStart; 3906 3907 oSettings.iInitDisplayStart = -1; 3908 } 3909 } 3910 3911 /** 3912 * Create an Ajax call based on the table's settings, taking into account that 3913 * parameters can have multiple forms, and backwards compatibility. 3914 * 3915 * @param {object} oSettings dataTables settings object 3916 * @param {array} data Data to send to the server, required by 3917 * DataTables - may be augmented by developer callbacks 3918 * @param {function} fn Callback function to run when data is obtained 3919 */ 3920 function _fnBuildAjax( oSettings, data, fn ) 3921 { 3922 // Compatibility with 1.9-, allow fnServerData and event to manipulate 3923 _fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] ); 3924 3925 // Convert to object based for 1.10+ if using the old array scheme which can 3926 // come from server-side processing or serverParams 3927 if ( data && Array.isArray(data) ) { 3928 var tmp = {}; 3929 var rbracket = /(.*?)\[\]$/; 3930 3931 $.each( data, function (key, val) { 3932 var match = val.name.match(rbracket); 3933 3934 if ( match ) { 3935 // Support for arrays 3936 var name = match[0]; 3937 3938 if ( ! tmp[ name ] ) { 3939 tmp[ name ] = []; 3940 } 3941 tmp[ name ].push( val.value ); 3942 } 3943 else { 3944 tmp[val.name] = val.value; 3945 } 3946 } ); 3947 data = tmp; 3948 } 3949 3950 var ajaxData; 3951 var ajax = oSettings.ajax; 3952 var instance = oSettings.oInstance; 3953 var callback = function ( json ) { 3954 var status = oSettings.jqXHR 3955 ? oSettings.jqXHR.status 3956 : null; 3957 3958 if ( json === null || (typeof status === 'number' && status == 204 ) ) { 3959 json = {}; 3960 _fnAjaxDataSrc( oSettings, json, [] ); 3961 } 3962 3963 var error = json.error || json.sError; 3964 if ( error ) { 3965 _fnLog( oSettings, 0, error ); 3966 } 3967 3968 oSettings.json = json; 3969 3970 _fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR] ); 3971 fn( json ); 3972 }; 3973 3974 if ( $.isPlainObject( ajax ) && ajax.data ) 3975 { 3976 ajaxData = ajax.data; 3977 3978 var newData = typeof ajaxData === 'function' ? 3979 ajaxData( data, oSettings ) : // fn can manipulate data or return 3980 ajaxData; // an object object or array to merge 3981 3982 // If the function returned something, use that alone 3983 data = typeof ajaxData === 'function' && newData ? 3984 newData : 3985 $.extend( true, data, newData ); 3986 3987 // Remove the data property as we've resolved it already and don't want 3988 // jQuery to do it again (it is restored at the end of the function) 3989 delete ajax.data; 3990 } 3991 3992 var baseAjax = { 3993 "data": data, 3994 "success": callback, 3995 "dataType": "json", 3996 "cache": false, 3997 "type": oSettings.sServerMethod, 3998 "error": function (xhr, error, thrown) { 3999 var ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR] ); 4000 4001 if ( $.inArray( true, ret ) === -1 ) { 4002 if ( error == "parsererror" ) { 4003 _fnLog( oSettings, 0, 'Invalid JSON response', 1 ); 4004 } 4005 else if ( xhr.readyState === 4 ) { 4006 _fnLog( oSettings, 0, 'Ajax error', 7 ); 4007 } 4008 } 4009 4010 _fnProcessingDisplay( oSettings, false ); 4011 } 4012 }; 4013 4014 // Store the data submitted for the API 4015 oSettings.oAjaxData = data; 4016 4017 // Allow plug-ins and external processes to modify the data 4018 _fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data] ); 4019 4020 if ( oSettings.fnServerData ) 4021 { 4022 // DataTables 1.9- compatibility 4023 oSettings.fnServerData.call( instance, 4024 oSettings.sAjaxSource, 4025 $.map( data, function (val, key) { // Need to convert back to 1.9 trad format 4026 return { name: key, value: val }; 4027 } ), 4028 callback, 4029 oSettings 4030 ); 4031 } 4032 else if ( oSettings.sAjaxSource || typeof ajax === 'string' ) 4033 { 4034 // DataTables 1.9- compatibility 4035 oSettings.jqXHR = $.ajax( $.extend( baseAjax, { 4036 url: ajax || oSettings.sAjaxSource 4037 } ) ); 4038 } 4039 else if ( typeof ajax === 'function' ) 4040 { 4041 // Is a function - let the caller define what needs to be done 4042 oSettings.jqXHR = ajax.call( instance, data, callback, oSettings ); 4043 } 4044 else 4045 { 4046 // Object to extend the base settings 4047 oSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) ); 4048 4049 // Restore for next time around 4050 ajax.data = ajaxData; 4051 } 4052 } 4053 4054 4055 /** 4056 * Update the table using an Ajax call 4057 * @param {object} settings dataTables settings object 4058 * @returns {boolean} Block the table drawing or not 4059 * @memberof DataTable#oApi 4060 */ 4061 function _fnAjaxUpdate( settings ) 4062 { 4063 settings.iDraw++; 4064 _fnProcessingDisplay( settings, true ); 4065 4066
vendor: 15,565 bytes, lines 4066-4571
4066_fnBuildAjax( 4067 settings, 4068 _fnAjaxParameters( settings ), 4069 function(json) { 4070 _fnAjaxUpdateDraw( settings, json ); 4071 } 4072 ); 4073 } 4074 4075 4076 /** 4077 * Build up the parameters in an object needed for a server-side processing 4078 * request. Note that this is basically done twice, is different ways - a modern 4079 * method which is used by default in DataTables 1.10 which uses objects and 4080 * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if 4081 * the sAjaxSource option is used in the initialisation, or the legacyAjax 4082 * option is set. 4083 * @param {object} oSettings dataTables settings object 4084 * @returns {bool} block the table drawing or not 4085 * @memberof DataTable#oApi 4086 */ 4087 function _fnAjaxParameters( settings ) 4088 { 4089 var 4090 columns = settings.aoColumns, 4091 columnCount = columns.length, 4092 features = settings.oFeatures, 4093 preSearch = settings.oPreviousSearch, 4094 preColSearch = settings.aoPreSearchCols, 4095 i, data = [], dataProp, column, columnSearch, 4096 sort = _fnSortFlatten( settings ), 4097 displayStart = settings._iDisplayStart, 4098 displayLength = features.bPaginate !== false ? 4099 settings._iDisplayLength : 4100 -1; 4101 4102 var param = function ( name, value ) { 4103 data.push( { 'name': name, 'value': value } ); 4104 }; 4105 4106 // DataTables 1.9- compatible method 4107 param( 'sEcho', settings.iDraw ); 4108 param( 'iColumns', columnCount ); 4109 param( 'sColumns', _pluck( columns, 'sName' ).join(',') ); 4110 param( 'iDisplayStart', displayStart ); 4111 param( 'iDisplayLength', displayLength ); 4112 4113 // DataTables 1.10+ method 4114 var d = { 4115 draw: settings.iDraw, 4116 columns: [], 4117 order: [], 4118 start: displayStart, 4119 length: displayLength, 4120 search: { 4121 value: preSearch.sSearch, 4122 regex: preSearch.bRegex 4123 } 4124 }; 4125 4126 for ( i=0 ; i<columnCount ; i++ ) { 4127 column = columns[i]; 4128 columnSearch = preColSearch[i]; 4129 dataProp = typeof column.mData=="function" ? 'function' : column.mData ; 4130 4131 d.columns.push( { 4132 data: dataProp, 4133 name: column.sName, 4134 searchable: column.bSearchable, 4135 orderable: column.bSortable, 4136 search: { 4137 value: columnSearch.sSearch, 4138 regex: columnSearch.bRegex 4139 } 4140 } ); 4141 4142 param( "mDataProp_"+i, dataProp ); 4143 4144 if ( features.bFilter ) { 4145 param( 'sSearch_'+i, columnSearch.sSearch ); 4146 param( 'bRegex_'+i, columnSearch.bRegex ); 4147 param( 'bSearchable_'+i, column.bSearchable ); 4148 } 4149 4150 if ( features.bSort ) { 4151 param( 'bSortable_'+i, column.bSortable ); 4152 } 4153 } 4154 4155 if ( features.bFilter ) { 4156 param( 'sSearch', preSearch.sSearch ); 4157 param( 'bRegex', preSearch.bRegex ); 4158 } 4159 4160 if ( features.bSort ) { 4161 $.each( sort, function ( i, val ) { 4162 d.order.push( { column: val.col, dir: val.dir } ); 4163 4164 param( 'iSortCol_'+i, val.col ); 4165 param( 'sSortDir_'+i, val.dir ); 4166 } ); 4167 4168 param( 'iSortingCols', sort.length ); 4169 } 4170 4171 // If the legacy.ajax parameter is null, then we automatically decide which 4172 // form to use, based on sAjaxSource 4173 var legacy = DataTable.ext.legacy.ajax; 4174 if ( legacy === null ) { 4175 return settings.sAjaxSource ? data : d; 4176 } 4177 4178 // Otherwise, if legacy has been specified then we use that to decide on the 4179 // form 4180 return legacy ? data : d; 4181 } 4182 4183 4184 /** 4185 * Data the data from the server (nuking the old) and redraw the table 4186 * @param {object} oSettings dataTables settings object 4187 * @param {object} json json data return from the server. 4188 * @param {string} json.sEcho Tracking flag for DataTables to match requests 4189 * @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering 4190 * @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering 4191 * @param {array} json.aaData The data to display on this page 4192 * @param {string} [json.sColumns] Column ordering (sName, comma separated) 4193 * @memberof DataTable#oApi 4194 */ 4195 function _fnAjaxUpdateDraw ( settings, json ) 4196 { 4197 // v1.10 uses camelCase variables, while 1.9 uses Hungarian notation. 4198 // Support both 4199 var compat = function ( old, modern ) { 4200 return json[old] !== undefined ? json[old] : json[modern]; 4201 }; 4202 4203 var data = _fnAjaxDataSrc( settings, json ); 4204 var draw = compat( 'sEcho', 'draw' ); 4205 var recordsTotal = compat( 'iTotalRecords', 'recordsTotal' ); 4206 var recordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' ); 4207 4208 if ( draw !== undefined ) { 4209 // Protect against out of sequence returns 4210 if ( draw*1 < settings.iDraw ) { 4211 return; 4212 } 4213 settings.iDraw = draw * 1; 4214 } 4215 4216 // No data in returned object, so rather than an array, we show an empty table 4217 if ( ! data ) { 4218 data = []; 4219 } 4220 4221 _fnClearTable( settings ); 4222 settings._iRecordsTotal = parseInt(recordsTotal, 10); 4223 settings._iRecordsDisplay = parseInt(recordsFiltered, 10); 4224 4225 for ( var i=0, ien=data.length ; i<ien ; i++ ) { 4226 _fnAddData( settings, data[i] ); 4227 } 4228 settings.aiDisplay = settings.aiDisplayMaster.slice(); 4229 4230 _fnDraw( settings, true ); 4231 4232 if ( ! settings._bInitComplete ) { 4233 _fnInitComplete( settings, json ); 4234 } 4235 4236 _fnProcessingDisplay( settings, false ); 4237 } 4238 4239 4240 /** 4241 * Get the data from the JSON data source to use for drawing a table. Using 4242 * `_fnGetObjectDataFn` allows the data to be sourced from a property of the 4243 * source object, or from a processing function. 4244 * @param {object} oSettings dataTables settings object 4245 * @param {object} json Data source object / array from the server 4246 * @return {array} Array of data to use 4247 */ 4248 function _fnAjaxDataSrc ( oSettings, json, write ) 4249 { 4250 var dataSrc = $.isPlainObject( oSettings.ajax ) && oSettings.ajax.dataSrc !== undefined ? 4251 oSettings.ajax.dataSrc : 4252 oSettings.sAjaxDataProp; // Compatibility with 1.9-. 4253 4254 if ( ! write ) { 4255 if ( dataSrc === 'data' ) { 4256 // If the default, then we still want to support the old style, and safely ignore 4257 // it if possible 4258 return json.aaData || json[dataSrc]; 4259 } 4260 4261 return dataSrc !== "" ? 4262 _fnGetObjectDataFn( dataSrc )( json ) : 4263 json; 4264 } 4265 4266 // set 4267 _fnSetObjectDataFn( dataSrc )( json, write ); 4268 } 4269 4270 /** 4271 * Generate the node required for filtering text 4272 * @returns {node} Filter control element 4273 * @param {object} oSettings dataTables settings object 4274 * @memberof DataTable#oApi 4275 */ 4276 function _fnFeatureHtmlFilter ( settings ) 4277 { 4278 var classes = settings.oClasses; 4279 var tableId = settings.sTableId; 4280 var language = settings.oLanguage; 4281 var previousSearch = settings.oPreviousSearch; 4282 var features = settings.aanFeatures; 4283 var input = '<input type="search" class="'+classes.sFilterInput+'"/>'; 4284 4285 var str = language.sSearch; 4286 str = str.match(/_INPUT_/) ? 4287 str.replace('_INPUT_', input) : 4288 str+input; 4289 4290 var filter = $('<div/>', { 4291 'id': ! features.f ? tableId+'_filter' : null, 4292 'class': classes.sFilter 4293 } ) 4294 .append( $('<label/>' ).append( str ) ); 4295 4296 var searchFn = function(event) { 4297 /* Update all other filter input elements for the new display */ 4298 var n = features.f; 4299 var val = !this.value ? "" : this.value; // mental IE8 fix :-( 4300 if(previousSearch.return && event.key !== "Enter") { 4301 return; 4302 } 4303 /* Now do the filter */ 4304 if ( val != previousSearch.sSearch ) { 4305 _fnFilterComplete( settings, { 4306 "sSearch": val, 4307 "bRegex": previousSearch.bRegex, 4308 "bSmart": previousSearch.bSmart , 4309 "bCaseInsensitive": previousSearch.bCaseInsensitive, 4310 "return": previousSearch.return 4311 } ); 4312 4313 // Need to redraw, without resorting 4314 settings._iDisplayStart = 0; 4315 _fnDraw( settings ); 4316 } 4317 }; 4318 4319 var searchDelay = settings.searchDelay !== null ? 4320 settings.searchDelay : 4321 _fnDataSource( settings ) === 'ssp' ? 4322 400 : 4323 0; 4324 4325 var jqFilter = $('input', filter) 4326 .val( previousSearch.sSearch ) 4327 .attr( 'placeholder', language.sSearchPlaceholder ) 4328 .on( 4329 'keyup.DT search.DT input.DT paste.DT cut.DT', 4330 searchDelay ? 4331 _fnThrottle( searchFn, searchDelay ) : 4332 searchFn 4333 ) 4334 .on( 'mouseup', function(e) { 4335 // Edge fix! Edge 17 does not trigger anything other than mouse events when clicking 4336 // on the clear icon (Edge bug 17584515). This is safe in other browsers as `searchFn` 4337 // checks the value to see if it has changed. In other browsers it won't have. 4338 setTimeout( function () { 4339 searchFn.call(jqFilter[0], e); 4340 }, 10); 4341 } ) 4342 .on( 'keypress.DT', function(e) { 4343 /* Prevent form submission */ 4344 if ( e.keyCode == 13 ) { 4345 return false; 4346 } 4347 } ) 4348 .attr('aria-controls', tableId); 4349 4350 // Update the input elements whenever the table is filtered 4351 $(settings.nTable).on( 'search.dt.DT', function ( ev, s ) { 4352 if ( settings === s ) { 4353 // IE9 throws an 'unknown error' if document.activeElement is used 4354 // inside an iframe or frame... 4355 try { 4356 if ( jqFilter[0] !== document.activeElement ) { 4357 jqFilter.val( previousSearch.sSearch ); 4358 } 4359 } 4360 catch ( e ) {} 4361 } 4362 } ); 4363 4364 return filter[0]; 4365 } 4366 4367 4368 /** 4369 * Filter the table using both the global filter and column based filtering 4370 * @param {object} oSettings dataTables settings object 4371 * @param {object} oSearch search information 4372 * @param {int} [iForce] force a research of the master array (1) or not (undefined or 0) 4373 * @memberof DataTable#oApi 4374 */ 4375 function _fnFilterComplete ( oSettings, oInput, iForce ) 4376 { 4377 var oPrevSearch = oSettings.oPreviousSearch; 4378 var aoPrevSearch = oSettings.aoPreSearchCols; 4379 var fnSaveFilter = function ( oFilter ) { 4380 /* Save the filtering values */ 4381 oPrevSearch.sSearch = oFilter.sSearch; 4382 oPrevSearch.bRegex = oFilter.bRegex; 4383 oPrevSearch.bSmart = oFilter.bSmart; 4384 oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive; 4385 oPrevSearch.return = oFilter.return; 4386 }; 4387 var fnRegex = function ( o ) { 4388 // Backwards compatibility with the bEscapeRegex option 4389 return o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex; 4390 }; 4391 4392 // Resolve any column types that are unknown due to addition or invalidation 4393 // @todo As per sort - can this be moved into an event handler? 4394 _fnColumnTypes( oSettings ); 4395 4396 /* In server-side processing all filtering is done by the server, so no point hanging around here */ 4397 if ( _fnDataSource( oSettings ) != 'ssp' ) 4398 { 4399 /* Global filter */ 4400 _fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive, oInput.return ); 4401 fnSaveFilter( oInput ); 4402 4403 /* Now do the individual column filter */ 4404 for ( var i=0 ; i<aoPrevSearch.length ; i++ ) 4405 { 4406 _fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, fnRegex(aoPrevSearch[i]), 4407 aoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive ); 4408 } 4409 4410 /* Custom filtering */ 4411 _fnFilterCustom( oSettings ); 4412 } 4413 else 4414 { 4415 fnSaveFilter( oInput ); 4416 } 4417 4418 /* Tell the draw function we have been filtering */ 4419 oSettings.bFiltered = true; 4420 _fnCallbackFire( oSettings, null, 'search', [oSettings] ); 4421 } 4422 4423 4424 /** 4425 * Apply custom filtering functions 4426 * @param {object} oSettings dataTables settings object 4427 * @memberof DataTable#oApi 4428 */ 4429 function _fnFilterCustom( settings ) 4430 { 4431 var filters = DataTable.ext.search; 4432 var displayRows = settings.aiDisplay; 4433 var row, rowIdx; 4434 4435 for ( var i=0, ien=filters.length ; i<ien ; i++ ) { 4436 var rows = []; 4437 4438 // Loop over each row and see if it should be included 4439 for ( var j=0, jen=displayRows.length ; j<jen ; j++ ) { 4440 rowIdx = displayRows[ j ]; 4441 row = settings.aoData[ rowIdx ]; 4442 4443 if ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) { 4444 rows.push( rowIdx ); 4445 } 4446 } 4447 4448 // So the array reference doesn't break set the results into the 4449 // existing array 4450 displayRows.length = 0; 4451 $.merge( displayRows, rows ); 4452 } 4453 } 4454 4455 4456 /** 4457 * Filter the table on a per-column basis 4458 * @param {object} oSettings dataTables settings object 4459 * @param {string} sInput string to filter on 4460 * @param {int} iColumn column to filter 4461 * @param {bool} bRegex treat search string as a regular expression or not 4462 * @param {bool} bSmart use smart filtering or not 4463 * @param {bool} bCaseInsensitive Do case insensitive matching or not 4464 * @memberof DataTable#oApi 4465 */ 4466 function _fnFilterColumn ( settings, searchStr, colIdx, regex, smart, caseInsensitive ) 4467 { 4468 if ( searchStr === '' ) { 4469 return; 4470 } 4471 4472 var data; 4473 var out = []; 4474 var display = settings.aiDisplay; 4475 var rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive ); 4476 4477 for ( var i=0 ; i<display.length ; i++ ) { 4478 data = settings.aoData[ display[i] ]._aFilterData[ colIdx ]; 4479 4480 if ( rpSearch.test( data ) ) { 4481 out.push( display[i] ); 4482 } 4483 } 4484 4485 settings.aiDisplay = out; 4486 } 4487 4488 4489 /** 4490 * Filter the data table based on user input and draw the table 4491 * @param {object} settings dataTables settings object 4492 * @param {string} input string to filter on 4493 * @param {int} force optional - force a research of the master array (1) or not (undefined or 0) 4494 * @param {bool} regex treat as a regular expression or not 4495 * @param {bool} smart perform smart filtering or not 4496 * @param {bool} caseInsensitive Do case insensitive matching or not 4497 * @memberof DataTable#oApi 4498 */ 4499 function _fnFilter( settings, input, force, regex, smart, caseInsensitive ) 4500 { 4501 var rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive ); 4502 var prevSearch = settings.oPreviousSearch.sSearch; 4503 var displayMaster = settings.aiDisplayMaster; 4504 var display, invalidated, i; 4505 var filtered = []; 4506 4507 // Need to take account of custom filtering functions - always filter 4508 if ( DataTable.ext.search.length !== 0 ) { 4509 force = true; 4510 } 4511 4512 // Check if any of the rows were invalidated 4513 invalidated = _fnFilterData( settings ); 4514 4515 // If the input is blank - we just want the full data set 4516 if ( input.length <= 0 ) { 4517 settings.aiDisplay = displayMaster.slice(); 4518 } 4519 else { 4520 // New search - start from the master array 4521 if ( invalidated || 4522 force || 4523 regex || 4524 prevSearch.length > input.length || 4525 input.indexOf(prevSearch) !== 0 || 4526 settings.bSorted // On resort, the display master needs to be 4527 // re-filtered since indexes will have changed 4528 ) { 4529 settings.aiDisplay = displayMaster.slice(); 4530 } 4531 4532 // Search the display array 4533 display = settings.aiDisplay; 4534 4535 for ( i=0 ; i<display.length ; i++ ) { 4536 if ( rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) { 4537 filtered.push( display[i] ); 4538 } 4539 } 4540 4541 settings.aiDisplay = filtered; 4542 } 4543 } 4544 4545 4546 /** 4547 * Build a regular expression object suitable for searching a table 4548 * @param {string} sSearch string to search for 4549 * @param {bool} bRegex treat as a regular expression or not 4550 * @param {bool} bSmart perform smart filtering or not 4551 * @param {bool} bCaseInsensitive Do case insensitive matching or not 4552 * @returns {RegExp} constructed object 4553 * @memberof DataTable#oApi 4554 */ 4555 function _fnFilterCreateSearch( search, regex, smart, caseInsensitive ) 4556 { 4557 search = regex ? 4558 search : 4559 _fnEscapeRegex( search ); 4560 4561 if ( smart ) { 4562 /* For smart filtering we want to allow the search to work regardless of 4563 * word order. We also want double quoted text to be preserved, so word 4564 * order is important - a la google. So this is what we want to 4565 * generate: 4566 * 4567 * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$ 4568 */ 4569 var a = $.map( search.match( /"[^"]+"|[^ ]+/g ) || [''], function ( word ) { 4570 if ( word.charAt(0) === '"' ) { 4571 var m = word.match( /^"(.*)"
vendor: 130,258 bytes, lines 4571-9377
4571$/ ); 4572 word = m ? m[1] : word; 4573 } 4574 4575 return word.replace('"', ''); 4576 } ); 4577 4578 search = '^(?=.*?'+a.join( ')(?=.*?' )+').*$'; 4579 } 4580 4581 return new RegExp( search, caseInsensitive ? 'i' : '' ); 4582 } 4583 4584 4585 /** 4586 * Escape a string such that it can be used in a regular expression 4587 * @param {string} sVal string to escape 4588 * @returns {string} escaped string 4589 * @memberof DataTable#oApi 4590 */ 4591 var _fnEscapeRegex = DataTable.util.escapeRegex; 4592 4593 var __filter_div = $('<div>')[0]; 4594 var __filter_div_textContent = __filter_div.textContent !== undefined; 4595 4596 // Update the filtering data for each row if needed (by invalidation or first run) 4597 function _fnFilterData ( settings ) 4598 { 4599 var columns = settings.aoColumns; 4600 var column; 4601 var i, j, ien, jen, filterData, cellData, row; 4602 var wasInvalidated = false; 4603 4604 for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) { 4605 row = settings.aoData[i]; 4606 4607 if ( ! row._aFilterData ) { 4608 filterData = []; 4609 4610 for ( j=0, jen=columns.length ; j<jen ; j++ ) { 4611 column = columns[j]; 4612 4613 if ( column.bSearchable ) { 4614 cellData = _fnGetCellData( settings, i, j, 'filter' ); 4615 4616 // Search in DataTables 1.10 is string based. In 1.11 this 4617 // should be altered to also allow strict type checking. 4618 if ( cellData === null ) { 4619 cellData = ''; 4620 } 4621 4622 if ( typeof cellData !== 'string' && cellData.toString ) { 4623 cellData = cellData.toString(); 4624 } 4625 } 4626 else { 4627 cellData = ''; 4628 } 4629 4630 // If it looks like there is an HTML entity in the string, 4631 // attempt to decode it so sorting works as expected. Note that 4632 // we could use a single line of jQuery to do this, but the DOM 4633 // method used here is much faster http://jsperf.com/html-decode 4634 if ( cellData.indexOf && cellData.indexOf('&') !== -1 ) { 4635 __filter_div.innerHTML = cellData; 4636 cellData = __filter_div_textContent ? 4637 __filter_div.textContent : 4638 __filter_div.innerText; 4639 } 4640 4641 if ( cellData.replace ) { 4642 cellData = cellData.replace(/[\r\n\u2028]/g, ''); 4643 } 4644 4645 filterData.push( cellData ); 4646 } 4647 4648 row._aFilterData = filterData; 4649 row._sFilterRow = filterData.join(' '); 4650 wasInvalidated = true; 4651 } 4652 } 4653 4654 return wasInvalidated; 4655 } 4656 4657 4658 /** 4659 * Convert from the internal Hungarian notation to camelCase for external 4660 * interaction 4661 * @param {object} obj Object to convert 4662 * @returns {object} Inverted object 4663 * @memberof DataTable#oApi 4664 */ 4665 function _fnSearchToCamel ( obj ) 4666 { 4667 return { 4668 search: obj.sSearch, 4669 smart: obj.bSmart, 4670 regex: obj.bRegex, 4671 caseInsensitive: obj.bCaseInsensitive 4672 }; 4673 } 4674 4675 4676 4677 /** 4678 * Convert from camelCase notation to the internal Hungarian. We could use the 4679 * Hungarian convert function here, but this is cleaner 4680 * @param {object} obj Object to convert 4681 * @returns {object} Inverted object 4682 * @memberof DataTable#oApi 4683 */ 4684 function _fnSearchToHung ( obj ) 4685 { 4686 return { 4687 sSearch: obj.search, 4688 bSmart: obj.smart, 4689 bRegex: obj.regex, 4690 bCaseInsensitive: obj.caseInsensitive 4691 }; 4692 } 4693 4694 /** 4695 * Generate the node required for the info display 4696 * @param {object} oSettings dataTables settings object 4697 * @returns {node} Information element 4698 * @memberof DataTable#oApi 4699 */ 4700 function _fnFeatureHtmlInfo ( settings ) 4701 { 4702 var 4703 tid = settings.sTableId, 4704 nodes = settings.aanFeatures.i, 4705 n = $('<div/>', { 4706 'class': settings.oClasses.sInfo, 4707 'id': ! nodes ? tid+'_info' : null 4708 } ); 4709 4710 if ( ! nodes ) { 4711 // Update display on each draw 4712 settings.aoDrawCallback.push( { 4713 "fn": _fnUpdateInfo, 4714 "sName": "information" 4715 } ); 4716 4717 n 4718 .attr( 'role', 'status' ) 4719 .attr( 'aria-live', 'polite' ); 4720 4721 // Table is described by our info div 4722 $(settings.nTable).attr( 'aria-describedby', tid+'_info' ); 4723 } 4724 4725 return n[0]; 4726 } 4727 4728 4729 /** 4730 * Update the information elements in the display 4731 * @param {object} settings dataTables settings object 4732 * @memberof DataTable#oApi 4733 */ 4734 function _fnUpdateInfo ( settings ) 4735 { 4736 /* Show information about the table */ 4737 var nodes = settings.aanFeatures.i; 4738 if ( nodes.length === 0 ) { 4739 return; 4740 } 4741 4742 var 4743 lang = settings.oLanguage, 4744 start = settings._iDisplayStart+1, 4745 end = settings.fnDisplayEnd(), 4746 max = settings.fnRecordsTotal(), 4747 total = settings.fnRecordsDisplay(), 4748 out = total ? 4749 lang.sInfo : 4750 lang.sInfoEmpty; 4751 4752 if ( total !== max ) { 4753 /* Record set after filtering */ 4754 out += ' ' + lang.sInfoFiltered; 4755 } 4756 4757 // Convert the macros 4758 out += lang.sInfoPostFix; 4759 out = _fnInfoMacros( settings, out ); 4760 4761 var callback = lang.fnInfoCallback; 4762 if ( callback !== null ) { 4763 out = callback.call( settings.oInstance, 4764 settings, start, end, max, total, out 4765 ); 4766 } 4767 4768 $(nodes).html( out ); 4769 } 4770 4771 4772 function _fnInfoMacros ( settings, str ) 4773 { 4774 // When infinite scrolling, we are always starting at 1. _iDisplayStart is used only 4775 // internally 4776 var 4777 formatter = settings.fnFormatNumber, 4778 start = settings._iDisplayStart+1, 4779 len = settings._iDisplayLength, 4780 vis = settings.fnRecordsDisplay(), 4781 all = len === -1; 4782 4783 return str. 4784 replace(/_START_/g, formatter.call( settings, start ) ). 4785 replace(/_END_/g, formatter.call( settings, settings.fnDisplayEnd() ) ). 4786 replace(/_MAX_/g, formatter.call( settings, settings.fnRecordsTotal() ) ). 4787 replace(/_TOTAL_/g, formatter.call( settings, vis ) ). 4788 replace(/_PAGE_/g, formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ). 4789 replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) ); 4790 } 4791 4792 4793 4794 /** 4795 * Draw the table for the first time, adding all required features 4796 * @param {object} settings dataTables settings object 4797 * @memberof DataTable#oApi 4798 */ 4799 function _fnInitialise ( settings ) 4800 { 4801 var i, iLen, iAjaxStart=settings.iInitDisplayStart; 4802 var columns = settings.aoColumns, column; 4803 var features = settings.oFeatures; 4804 var deferLoading = settings.bDeferLoading; // value modified by the draw 4805 4806 /* Ensure that the table data is fully initialised */ 4807 if ( ! settings.bInitialised ) { 4808 setTimeout( function(){ _fnInitialise( settings ); }, 200 ); 4809 return; 4810 } 4811 4812 /* Show the display HTML options */ 4813 _fnAddOptionsHtml( settings ); 4814 4815 /* Build and draw the header / footer for the table */ 4816 _fnBuildHead( settings ); 4817 _fnDrawHead( settings, settings.aoHeader ); 4818 _fnDrawHead( settings, settings.aoFooter ); 4819 4820 /* Okay to show that something is going on now */ 4821 _fnProcessingDisplay( settings, true ); 4822 4823 /* Calculate sizes for columns */ 4824 if ( features.bAutoWidth ) { 4825 _fnCalculateColumnWidths( settings ); 4826 } 4827 4828 for ( i=0, iLen=columns.length ; i<iLen ; i++ ) { 4829 column = columns[i]; 4830 4831 if ( column.sWidth ) { 4832 column.nTh.style.width = _fnStringToCss( column.sWidth ); 4833 } 4834 } 4835 4836 _fnCallbackFire( settings, null, 'preInit', [settings] ); 4837 4838 // If there is default sorting required - let's do it. The sort function 4839 // will do the drawing for us. Otherwise we draw the table regardless of the 4840 // Ajax source - this allows the table to look initialised for Ajax sourcing 4841 // data (show 'loading' message possibly) 4842 _fnReDraw( settings ); 4843 4844 // Server-side processing init complete is done by _fnAjaxUpdateDraw 4845 var dataSrc = _fnDataSource( settings ); 4846 if ( dataSrc != 'ssp' || deferLoading ) { 4847 // if there is an ajax source load the data 4848 if ( dataSrc == 'ajax' ) { 4849 _fnBuildAjax( settings, [], function(json) { 4850 var aData = _fnAjaxDataSrc( settings, json ); 4851 4852 // Got the data - add it to the table 4853 for ( i=0 ; i<aData.length ; i++ ) { 4854 _fnAddData( settings, aData[i] ); 4855 } 4856 4857 // Reset the init display for cookie saving. We've already done 4858 // a filter, and therefore cleared it before. So we need to make 4859 // it appear 'fresh' 4860 settings.iInitDisplayStart = iAjaxStart; 4861 4862 _fnReDraw( settings ); 4863 4864 _fnProcessingDisplay( settings, false ); 4865 _fnInitComplete( settings, json ); 4866 }, settings ); 4867 } 4868 else { 4869 _fnProcessingDisplay( settings, false ); 4870 _fnInitComplete( settings ); 4871 } 4872 } 4873 } 4874 4875 4876 /** 4877 * Draw the table for the first time, adding all required features 4878 * @param {object} oSettings dataTables settings object 4879 * @param {object} [json] JSON from the server that completed the table, if using Ajax source 4880 * with client-side processing (optional) 4881 * @memberof DataTable#oApi 4882 */ 4883 function _fnInitComplete ( settings, json ) 4884 { 4885 settings._bInitComplete = true; 4886 4887 // When data was added after the initialisation (data or Ajax) we need to 4888 // calculate the column sizing 4889 if ( json || settings.oInit.aaData ) { 4890 _fnAdjustColumnSizing( settings ); 4891 } 4892 4893 _fnCallbackFire( settings, null, 'plugin-init', [settings, json] ); 4894 _fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] ); 4895 } 4896 4897 4898 function _fnLengthChange ( settings, val ) 4899 { 4900 var len = parseInt( val, 10 ); 4901 settings._iDisplayLength = len; 4902 4903 _fnLengthOverflow( settings ); 4904 4905 // Fire length change event 4906 _fnCallbackFire( settings, null, 'length', [settings, len] ); 4907 } 4908 4909 4910 /** 4911 * Generate the node required for user display length changing 4912 * @param {object} settings dataTables settings object 4913 * @returns {node} Display length feature node 4914 * @memberof DataTable#oApi 4915 */ 4916 function _fnFeatureHtmlLength ( settings ) 4917 { 4918 var 4919 classes = settings.oClasses, 4920 tableId = settings.sTableId, 4921 menu = settings.aLengthMenu, 4922 d2 = Array.isArray( menu[0] ), 4923 lengths = d2 ? menu[0] : menu, 4924 language = d2 ? menu[1] : menu; 4925 4926 var select = $('<select/>', { 4927 'name': tableId+'_length', 4928 'aria-controls': tableId, 4929 'class': classes.sLengthSelect 4930 } ); 4931 4932 for ( var i=0, ien=lengths.length ; i<ien ; i++ ) { 4933 select[0][ i ] = new Option( 4934 typeof language[i] === 'number' ? 4935 settings.fnFormatNumber( language[i] ) : 4936 language[i], 4937 lengths[i] 4938 ); 4939 } 4940 4941 var div = $('<div><label/></div>').addClass( classes.sLength ); 4942 if ( ! settings.aanFeatures.l ) { 4943 div[0].id = tableId+'_length'; 4944 } 4945 4946 div.children().append( 4947 settings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML ) 4948 ); 4949 4950 // Can't use `select` variable as user might provide their own and the 4951 // reference is broken by the use of outerHTML 4952 $('select', div) 4953 .val( settings._iDisplayLength ) 4954 .on( 'change.DT', function(e) { 4955 _fnLengthChange( settings, $(this).val() ); 4956 _fnDraw( settings ); 4957 } ); 4958 4959 // Update node value whenever anything changes the table's length 4960 $(settings.nTable).on( 'length.dt.DT', function (e, s, len) { 4961 if ( settings === s ) { 4962 $('select', div).val( len ); 4963 } 4964 } ); 4965 4966 return div[0]; 4967 } 4968 4969 4970 4971 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 4972 * Note that most of the paging logic is done in 4973 * DataTable.ext.pager 4974 */ 4975 4976 /** 4977 * Generate the node required for default pagination 4978 * @param {object} oSettings dataTables settings object 4979 * @returns {node} Pagination feature node 4980 * @memberof DataTable#oApi 4981 */ 4982 function _fnFeatureHtmlPaginate ( settings ) 4983 { 4984 var 4985 type = settings.sPaginationType, 4986 plugin = DataTable.ext.pager[ type ], 4987 modern = typeof plugin === 'function', 4988 redraw = function( settings ) { 4989 _fnDraw( settings ); 4990 }, 4991 node = $('<div/>').addClass( settings.oClasses.sPaging + type )[0], 4992 features = settings.aanFeatures; 4993 4994 if ( ! modern ) { 4995 plugin.fnInit( settings, node, redraw ); 4996 } 4997 4998 /* Add a draw callback for the pagination on first instance, to update the paging display */ 4999 if ( ! features.p ) 5000 { 5001 node.id = settings.sTableId+'_paginate'; 5002 5003 settings.aoDrawCallback.push( { 5004 "fn": function( settings ) { 5005 if ( modern ) { 5006 var 5007 start = settings._iDisplayStart, 5008 len = settings._iDisplayLength, 5009 visRecords = settings.fnRecordsDisplay(), 5010 all = len === -1, 5011 page = all ? 0 : Math.ceil( start / len ), 5012 pages = all ? 1 : Math.ceil( visRecords / len ), 5013 buttons = plugin(page, pages), 5014 i, ien; 5015 5016 for ( i=0, ien=features.p.length ; i<ien ; i++ ) { 5017 _fnRenderer( settings, 'pageButton' )( 5018 settings, features.p[i], i, buttons, page, pages 5019 ); 5020 } 5021 } 5022 else { 5023 plugin.fnUpdate( settings, redraw ); 5024 } 5025 }, 5026 "sName": "pagination" 5027 } ); 5028 } 5029 5030 return node; 5031 } 5032 5033 5034 /** 5035 * Alter the display settings to change the page 5036 * @param {object} settings DataTables settings object 5037 * @param {string|int} action Paging action to take: "first", "previous", 5038 * "next" or "last" or page number to jump to (integer) 5039 * @param [bool] redraw Automatically draw the update or not 5040 * @returns {bool} true page has changed, false - no change 5041 * @memberof DataTable#oApi 5042 */ 5043 function _fnPageChange ( settings, action, redraw ) 5044 { 5045 var 5046 start = settings._iDisplayStart, 5047 len = settings._iDisplayLength, 5048 records = settings.fnRecordsDisplay(); 5049 5050 if ( records === 0 || len === -1 ) 5051 { 5052 start = 0; 5053 } 5054 else if ( typeof action === "number" ) 5055 { 5056 start = action * len; 5057 5058 if ( start > records ) 5059 { 5060 start = 0; 5061 } 5062 } 5063 else if ( action == "first" ) 5064 { 5065 start = 0; 5066 } 5067 else if ( action == "previous" ) 5068 { 5069 start = len >= 0 ? 5070 start - len : 5071 0; 5072 5073 if ( start < 0 ) 5074 { 5075 start = 0; 5076 } 5077 } 5078 else if ( action == "next" ) 5079 { 5080 if ( start + len < records ) 5081 { 5082 start += len; 5083 } 5084 } 5085 else if ( action == "last" ) 5086 { 5087 start = Math.floor( (records-1) / len) * len; 5088 } 5089 else 5090 { 5091 _fnLog( settings, 0, "Unknown paging action: "+action, 5 ); 5092 } 5093 5094 var changed = settings._iDisplayStart !== start; 5095 settings._iDisplayStart = start; 5096 5097 if ( changed ) { 5098 _fnCallbackFire( settings, null, 'page', [settings] ); 5099 5100 if ( redraw ) { 5101 _fnDraw( settings ); 5102 } 5103 } 5104 else { 5105 // No change event - paging was called, but no change 5106 _fnCallbackFire( settings, null, 'page-nc', [settings] ); 5107 } 5108 5109 return changed; 5110 } 5111 5112 5113 5114 /** 5115 * Generate the node required for the processing node 5116 * @param {object} settings dataTables settings object 5117 * @returns {node} Processing element 5118 * @memberof DataTable#oApi 5119 */ 5120 function _fnFeatureHtmlProcessing ( settings ) 5121 { 5122 return $('<div/>', { 5123 'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null, 5124 'class': settings.oClasses.sProcessing, 5125 'role': 'status' 5126 } ) 5127 .html( settings.oLanguage.sProcessing ) 5128 .append('<div><div></div><div></div><div></div><div></div></div>') 5129 .insertBefore( settings.nTable )[0]; 5130 } 5131 5132 5133 /** 5134 * Display or hide the processing indicator 5135 * @param {object} settings dataTables settings object 5136 * @param {bool} show Show the processing indicator (true) or not (false) 5137 * @memberof DataTable#oApi 5138 */ 5139 function _fnProcessingDisplay ( settings, show ) 5140 { 5141 if ( settings.oFeatures.bProcessing ) { 5142 $(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' ); 5143 } 5144 5145 _fnCallbackFire( settings, null, 'processing', [settings, show] ); 5146 } 5147 5148 /** 5149 * Add any control elements for the table - specifically scrolling 5150 * @param {object} settings dataTables settings object 5151 * @returns {node} Node to add to the DOM 5152 * @memberof DataTable#oApi 5153 */ 5154 function _fnFeatureHtmlTable ( settings ) 5155 { 5156 var table = $(settings.nTable); 5157 5158 // Scrolling from here on in 5159 var scroll = settings.oScroll; 5160 5161 if ( scroll.sX === '' && scroll.sY === '' ) { 5162 return settings.nTable; 5163 } 5164 5165 var scrollX = scroll.sX; 5166 var scrollY = scroll.sY; 5167 var classes = settings.oClasses; 5168 var caption = table.children('caption'); 5169 var captionSide = caption.length ? caption[0]._captionSide : null; 5170 var headerClone = $( table[0].cloneNode(false) ); 5171 var footerClone = $( table[0].cloneNode(false) ); 5172 var footer = table.children('tfoot'); 5173 var _div = '<div/>'; 5174 var size = function ( s ) { 5175 return !s ? null : _fnStringToCss( s ); 5176 }; 5177 5178 if ( ! footer.length ) { 5179 footer = null; 5180 } 5181 5182 /* 5183 * The HTML structure that we want to generate in this function is: 5184 * div - scroller 5185 * div - scroll head 5186 * div - scroll head inner 5187 * table - scroll head table 5188 * thead - thead 5189 * div - scroll body 5190 * table - table (master table) 5191 * thead - thead clone for sizing 5192 * tbody - tbody 5193 * div - scroll foot 5194 * div - scroll foot inner 5195 * table - scroll foot table 5196 * tfoot - tfoot 5197 */ 5198 var scroller = $( _div, { 'class': classes.sScrollWrapper } ) 5199 .append( 5200 $(_div, { 'class': classes.sScrollHead } ) 5201 .css( { 5202 overflow: 'hidden', 5203 position: 'relative', 5204 border: 0, 5205 width: scrollX ? size(scrollX) : '100%' 5206 } ) 5207 .append( 5208 $(_div, { 'class': classes.sScrollHeadInner } ) 5209 .css( { 5210 'box-sizing': 'content-box', 5211 width: scroll.sXInner || '100%' 5212 } ) 5213 .append( 5214 headerClone 5215 .removeAttr('id') 5216 .css( 'margin-left', 0 ) 5217 .append( captionSide === 'top' ? caption : null ) 5218 .append( 5219 table.children('thead') 5220 ) 5221 ) 5222 ) 5223 ) 5224 .append( 5225 $(_div, { 'class': classes.sScrollBody } ) 5226 .css( { 5227 position: 'relative', 5228 overflow: 'auto', 5229 width: size( scrollX ) 5230 } ) 5231 .append( table ) 5232 ); 5233 5234 if ( footer ) { 5235 scroller.append( 5236 $(_div, { 'class': classes.sScrollFoot } ) 5237 .css( { 5238 overflow: 'hidden', 5239 border: 0, 5240 width: scrollX ? size(scrollX) : '100%' 5241 } ) 5242 .append( 5243 $(_div, { 'class': classes.sScrollFootInner } ) 5244 .append( 5245 footerClone 5246 .removeAttr('id') 5247 .css( 'margin-left', 0 ) 5248 .append( captionSide === 'bottom' ? caption : null ) 5249 .append( 5250 table.children('tfoot') 5251 ) 5252 ) 5253 ) 5254 ); 5255 } 5256 5257 var children = scroller.children(); 5258 var scrollHead = children[0]; 5259 var scrollBody = children[1]; 5260 var scrollFoot = footer ? children[2] : null; 5261 5262 // When the body is scrolled, then we also want to scroll the headers 5263 if ( scrollX ) { 5264 $(scrollBody).on( 'scroll.DT', function (e) { 5265 var scrollLeft = this.scrollLeft; 5266 5267 scrollHead.scrollLeft = scrollLeft; 5268 5269 if ( footer ) { 5270 scrollFoot.scrollLeft = scrollLeft; 5271 } 5272 } ); 5273 } 5274 5275 $(scrollBody).css('max-height', scrollY); 5276 if (! scroll.bCollapse) { 5277 $(scrollBody).css('height', scrollY); 5278 } 5279 5280 settings.nScrollHead = scrollHead; 5281 settings.nScrollBody = scrollBody; 5282 settings.nScrollFoot = scrollFoot; 5283 5284 // On redraw - align columns 5285 settings.aoDrawCallback.push( { 5286 "fn": _fnScrollDraw, 5287 "sName": "scrolling" 5288 } ); 5289 5290 return scroller[0]; 5291 } 5292 5293 5294 5295 /** 5296 * Update the header, footer and body tables for resizing - i.e. column 5297 * alignment. 5298 * 5299 * Welcome to the most horrible function DataTables. The process that this 5300 * function follows is basically: 5301 * 1. Re-create the table inside the scrolling div 5302 * 2. Take live measurements from the DOM 5303 * 3. Apply the measurements to align the columns 5304 * 4. Clean up 5305 * 5306 * @param {object} settings dataTables settings object 5307 * @memberof DataTable#oApi 5308 */ 5309 function _fnScrollDraw ( settings ) 5310 { 5311 // Given that this is such a monster function, a lot of variables are use 5312 // to try and keep the minimised size as small as possible 5313 var 5314 scroll = settings.oScroll, 5315 scrollX = scroll.sX, 5316 scrollXInner = scroll.sXInner, 5317 scrollY = scroll.sY, 5318 barWidth = scroll.iBarWidth, 5319 divHeader = $(settings.nScrollHead), 5320 divHeaderStyle = divHeader[0].style, 5321 divHeaderInner = divHeader.children('div'), 5322 divHeaderInnerStyle = divHeaderInner[0].style, 5323 divHeaderTable = divHeaderInner.children('table'), 5324 divBodyEl = settings.nScrollBody, 5325 divBody = $(divBodyEl), 5326 divBodyStyle = divBodyEl.style, 5327 divFooter = $(settings.nScrollFoot), 5328 divFooterInner = divFooter.children('div'), 5329 divFooterTable = divFooterInner.children('table'), 5330 header = $(settings.nTHead), 5331 table = $(settings.nTable), 5332 tableEl = table[0], 5333 tableStyle = tableEl.style, 5334 footer = settings.nTFoot ? $(settings.nTFoot) : null, 5335 browser = settings.oBrowser, 5336 ie67 = browser.bScrollOversize, 5337 dtHeaderCells = _pluck( settings.aoColumns, 'nTh' ), 5338 headerTrgEls, footerTrgEls, 5339 headerSrcEls, footerSrcEls, 5340 headerCopy, footerCopy, 5341 headerWidths=[], footerWidths=[], 5342 headerContent=[], footerContent=[], 5343 idx, correction, sanityWidth, 5344 zeroOut = function(nSizer) { 5345 var style = nSizer.style; 5346 style.paddingTop = "0"; 5347 style.paddingBottom = "0"; 5348 style.borderTopWidth = "0"; 5349 style.borderBottomWidth = "0"; 5350 style.height = 0; 5351 }; 5352 5353 // If the scrollbar visibility has changed from the last draw, we need to 5354 // adjust the column sizes as the table width will have changed to account 5355 // for the scrollbar 5356 var scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight; 5357 5358 if ( settings.scrollBarVis !== scrollBarVis && settings.scrollBarVis !== undefined ) { 5359 settings.scrollBarVis = scrollBarVis; 5360 _fnAdjustColumnSizing( settings ); 5361 return; // adjust column sizing will call this function again 5362 } 5363 else { 5364 settings.scrollBarVis = scrollBarVis; 5365 } 5366 5367 /* 5368 * 1. Re-create the table inside the scrolling div 5369 */ 5370 5371 // Remove the old minimised thead and tfoot elements in the inner table 5372 table.children('thead, tfoot').remove(); 5373 5374 if ( footer ) { 5375 footerCopy = footer.clone().prependTo( table ); 5376 footerTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized 5377 footerSrcEls = footerCopy.find('tr'); 5378 footerCopy.find('[id]').removeAttr('id'); 5379 } 5380 5381 // Clone the current header and footer elements and then place it into the inner table 5382 headerCopy = header.clone().prependTo( table ); 5383 headerTrgEls = header.find('tr'); // original header is in its own table 5384 headerSrcEls = headerCopy.find('tr'); 5385 headerCopy.find('th, td').removeAttr('tabindex'); 5386 headerCopy.find('[id]').removeAttr('id'); 5387 5388 5389 /* 5390 * 2. Take live measurements from the DOM - do not alter the DOM itself! 5391 */ 5392 5393 // Remove old sizing and apply the calculated column widths 5394 // Get the unique column headers in the newly created (cloned) header. We want to apply the 5395 // calculated sizes to this header 5396 if ( ! scrollX ) 5397 { 5398 divBodyStyle.width = '100%'; 5399 divHeader[0].style.width = '100%'; 5400 } 5401 5402 $.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) { 5403 idx = _fnVisibleToColumnIndex( settings, i ); 5404 el.style.width = settings.aoColumns[idx].sWidth; 5405 } ); 5406 5407 if ( footer ) { 5408 _fnApplyToChildren( function(n) { 5409 n.style.width = ""; 5410 }, footerSrcEls ); 5411 } 5412 5413 // Size the table as a whole 5414 sanityWidth = table.outerWidth(); 5415 if ( scrollX === "" ) { 5416 // No x scrolling 5417 tableStyle.width = "100%"; 5418 5419 // IE7 will make the width of the table when 100% include the scrollbar 5420 // - which is shouldn't. When there is a scrollbar we need to take this 5421 // into account. 5422 if ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight || 5423 divBody.css('overflow-y') == "scroll") 5424 ) { 5425 tableStyle.width = _fnStringToCss( table.outerWidth() - barWidth); 5426 } 5427 5428 // Recalculate the sanity width 5429 sanityWidth = table.outerWidth(); 5430 } 5431 else if ( scrollXInner !== "" ) { 5432 // legacy x scroll inner has been given - use it 5433 tableStyle.width = _fnStringToCss(scrollXInner); 5434 5435 // Recalculate the sanity width 5436 sanityWidth = table.outerWidth(); 5437 } 5438 5439 // Hidden header should have zero height, so remove padding and borders. Then 5440 // set the width based on the real headers 5441 5442 // Apply all styles in one pass 5443 _fnApplyToChildren( zeroOut, headerSrcEls ); 5444 5445 // Read all widths in next pass 5446 _fnApplyToChildren( function(nSizer) { 5447 var style = window.getComputedStyle ? 5448 window.getComputedStyle(nSizer).width : 5449 _fnStringToCss( $(nSizer).width() ); 5450 5451 headerContent.push( nSizer.innerHTML ); 5452 headerWidths.push( style ); 5453 }, headerSrcEls ); 5454 5455 // Apply all widths in final pass 5456 _fnApplyToChildren( function(nToSize, i) { 5457 nToSize.style.width = headerWidths[i]; 5458 }, headerTrgEls ); 5459 5460 $(headerSrcEls).css('height', 0); 5461 5462 /* Same again with the footer if we have one */ 5463 if ( footer ) 5464 { 5465 _fnApplyToChildren( zeroOut, footerSrcEls ); 5466 5467 _fnApplyToChildren( function(nSizer) { 5468 footerContent.push( nSizer.innerHTML ); 5469 footerWidths.push( _fnStringToCss( $(nSizer).css('width') ) ); 5470 }, footerSrcEls ); 5471 5472 _fnApplyToChildren( function(nToSize, i) { 5473 nToSize.style.width = footerWidths[i]; 5474 }, footerTrgEls ); 5475 5476 $(footerSrcEls).height(0); 5477 } 5478 5479 5480 /* 5481 * 3. Apply the measurements 5482 */ 5483 5484 // "Hide" the header and footer that we used for the sizing. We need to keep 5485 // the content of the cell so that the width applied to the header and body 5486 // both match, but we want to hide it completely. We want to also fix their 5487 // width to what they currently are 5488 _fnApplyToChildren( function(nSizer, i) { 5489 nSizer.innerHTML = '<div class="dataTables_sizing">'+headerContent[i]+'</div>'; 5490 nSizer.childNodes[0].style.height = "0"; 5491 nSizer.childNodes[0].style.overflow = "hidden"; 5492 nSizer.style.width = headerWidths[i]; 5493 }, headerSrcEls ); 5494 5495 if ( footer ) 5496 { 5497 _fnApplyToChildren( function(nSizer, i) { 5498 nSizer.innerHTML = '<div class="dataTables_sizing">'+footerContent[i]+'</div>'; 5499 nSizer.childNodes[0].style.height = "0"; 5500 nSizer.childNodes[0].style.overflow = "hidden"; 5501 nSizer.style.width = footerWidths[i]; 5502 }, footerSrcEls ); 5503 } 5504 5505 // Sanity check that the table is of a sensible width. If not then we are going to get 5506 // misalignment - try to prevent this by not allowing the table to shrink below its min width 5507 if ( Math.round(table.outerWidth()) < Math.round(sanityWidth) ) 5508 { 5509 // The min width depends upon if we have a vertical scrollbar visible or not */ 5510 correction = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight || 5511 divBody.css('overflow-y') == "scroll")) ? 5512 sanityWidth+barWidth : 5513 sanityWidth; 5514 5515 // IE6/7 are a law unto themselves... 5516 if ( ie67 && (divBodyEl.scrollHeight > 5517 divBodyEl.offsetHeight || divBody.css('overflow-y') == "scroll") 5518 ) { 5519 tableStyle.width = _fnStringToCss( correction-barWidth ); 5520 } 5521 5522 // And give the user a warning that we've stopped the table getting too small 5523 if ( scrollX === "" || scrollXInner !== "" ) { 5524 _fnLog( settings, 1, 'Possible column misalignment', 6 ); 5525 } 5526 } 5527 else 5528 { 5529 correction = '100%'; 5530 } 5531 5532 // Apply to the container elements 5533 divBodyStyle.width = _fnStringToCss( correction ); 5534 divHeaderStyle.width = _fnStringToCss( correction ); 5535 5536 if ( footer ) { 5537 settings.nScrollFoot.style.width = _fnStringToCss( correction ); 5538 } 5539 5540 5541 /* 5542 * 4. Clean up 5543 */ 5544 if ( ! scrollY ) { 5545 /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting 5546 * the scrollbar height from the visible display, rather than adding it on. We need to 5547 * set the height in order to sort this. Don't want to do it in any other browsers. 5548 */ 5549 if ( ie67 ) { 5550 divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth ); 5551 } 5552 } 5553 5554 /* Finally set the width's of the header and footer tables */ 5555 var iOuterWidth = table.outerWidth(); 5556 divHeaderTable[0].style.width = _fnStringToCss( iOuterWidth ); 5557 divHeaderInnerStyle.width = _fnStringToCss( iOuterWidth ); 5558 5559 // Figure out if there are scrollbar present - if so then we need a the header and footer to 5560 // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar) 5561 var bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll"; 5562 var padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' ); 5563 divHeaderInnerStyle[ padding ] = bScrolling ? barWidth+"px" : "0px"; 5564 5565 if ( footer ) { 5566 divFooterTable[0].style.width = _fnStringToCss( iOuterWidth ); 5567 divFooterInner[0].style.width = _fnStringToCss( iOuterWidth ); 5568 divFooterInner[0].style[padding] = bScrolling ? barWidth+"px" : "0px"; 5569 } 5570 5571 // Correct DOM ordering for colgroup - comes before the thead 5572 table.children('colgroup').insertBefore( table.children('thead') ); 5573 5574 /* Adjust the position of the header in case we loose the y-scrollbar */ 5575 divBody.trigger('scroll'); 5576 5577 // If sorting or filtering has occurred, jump the scrolling back to the top 5578 // only if we aren't holding the position 5579 if ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) { 5580 divBodyEl.scrollTop = 0; 5581 } 5582 } 5583 5584 5585 5586 /** 5587 * Apply a given function to the display child nodes of an element array (typically 5588 * TD children of TR rows 5589 * @param {function} fn Method to apply to the objects 5590 * @param array {nodes} an1 List of elements to look through for display children 5591 * @param array {nodes} an2 Another list (identical structure to the first) - optional 5592 * @memberof DataTable#oApi 5593 */ 5594 function _fnApplyToChildren( fn, an1, an2 ) 5595 { 5596 var index=0, i=0, iLen=an1.length; 5597 var nNode1, nNode2; 5598 5599 while ( i < iLen ) { 5600 nNode1 = an1[i].firstChild; 5601 nNode2 = an2 ? an2[i].firstChild : null; 5602 5603 while ( nNode1 ) { 5604 if ( nNode1.nodeType === 1 ) { 5605 if ( an2 ) { 5606 fn( nNode1, nNode2, index ); 5607 } 5608 else { 5609 fn( nNode1, index ); 5610 } 5611 5612 index++; 5613 } 5614 5615 nNode1 = nNode1.nextSibling; 5616 nNode2 = an2 ? nNode2.nextSibling : null; 5617 } 5618 5619 i++; 5620 } 5621 } 5622 5623 5624 5625 var __re_html_remove = /<.*?>/g; 5626 5627 5628 /** 5629 * Calculate the width of columns for the table 5630 * @param {object} oSettings dataTables settings object 5631 * @memberof DataTable#oApi 5632 */ 5633 function _fnCalculateColumnWidths ( oSettings ) 5634 { 5635 var 5636 table = oSettings.nTable, 5637 columns = oSettings.aoColumns, 5638 scroll = oSettings.oScroll, 5639 scrollY = scroll.sY, 5640 scrollX = scroll.sX, 5641 scrollXInner = scroll.sXInner, 5642 columnCount = columns.length, 5643 visibleColumns = _fnGetColumns( oSettings, 'bVisible' ), 5644 headerCells = $('th', oSettings.nTHead), 5645 tableWidthAttr = table.getAttribute('width'), // from DOM element 5646 tableContainer = table.parentNode, 5647 userInputs = false, 5648 i, column, columnIdx, width, outerWidth, 5649 browser = oSettings.oBrowser, 5650 ie67 = browser.bScrollOversize; 5651 5652 var styleWidth = table.style.width; 5653 if ( styleWidth && styleWidth.indexOf('%') !== -1 ) { 5654 tableWidthAttr = styleWidth; 5655 } 5656 5657 /* Convert any user input sizes into pixel sizes */ 5658 for ( i=0 ; i<visibleColumns.length ; i++ ) { 5659 column = columns[ visibleColumns[i] ]; 5660 5661 if ( column.sWidth !== null ) { 5662 column.sWidth = _fnConvertToWidth( column.sWidthOrig, tableContainer ); 5663 5664 userInputs = true; 5665 } 5666 } 5667 5668 /* If the number of columns in the DOM equals the number that we have to 5669 * process in DataTables, then we can use the offsets that are created by 5670 * the web- browser. No custom sizes can be set in order for this to happen, 5671 * nor scrolling used 5672 */ 5673 if ( ie67 || ! userInputs && ! scrollX && ! scrollY && 5674 columnCount == _fnVisbleColumns( oSettings ) && 5675 columnCount == headerCells.length 5676 ) { 5677 for ( i=0 ; i<columnCount ; i++ ) { 5678 var colIdx = _fnVisibleToColumnIndex( oSettings, i ); 5679 5680 if ( colIdx !== null ) { 5681 columns[ colIdx ].sWidth = _fnStringToCss( headerCells.eq(i).width() ); 5682 } 5683 } 5684 } 5685 else 5686 { 5687 // Otherwise construct a single row, worst case, table with the widest 5688 // node in the data, assign any user defined widths, then insert it into 5689 // the DOM and allow the browser to do all the hard work of calculating 5690 // table widths 5691 var tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table 5692 .css( 'visibility', 'hidden' ) 5693 .removeAttr( 'id' ); 5694 5695 // Clean up the table body 5696 tmpTable.find('tbody tr').remove(); 5697 var tr = $('<tr/>').appendTo( tmpTable.find('tbody') ); 5698 5699 // Clone the table header and footer - we can't use the header / footer 5700 // from the cloned table, since if scrolling is active, the table's 5701 // real header and footer are contained in different table tags 5702 tmpTable.find('thead, tfoot').remove(); 5703 tmpTable 5704 .append( $(oSettings.nTHead).clone() ) 5705 .append( $(oSettings.nTFoot).clone() ); 5706 5707 // Remove any assigned widths from the footer (from scrolling) 5708 tmpTable.find('tfoot th, tfoot td').css('width', ''); 5709 5710 // Apply custom sizing to the cloned header 5711 headerCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] ); 5712 5713 for ( i=0 ; i<visibleColumns.length ; i++ ) { 5714 column = columns[ visibleColumns[i] ]; 5715 5716 headerCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ? 5717 _fnStringToCss( column.sWidthOrig ) : 5718 ''; 5719 5720 // For scrollX we need to force the column width otherwise the 5721 // browser will collapse it. If this width is smaller than the 5722 // width the column requires, then it will have no effect 5723 if ( column.sWidthOrig && scrollX ) { 5724 $( headerCells[i] ).append( $('<div/>').css( { 5725 width: column.sWidthOrig, 5726 margin: 0, 5727 padding: 0, 5728 border: 0, 5729 height: 1 5730 } ) ); 5731 } 5732 } 5733 5734 // Find the widest cell for each column and put it into the table 5735 if ( oSettings.aoData.length ) { 5736 for ( i=0 ; i<visibleColumns.length ; i++ ) { 5737 columnIdx = visibleColumns[i]; 5738 column = columns[ columnIdx ]; 5739 5740 $( _fnGetWidestNode( oSettings, columnIdx ) ) 5741 .clone( false ) 5742 .append( column.sContentPadding ) 5743 .appendTo( tr ); 5744 } 5745 } 5746 5747 // Tidy the temporary table - remove name attributes so there aren't 5748 // duplicated in the dom (radio elements for example) 5749 $('[name]', tmpTable).removeAttr('name'); 5750 5751 // Table has been built, attach to the document so we can work with it. 5752 // A holding element is used, positioned at the top of the container 5753 // with minimal height, so it has no effect on if the container scrolls 5754 // or not. Otherwise it might trigger scrolling when it actually isn't 5755 // needed 5756 var holder = $('<div/>').css( scrollX || scrollY ? 5757 { 5758 position: 'absolute', 5759 top: 0, 5760 left: 0, 5761 height: 1, 5762 right: 0, 5763 overflow: 'hidden' 5764 } : 5765 {} 5766 ) 5767 .append( tmpTable ) 5768 .appendTo( tableContainer ); 5769 5770 // When scrolling (X or Y) we want to set the width of the table as 5771 // appropriate. However, when not scrolling leave the table width as it 5772 // is. This results in slightly different, but I think correct behaviour 5773 if ( scrollX && scrollXInner ) { 5774 tmpTable.width( scrollXInner ); 5775 } 5776 else if ( scrollX ) { 5777 tmpTable.css( 'width', 'auto' ); 5778 tmpTable.removeAttr('width'); 5779 5780 // If there is no width attribute or style, then allow the table to 5781 // collapse 5782 if ( tmpTable.width() < tableContainer.clientWidth && tableWidthAttr ) { 5783 tmpTable.width( tableContainer.clientWidth ); 5784 } 5785 } 5786 else if ( scrollY ) { 5787 tmpTable.width( tableContainer.clientWidth ); 5788 } 5789 else if ( tableWidthAttr ) { 5790 tmpTable.width( tableWidthAttr ); 5791 } 5792 5793 // Get the width of each column in the constructed table - we need to 5794 // know the inner width (so it can be assigned to the other table's 5795 // cells) and the outer width so we can calculate the full width of the 5796 // table. This is safe since DataTables requires a unique cell for each 5797 // column, but if ever a header can span multiple columns, this will 5798 // need to be modified. 5799 var total = 0; 5800 for ( i=0 ; i<visibleColumns.length ; i++ ) { 5801 var cell = $(headerCells[i]); 5802 var border = cell.outerWidth() - cell.width(); 5803 5804 // Use getBounding... where possible (not IE8-) because it can give 5805 // sub-pixel accuracy, which we then want to round up! 5806 var bounding = browser.bBounding ? 5807 Math.ceil( headerCells[i].getBoundingClientRect().width ) : 5808 cell.outerWidth(); 5809 5810 // Total is tracked to remove any sub-pixel errors as the outerWidth 5811 // of the table might not equal the total given here (IE!). 5812 total += bounding; 5813 5814 // Width for each column to use 5815 columns[ visibleColumns[i] ].sWidth = _fnStringToCss( bounding - border ); 5816 } 5817 5818 table.style.width = _fnStringToCss( total ); 5819 5820 // Finished with the table - ditch it 5821 holder.remove(); 5822 } 5823 5824 // If there is a width attr, we want to attach an event listener which 5825 // allows the table sizing to automatically adjust when the window is 5826 // resized. Use the width attr rather than CSS, since we can't know if the 5827 // CSS is a relative value or absolute - DOM read is always px. 5828 if ( tableWidthAttr ) { 5829 table.style.width = _fnStringToCss( tableWidthAttr ); 5830 } 5831 5832 if ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) { 5833 var bindResize = function () { 5834 $(window).on('resize.DT-'+oSettings.sInstance, _fnThrottle( function () { 5835 _fnAdjustColumnSizing( oSettings ); 5836 } ) ); 5837 }; 5838 5839 // IE6/7 will crash if we bind a resize event handler on page load. 5840 // To be removed in 1.11 which drops IE6/7 support 5841 if ( ie67 ) { 5842 setTimeout( bindResize, 1000 ); 5843 } 5844 else { 5845 bindResize(); 5846 } 5847 5848 oSettings._reszEvt = true; 5849 } 5850 } 5851 5852 5853 /** 5854 * Throttle the calls to a function. Arguments and context are maintained for 5855 * the throttled function 5856 * @param {function} fn Function to be called 5857 * @param {int} [freq=200] call frequency in mS 5858 * @returns {function} wrapped function 5859 * @memberof DataTable#oApi 5860 */ 5861 var _fnThrottle = DataTable.util.throttle; 5862 5863 5864 /** 5865 * Convert a CSS unit width to pixels (e.g. 2em) 5866 * @param {string} width width to be converted 5867 * @param {node} parent parent to get the with for (required for relative widths) - optional 5868 * @returns {int} width in pixels 5869 * @memberof DataTable#oApi 5870 */ 5871 function _fnConvertToWidth ( width, parent ) 5872 { 5873 if ( ! width ) { 5874 return 0; 5875 } 5876 5877 var n = $('<div/>') 5878 .css( 'width', _fnStringToCss( width ) ) 5879 .appendTo( parent || document.body ); 5880 5881 var val = n[0].offsetWidth; 5882 n.remove(); 5883 5884 return val; 5885 } 5886 5887 5888 /** 5889 * Get the widest node 5890 * @param {object} settings dataTables settings object 5891 * @param {int} colIdx column of interest 5892 * @returns {node} widest table node 5893 * @memberof DataTable#oApi 5894 */ 5895 function _fnGetWidestNode( settings, colIdx ) 5896 { 5897 var idx = _fnGetMaxLenString( settings, colIdx ); 5898 if ( idx < 0 ) { 5899 return null; 5900 } 5901 5902 var data = settings.aoData[ idx ]; 5903 return ! data.nTr ? // Might not have been created when deferred rendering 5904 $('<td/>').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] : 5905 data.anCells[ colIdx ]; 5906 } 5907 5908 5909 /** 5910 * Get the maximum strlen for each data column 5911 * @param {object} settings dataTables settings object 5912 * @param {int} colIdx column of interest 5913 * @returns {string} max string length for each column 5914 * @memberof DataTable#oApi 5915 */ 5916 function _fnGetMaxLenString( settings, colIdx ) 5917 { 5918 var s, max=-1, maxIdx = -1; 5919 5920 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) { 5921 s = _fnGetCellData( settings, i, colIdx, 'display' )+''; 5922 s = s.replace( __re_html_remove, '' ); 5923 s = s.replace( / /g, ' ' ); 5924 5925 if ( s.length > max ) { 5926 max = s.length; 5927 maxIdx = i; 5928 } 5929 } 5930 5931 return maxIdx; 5932 } 5933 5934 5935 /** 5936 * Append a CSS unit (only if required) to a string 5937 * @param {string} value to css-ify 5938 * @returns {string} value with css unit 5939 * @memberof DataTable#oApi 5940 */ 5941 function _fnStringToCss( s ) 5942 { 5943 if ( s === null ) { 5944 return '0px'; 5945 } 5946 5947 if ( typeof s == 'number' ) { 5948 return s < 0 ? 5949 '0px' : 5950 s+'px'; 5951 } 5952 5953 // Check it has a unit character already 5954 return s.match(/\d$/) ? 5955 s+'px' : 5956 s; 5957 } 5958 5959 5960 5961 function _fnSortFlatten ( settings ) 5962 { 5963 var 5964 i, iLen, k, kLen, 5965 aSort = [], 5966 aiOrig = [], 5967 aoColumns = settings.aoColumns, 5968 aDataSort, iCol, sType, srcCol, 5969 fixed = settings.aaSortingFixed, 5970 fixedObj = $.isPlainObject( fixed ), 5971 nestedSort = [], 5972 add = function ( a ) { 5973 if ( a.length && ! Array.isArray( a[0] ) ) { 5974 // 1D array 5975 nestedSort.push( a ); 5976 } 5977 else { 5978 // 2D array 5979 $.merge( nestedSort, a ); 5980 } 5981 }; 5982 5983 // Build the sort array, with pre-fix and post-fix options if they have been 5984 // specified 5985 if ( Array.isArray( fixed ) ) { 5986 add( fixed ); 5987 } 5988 5989 if ( fixedObj && fixed.pre ) { 5990 add( fixed.pre ); 5991 } 5992 5993 add( settings.aaSorting ); 5994 5995 if (fixedObj && fixed.post ) { 5996 add( fixed.post ); 5997 } 5998 5999 for ( i=0 ; i<nestedSort.length ; i++ ) 6000 { 6001 srcCol = nestedSort[i][0]; 6002 aDataSort = aoColumns[ srcCol ].aDataSort; 6003 6004 for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ ) 6005 { 6006 iCol = aDataSort[k]; 6007 sType = aoColumns[ iCol ].sType || 'string'; 6008 6009 if ( nestedSort[i]._idx === undefined ) { 6010 nestedSort[i]._idx = $.inArray( nestedSort[i][1], aoColumns[iCol].asSorting ); 6011 } 6012 6013 aSort.push( { 6014 src: srcCol, 6015 col: iCol, 6016 dir: nestedSort[i][1], 6017 index: nestedSort[i]._idx, 6018 type: sType, 6019 formatter: DataTable.ext.type.order[ sType+"-pre" ] 6020 } ); 6021 } 6022 } 6023 6024 return aSort; 6025 } 6026 6027 /** 6028 * Change the order of the table 6029 * @param {object} oSettings dataTables settings object 6030 * @memberof DataTable#oApi 6031 * @todo This really needs split up! 6032 */ 6033 function _fnSort ( oSettings ) 6034 { 6035 var 6036 i, ien, iLen, j, jLen, k, kLen, 6037 sDataType, nTh, 6038 aiOrig = [], 6039 oExtSort = DataTable.ext.type.order, 6040 aoData = oSettings.aoData, 6041 aoColumns = oSettings.aoColumns, 6042 aDataSort, data, iCol, sType, oSort, 6043 formatters = 0, 6044 sortCol, 6045 displayMaster = oSettings.aiDisplayMaster, 6046 aSort; 6047 6048 // Resolve any column types that are unknown due to addition or invalidation 6049 // @todo Can this be moved into a 'data-ready' handler which is called when 6050 // data is going to be used in the table? 6051 _fnColumnTypes( oSettings ); 6052 6053 aSort = _fnSortFlatten( oSettings ); 6054 6055 for ( i=0, ien=aSort.length ; i<ien ; i++ ) { 6056 sortCol = aSort[i]; 6057 6058 // Track if we can use the fast sort algorithm 6059 if ( sortCol.formatter ) { 6060 formatters++; 6061 } 6062 6063 // Load the data needed for the sort, for each cell 6064 _fnSortData( oSettings, sortCol.col ); 6065 } 6066 6067 /* No sorting required if server-side or no sorting array */ 6068 if ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 ) 6069 { 6070 // Create a value - key array of the current row positions such that we can use their 6071 // current position during the sort, if values match, in order to perform stable sorting 6072 for ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) { 6073 aiOrig[ displayMaster[i] ] = i; 6074 } 6075 6076 /* Do the sort - here we want multi-column sorting based on a given data source (column) 6077 * and sorting function (from oSort) in a certain direction. It's reasonably complex to 6078 * follow on it's own, but this is what we want (example two column sorting): 6079 * fnLocalSorting = function(a,b){ 6080 * var iTest; 6081 * iTest = oSort['string-asc']('data11', 'data12'); 6082 * if (iTest !== 0) 6083 * return iTest; 6084 * iTest = oSort['numeric-desc']('data21', 'data22'); 6085 * if (iTest !== 0) 6086 * return iTest; 6087 * return oSort['numeric-asc']( aiOrig[a], aiOrig[b] ); 6088 * } 6089 * Basically we have a test for each sorting column, if the data in that column is equal, 6090 * test the next column. If all columns match, then we use a numeric sort on the row 6091 * positions in the original data array to provide a stable sort. 6092 * 6093 * Note - I know it seems excessive to have two sorting methods, but the first is around 6094 * 15% faster, so the second is only maintained for backwards compatibility with sorting 6095 * methods which do not have a pre-sort formatting function. 6096 */ 6097 if ( formatters === aSort.length ) { 6098 // All sort types have formatting functions 6099 displayMaster.sort( function ( a, b ) { 6100 var 6101 x, y, k, test, sort, 6102 len=aSort.length, 6103 dataA = aoData[a]._aSortData, 6104 dataB = aoData[b]._aSortData; 6105 6106 for ( k=0 ; k<len ; k++ ) { 6107 sort = aSort[k]; 6108 6109 x = dataA[ sort.col ]; 6110 y = dataB[ sort.col ]; 6111 6112 test = x<y ? -1 : x>y ? 1 : 0; 6113 if ( test !== 0 ) { 6114 return sort.dir === 'asc' ? test : -test; 6115 } 6116 } 6117 6118 x = aiOrig[a]; 6119 y = aiOrig[b]; 6120 return x<y ? -1 : x>y ? 1 : 0; 6121 } ); 6122 } 6123 else { 6124 // Depreciated - remove in 1.11 (providing a plug-in option) 6125 // Not all sort types have formatting methods, so we have to call their sorting 6126 // methods. 6127 displayMaster.sort( function ( a, b ) { 6128 var 6129 x, y, k, l, test, sort, fn, 6130 len=aSort.length, 6131 dataA = aoData[a]._aSortData, 6132 dataB = aoData[b]._aSortData; 6133 6134 for ( k=0 ; k<len ; k++ ) { 6135 sort = aSort[k]; 6136 6137 x = dataA[ sort.col ]; 6138 y = dataB[ sort.col ]; 6139 6140 fn = oExtSort[ sort.type+"-"+sort.dir ] || oExtSort[ "string-"+sort.dir ]; 6141 test = fn( x, y ); 6142 if ( test !== 0 ) { 6143 return test; 6144 } 6145 } 6146 6147 x = aiOrig[a]; 6148 y = aiOrig[b]; 6149 return x<y ? -1 : x>y ? 1 : 0; 6150 } ); 6151 } 6152 } 6153 6154 /* Tell the draw function that we have sorted the data */ 6155 oSettings.bSorted = true; 6156 } 6157 6158 6159 function _fnSortAria ( settings ) 6160 { 6161 var label; 6162 var nextSort; 6163 var columns = settings.aoColumns; 6164 var aSort = _fnSortFlatten( settings ); 6165 var oAria = settings.oLanguage.oAria; 6166 6167 // ARIA attributes - need to loop all columns, to update all (removing old 6168 // attributes as needed) 6169 for ( var i=0, iLen=columns.length ; i<iLen ; i++ ) 6170 { 6171 var col = columns[i]; 6172 var asSorting = col.asSorting; 6173 var sTitle = col.ariaTitle || col.sTitle.replace( /<.*?>/g, "" ); 6174 var th = col.nTh; 6175 6176 // IE7 is throwing an error when setting these properties with jQuery's 6177 // attr() and removeAttr() methods... 6178 th.removeAttribute('aria-sort'); 6179 6180 /* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */ 6181 if ( col.bSortable ) { 6182 if ( aSort.length > 0 && aSort[0].col == i ) { 6183 th.setAttribute('aria-sort', aSort[0].dir=="asc" ? "ascending" : "descending" ); 6184 nextSort = asSorting[ aSort[0].index+1 ] || asSorting[0]; 6185 } 6186 else { 6187 nextSort = asSorting[0]; 6188 } 6189 6190 label = sTitle + ( nextSort === "asc" ? 6191 oAria.sSortAscending : 6192 oAria.sSortDescending 6193 ); 6194 } 6195 else { 6196 label = sTitle; 6197 } 6198 6199 th.setAttribute('aria-label', label); 6200 } 6201 } 6202 6203 6204 /** 6205 * Function to run on user sort request 6206 * @param {object} settings dataTables settings object 6207 * @param {node} attachTo node to attach the handler to 6208 * @param {int} colIdx column sorting index 6209 * @param {boolean} [append=false] Append the requested sort to the existing 6210 * sort if true (i.e. multi-column sort) 6211 * @param {function} [callback] callback function 6212 * @memberof DataTable#oApi 6213 */ 6214 function _fnSortListener ( settings, colIdx, append, callback ) 6215 { 6216 var col = settings.aoColumns[ colIdx ]; 6217 var sorting = settings.aaSorting; 6218 var asSorting = col.asSorting; 6219 var nextSortIdx; 6220 var next = function ( a, overflow ) { 6221 var idx = a._idx; 6222 if ( idx === undefined ) { 6223 idx = $.inArray( a[1], asSorting ); 6224 } 6225 6226 return idx+1 < asSorting.length ? 6227 idx+1 : 6228 overflow ? 6229 null : 6230 0; 6231 }; 6232 6233 // Convert to 2D array if needed 6234 if ( typeof sorting[0] === 'number' ) { 6235 sorting = settings.aaSorting = [ sorting ]; 6236 } 6237 6238 // If appending the sort then we are multi-column sorting 6239 if ( append && settings.oFeatures.bSortMulti ) { 6240 // Are we already doing some kind of sort on this column? 6241 var sortIdx = $.inArray( colIdx, _pluck(sorting, '0') ); 6242 6243 if ( sortIdx !== -1 ) { 6244 // Yes, modify the sort 6245 nextSortIdx = next( sorting[sortIdx], true ); 6246 6247 if ( nextSortIdx === null && sorting.length === 1 ) { 6248 nextSortIdx = 0; // can't remove sorting completely 6249 } 6250 6251 if ( nextSortIdx === null ) { 6252 sorting.splice( sortIdx, 1 ); 6253 } 6254 else { 6255 sorting[sortIdx][1] = asSorting[ nextSortIdx ]; 6256 sorting[sortIdx]._idx = nextSortIdx; 6257 } 6258 } 6259 else { 6260 // No sort on this column yet 6261 sorting.push( [ colIdx, asSorting[0], 0 ] ); 6262 sorting[sorting.length-1]._idx = 0; 6263 } 6264 } 6265 else if ( sorting.length && sorting[0][0] == colIdx ) { 6266 // Single column - already sorting on this column, modify the sort 6267 nextSortIdx = next( sorting[0] ); 6268 6269 sorting.length = 1; 6270 sorting[0][1] = asSorting[ nextSortIdx ]; 6271 sorting[0]._idx = nextSortIdx; 6272 } 6273 else { 6274 // Single column - sort only on this column 6275 sorting.length = 0; 6276 sorting.push( [ colIdx, asSorting[0] ] ); 6277 sorting[0]._idx = 0; 6278 } 6279 6280 // Run the sort by calling a full redraw 6281 _fnReDraw( settings ); 6282 6283 // callback used for async user interaction 6284 if ( typeof callback == 'function' ) { 6285 callback( settings ); 6286 } 6287 } 6288 6289 6290 /** 6291 * Attach a sort handler (click) to a node 6292 * @param {object} settings dataTables settings object 6293 * @param {node} attachTo node to attach the handler to 6294 * @param {int} colIdx column sorting index 6295 * @param {function} [callback] callback function 6296 * @memberof DataTable#oApi 6297 */ 6298 function _fnSortAttachListener ( settings, attachTo, colIdx, callback ) 6299 { 6300 var col = settings.aoColumns[ colIdx ]; 6301 6302 _fnBindAction( attachTo, {}, function (e) { 6303 /* If the column is not sortable - don't to anything */ 6304 if ( col.bSortable === false ) { 6305 return; 6306 } 6307 6308 // If processing is enabled use a timeout to allow the processing 6309 // display to be shown - otherwise to it synchronously 6310 if ( settings.oFeatures.bProcessing ) { 6311 _fnProcessingDisplay( settings, true ); 6312 6313 setTimeout( function() { 6314 _fnSortListener( settings, colIdx, e.shiftKey, callback ); 6315 6316 // In server-side processing, the draw callback will remove the 6317 // processing display 6318 if ( _fnDataSource( settings ) !== 'ssp' ) { 6319 _fnProcessingDisplay( settings, false ); 6320 } 6321 }, 0 ); 6322 } 6323 else { 6324 _fnSortListener( settings, colIdx, e.shiftKey, callback ); 6325 } 6326 } ); 6327 } 6328 6329 6330 /** 6331 * Set the sorting classes on table's body, Note: it is safe to call this function 6332 * when bSort and bSortClasses are false 6333 * @param {object} oSettings dataTables settings object 6334 * @memberof DataTable#oApi 6335 */ 6336 function _fnSortingClasses( settings ) 6337 { 6338 var oldSort = settings.aLastSort; 6339 var sortClass = settings.oClasses.sSortColumn; 6340 var sort = _fnSortFlatten( settings ); 6341 var features = settings.oFeatures; 6342 var i, ien, colIdx; 6343 6344 if ( features.bSort && features.bSortClasses ) { 6345 // Remove old sorting classes 6346 for ( i=0, ien=oldSort.length ; i<ien ; i++ ) { 6347 colIdx = oldSort[i].src; 6348 6349 // Remove column sorting 6350 $( _pluck( settings.aoData, 'anCells', colIdx ) ) 6351 .removeClass( sortClass + (i<2 ? i+1 : 3) ); 6352 } 6353 6354 // Add new column sorting 6355 for ( i=0, ien=sort.length ; i<ien ; i++ ) { 6356 colIdx = sort[i].src; 6357 6358 $( _pluck( settings.aoData, 'anCells', colIdx ) ) 6359 .addClass( sortClass + (i<2 ? i+1 : 3) ); 6360 } 6361 } 6362 6363 settings.aLastSort = sort; 6364 } 6365 6366 6367 // Get the data to sort a column, be it from cache, fresh (populating the 6368 // cache), or from a sort formatter 6369 function _fnSortData( settings, idx ) 6370 { 6371 // Custom sorting function - provided by the sort data type 6372 var column = settings.aoColumns[ idx ]; 6373 var customSort = DataTable.ext.order[ column.sSortDataType ]; 6374 var customData; 6375 6376 if ( customSort ) { 6377 customData = customSort.call( settings.oInstance, settings, idx, 6378 _fnColumnIndexToVisible( settings, idx ) 6379 ); 6380 } 6381 6382 // Use / populate cache 6383 var row, cellData; 6384 var formatter = DataTable.ext.type.order[ column.sType+"-pre" ]; 6385 6386 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) { 6387 row = settings.aoData[i]; 6388 6389 if ( ! row._aSortData ) { 6390 row._aSortData = []; 6391 } 6392 6393 if ( ! row._aSortData[idx] || customSort ) { 6394 cellData = customSort ? 6395 customData[i] : // If there was a custom sort function, use data from there 6396 _fnGetCellData( settings, i, idx, 'sort' ); 6397 6398 row._aSortData[ idx ] = formatter ? 6399 formatter( cellData ) : 6400 cellData; 6401 } 6402 } 6403 } 6404 6405 6406 6407 /** 6408 * Save the state of a table 6409 * @param {object} oSettings dataTables settings object 6410 * @memberof DataTable#oApi 6411 */ 6412 function _fnSaveState ( settings ) 6413 { 6414 if (settings._bLoadingState) { 6415 return; 6416 } 6417 6418 /* Store the interesting variables */ 6419 var state = { 6420 time: +new Date(), 6421 start: settings._iDisplayStart, 6422 length: settings._iDisplayLength, 6423 order: $.extend( true, [], settings.aaSorting ), 6424 search: _fnSearchToCamel( settings.oPreviousSearch ), 6425 columns: $.map( settings.aoColumns, function ( col, i ) { 6426 return { 6427 visible: col.bVisible, 6428 search: _fnSearchToCamel( settings.aoPreSearchCols[i] ) 6429 }; 6430 } ) 6431 }; 6432 6433 settings.oSavedState = state; 6434 _fnCallbackFire( settings, "aoStateSaveParams", 'stateSaveParams', [settings, state] ); 6435 6436 if ( settings.oFeatures.bStateSave && !settings.bDestroying ) 6437 { 6438 settings.fnStateSaveCallback.call( settings.oInstance, settings, state ); 6439 } 6440 } 6441 6442 6443 /** 6444 * Attempt to load a saved table state 6445 * @param {object} oSettings dataTables settings object 6446 * @param {object} oInit DataTables init object so we can override settings 6447 * @param {function} callback Callback to execute when the state has been loaded 6448 * @memberof DataTable#oApi 6449 */ 6450 function _fnLoadState ( settings, oInit, callback ) 6451 { 6452 if ( ! settings.oFeatures.bStateSave ) { 6453 callback(); 6454 return; 6455 } 6456 6457 var loaded = function(state) { 6458 _fnImplementState(settings, state, callback); 6459 } 6460 6461 var state = settings.fnStateLoadCallback.call( settings.oInstance, settings, loaded ); 6462 6463 if ( state !== undefined ) { 6464 _fnImplementState( settings, state, callback ); 6465 } 6466 // otherwise, wait for the loaded callback to be executed 6467 6468 return true; 6469 } 6470 6471 function _fnImplementState ( settings, s, callback) { 6472 var i, ien; 6473 var columns = settings.aoColumns; 6474 settings._bLoadingState = true; 6475 6476 // When StateRestore was introduced the state could now be implemented at any time 6477 // Not just initialisation. To do this an api instance is required in some places 6478 var api = settings._bInitComplete ? new DataTable.Api(settings) : null; 6479 6480 if ( ! s || ! s.time ) { 6481 settings._bLoadingState = false; 6482 callback(); 6483 return; 6484 } 6485 6486 // Allow custom and plug-in manipulation functions to alter the saved data set and 6487 // cancelling of loading by returning false 6488 var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, s] ); 6489 if ( $.inArray( false, abStateLoad ) !== -1 ) { 6490 settings._bLoadingState = false; 6491 callback(); 6492 return; 6493 } 6494 6495 // Reject old data 6496 var duration = settings.iStateDuration; 6497 if ( duration > 0 && s.time < +new Date() - (duration*1000) ) { 6498 settings._bLoadingState = false; 6499 callback(); 6500 return; 6501 } 6502 6503 // Number of columns have changed - all bets are off, no restore of settings 6504 if ( s.columns && columns.length !== s.columns.length ) { 6505 settings._bLoadingState = false; 6506 callback(); 6507 return; 6508 } 6509 6510 // Store the saved state so it might be accessed at any time 6511 settings.oLoadedState = $.extend( true, {}, s ); 6512 6513 // Page Length 6514 if ( s.length !== undefined ) { 6515 // If already initialised just set the value directly so that the select element is also updated 6516 if (api) { 6517 api.page.len(s.length) 6518 } 6519 else { 6520 settings._iDisplayLength = s.length; 6521 } 6522 } 6523 6524 // Restore key features - todo - for 1.11 this needs to be done by 6525 // subscribed events 6526 if ( s.start !== undefined ) { 6527 if(api === null) { 6528 settings._iDisplayStart = s.start; 6529 settings.iInitDisplayStart = s.start; 6530 } 6531 else { 6532 _fnPageChange(settings, s.start/settings._iDisplayLength); 6533 } 6534 } 6535 6536 // Order 6537 if ( s.order !== undefined ) { 6538 settings.aaSorting = []; 6539 $.each( s.order, function ( i, col ) { 6540 settings.aaSorting.push( col[0] >= columns.length ? 6541 [ 0, col[1] ] : 6542 col 6543 ); 6544 } ); 6545 } 6546 6547 // Search 6548 if ( s.search !== undefined ) { 6549 $.extend( settings.oPreviousSearch, _fnSearchToHung( s.search ) ); 6550 } 6551 6552 // Columns 6553 if ( s.columns ) { 6554 for ( i=0, ien=s.columns.length ; i<ien ; i++ ) { 6555 var col = s.columns[i]; 6556 6557 // Visibility 6558 if ( col.visible !== undefined ) { 6559 // If the api is defined, the table has been initialised so we need to use it rather than internal settings 6560 if (api) { 6561 // Don't redraw the columns on every iteration of this loop, we will do this at the end instead 6562 api.column(i).visible(col.visible, false); 6563 } 6564 else { 6565 columns[i].bVisible = col.visible; 6566 } 6567 } 6568 6569 // Search 6570 if ( col.search !== undefined ) { 6571 $.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) ); 6572 } 6573 } 6574 6575 // If the api is defined then we need to adjust the columns once the visibility has been changed 6576 if (api) { 6577 api.columns.adjust(); 6578 } 6579 } 6580 6581 settings._bLoadingState = false; 6582 _fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, s] ); 6583 callback(); 6584 }; 6585 6586 6587 /** 6588 * Return the settings object for a particular table 6589 * @param {node} table table we are using as a dataTable 6590 * @returns {object} Settings object - or null if not found 6591 * @memberof DataTable#oApi 6592 */ 6593 function _fnSettingsFromNode ( table ) 6594 { 6595 var settings = DataTable.settings; 6596 var idx = $.inArray( table, _pluck( settings, 'nTable' ) ); 6597 6598 return idx !== -1 ? 6599 settings[ idx ] : 6600 null; 6601 } 6602 6603 6604 /** 6605 * Log an error message 6606 * @param {object} settings dataTables settings object 6607 * @param {int} level log error messages, or display them to the user 6608 * @param {string} msg error message 6609 * @param {int} tn Technical note id to get more information about the error. 6610 * @memberof DataTable#oApi 6611 */ 6612 function _fnLog( settings, level, msg, tn ) 6613 { 6614 msg = 'DataTables warning: '+ 6615 (settings ? 'table id='+settings.sTableId+' - ' : '')+msg; 6616 6617 if ( tn ) { 6618 msg += '. For more information about this error, please see '+ 6619 'http://datatables.net/tn/'+tn; 6620 } 6621 6622 if ( ! level ) { 6623 // Backwards compatibility pre 1.10 6624 var ext = DataTable.ext; 6625 var type = ext.sErrMode || ext.errMode; 6626 6627 if ( settings ) { 6628 _fnCallbackFire( settings, null, 'error', [ settings, tn, msg ] ); 6629 } 6630 6631 if ( type == 'alert' ) { 6632 alert( msg ); 6633 } 6634 else if ( type == 'throw' ) { 6635 throw new Error(msg); 6636 } 6637 else if ( typeof type == 'function' ) { 6638 type( settings, tn, msg ); 6639 } 6640 } 6641 else if ( window.console && console.log ) { 6642 console.log( msg ); 6643 } 6644 } 6645 6646 6647 /** 6648 * See if a property is defined on one object, if so assign it to the other object 6649 * @param {object} ret target object 6650 * @param {object} src source object 6651 * @param {string} name property 6652 * @param {string} [mappedName] name to map too - optional, name used if not given 6653 * @memberof DataTable#oApi 6654 */ 6655 function _fnMap( ret, src, name, mappedName ) 6656 { 6657 if ( Array.isArray( name ) ) { 6658 $.each( name, function (i, val) { 6659 if ( Array.isArray( val ) ) { 6660 _fnMap( ret, src, val[0], val[1] ); 6661 } 6662 else { 6663 _fnMap( ret, src, val ); 6664 } 6665 } ); 6666 6667 return; 6668 } 6669 6670 if ( mappedName === undefined ) { 6671 mappedName = name; 6672 } 6673 6674 if ( src[name] !== undefined ) { 6675 ret[mappedName] = src[name]; 6676 } 6677 } 6678 6679 6680 /** 6681 * Extend objects - very similar to jQuery.extend, but deep copy objects, and 6682 * shallow copy arrays. The reason we need to do this, is that we don't want to 6683 * deep copy array init values (such as aaSorting) since the dev wouldn't be 6684 * able to override them, but we do want to deep copy arrays. 6685 * @param {object} out Object to extend 6686 * @param {object} extender Object from which the properties will be applied to 6687 * out 6688 * @param {boolean} breakRefs If true, then arrays will be sliced to take an 6689 * independent copy with the exception of the `data` or `aaData` parameters 6690 * if they are present. This is so you can pass in a collection to 6691 * DataTables and have that used as your data source without breaking the 6692 * references 6693 * @returns {object} out Reference, just for convenience - out === the return. 6694 * @memberof DataTable#oApi 6695 * @todo This doesn't take account of arrays inside the deep copied objects. 6696 */ 6697 function _fnExtend( out, extender, breakRefs ) 6698 { 6699 var val; 6700 6701 for ( var prop in extender ) { 6702 if ( extender.hasOwnProperty(prop) ) { 6703 val = extender[prop]; 6704 6705 if ( $.isPlainObject( val ) ) { 6706 if ( ! $.isPlainObject( out[prop] ) ) { 6707 out[prop] = {}; 6708 } 6709 $.extend( true, out[prop], val ); 6710 } 6711 else if ( breakRefs && prop !== 'data' && prop !== 'aaData' && Array.isArray(val) ) { 6712 out[prop] = val.slice(); 6713 } 6714 else { 6715 out[prop] = val; 6716 } 6717 } 6718 } 6719 6720 return out; 6721 } 6722 6723 6724 /** 6725 * Bind an event handers to allow a click or return key to activate the callback. 6726 * This is good for accessibility since a return on the keyboard will have the 6727 * same effect as a click, if the element has focus. 6728 * @param {element} n Element to bind the action to 6729 * @param {object} oData Data object to pass to the triggered function 6730 * @param {function} fn Callback function for when the event is triggered 6731 * @memberof DataTable#oApi 6732 */ 6733 function _fnBindAction( n, oData, fn ) 6734 { 6735 $(n) 6736 .on( 'click.DT', oData, function (e) { 6737 $(n).trigger('blur'); // Remove focus outline for mouse users 6738 fn(e); 6739 } ) 6740 .on( 'keypress.DT', oData, function (e){ 6741 if ( e.which === 13 ) { 6742 e.preventDefault(); 6743 fn(e); 6744 } 6745 } ) 6746 .on( 'selectstart.DT', function () { 6747 /* Take the brutal approach to cancelling text selection */ 6748 return false; 6749 } ); 6750 } 6751 6752 6753 /** 6754 * Register a callback function. Easily allows a callback function to be added to 6755 * an array store of callback functions that can then all be called together. 6756 * @param {object} oSettings dataTables settings object 6757 * @param {string} sStore Name of the array storage for the callbacks in oSettings 6758 * @param {function} fn Function to be called back 6759 * @param {string} sName Identifying name for the callback (i.e. a label) 6760 * @memberof DataTable#oApi 6761 */ 6762 function _fnCallbackReg( oSettings, sStore, fn, sName ) 6763 { 6764 if ( fn ) 6765 { 6766 oSettings[sStore].push( { 6767 "fn": fn, 6768 "sName": sName 6769 } ); 6770 } 6771 } 6772 6773 6774 /** 6775 * Fire callback functions and trigger events. Note that the loop over the 6776 * callback array store is done backwards! Further note that you do not want to 6777 * fire off triggers in time sensitive applications (for example cell creation) 6778 * as its slow. 6779 * @param {object} settings dataTables settings object 6780 * @param {string} callbackArr Name of the array storage for the callbacks in 6781 * oSettings 6782 * @param {string} eventName Name of the jQuery custom event to trigger. If 6783 * null no trigger is fired 6784 * @param {array} args Array of arguments to pass to the callback function / 6785 * trigger 6786 * @memberof DataTable#oApi 6787 */ 6788 function _fnCallbackFire( settings, callbackArr, eventName, args ) 6789 { 6790 var ret = []; 6791 6792 if ( callbackArr ) { 6793 ret = $.map( settings[callbackArr].slice().reverse(), function (val, i) { 6794 return val.fn.apply( settings.oInstance, args ); 6795 } ); 6796 } 6797 6798 if ( eventName !== null ) { 6799 var e = $.Event( eventName+'.dt' ); 6800 var table = $(settings.nTable); 6801 6802 table.trigger( e, args ); 6803 6804 // If not yet attached to the document, trigger the event 6805 // on the body directly to sort of simulate the bubble 6806 if (table.parents('body').length === 0) { 6807 $('body').trigger( e, args ); 6808 } 6809 6810 ret.push( e.result ); 6811 } 6812 6813 return ret; 6814 } 6815 6816 6817 function _fnLengthOverflow ( settings ) 6818 { 6819 var 6820 start = settings._iDisplayStart, 6821 end = settings.fnDisplayEnd(), 6822 len = settings._iDisplayLength; 6823 6824 /* If we have space to show extra rows (backing up from the end point - then do so */ 6825 if ( start >= end ) 6826 { 6827 start = end - len; 6828 } 6829 6830 // Keep the start record on the current page 6831 start -= (start % len); 6832 6833 if ( len === -1 || start < 0 ) 6834 { 6835 start = 0; 6836 } 6837 6838 settings._iDisplayStart = start; 6839 } 6840 6841 6842 function _fnRenderer( settings, type ) 6843 { 6844 var renderer = settings.renderer; 6845 var host = DataTable.ext.renderer[type]; 6846 6847 if ( $.isPlainObject( renderer ) && renderer[type] ) { 6848 // Specific renderer for this type. If available use it, otherwise use 6849 // the default. 6850 return host[renderer[type]] || host._; 6851 } 6852 else if ( typeof renderer === 'string' ) { 6853 // Common renderer - if there is one available for this type use it, 6854 // otherwise use the default 6855 return host[renderer] || host._; 6856 } 6857 6858 // Use the default 6859 return host._; 6860 } 6861 6862 6863 /** 6864 * Detect the data source being used for the table. Used to simplify the code 6865 * a little (ajax) and to make it compress a little smaller. 6866 * 6867 * @param {object} settings dataTables settings object 6868 * @returns {string} Data source 6869 * @memberof DataTable#oApi 6870 */ 6871 function _fnDataSource ( settings ) 6872 { 6873 if ( settings.oFeatures.bServerSide ) { 6874 return 'ssp'; 6875 } 6876 else if ( settings.ajax || settings.sAjaxSource ) { 6877 return 'ajax'; 6878 } 6879 return 'dom'; 6880 } 6881 6882 6883 6884 6885 /** 6886 * Computed structure of the DataTables API, defined by the options passed to 6887 * `DataTable.Api.register()` when building the API. 6888 * 6889 * The structure is built in order to speed creation and extension of the Api 6890 * objects since the extensions are effectively pre-parsed. 6891 * 6892 * The array is an array of objects with the following structure, where this 6893 * base array represents the Api prototype base: 6894 * 6895 * [ 6896 * { 6897 * name: 'data' -- string - Property name 6898 * val: function () {}, -- function - Api method (or undefined if just an object 6899 * methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result 6900 * propExt: [ ... ] -- array - Array of Api object definitions to extend the property 6901 * }, 6902 * { 6903 * name: 'row' 6904 * val: {}, 6905 * methodExt: [ ... ], 6906 * propExt: [ 6907 * { 6908 * name: 'data' 6909 * val: function () {}, 6910 * methodExt: [ ... ], 6911 * propExt: [ ... ] 6912 * }, 6913 * ... 6914 * ] 6915 * } 6916 * ] 6917 * 6918 * @type {Array} 6919 * @ignore 6920 */ 6921 var __apiStruct = []; 6922 6923 6924 /** 6925 * `Array.prototype` reference. 6926 * 6927 * @type object 6928 * @ignore 6929 */ 6930 var __arrayProto = Array.prototype; 6931 6932 6933 /** 6934 * Abstraction for `context` parameter of the `Api` constructor to allow it to 6935 * take several different forms for ease of use. 6936 * 6937 * Each of the input parameter types will be converted to a DataTables settings 6938 * object where possible. 6939 * 6940 * @param {string|node|jQuery|object} mixed DataTable identifier. Can be one 6941 * of: 6942 * 6943 * * `string` - jQuery selector. Any DataTables' matching the given selector 6944 * with be found and used. 6945 * * `node` - `TABLE` node which has already been formed into a DataTable. 6946 * * `jQuery` - A jQuery object of `TABLE` nodes. 6947 * * `object` - DataTables settings object 6948 * * `DataTables.Api` - API instance 6949 * @return {array|null} Matching DataTables settings objects. `null` or 6950 * `undefined` is returned if no matching DataTable is found. 6951 * @ignore 6952 */ 6953 var _toSettings = function ( mixed ) 6954 { 6955 var idx, jq; 6956 var settings = DataTable.settings; 6957 var tables = $.map( settings, function (el, i) { 6958 return el.nTable; 6959 } ); 6960 6961 if ( ! mixed ) { 6962 return []; 6963 } 6964 else if ( mixed.nTable && mixed.oApi ) { 6965 // DataTables settings object 6966 return [ mixed ]; 6967 } 6968 else if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) { 6969 // Table node 6970 idx = $.inArray( mixed, tables ); 6971 return idx !== -1 ? [ settings[idx] ] : null; 6972 } 6973 else if ( mixed && typeof mixed.settings === 'function' ) { 6974 return mixed.settings().toArray(); 6975 } 6976 else if ( typeof mixed === 'string' ) { 6977 // jQuery selector 6978 jq = $(mixed); 6979 } 6980 else if ( mixed instanceof $ ) { 6981 // jQuery object (also DataTables instance) 6982 jq = mixed; 6983 } 6984 6985 if ( jq ) { 6986 return jq.map( function(i) { 6987 idx = $.inArray( this, tables ); 6988 return idx !== -1 ? settings[idx] : null; 6989 } ).toArray(); 6990 } 6991 }; 6992 6993 6994 /** 6995 * DataTables API class - used to control and interface with one or more 6996 * DataTables enhanced tables. 6997 * 6998 * The API class is heavily based on jQuery, presenting a chainable interface 6999 * that you can use to interact with tables. Each instance of the API class has 7000 * a "context" - i.e. the tables that it will operate on. This could be a single 7001 * table, all tables on a page or a sub-set thereof. 7002 * 7003 * Additionally the API is designed to allow you to easily work with the data in 7004 * the tables, retrieving and manipulating it as required. This is done by 7005 * presenting the API class as an array like interface. The contents of the 7006 * array depend upon the actions requested by each method (for example 7007 * `rows().nodes()` will return an array of nodes, while `rows().data()` will 7008 * return an array of objects or arrays depending upon your table's 7009 * configuration). The API object has a number of array like methods (`push`, 7010 * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`, 7011 * `unique` etc) to assist your working with the data held in a table. 7012 * 7013 * Most methods (those which return an Api instance) are chainable, which means 7014 * the return from a method call also has all of the methods available that the 7015 * top level object had. For example, these two calls are equivalent: 7016 * 7017 * // Not chained 7018 * api.row.add( {...} ); 7019 * api.draw(); 7020 * 7021 * // Chained 7022 * api.row.add( {...} ).draw(); 7023 * 7024 * @class DataTable.Api 7025 * @param {array|object|string|jQuery} context DataTable identifier. This is 7026 * used to define which DataTables enhanced tables this API will operate on. 7027 * Can be one of: 7028 * 7029 * * `string` - jQuery selector. Any DataTables' matching the given selector 7030 * with be found and used. 7031 * * `node` - `TABLE` node which has already been formed into a DataTable. 7032 * * `jQuery` - A jQuery object of `TABLE` nodes. 7033 * * `object` - DataTables settings object 7034 * @param {array} [data] Data to initialise the Api instance with. 7035 * 7036 * @example 7037 * // Direct initialisation during DataTables construction 7038 * var api = $('#example').DataTable(); 7039 * 7040 * @example 7041 * // Initialisation using a DataTables jQuery object 7042 * var api = $('#example').dataTable().api(); 7043 * 7044 * @example 7045 * // Initialisation as a constructor 7046 * var api = new $.fn.DataTable.Api( 'table.dataTable' ); 7047 */ 7048 _Api = function ( context, data ) 7049 { 7050 if ( ! (this instanceof _Api) ) { 7051 return new _Api( context, data ); 7052 } 7053 7054 var settings = []; 7055 var ctxSettings = function ( o ) { 7056 var a = _toSettings( o ); 7057 if ( a ) { 7058 settings.push.apply( settings, a ); 7059 } 7060 }; 7061 7062 if ( Array.isArray( context ) ) { 7063 for ( var i=0, ien=context.length ; i<ien ; i++ ) { 7064 ctxSettings( context[i] ); 7065 } 7066 } 7067 else { 7068 ctxSettings( context ); 7069 } 7070 7071 // Remove duplicates 7072 this.context = _unique( settings ); 7073 7074 // Initial data 7075 if ( data ) { 7076 $.merge( this, data ); 7077 } 7078 7079 // selector 7080 this.selector = { 7081 rows: null, 7082 cols: null, 7083 opts: null 7084 }; 7085 7086 _Api.extend( this, this, __apiStruct ); 7087 }; 7088 7089 DataTable.Api = _Api; 7090 7091 // Don't destroy the existing prototype, just extend it. Required for jQuery 2's 7092 // isPlainObject. 7093 $.extend( _Api.prototype, { 7094 any: function () 7095 { 7096 return this.count() !== 0; 7097 }, 7098 7099 7100 concat: __arrayProto.concat, 7101 7102 7103 context: [], // array of table settings objects 7104 7105 7106 count: function () 7107 { 7108 return this.flatten().length; 7109 }, 7110 7111 7112 each: function ( fn ) 7113 { 7114 for ( var i=0, ien=this.length ; i<ien; i++ ) { 7115 fn.call( this, this[i], i, this ); 7116 } 7117 7118 return this; 7119 }, 7120 7121 7122 eq: function ( idx ) 7123 { 7124 var ctx = this.context; 7125 7126 return ctx.length > idx ? 7127 new _Api( ctx[idx], this[idx] ) : 7128 null; 7129 }, 7130 7131 7132 filter: function ( fn ) 7133 { 7134 var a = []; 7135 7136 if ( __arrayProto.filter ) { 7137 a = __arrayProto.filter.call( this, fn, this ); 7138 } 7139 else { 7140 // Compatibility for browsers without EMCA-252-5 (JS 1.6) 7141 for ( var i=0, ien=this.length ; i<ien ; i++ ) { 7142 if ( fn.call( this, this[i], i, this ) ) { 7143 a.push( this[i] ); 7144 } 7145 } 7146 } 7147 7148 return new _Api( this.context, a ); 7149 }, 7150 7151 7152 flatten: function () 7153 { 7154 var a = []; 7155 return new _Api( this.context, a.concat.apply( a, this.toArray() ) ); 7156 }, 7157 7158 7159 join: __arrayProto.join, 7160 7161 7162 indexOf: __arrayProto.indexOf || function (obj, start) 7163 { 7164 for ( var i=(start || 0), ien=this.length ; i<ien ; i++ ) { 7165 if ( this[i] === obj ) { 7166 return i; 7167 } 7168 } 7169 return -1; 7170 }, 7171 7172 iterator: function ( flatten, type, fn, alwaysNew ) { 7173 var 7174 a = [], ret, 7175 i, ien, j, jen, 7176 context = this.context, 7177 rows, items, item, 7178 selector = this.selector; 7179 7180 // Argument shifting 7181 if ( typeof flatten === 'string' ) { 7182 alwaysNew = fn; 7183 fn = type; 7184 type = flatten; 7185 flatten = false; 7186 } 7187 7188 for ( i=0, ien=context.length ; i<ien ; i++ ) { 7189 var apiInst = new _Api( context[i] ); 7190 7191 if ( type === 'table' ) { 7192 ret = fn.call( apiInst, context[i], i ); 7193 7194 if ( ret !== undefined ) { 7195 a.push( ret ); 7196 } 7197 } 7198 else if ( type === 'columns' || type === 'rows' ) { 7199 // this has same length as context - one entry for each table 7200 ret = fn.call( apiInst, context[i], this[i], i ); 7201 7202 if ( ret !== undefined ) { 7203 a.push( ret ); 7204 } 7205 } 7206 else if ( type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) { 7207 // columns and rows share the same structure. 7208 // 'this' is an array of column indexes for each context 7209 items = this[i]; 7210 7211 if ( type === 'column-rows' ) { 7212 rows = _selector_row_indexes( context[i], selector.opts ); 7213 } 7214 7215 for ( j=0, jen=items.length ; j<jen ; j++ ) { 7216 item = items[j]; 7217 7218 if ( type === 'cell' ) { 7219 ret = fn.call( apiInst, context[i], item.row, item.column, i, j ); 7220 } 7221 else { 7222 ret = fn.call( apiInst, context[i], item, i, j, rows ); 7223 } 7224 7225 if ( ret !== undefined ) { 7226 a.push( ret ); 7227 } 7228 } 7229 } 7230 } 7231 7232 if ( a.length || alwaysNew ) { 7233 var api = new _Api( context, flatten ? a.concat.apply( [], a ) : a ); 7234 var apiSelector = api.selector; 7235 apiSelector.rows = selector.rows; 7236 apiSelector.cols = selector.cols; 7237 apiSelector.opts = selector.opts; 7238 return api; 7239 } 7240 return this; 7241 }, 7242 7243 7244 lastIndexOf: __arrayProto.lastIndexOf || function (obj, start) 7245 { 7246 // Bit cheeky... 7247 return this.indexOf.apply( this.toArray.reverse(), arguments ); 7248 }, 7249 7250 7251 length: 0, 7252 7253 7254 map: function ( fn ) 7255 { 7256 var a = []; 7257 7258 if ( __arrayProto.map ) { 7259 a = __arrayProto.map.call( this, fn, this ); 7260 } 7261 else { 7262 // Compatibility for browsers without EMCA-252-5 (JS 1.6) 7263 for ( var i=0, ien=this.length ; i<ien ; i++ ) { 7264 a.push( fn.call( this, this[i], i ) ); 7265 } 7266 } 7267 7268 return new _Api( this.context, a ); 7269 }, 7270 7271 7272 pluck: function ( prop ) 7273 { 7274 var fn = DataTable.util.get(prop); 7275 7276 return this.map( function ( el ) { 7277 return fn(el); 7278 } ); 7279 }, 7280 7281 pop: __arrayProto.pop, 7282 7283 7284 push: __arrayProto.push, 7285 7286 7287 // Does not return an API instance 7288 reduce: __arrayProto.reduce || function ( fn, init ) 7289 { 7290 return _fnReduce( this, fn, init, 0, this.length, 1 ); 7291 }, 7292 7293 7294 reduceRight: __arrayProto.reduceRight || function ( fn, init ) 7295 { 7296 return _fnReduce( this, fn, init, this.length-1, -1, -1 ); 7297 }, 7298 7299 7300 reverse: __arrayProto.reverse, 7301 7302 7303 // Object with rows, columns and opts 7304 selector: null, 7305 7306 7307 shift: __arrayProto.shift, 7308 7309 7310 slice: function () { 7311 return new _Api( this.context, this ); 7312 }, 7313 7314 7315 sort: __arrayProto.sort, // ? name - order? 7316 7317 7318 splice: __arrayProto.splice, 7319 7320 7321 toArray: function () 7322 { 7323 return __arrayProto.slice.call( this ); 7324 }, 7325 7326 7327 to$: function () 7328 { 7329 return $( this ); 7330 }, 7331 7332 7333 toJQuery: function () 7334 { 7335 return $( this ); 7336 }, 7337 7338 7339 unique: function () 7340 { 7341 return new _Api( this.context, _unique(this) ); 7342 }, 7343 7344 7345 unshift: __arrayProto.unshift 7346 } ); 7347 7348 7349 _Api.extend = function ( scope, obj, ext ) 7350 { 7351 // Only extend API instances and static properties of the API 7352 if ( ! ext.length || ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) { 7353 return; 7354 } 7355 7356 var 7357 i, ien, 7358 struct, 7359 methodScoping = function ( scope, fn, struc ) { 7360 return function () { 7361 var ret = fn.apply( scope, arguments ); 7362 7363 // Method extension 7364 _Api.extend( ret, ret, struc.methodExt ); 7365 return ret; 7366 }; 7367 }; 7368 7369 for ( i=0, ien=ext.length ; i<ien ; i++ ) { 7370 struct = ext[i]; 7371 7372 // Value 7373 obj[ struct.name ] = struct.type === 'function' ? 7374 methodScoping( scope, struct.val, struct ) : 7375 struct.type === 'object' ? 7376 {} : 7377 struct.val; 7378 7379 obj[ struct.name ].__dt_wrapper = true; 7380 7381 // Property extension 7382 _Api.extend( scope, obj[ struct.name ], struct.propExt ); 7383 } 7384 }; 7385 7386 7387 // @todo - Is there need for an augment function? 7388 // _Api.augment = function ( inst, name ) 7389 // { 7390 // // Find src object in the structure from the name 7391 // var parts = name.split('.'); 7392 7393 // _Api.extend( inst, obj ); 7394 // }; 7395 7396 7397 // [ 7398 // { 7399 // name: 'data' -- string - Property name 7400 // val: function () {}, -- function - Api method (or undefined if just an object 7401 // methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result 7402 // propExt: [ ... ] -- array - Array of Api object definitions to extend the property 7403 // }, 7404 // { 7405 // name: 'row' 7406 // val: {}, 7407 // methodExt: [ ... ], 7408 // propExt: [ 7409 // { 7410 // name: 'data' 7411 // val: function () {}, 7412 // methodExt: [ ... ], 7413 // propExt: [ ... ] 7414 // }, 7415 // ... 7416 // ] 7417 // } 7418 // ] 7419 7420 _Api.register = _api_register = function ( name, val ) 7421 { 7422 if ( Array.isArray( name ) ) { 7423 for ( var j=0, jen=name.length ; j<jen ; j++ ) { 7424 _Api.register( name[j], val ); 7425 } 7426 return; 7427 } 7428 7429 var 7430 i, ien, 7431 heir = name.split('.'), 7432 struct = __apiStruct, 7433 key, method; 7434 7435 var find = function ( src, name ) { 7436 for ( var i=0, ien=src.length ; i<ien ; i++ ) { 7437 if ( src[i].name === name ) { 7438 return src[i]; 7439 } 7440 } 7441 return null; 7442 }; 7443 7444 for ( i=0, ien=heir.length ; i<ien ; i++ ) { 7445 method = heir[i].indexOf('()') !== -1; 7446 key = method ? 7447 heir[i].replace('()', '') : 7448 heir[i]; 7449 7450 var src = find( struct, key ); 7451 if ( ! src ) { 7452 src = { 7453 name: key, 7454 val: {}, 7455 methodExt: [], 7456 propExt: [], 7457 type: 'object' 7458 }; 7459 struct.push( src ); 7460 } 7461 7462 if ( i === ien-1 ) { 7463 src.val = val; 7464 src.type = typeof val === 'function' ? 7465 'function' : 7466 $.isPlainObject( val ) ? 7467 'object' : 7468 'other'; 7469 } 7470 else { 7471 struct = method ? 7472 src.methodExt : 7473 src.propExt; 7474 } 7475 } 7476 }; 7477 7478 _Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) { 7479 _Api.register( pluralName, val ); 7480 7481 _Api.register( singularName, function () { 7482 var ret = val.apply( this, arguments ); 7483 7484 if ( ret === this ) { 7485 // Returned item is the API instance that was passed in, return it 7486 return this; 7487 } 7488 else if ( ret instanceof _Api ) { 7489 // New API instance returned, want the value from the first item 7490 // in the returned array for the singular result. 7491 return ret.length ? 7492 Array.isArray( ret[0] ) ? 7493 new _Api( ret.context, ret[0] ) : // Array results are 'enhanced' 7494 ret[0] : 7495 undefined; 7496 } 7497 7498 // Non-API return - just fire it back 7499 return ret; 7500 } ); 7501 }; 7502 7503 7504 /** 7505 * Selector for HTML tables. Apply the given selector to the give array of 7506 * DataTables settings objects. 7507 * 7508 * @param {string|integer} [selector] jQuery selector string or integer 7509 * @param {array} Array of DataTables settings objects to be filtered 7510 * @return {array} 7511 * @ignore 7512 */ 7513 var __table_selector = function ( selector, a ) 7514 { 7515 if ( Array.isArray(selector) ) { 7516 return $.map( selector, function (item) { 7517 return __table_selector(item, a); 7518 } ); 7519 } 7520 7521 // Integer is used to pick out a table by index 7522 if ( typeof selector === 'number' ) { 7523 return [ a[ selector ] ]; 7524 } 7525 7526 // Perform a jQuery selector on the table nodes 7527 var nodes = $.map( a, function (el, i) { 7528 return el.nTable; 7529 } ); 7530 7531 return $(nodes) 7532 .filter( selector ) 7533 .map( function (i) { 7534 // Need to translate back from the table node to the settings 7535 var idx = $.inArray( this, nodes ); 7536 return a[ idx ]; 7537 } ) 7538 .toArray(); 7539 }; 7540 7541 7542 7543 /** 7544 * Context selector for the API's context (i.e. the tables the API instance 7545 * refers to. 7546 * 7547 * @name DataTable.Api#tables 7548 * @param {string|integer} [selector] Selector to pick which tables the iterator 7549 * should operate on. If not given, all tables in the current context are 7550 * used. This can be given as a jQuery selector (for example `':gt(0)'`) to 7551 * select multiple tables or as an integer to select a single table. 7552 * @returns {DataTable.Api} Returns a new API instance if a selector is given. 7553 */ 7554 _api_register( 'tables()', function ( selector ) { 7555 // A new instance is created if there was a selector specified 7556 return selector !== undefined && selector !== null ? 7557 new _Api( __table_selector( selector, this.context ) ) : 7558 this; 7559 } ); 7560 7561 7562 _api_register( 'table()', function ( selector ) { 7563 var tables = this.tables( selector ); 7564 var ctx = tables.context; 7565 7566 // Truncate to the first matched table 7567 return ctx.length ? 7568 new _Api( ctx[0] ) : 7569 tables; 7570 } ); 7571 7572 7573 _api_registerPlural( 'tables().nodes()', 'table().node()' , function () { 7574 return this.iterator( 'table', function ( ctx ) { 7575 return ctx.nTable; 7576 }, 1 ); 7577 } ); 7578 7579 7580 _api_registerPlural( 'tables().body()', 'table().body()' , function () { 7581 return this.iterator( 'table', function ( ctx ) { 7582 return ctx.nTBody; 7583 }, 1 ); 7584 } ); 7585 7586 7587 _api_registerPlural( 'tables().header()', 'table().header()' , function () { 7588 return this.iterator( 'table', function ( ctx ) { 7589 return ctx.nTHead; 7590 }, 1 ); 7591 } ); 7592 7593 7594 _api_registerPlural( 'tables().footer()', 'table().footer()' , function () { 7595 return this.iterator( 'table', function ( ctx ) { 7596 return ctx.nTFoot; 7597 }, 1 ); 7598 } ); 7599 7600 7601 _api_registerPlural( 'tables().containers()', 'table().container()' , function () { 7602 return this.iterator( 'table', function ( ctx ) { 7603 return ctx.nTableWrapper; 7604 }, 1 ); 7605 } ); 7606 7607 7608 7609 /** 7610 * Redraw the tables in the current context. 7611 */ 7612 _api_register( 'draw()', function ( paging ) { 7613 return this.iterator( 'table', function ( settings ) { 7614 if ( paging === 'page' ) { 7615 _fnDraw( settings ); 7616 } 7617 else { 7618 if ( typeof paging === 'string' ) { 7619 paging = paging === 'full-hold' ? 7620 false : 7621 true; 7622 } 7623 7624 _fnReDraw( settings, paging===false ); 7625 } 7626 } ); 7627 } ); 7628 7629 7630 7631 /** 7632 * Get the current page index. 7633 * 7634 * @return {integer} Current page index (zero based) 7635 *//** 7636 * Set the current page. 7637 * 7638 * Note that if you attempt to show a page which does not exist, DataTables will 7639 * not throw an error, but rather reset the paging. 7640 * 7641 * @param {integer|string} action The paging action to take. This can be one of: 7642 * * `integer` - The page index to jump to 7643 * * `string` - An action to take: 7644 * * `first` - Jump to first page. 7645 * * `next` - Jump to the next page 7646 * * `previous` - Jump to previous page 7647 * * `last` - Jump to the last page. 7648 * @returns {DataTables.Api} this 7649 */ 7650 _api_register( 'page()', function ( action ) { 7651 if ( action === undefined ) { 7652 return this.page.info().page; // not an expensive call 7653 } 7654 7655 // else, have an action to take on all tables 7656 return this.iterator( 'table', function ( settings ) { 7657 _fnPageChange( settings, action ); 7658 } ); 7659 } ); 7660 7661 7662 /** 7663 * Paging information for the first table in the current context. 7664 * 7665 * If you require paging information for another table, use the `table()` method 7666 * with a suitable selector. 7667 * 7668 * @return {object} Object with the following properties set: 7669 * * `page` - Current page index (zero based - i.e. the first page is `0`) 7670 * * `pages` - Total number of pages 7671 * * `start` - Display index for the first record shown on the current page 7672 * * `end` - Display index for the last record shown on the current page 7673 * * `length` - Display length (number of records). Note that generally `start 7674 * + length = end`, but this is not always true, for example if there are 7675 * only 2 records to show on the final page, with a length of 10. 7676 * * `recordsTotal` - Full data set length 7677 * * `recordsDisplay` - Data set length once the current filtering criterion 7678 * are applied. 7679 */ 7680 _api_register( 'page.info()', function ( action ) { 7681 if ( this.context.length === 0 ) { 7682 return undefined; 7683 } 7684 7685 var 7686 settings = this.context[0], 7687 start = settings._iDisplayStart, 7688 len = settings.oFeatures.bPaginate ? settings._iDisplayLength : -1, 7689 visRecords = settings.fnRecordsDisplay(), 7690 all = len === -1; 7691 7692 return { 7693 "page": all ? 0 : Math.floor( start / len ), 7694 "pages": all ? 1 : Math.ceil( visRecords / len ), 7695 "start": start, 7696 "end": settings.fnDisplayEnd(), 7697 "length": len, 7698 "recordsTotal": settings.fnRecordsTotal(), 7699 "recordsDisplay": visRecords, 7700 "serverSide": _fnDataSource( settings ) === 'ssp' 7701 }; 7702 } ); 7703 7704 7705 /** 7706 * Get the current page length. 7707 * 7708 * @return {integer} Current page length. Note `-1` indicates that all records 7709 * are to be shown. 7710 *//** 7711 * Set the current page length. 7712 * 7713 * @param {integer} Page length to set. Use `-1` to show all records. 7714 * @returns {DataTables.Api} this 7715 */ 7716 _api_register( 'page.len()', function ( len ) { 7717 // Note that we can't call this function 'length()' because `length` 7718 // is a Javascript property of functions which defines how many arguments 7719 // the function expects. 7720 if ( len === undefined ) { 7721 return this.context.length !== 0 ? 7722 this.context[0]._iDisplayLength : 7723 undefined; 7724 } 7725 7726 // else, set the page length 7727 return this.iterator( 'table', function ( settings ) { 7728 _fnLengthChange( settings, len ); 7729 } ); 7730 } ); 7731 7732 7733 7734 var __reload = function ( settings, holdPosition, callback ) { 7735 // Use the draw event to trigger a callback 7736 if ( callback ) { 7737 var api = new _Api( settings ); 7738 7739 api.one( 'draw', function () { 7740 callback( api.ajax.json() ); 7741 } ); 7742 } 7743 7744 if ( _fnDataSource( settings ) == 'ssp' ) { 7745 _fnReDraw( settings, holdPosition ); 7746 } 7747 else { 7748 _fnProcessingDisplay( settings, true ); 7749 7750 // Cancel an existing request 7751 var xhr = settings.jqXHR; 7752 if ( xhr && xhr.readyState !== 4 ) { 7753 xhr.abort(); 7754 } 7755 7756 // Trigger xhr 7757 _fnBuildAjax( settings, [], function( json ) { 7758 _fnClearTable( settings ); 7759 7760 var data = _fnAjaxDataSrc( settings, json ); 7761 for ( var i=0, ien=data.length ; i<ien ; i++ ) { 7762 _fnAddData( settings, data[i] ); 7763 } 7764 7765 _fnReDraw( settings, holdPosition ); 7766 _fnProcessingDisplay( settings, false ); 7767 } ); 7768 } 7769 }; 7770 7771 7772 /** 7773 * Get the JSON response from the last Ajax request that DataTables made to the 7774 * server. Note that this returns the JSON from the first table in the current 7775 * context. 7776 * 7777 * @return {object} JSON received from the server. 7778 */ 7779 _api_register( 'ajax.json()', function () { 7780 var ctx = this.context; 7781 7782 if ( ctx.length > 0 ) { 7783 return ctx[0].json; 7784 } 7785 7786 // else return undefined; 7787 } ); 7788 7789 7790 /** 7791 * Get the data submitted in the last Ajax request 7792 */ 7793 _api_register( 'ajax.params()', function () { 7794 var ctx = this.context; 7795 7796 if ( ctx.length > 0 ) { 7797 return ctx[0].oAjaxData; 7798 } 7799 7800 // else return undefined; 7801 } ); 7802 7803 7804 /** 7805 * Reload tables from the Ajax data source. Note that this function will 7806 * automatically re-draw the table when the remote data has been loaded. 7807 * 7808 * @param {boolean} [reset=true] Reset (default) or hold the current paging 7809 * position. A full re-sort and re-filter is performed when this method is 7810 * called, which is why the pagination reset is the default action. 7811 * @returns {DataTables.Api} this 7812 */ 7813 _api_register( 'ajax.reload()', function ( callback, resetPaging ) { 7814 return this.iterator( 'table', function (settings) { 7815 __reload( settings, resetPaging===false, callback ); 7816 } ); 7817 } ); 7818 7819 7820 /** 7821 * Get the current Ajax URL. Note that this returns the URL from the first 7822 * table in the current context. 7823 * 7824 * @return {string} Current Ajax source URL 7825 *//** 7826 * Set the Ajax URL. Note that this will set the URL for all tables in the 7827 * current context. 7828 * 7829 * @param {string} url URL to set. 7830 * @returns {DataTables.Api} this 7831 */ 7832 _api_register( 'ajax.url()', function ( url ) { 7833 var ctx = this.context; 7834 7835 if ( url === undefined ) { 7836 // get 7837 if ( ctx.length === 0 ) { 7838 return undefined; 7839 } 7840 ctx = ctx[0]; 7841 7842 return ctx.ajax ? 7843 $.isPlainObject( ctx.ajax ) ? 7844 ctx.ajax.url : 7845 ctx.ajax : 7846 ctx.sAjaxSource; 7847 } 7848 7849 // set 7850 return this.iterator( 'table', function ( settings ) { 7851 if ( $.isPlainObject( settings.ajax ) ) { 7852 settings.ajax.url = url; 7853 } 7854 else { 7855 settings.ajax = url; 7856 } 7857 // No need to consider sAjaxSource here since DataTables gives priority 7858 // to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any 7859 // value of `sAjaxSource` redundant. 7860 } ); 7861 } ); 7862 7863 7864 /** 7865 * Load data from the newly set Ajax URL. Note that this method is only 7866 * available when `ajax.url()` is used to set a URL. Additionally, this method 7867 * has the same effect as calling `ajax.reload()` but is provided for 7868 * convenience when setting a new URL. Like `ajax.reload()` it will 7869 * automatically redraw the table once the remote data has been loaded. 7870 * 7871 * @returns {DataTables.Api} this 7872 */ 7873 _api_register( 'ajax.url().load()', function ( callback, resetPaging ) { 7874 // Same as a reload, but makes sense to present it for easy access after a 7875 // url change 7876 return this.iterator( 'table', function ( ctx ) { 7877 __reload( ctx, resetPaging===false, callback ); 7878 } ); 7879 } ); 7880 7881 7882 7883 7884 var _selector_run = function ( type, selector, selectFn, settings, opts ) 7885 { 7886 var 7887 out = [], res, 7888 a, i, ien, j, jen, 7889 selectorType = typeof selector; 7890 7891 // Can't just check for isArray here, as an API or jQuery instance might be 7892 // given with their array like look 7893 if ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) { 7894 selector = [ selector ]; 7895 } 7896 7897 for ( i=0, ien=selector.length ; i<ien ; i++ ) { 7898 // Only split on simple strings - complex expressions will be jQuery selectors 7899 a = selector[i] && selector[i].split && ! selector[i].match(/[\[\(:]/) ? 7900 selector[i].split(',') : 7901 [ selector[i] ]; 7902 7903 for ( j=0, jen=a.length ; j<jen ; j++ ) { 7904 res = selectFn( typeof a[j] === 'string' ? (a[j]).trim() : a[j] ); 7905 7906 if ( res && res.length ) { 7907 out = out.concat( res ); 7908 } 7909 } 7910 } 7911 7912 // selector extensions 7913 var ext = _ext.selector[ type ]; 7914 if ( ext.length ) { 7915 for ( i=0, ien=ext.length ; i<ien ; i++ ) { 7916 out = ext[i]( settings, opts, out ); 7917 } 7918 } 7919 7920 return _unique( out ); 7921 }; 7922 7923 7924 var _selector_opts = function ( opts ) 7925 { 7926 if ( ! opts ) { 7927 opts = {}; 7928 } 7929 7930 // Backwards compatibility for 1.9- which used the terminology filter rather 7931 // than search 7932 if ( opts.filter && opts.search === undefined ) { 7933 opts.search = opts.filter; 7934 } 7935 7936 return $.extend( { 7937 search: 'none', 7938 order: 'current', 7939 page: 'all' 7940 }, opts ); 7941 }; 7942 7943 7944 var _selector_first = function ( inst ) 7945 { 7946 // Reduce the API instance to the first item found 7947 for ( var i=0, ien=inst.length ; i<ien ; i++ ) { 7948 if ( inst[i].length > 0 ) { 7949 // Assign the first element to the first item in the instance 7950 // and truncate the instance and context 7951 inst[0] = inst[i]; 7952 inst[0].length = 1; 7953 inst.length = 1; 7954 inst.context = [ inst.context[i] ]; 7955 7956 return inst; 7957 } 7958 } 7959 7960 // Not found - return an empty instance 7961 inst.length = 0; 7962 return inst; 7963 }; 7964 7965 7966 var _selector_row_indexes = function ( settings, opts ) 7967 { 7968 var 7969 i, ien, tmp, a=[], 7970 displayFiltered = settings.aiDisplay, 7971 displayMaster = settings.aiDisplayMaster; 7972 7973 var 7974 search = opts.search, // none, applied, removed 7975 order = opts.order, // applied, current, index (original - compatibility with 1.9) 7976 page = opts.page; // all, current 7977 7978 if ( _fnDataSource( settings ) == 'ssp' ) { 7979 // In server-side processing mode, most options are irrelevant since 7980 // rows not shown don't exist and the index order is the applied order 7981 // Removed is a special case - for consistency just return an empty 7982 // array 7983 return search === 'removed' ? 7984 [] : 7985 _range( 0, displayMaster.length ); 7986 } 7987 else if ( page == 'current' ) { 7988 // Current page implies that order=current and filter=applied, since it is 7989 // fairly senseless otherwise, regardless of what order and search actually 7990 // are 7991 for ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) { 7992 a.push( displayFiltered[i] ); 7993 } 7994 } 7995 else if ( order == 'current' || order == 'applied' ) { 7996 if ( search == 'none') { 7997 a = displayMaster.slice(); 7998 } 7999 else if ( search == 'applied' ) { 8000 a = displayFiltered.slice(); 8001 } 8002 else if ( search == 'removed' ) { 8003 // O(n+m) solution by creating a hash map 8004 var displayFilteredMap = {}; 8005 8006 for ( var i=0, ien=displayFiltered.length ; i<ien ; i++ ) { 8007 displayFilteredMap[displayFiltered[i]] = null; 8008 } 8009 8010 a = $.map( displayMaster, function (el) { 8011 return ! displayFilteredMap.hasOwnProperty(el) ? 8012 el : 8013 null; 8014 } ); 8015 } 8016 } 8017 else if ( order == 'index' || order == 'original' ) { 8018 for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) { 8019 if ( search == 'none' ) { 8020 a.push( i ); 8021 } 8022 else { // applied | removed 8023 tmp = $.inArray( i, displayFiltered ); 8024 8025 if ((tmp === -1 && search == 'removed') || 8026 (tmp >= 0 && search == 'applied') ) 8027 { 8028 a.push( i ); 8029 } 8030 } 8031 } 8032 } 8033 8034 return a; 8035 }; 8036 8037 8038 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 8039 * Rows 8040 * 8041 * {} - no selector - use all available rows 8042 * {integer} - row aoData index 8043 * {node} - TR node 8044 * {string} - jQuery selector to apply to the TR elements 8045 * {array} - jQuery array of nodes, or simply an array of TR nodes 8046 * 8047 */ 8048 var __row_selector = function ( settings, selector, opts ) 8049 { 8050 var rows; 8051 var run = function ( sel ) { 8052 var selInt = _intVal( sel ); 8053 var i, ien; 8054 var aoData = settings.aoData; 8055 8056 // Short cut - selector is a number and no options provided (default is 8057 // all records, so no need to check if the index is in there, since it 8058 // must be - dev error if the index doesn't exist). 8059 if ( selInt !== null && ! opts ) { 8060 return [ selInt ]; 8061 } 8062 8063 if ( ! rows ) { 8064 rows = _selector_row_indexes( settings, opts ); 8065 } 8066 8067 if ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) { 8068 // Selector - integer 8069 return [ selInt ]; 8070 } 8071 else if ( sel === null || sel === undefined || sel === '' ) { 8072 // Selector - none 8073 return rows; 8074 } 8075 8076 // Selector - function 8077 if ( typeof sel === 'function' ) { 8078 return $.map( rows, function (idx) { 8079 var row = aoData[ idx ]; 8080 return sel( idx, row._aData, row.nTr ) ? idx : null; 8081 } ); 8082 } 8083 8084 // Selector - node 8085 if ( sel.nodeName ) { 8086 var rowIdx = sel._DT_RowIndex; // Property added by DT for fast lookup 8087 var cellIdx = sel._DT_CellIndex; 8088 8089 if ( rowIdx !== undefined ) { 8090 // Make sure that the row is actually still present in the table 8091 return aoData[ rowIdx ] && aoData[ rowIdx ].nTr === sel ? 8092 [ rowIdx ] : 8093 []; 8094 } 8095 else if ( cellIdx ) { 8096 return aoData[ cellIdx.row ] && aoData[ cellIdx.row ].nTr === sel.parentNode ? 8097 [ cellIdx.row ] : 8098 []; 8099 } 8100 else { 8101 var host = $(sel).closest('*[data-dt-row]'); 8102 return host.length ? 8103 [ host.data('dt-row') ] : 8104 []; 8105 } 8106 } 8107 8108 // ID selector. Want to always be able to select rows by id, regardless 8109 // of if the tr element has been created or not, so can't rely upon 8110 // jQuery here - hence a custom implementation. This does not match 8111 // Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything, 8112 // but to select it using a CSS selector engine (like Sizzle or 8113 // querySelect) it would need to need to be escaped for some characters. 8114 // DataTables simplifies this for row selectors since you can select 8115 // only a row. A # indicates an id any anything that follows is the id - 8116 // unescaped. 8117 if ( typeof sel === 'string' && sel.charAt(0) === '#' ) { 8118 // get row index from id 8119 var rowObj = settings.aIds[ sel.replace( /^#/, '' ) ]; 8120 if ( rowObj !== undefined ) { 8121 return [ rowObj.idx ]; 8122 } 8123 8124 // need to fall through to jQuery in case there is DOM id that 8125 // matches 8126 } 8127 8128 // Get nodes in the order from the `rows` array with null values removed 8129 var nodes = _removeEmpty( 8130 _pluck_order( settings.aoData, rows, 'nTr' ) 8131 ); 8132 8133 // Selector - jQuery selector string, array of nodes or jQuery object/ 8134 // As jQuery's .filter() allows jQuery objects to be passed in filter, 8135 // it also allows arrays, so this will cope with all three options 8136 return $(nodes) 8137 .filter( sel ) 8138 .map( function () { 8139 return this._DT_RowIndex; 8140 } ) 8141 .toArray(); 8142 }; 8143 8144 return _selector_run( 'row', selector, run, settings, opts ); 8145 }; 8146 8147 8148 _api_register( 'rows()', function ( selector, opts ) { 8149 // argument shifting 8150 if ( selector === undefined ) { 8151 selector = ''; 8152 } 8153 else if ( $.isPlainObject( selector ) ) { 8154 opts = selector; 8155 selector = ''; 8156 } 8157 8158 opts = _selector_opts( opts ); 8159 8160 var inst = this.iterator( 'table', function ( settings ) { 8161 return __row_selector( settings, selector, opts ); 8162 }, 1 ); 8163 8164 // Want argument shifting here and in __row_selector? 8165 inst.selector.rows = selector; 8166 inst.selector.opts = opts; 8167 8168 return inst; 8169 } ); 8170 8171 _api_register( 'rows().nodes()', function () { 8172 return this.iterator( 'row', function ( settings, row ) { 8173 return settings.aoData[ row ].nTr || undefined; 8174 }, 1 ); 8175 } ); 8176 8177 _api_register( 'rows().data()', function () { 8178 return this.iterator( true, 'rows', function ( settings, rows ) { 8179 return _pluck_order( settings.aoData, rows, '_aData' ); 8180 }, 1 ); 8181 } ); 8182 8183 _api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) { 8184 return this.iterator( 'row', function ( settings, row ) { 8185 var r = settings.aoData[ row ]; 8186 return type === 'search' ? r._aFilterData : r._aSortData; 8187 }, 1 ); 8188 } ); 8189 8190 _api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) { 8191 return this.iterator( 'row', function ( settings, row ) { 8192 _fnInvalidate( settings, row, src ); 8193 } ); 8194 } ); 8195 8196 _api_registerPlural( 'rows().indexes()', 'row().index()', function () { 8197 return this.iterator( 'row', function ( settings, row ) { 8198 return row; 8199 }, 1 ); 8200 } ); 8201 8202 _api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) { 8203 var a = []; 8204 var context = this.context; 8205 8206 // `iterator` will drop undefined values, but in this case we want them 8207 for ( var i=0, ien=context.length ; i<ien ; i++ ) { 8208 for ( var j=0, jen=this[i].length ; j<jen ; j++ ) { 8209 var id = context[i].rowIdFn( context[i].aoData[ this[i][j] ]._aData ); 8210 a.push( (hash === true ? '#' : '' )+ id ); 8211 } 8212 } 8213 8214 return new _Api( context, a ); 8215 } ); 8216 8217 _api_registerPlural( 'rows().remove()', 'row().remove()', function () { 8218 var that = this; 8219 8220 this.iterator( 'row', function ( settings, row, thatIdx ) { 8221 var data = settings.aoData; 8222 var rowData = data[ row ]; 8223 var i, ien, j, jen; 8224 var loopRow, loopCells; 8225 8226 data.splice( row, 1 ); 8227 8228 // Update the cached indexes 8229 for ( i=0, ien=data.length ; i<ien ; i++ ) { 8230 loopRow = data[i]; 8231 loopCells = loopRow.anCells; 8232 8233 // Rows 8234 if ( loopRow.nTr !== null ) { 8235 loopRow.nTr._DT_RowIndex = i; 8236 } 8237 8238 // Cells 8239 if ( loopCells !== null ) { 8240 for ( j=0, jen=loopCells.length ; j<jen ; j++ ) { 8241 loopCells[j]._DT_CellIndex.row = i; 8242 } 8243 } 8244 } 8245 8246 // Delete from the display arrays 8247 _fnDeleteIndex( settings.aiDisplayMaster, row ); 8248 _fnDeleteIndex( settings.aiDisplay, row ); 8249 _fnDeleteIndex( that[ thatIdx ], row, false ); // maintain local indexes 8250 8251 // For server-side processing tables - subtract the deleted row from the count 8252 if ( settings._iRecordsDisplay > 0 ) { 8253 settings._iRecordsDisplay--; 8254 } 8255 8256 // Check for an 'overflow' they case for displaying the table 8257 _fnLengthOverflow( settings ); 8258 8259 // Remove the row's ID reference if there is one 8260 var id = settings.rowIdFn( rowData._aData ); 8261 if ( id !== undefined ) { 8262 delete settings.aIds[ id ]; 8263 } 8264 } ); 8265 8266 this.iterator( 'table', function ( settings ) { 8267 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) { 8268 settings.aoData[i].idx = i; 8269 } 8270 } ); 8271 8272 return this; 8273 } ); 8274 8275 8276 _api_register( 'rows.add()', function ( rows ) { 8277 var newRows = this.iterator( 'table', function ( settings ) { 8278 var row, i, ien; 8279 var out = []; 8280 8281 for ( i=0, ien=rows.length ; i<ien ; i++ ) { 8282 row = rows[i]; 8283 8284 if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) { 8285 out.push( _fnAddTr( settings, row )[0] ); 8286 } 8287 else { 8288 out.push( _fnAddData( settings, row ) ); 8289 } 8290 } 8291 8292 return out; 8293 }, 1 ); 8294 8295 // Return an Api.rows() extended instance, so rows().nodes() etc can be used 8296 var modRows = this.rows( -1 ); 8297 modRows.pop(); 8298 $.merge( modRows, newRows ); 8299 8300 return modRows; 8301 } ); 8302 8303 8304 8305 8306 8307 /** 8308 * 8309 */ 8310 _api_register( 'row()', function ( selector, opts ) { 8311 return _selector_first( this.rows( selector, opts ) ); 8312 } ); 8313 8314 8315 _api_register( 'row().data()', function ( data ) { 8316 var ctx = this.context; 8317 8318 if ( data === undefined ) { 8319 // Get 8320 return ctx.length && this.length ? 8321 ctx[0].aoData[ this[0] ]._aData : 8322 undefined; 8323 } 8324 8325 // Set 8326 var row = ctx[0].aoData[ this[0] ]; 8327 row._aData = data; 8328 8329 // If the DOM has an id, and the data source is an array 8330 if ( Array.isArray( data ) && row.nTr && row.nTr.id ) { 8331 _fnSetObjectDataFn( ctx[0].rowId )( data, row.nTr.id ); 8332 } 8333 8334 // Automatically invalidate 8335 _fnInvalidate( ctx[0], this[0], 'data' ); 8336 8337 return this; 8338 } ); 8339 8340 8341 _api_register( 'row().node()', function () { 8342 var ctx = this.context; 8343 8344 return ctx.length && this.length ? 8345 ctx[0].aoData[ this[0] ].nTr || null : 8346 null; 8347 } ); 8348 8349 8350 _api_register( 'row.add()', function ( row ) { 8351 // Allow a jQuery object to be passed in - only a single row is added from 8352 // it though - the first element in the set 8353 if ( row instanceof $ && row.length ) { 8354 row = row[0]; 8355 } 8356 8357 var rows = this.iterator( 'table', function ( settings ) { 8358 if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) { 8359 return _fnAddTr( settings, row )[0]; 8360 } 8361 return _fnAddData( settings, row ); 8362 } ); 8363 8364 // Return an Api.rows() extended instance, with the newly added row selected 8365 return this.row( rows[0] ); 8366 } ); 8367 8368 8369 $(document).on('plugin-init.dt', function (e, context) { 8370 var api = new _Api( context ); 8371 var namespace = 'on-plugin-init'; 8372 var stateSaveParamsEvent = 'stateSaveParams.' + namespace; 8373 var destroyEvent = 'destroy. ' + namespace; 8374 8375 api.on( stateSaveParamsEvent, function ( e, settings, d ) { 8376 // This could be more compact with the API, but it is a lot faster as a simple 8377 // internal loop 8378 var idFn = settings.rowIdFn; 8379 var data = settings.aoData; 8380 var ids = []; 8381 8382 for (var i=0 ; i<data.length ; i++) { 8383 if (data[i]._detailsShow) { 8384 ids.push( '#' + idFn(data[i]._aData) ); 8385 } 8386 } 8387 8388 d.childRows = ids; 8389 }); 8390 8391 api.on( destroyEvent, function () { 8392 api.off(stateSaveParamsEvent + ' ' + destroyEvent); 8393 }); 8394 8395 var loaded = api.state.loaded(); 8396 8397 if ( loaded && loaded.childRows ) { 8398 api 8399 .rows( $.map(loaded.childRows, function (id){ 8400 return id.replace(/:/g, '\\:') 8401 }) ) 8402 .every( function () { 8403 _fnCallbackFire( context, null, 'requestChild', [ this ] ) 8404 }); 8405 } 8406 }); 8407 8408 var __details_add = function ( ctx, row, data, klass ) 8409 { 8410 // Convert to array of TR elements 8411 var rows = []; 8412 var addRow = function ( r, k ) { 8413 // Recursion to allow for arrays of jQuery objects 8414 if ( Array.isArray( r ) || r instanceof $ ) { 8415 for ( var i=0, ien=r.length ; i<ien ; i++ ) { 8416 addRow( r[i], k ); 8417 } 8418 return; 8419 } 8420 8421 // If we get a TR element, then just add it directly - up to the dev 8422 // to add the correct number of columns etc 8423 if ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) { 8424 rows.push( r ); 8425 } 8426 else { 8427 // Otherwise create a row with a wrapper 8428 var created = $('<tr><td></td></tr>').addClass( k ); 8429 $('td', created) 8430 .addClass( k ) 8431 .html( r ) 8432 [0].colSpan = _fnVisbleColumns( ctx ); 8433 8434 rows.push( created[0] ); 8435 } 8436 }; 8437 8438 addRow( data, klass ); 8439 8440 if ( row._details ) { 8441 row._details.detach(); 8442 } 8443 8444 row._details = $(rows); 8445 8446 // If the children were already shown, that state should be retained 8447 if ( row._detailsShow ) { 8448 row._details.insertAfter( row.nTr ); 8449 } 8450 }; 8451 8452 8453 // Make state saving of child row details async to allow them to be batch processed 8454 var __details_state = DataTable.util.throttle( 8455 function (ctx) { 8456 _fnSaveState( ctx[0] ) 8457 }, 8458 500 8459 ); 8460 8461 8462 var __details_remove = function ( api, idx ) 8463 { 8464 var ctx = api.context; 8465 8466 if ( ctx.length ) { 8467 var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ]; 8468 8469 if ( row && row._details ) { 8470 row._details.remove(); 8471 8472 row._detailsShow = undefined; 8473 row._details = undefined; 8474 $( row.nTr ).removeClass( 'dt-hasChild' ); 8475 __details_state( ctx ); 8476 } 8477 } 8478 }; 8479 8480 8481 var __details_display = function ( api, show ) { 8482 var ctx = api.context; 8483 8484 if ( ctx.length && api.length ) { 8485 var row = ctx[0].aoData[ api[0] ]; 8486 8487 if ( row._details ) { 8488 row._detailsShow = show; 8489 8490 if ( show ) { 8491 row._details.insertAfter( row.nTr ); 8492 $( row.nTr ).addClass( 'dt-hasChild' ); 8493 } 8494 else { 8495 row._details.detach(); 8496 $( row.nTr ).removeClass( 'dt-hasChild' ); 8497 } 8498 8499 _fnCallbackFire( ctx[0], null, 'childRow', [ show, api.row( api[0] ) ] ) 8500 8501 __details_events( ctx[0] ); 8502 __details_state( ctx ); 8503 } 8504 } 8505 }; 8506 8507 8508 var __details_events = function ( settings ) 8509 { 8510 var api = new _Api( settings ); 8511 var namespace = '.dt.DT_details'; 8512 var drawEvent = 'draw'+namespace; 8513 var colvisEvent = 'column-sizing'+namespace; 8514 var destroyEvent = 'destroy'+namespace; 8515 var data = settings.aoData; 8516 8517 api.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent ); 8518 8519 if ( _pluck( data, '_details' ).length > 0 ) { 8520 // On each draw, insert the required elements into the document 8521 api.on( drawEvent, function ( e, ctx ) { 8522 if ( settings !== ctx ) { 8523 return; 8524 } 8525 8526 api.rows( {page:'current'} ).eq(0).each( function (idx) { 8527 // Internal data grab 8528 var row = data[ idx ]; 8529 8530 if ( row._detailsShow ) { 8531 row._details.insertAfter( row.nTr ); 8532 } 8533 } ); 8534 } ); 8535 8536 // Column visibility change - update the colspan 8537 api.on( colvisEvent, function ( e, ctx, idx, vis ) { 8538 if ( settings !== ctx ) { 8539 return; 8540 } 8541 8542 // Update the colspan for the details rows (note, only if it already has 8543 // a colspan) 8544 var row, visible = _fnVisbleColumns( ctx ); 8545 8546 for ( var i=0, ien=data.length ; i<ien ; i++ ) { 8547 row = data[i]; 8548 8549 if ( row._details ) { 8550 row._details.children('td[colspan]').attr('colspan', visible ); 8551 } 8552 } 8553 } ); 8554 8555 // Table destroyed - nuke any child rows 8556 api.on( destroyEvent, function ( e, ctx ) { 8557 if ( settings !== ctx ) { 8558 return; 8559 } 8560 8561 for ( var i=0, ien=data.length ; i<ien ; i++ ) { 8562 if ( data[i]._details ) { 8563 __details_remove( api, i ); 8564 } 8565 } 8566 } ); 8567 } 8568 }; 8569 8570 // Strings for the method names to help minification 8571 var _emp = ''; 8572 var _child_obj = _emp+'row().child'; 8573 var _child_mth = _child_obj+'()'; 8574 8575 // data can be: 8576 // tr 8577 // string 8578 // jQuery or array of any of the above 8579 _api_register( _child_mth, function ( data, klass ) { 8580 var ctx = this.context; 8581 8582 if ( data === undefined ) { 8583 // get 8584 return ctx.length && this.length ? 8585 ctx[0].aoData[ this[0] ]._details : 8586 undefined; 8587 } 8588 else if ( data === true ) { 8589 // show 8590 this.child.show(); 8591 } 8592 else if ( data === false ) { 8593 // remove 8594 __details_remove( this ); 8595 } 8596 else if ( ctx.length && this.length ) { 8597 // set 8598 __details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass ); 8599 } 8600 8601 return this; 8602 } ); 8603 8604 8605 _api_register( [ 8606 _child_obj+'.show()', 8607 _child_mth+'.show()' // only when `child()` was called with parameters (without 8608 ], function ( show ) { // it returns an object and this method is not executed) 8609 __details_display( this, true ); 8610 return this; 8611 } ); 8612 8613 8614 _api_register( [ 8615 _child_obj+'.hide()', 8616 _child_mth+'.hide()' // only when `child()` was called with parameters (without 8617 ], function () { // it returns an object and this method is not executed) 8618 __details_display( this, false ); 8619 return this; 8620 } ); 8621 8622 8623 _api_register( [ 8624 _child_obj+'.remove()', 8625 _child_mth+'.remove()' // only when `child()` was called with parameters (without 8626 ], function () { // it returns an object and this method is not executed) 8627 __details_remove( this ); 8628 return this; 8629 } ); 8630 8631 8632 _api_register( _child_obj+'.isShown()', function () { 8633 var ctx = this.context; 8634 8635 if ( ctx.length && this.length ) { 8636 // _detailsShown as false or undefined will fall through to return false 8637 return ctx[0].aoData[ this[0] ]._detailsShow || false; 8638 } 8639 return false; 8640 } ); 8641 8642 8643 8644 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 8645 * Columns 8646 * 8647 * {integer} - column index (>=0 count from left, <0 count from right) 8648 * "{integer}:visIdx" - visible column index (i.e. translate to column index) (>=0 count from left, <0 count from right) 8649 * "{integer}:visible" - alias for {integer}:visIdx (>=0 count from left, <0 count from right) 8650 * "{string}:name" - column name 8651 * "{string}" - jQuery selector on column header nodes 8652 * 8653 */ 8654 8655 // can be an array of these items, comma separated list, or an array of comma 8656 // separated lists 8657 8658 var __re_column_selector = /^([^:]+):(name|visIdx|visible)$/; 8659 8660 8661 // r1 and r2 are redundant - but it means that the parameters match for the 8662 // iterator callback in columns().data() 8663 var __columnData = function ( settings, column, r1, r2, rows ) { 8664 var a = []; 8665 for ( var row=0, ien=rows.length ; row<ien ; row++ ) { 8666 a.push( _fnGetCellData( settings, rows[row], column ) ); 8667 } 8668 return a; 8669 }; 8670 8671 8672 var __column_selector = function ( settings, selector, opts ) 8673 { 8674 var 8675 columns = settings.aoColumns, 8676 names = _pluck( columns, 'sName' ), 8677 nodes = _pluck( columns, 'nTh' ); 8678 8679 var run = function ( s ) { 8680 var selInt = _intVal( s ); 8681 8682 // Selector - all 8683 if ( s === '' ) { 8684 return _range( columns.length ); 8685 } 8686 8687 // Selector - index 8688 if ( selInt !== null ) { 8689 return [ selInt >= 0 ? 8690 selInt : // Count from left 8691 columns.length + selInt // Count from right (+ because its a negative value) 8692 ]; 8693 } 8694 8695 // Selector = function 8696 if ( typeof s === 'function' ) { 8697 var rows = _selector_row_indexes( settings, opts ); 8698 8699 return $.map( columns, function (col, idx) { 8700 return s( 8701 idx, 8702 __columnData( settings, idx, 0, 0, rows ), 8703 nodes[ idx ] 8704 ) ? idx : null; 8705 } ); 8706 } 8707 8708 // jQuery or string selector 8709 var match = typeof s === 'string' ? 8710 s.match( __re_column_selector ) : 8711 ''; 8712 8713 if ( match ) { 8714 switch( match[2] ) { 8715 case 'visIdx': 8716 case 'visible': 8717 var idx = parseInt( match[1], 10 ); 8718 // Visible index given, convert to column index 8719 if ( idx < 0 ) { 8720 // Counting from the right 8721 var visColumns = $.map( columns, function (col,i) { 8722 return col.bVisible ? i : null; 8723 } ); 8724 return [ visColumns[ visColumns.length + idx ] ]; 8725 } 8726 // Counting from the left 8727 return [ _fnVisibleToColumnIndex( settings, idx ) ]; 8728 8729 case 'name': 8730 // match by name. `names` is column index complete and in order 8731 return $.map( names, function (name, i) { 8732 return name === match[1] ? i : null; 8733 } ); 8734 8735 default: 8736 return []; 8737 } 8738 } 8739 8740 // Cell in the table body 8741 if ( s.nodeName && s._DT_CellIndex ) { 8742 return [ s._DT_CellIndex.column ]; 8743 } 8744 8745 // jQuery selector on the TH elements for the columns 8746 var jqResult = $( nodes ) 8747 .filter( s ) 8748 .map( function () { 8749 return $.inArray( this, nodes ); // `nodes` is column index complete and in order 8750 } ) 8751 .toArray(); 8752 8753 if ( jqResult.length || ! s.nodeName ) { 8754 return jqResult; 8755 } 8756 8757 // Otherwise a node which might have a `dt-column` data attribute, or be 8758 // a child or such an element 8759 var host = $(s).closest('*[data-dt-column]'); 8760 return host.length ? 8761 [ host.data('dt-column') ] : 8762 []; 8763 }; 8764 8765 return _selector_run( 'column', selector, run, settings, opts ); 8766 }; 8767 8768 8769 var __setColumnVis = function ( settings, column, vis ) { 8770 var 8771 cols = settings.aoColumns, 8772 col = cols[ column ], 8773 data = settings.aoData, 8774 row, cells, i, ien, tr; 8775 8776 // Get 8777 if ( vis === undefined ) { 8778 return col.bVisible; 8779 } 8780 8781 // Set 8782 // No change 8783 if ( col.bVisible === vis ) { 8784 return; 8785 } 8786 8787 if ( vis ) { 8788 // Insert column 8789 // Need to decide if we should use appendChild or insertBefore 8790 var insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 ); 8791 8792 for ( i=0, ien=data.length ; i<ien ; i++ ) { 8793 tr = data[i].nTr; 8794 cells = data[i].anCells; 8795 8796 if ( tr ) { 8797 // insertBefore can act like appendChild if 2nd arg is null 8798 tr.insertBefore( cells[ column ], cells[ insertBefore ] || null ); 8799 } 8800 } 8801 } 8802 else { 8803 // Remove column 8804 $( _pluck( settings.aoData, 'anCells', column ) ).detach(); 8805 } 8806 8807 // Common actions 8808 col.bVisible = vis; 8809 }; 8810 8811 8812 _api_register( 'columns()', function ( selector, opts ) { 8813 // argument shifting 8814 if ( selector === undefined ) { 8815 selector = ''; 8816 } 8817 else if ( $.isPlainObject( selector ) ) { 8818 opts = selector; 8819 selector = ''; 8820 } 8821 8822 opts = _selector_opts( opts ); 8823 8824 var inst = this.iterator( 'table', function ( settings ) { 8825 return __column_selector( settings, selector, opts ); 8826 }, 1 ); 8827 8828 // Want argument shifting here and in _row_selector? 8829 inst.selector.cols = selector; 8830 inst.selector.opts = opts; 8831 8832 return inst; 8833 } ); 8834 8835 _api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) { 8836 return this.iterator( 'column', function ( settings, column ) { 8837 return settings.aoColumns[column].nTh; 8838 }, 1 ); 8839 } ); 8840 8841 _api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) { 8842 return this.iterator( 'column', function ( settings, column ) { 8843 return settings.aoColumns[column].nTf; 8844 }, 1 ); 8845 } ); 8846 8847 _api_registerPlural( 'columns().data()', 'column().data()', function () { 8848 return this.iterator( 'column-rows', __columnData, 1 ); 8849 } ); 8850 8851 _api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () { 8852 return this.iterator( 'column', function ( settings, column ) { 8853 return settings.aoColumns[column].mData; 8854 }, 1 ); 8855 } ); 8856 8857 _api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) { 8858 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) { 8859 return _pluck_order( settings.aoData, rows, 8860 type === 'search' ? '_aFilterData' : '_aSortData', column 8861 ); 8862 }, 1 ); 8863 } ); 8864 8865 _api_registerPlural( 'columns().nodes()', 'column().nodes()', function () { 8866 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) { 8867 return _pluck_order( settings.aoData, rows, 'anCells', column ) ; 8868 }, 1 ); 8869 } ); 8870 8871 _api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) { 8872 var that = this; 8873 var ret = this.iterator( 'column', function ( settings, column ) { 8874 if ( vis === undefined ) { 8875 return settings.aoColumns[ column ].bVisible; 8876 } // else 8877 __setColumnVis( settings, column, vis ); 8878 } ); 8879 8880 // Group the column visibility changes 8881 if ( vis !== undefined ) { 8882 this.iterator( 'table', function ( settings ) { 8883 // Redraw the header after changes 8884 _fnDrawHead( settings, settings.aoHeader ); 8885 _fnDrawHead( settings, settings.aoFooter ); 8886 8887 // Update colspan for no records display. Child rows and extensions will use their own 8888 // listeners to do this - only need to update the empty table item here 8889 if ( ! settings.aiDisplay.length ) { 8890 $(settings.nTBody).find('td[colspan]').attr('colspan', _fnVisbleColumns(settings)); 8891 } 8892 8893 _fnSaveState( settings ); 8894 8895 // Second loop once the first is done for events 8896 that.iterator( 'column', function ( settings, column ) { 8897 _fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis, calc] ); 8898 } ); 8899 8900 if ( calc === undefined || calc ) { 8901 that.columns.adjust(); 8902 } 8903 }); 8904 } 8905 8906 return ret; 8907 } ); 8908 8909 _api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) { 8910 return this.iterator( 'column', function ( settings, column ) { 8911 return type === 'visible' ? 8912 _fnColumnIndexToVisible( settings, column ) : 8913 column; 8914 }, 1 ); 8915 } ); 8916 8917 _api_register( 'columns.adjust()', function () { 8918 return this.iterator( 'table', function ( settings ) { 8919 _fnAdjustColumnSizing( settings ); 8920 }, 1 ); 8921 } ); 8922 8923 _api_register( 'column.index()', function ( type, idx ) { 8924 if ( this.context.length !== 0 ) { 8925 var ctx = this.context[0]; 8926 8927 if ( type === 'fromVisible' || type === 'toData' ) { 8928 return _fnVisibleToColumnIndex( ctx, idx ); 8929 } 8930 else if ( type === 'fromData' || type === 'toVisible' ) { 8931 return _fnColumnIndexToVisible( ctx, idx ); 8932 } 8933 } 8934 } ); 8935 8936 _api_register( 'column()', function ( selector, opts ) { 8937 return _selector_first( this.columns( selector, opts ) ); 8938 } ); 8939 8940 var __cell_selector = function ( settings, selector, opts ) 8941 { 8942 var data = settings.aoData; 8943 var rows = _selector_row_indexes( settings, opts ); 8944 var cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) ); 8945 var allCells = $(_flatten( [], cells )); 8946 var row; 8947 var columns = settings.aoColumns.length; 8948 var a, i, ien, j, o, host; 8949 8950 var run = function ( s ) { 8951 var fnSelector = typeof s === 'function'; 8952 8953 if ( s === null || s === undefined || fnSelector ) { 8954 // All cells and function selectors 8955 a = []; 8956 8957 for ( i=0, ien=rows.length ; i<ien ; i++ ) { 8958 row = rows[i]; 8959 8960 for ( j=0 ; j<columns ; j++ ) { 8961 o = { 8962 row: row, 8963 column: j 8964 }; 8965 8966 if ( fnSelector ) { 8967 // Selector - function 8968 host = data[ row ]; 8969 8970 if ( s( o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null ) ) { 8971 a.push( o ); 8972 } 8973 } 8974 else { 8975 // Selector - all 8976 a.push( o ); 8977 } 8978 } 8979 } 8980 8981 return a; 8982 } 8983 8984 // Selector - index 8985 if ( $.isPlainObject( s ) ) { 8986 // Valid cell index and its in the array of selectable rows 8987 return s.column !== undefined && s.row !== undefined && $.inArray( s.row, rows ) !== -1 ? 8988 [s] : 8989 []; 8990 } 8991 8992 // Selector - jQuery filtered cells 8993 var jqResult = allCells 8994 .filter( s ) 8995 .map( function (i, el) { 8996 return { // use a new object, in case someone changes the values 8997 row: el._DT_CellIndex.row, 8998 column: el._DT_CellIndex.column 8999 }; 9000 } ) 9001 .toArray(); 9002 9003 if ( jqResult.length || ! s.nodeName ) { 9004 return jqResult; 9005 } 9006 9007 // Otherwise the selector is a node, and there is one last option - the 9008 // element might be a child of an element which has dt-row and dt-column 9009 // data attributes 9010 host = $(s).closest('*[data-dt-row]'); 9011 return host.length ? 9012 [ { 9013 row: host.data('dt-row'), 9014 column: host.data('dt-column') 9015 } ] : 9016 []; 9017 }; 9018 9019 return _selector_run( 'cell', selector, run, settings, opts ); 9020 }; 9021 9022 9023 9024 9025 _api_register( 'cells()', function ( rowSelector, columnSelector, opts ) { 9026 // Argument shifting 9027 if ( $.isPlainObject( rowSelector ) ) { 9028 // Indexes 9029 if ( rowSelector.row === undefined ) { 9030 // Selector options in first parameter 9031 opts = rowSelector; 9032 rowSelector = null; 9033 } 9034 else { 9035 // Cell index objects in first parameter 9036 opts = columnSelector; 9037 columnSelector = null; 9038 } 9039 } 9040 if ( $.isPlainObject( columnSelector ) ) { 9041 opts = columnSelector; 9042 columnSelector = null; 9043 } 9044 9045 // Cell selector 9046 if ( columnSelector === null || columnSelector === undefined ) { 9047 return this.iterator( 'table', function ( settings ) { 9048 return __cell_selector( settings, rowSelector, _selector_opts( opts ) ); 9049 } ); 9050 } 9051 9052 // The default built in options need to apply to row and columns 9053 var internalOpts = opts ? { 9054 page: opts.page, 9055 order: opts.order, 9056 search: opts.search 9057 } : {}; 9058 9059 // Row + column selector 9060 var columns = this.columns( columnSelector, internalOpts ); 9061 var rows = this.rows( rowSelector, internalOpts ); 9062 var i, ien, j, jen; 9063 9064 var cellsNoOpts = this.iterator( 'table', function ( settings, idx ) { 9065 var a = []; 9066 9067 for ( i=0, ien=rows[idx].length ; i<ien ; i++ ) { 9068 for ( j=0, jen=columns[idx].length ; j<jen ; j++ ) { 9069 a.push( { 9070 row: rows[idx][i], 9071 column: columns[idx][j] 9072 } ); 9073 } 9074 } 9075 9076 return a; 9077 }, 1 ); 9078 9079 // There is currently only one extension which uses a cell selector extension 9080 // It is a _major_ performance drag to run this if it isn't needed, so this is 9081 // an extension specific check at the moment 9082 var cells = opts && opts.selected ? 9083 this.cells( cellsNoOpts, opts ) : 9084 cellsNoOpts; 9085 9086 $.extend( cells.selector, { 9087 cols: columnSelector, 9088 rows: rowSelector, 9089 opts: opts 9090 } ); 9091 9092 return cells; 9093 } ); 9094 9095 9096 _api_registerPlural( 'cells().nodes()', 'cell().node()', function () { 9097 return this.iterator( 'cell', function ( settings, row, column ) { 9098 var data = settings.aoData[ row ]; 9099 9100 return data && data.anCells ? 9101 data.anCells[ column ] : 9102 undefined; 9103 }, 1 ); 9104 } ); 9105 9106 9107 _api_register( 'cells().data()', function () { 9108 return this.iterator( 'cell', function ( settings, row, column ) { 9109 return _fnGetCellData( settings, row, column ); 9110 }, 1 ); 9111 } ); 9112 9113 9114 _api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) { 9115 type = type === 'search' ? '_aFilterData' : '_aSortData'; 9116 9117 return this.iterator( 'cell', function ( settings, row, column ) { 9118 return settings.aoData[ row ][ type ][ column ]; 9119 }, 1 ); 9120 } ); 9121 9122 9123 _api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) { 9124 return this.iterator( 'cell', function ( settings, row, column ) { 9125 return _fnGetCellData( settings, row, column, type ); 9126 }, 1 ); 9127 } ); 9128 9129 9130 _api_registerPlural( 'cells().indexes()', 'cell().index()', function () { 9131 return this.iterator( 'cell', function ( settings, row, column ) { 9132 return { 9133 row: row, 9134 column: column, 9135 columnVisible: _fnColumnIndexToVisible( settings, column ) 9136 }; 9137 }, 1 ); 9138 } ); 9139 9140 9141 _api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) { 9142 return this.iterator( 'cell', function ( settings, row, column ) { 9143 _fnInvalidate( settings, row, src, column ); 9144 } ); 9145 } ); 9146 9147 9148 9149 _api_register( 'cell()', function ( rowSelector, columnSelector, opts ) { 9150 return _selector_first( this.cells( rowSelector, columnSelector, opts ) ); 9151 } ); 9152 9153 9154 _api_register( 'cell().data()', function ( data ) { 9155 var ctx = this.context; 9156 var cell = this[0]; 9157 9158 if ( data === undefined ) { 9159 // Get 9160 return ctx.length && cell.length ? 9161 _fnGetCellData( ctx[0], cell[0].row, cell[0].column ) : 9162 undefined; 9163 } 9164 9165 // Set 9166 _fnSetCellData( ctx[0], cell[0].row, cell[0].column, data ); 9167 _fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column ); 9168 9169 return this; 9170 } ); 9171 9172 9173 9174 /** 9175 * Get current ordering (sorting) that has been applied to the table. 9176 * 9177 * @returns {array} 2D array containing the sorting information for the first 9178 * table in the current context. Each element in the parent array represents 9179 * a column being sorted upon (i.e. multi-sorting with two columns would have 9180 * 2 inner arrays). The inner arrays may have 2 or 3 elements. The first is 9181 * the column index that the sorting condition applies to, the second is the 9182 * direction of the sort (`desc` or `asc`) and, optionally, the third is the 9183 * index of the sorting order from the `column.sorting` initialisation array. 9184 *//** 9185 * Set the ordering for the table. 9186 * 9187 * @param {integer} order Column index to sort upon. 9188 * @param {string} direction Direction of the sort to be applied (`asc` or `desc`) 9189 * @returns {DataTables.Api} this 9190 *//** 9191 * Set the ordering for the table. 9192 * 9193 * @param {array} order 1D array of sorting information to be applied. 9194 * @param {array} [...] Optional additional sorting conditions 9195 * @returns {DataTables.Api} this 9196 *//** 9197 * Set the ordering for the table. 9198 * 9199 * @param {array} order 2D array of sorting information to be applied. 9200 * @returns {DataTables.Api} this 9201 */ 9202 _api_register( 'order()', function ( order, dir ) { 9203 var ctx = this.context; 9204 9205 if ( order === undefined ) { 9206 // get 9207 return ctx.length !== 0 ? 9208 ctx[0].aaSorting : 9209 undefined; 9210 } 9211 9212 // set 9213 if ( typeof order === 'number' ) { 9214 // Simple column / direction passed in 9215 order = [ [ order, dir ] ]; 9216 } 9217 else if ( order.length && ! Array.isArray( order[0] ) ) { 9218 // Arguments passed in (list of 1D arrays) 9219 order = Array.prototype.slice.call( arguments ); 9220 } 9221 // otherwise a 2D array was passed in 9222 9223 return this.iterator( 'table', function ( settings ) { 9224 settings.aaSorting = order.slice(); 9225 } ); 9226 } ); 9227 9228 9229 /** 9230 * Attach a sort listener to an element for a given column 9231 * 9232 * @param {node|jQuery|string} node Identifier for the element(s) to attach the 9233 * listener to. This can take the form of a single DOM node, a jQuery 9234 * collection of nodes or a jQuery selector which will identify the node(s). 9235 * @param {integer} column the column that a click on this node will sort on 9236 * @param {function} [callback] callback function when sort is run 9237 * @returns {DataTables.Api} this 9238 */ 9239 _api_register( 'order.listener()', function ( node, column, callback ) { 9240 return this.iterator( 'table', function ( settings ) { 9241 _fnSortAttachListener( settings, node, column, callback ); 9242 } ); 9243 } ); 9244 9245 9246 _api_register( 'order.fixed()', function ( set ) { 9247 if ( ! set ) { 9248 var ctx = this.context; 9249 var fixed = ctx.length ? 9250 ctx[0].aaSortingFixed : 9251 undefined; 9252 9253 return Array.isArray( fixed ) ? 9254 { pre: fixed } : 9255 fixed; 9256 } 9257 9258 return this.iterator( 'table', function ( settings ) { 9259 settings.aaSortingFixed = $.extend( true, {}, set ); 9260 } ); 9261 } ); 9262 9263 9264 // Order by the selected column(s) 9265 _api_register( [ 9266 'columns().order()', 9267 'column().order()' 9268 ], function ( dir ) { 9269 var that = this; 9270 9271 return this.iterator( 'table', function ( settings, i ) { 9272 var sort = []; 9273 9274 $.each( that[i], function (j, col) { 9275 sort.push( [ col, dir ] ); 9276 } ); 9277 9278 settings.aaSorting = sort; 9279 } ); 9280 } ); 9281 9282 9283 9284 _api_register( 'search()', function ( input, regex, smart, caseInsen ) { 9285 var ctx = this.context; 9286 9287 if ( input === undefined ) { 9288 // get 9289 return ctx.length !== 0 ? 9290 ctx[0].oPreviousSearch.sSearch : 9291 undefined; 9292 } 9293 9294 // set 9295 return this.iterator( 'table', function ( settings ) { 9296 if ( ! settings.oFeatures.bFilter ) { 9297 return; 9298 } 9299 9300 _fnFilterComplete( settings, $.extend( {}, settings.oPreviousSearch, { 9301 "sSearch": input+"", 9302 "bRegex": regex === null ? false : regex, 9303 "bSmart": smart === null ? true : smart, 9304 "bCaseInsensitive": caseInsen === null ? true : caseInsen 9305 } ), 1 ); 9306 } ); 9307 } ); 9308 9309 9310 _api_registerPlural( 9311 'columns().search()', 9312 'column().search()', 9313 function ( input, regex, smart, caseInsen ) { 9314 return this.iterator( 'column', function ( settings, column ) { 9315 var preSearch = settings.aoPreSearchCols; 9316 9317 if ( input === undefined ) { 9318 // get 9319 return preSearch[ column ].sSearch; 9320 } 9321 9322 // set 9323 if ( ! settings.oFeatures.bFilter ) { 9324 return; 9325 } 9326 9327 $.extend( preSearch[ column ], { 9328 "sSearch": input+"", 9329 "bRegex": regex === null ? false : regex, 9330 "bSmart": smart === null ? true : smart, 9331 "bCaseInsensitive": caseInsen === null ? true : caseInsen 9332 } ); 9333 9334 _fnFilterComplete( settings, settings.oPreviousSearch, 1 ); 9335 } ); 9336 } 9337 ); 9338 9339 /* 9340 * State API methods 9341 */ 9342 9343 _api_register( 'state()', function () { 9344 return this.context.length ? 9345 this.context[0].oSavedState : 9346 null; 9347 } ); 9348 9349 9350 _api_register( 'state.clear()', function () { 9351 return this.iterator( 'table', function ( settings ) { 9352 // Save an empty object 9353 settings.fnStateSaveCallback.call( settings.oInstance, settings, {} ); 9354 } ); 9355 } ); 9356 9357 9358 _api_register( 'state.loaded()', function () { 9359 return this.context.length ? 9360 this.context[0].oLoadedState : 9361 null; 9362 } ); 9363 9364 9365 _api_register( 'state.save()', function () { 9366 return this.iterator( 'table', function ( settings ) { 9367 _fnSaveState( settings ); 9368 } ); 9369 } ); 9370 9371 9372 9373 /** 9374 * Set the jQuery or window object to be used by DataTables 9375 * 9376 * @param {*} module Library / container object 9377 * @param {string}
9377type Library or container type `lib` or `win`. 9378 */ 9379 DataTable.use = function (module, type) { 9380 if (type === 'lib' || module.fn) { 9381 $ = module; 9382 } 9383 else if (type == 'win' || module.document) { 9384 window = module; 9385 document = module.document
vendor: 10,052 bytes, lines 9385-9746
9385; 9386 } 9387 } 9388 9389 /** 9390 * CommonJS factory function pass through. This will check if the arguments 9391 * given are a window object or a jQuery object. If so they are set 9392 * accordingly. 9393 * @param {*} root Window 9394 * @param {*} jq jQUery 9395 * @returns {boolean} Indicator 9396 */ 9397 DataTable.factory = function (root, jq) { 9398 var is = false; 9399 9400 // Test if the first parameter is a window object 9401 if (root && root.document) { 9402 window = root; 9403 document = root.document; 9404 } 9405 9406 // Test if the second parameter is a jQuery object 9407 if (jq && jq.fn && jq.fn.jquery) { 9408 $ = jq; 9409 is = true; 9410 } 9411 9412 return is; 9413 } 9414 9415 /** 9416 * Provide a common method for plug-ins to check the version of DataTables being 9417 * used, in order to ensure compatibility. 9418 * 9419 * @param {string} version Version string to check for, in the format "X.Y.Z". 9420 * Note that the formats "X" and "X.Y" are also acceptable. 9421 * @returns {boolean} true if this version of DataTables is greater or equal to 9422 * the required version, or false if this version of DataTales is not 9423 * suitable 9424 * @static 9425 * @dtopt API-Static 9426 * 9427 * @example 9428 * alert( $.fn.dataTable.versionCheck( '1.9.0' ) ); 9429 */ 9430 DataTable.versionCheck = DataTable.fnVersionCheck = function( version ) 9431 { 9432 var aThis = DataTable.version.split('.'); 9433 var aThat = version.split('.'); 9434 var iThis, iThat; 9435 9436 for ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) { 9437 iThis = parseInt( aThis[i], 10 ) || 0; 9438 iThat = parseInt( aThat[i], 10 ) || 0; 9439 9440 // Parts are the same, keep comparing 9441 if (iThis === iThat) { 9442 continue; 9443 } 9444 9445 // Parts are different, return immediately 9446 return iThis > iThat; 9447 } 9448 9449 return true; 9450 }; 9451 9452 9453 /** 9454 * Check if a `<table>` node is a DataTable table already or not. 9455 * 9456 * @param {node|jquery|string} table Table node, jQuery object or jQuery 9457 * selector for the table to test. Note that if more than more than one 9458 * table is passed on, only the first will be checked 9459 * @returns {boolean} true the table given is a DataTable, or false otherwise 9460 * @static 9461 * @dtopt API-Static 9462 * 9463 * @example 9464 * if ( ! $.fn.DataTable.isDataTable( '#example' ) ) { 9465 * $('#example').dataTable(); 9466 * } 9467 */ 9468 DataTable.isDataTable = DataTable.fnIsDataTable = function ( table ) 9469 { 9470 var t = $(table).get(0); 9471 var is = false; 9472 9473 if ( table instanceof DataTable.Api ) { 9474 return true; 9475 } 9476 9477 $.each( DataTable.settings, function (i, o) { 9478 var head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null; 9479 var foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null; 9480 9481 if ( o.nTable === t || head === t || foot === t ) { 9482 is = true; 9483 } 9484 } ); 9485 9486 return is; 9487 }; 9488 9489 9490 /** 9491 * Get all DataTable tables that have been initialised - optionally you can 9492 * select to get only currently visible tables. 9493 * 9494 * @param {boolean} [visible=false] Flag to indicate if you want all (default) 9495 * or visible tables only. 9496 * @returns {array} Array of `table` nodes (not DataTable instances) which are 9497 * DataTables 9498 * @static 9499 * @dtopt API-Static 9500 * 9501 * @example 9502 * $.each( $.fn.dataTable.tables(true), function () { 9503 * $(table).DataTable().columns.adjust(); 9504 * } ); 9505 */ 9506 DataTable.tables = DataTable.fnTables = function ( visible ) 9507 { 9508 var api = false; 9509 9510 if ( $.isPlainObject( visible ) ) { 9511 api = visible.api; 9512 visible = visible.visible; 9513 } 9514 9515 var a = $.map( DataTable.settings, function (o) { 9516 if ( !visible || (visible && $(o.nTable).is(':visible')) ) { 9517 return o.nTable; 9518 } 9519 } ); 9520 9521 return api ? 9522 new _Api( a ) : 9523 a; 9524 }; 9525 9526 9527 /** 9528 * Convert from camel case parameters to Hungarian notation. This is made public 9529 * for the extensions to provide the same ability as DataTables core to accept 9530 * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase 9531 * parameters. 9532 * 9533 * @param {object} src The model object which holds all parameters that can be 9534 * mapped. 9535 * @param {object} user The object to convert from camel case to Hungarian. 9536 * @param {boolean} force When set to `true`, properties which already have a 9537 * Hungarian value in the `user` object will be overwritten. Otherwise they 9538 * won't be. 9539 */ 9540 DataTable.camelToHungarian = _fnCamelToHungarian; 9541 9542 9543 9544 /** 9545 * 9546 */ 9547 _api_register( '$()', function ( selector, opts ) { 9548 var 9549 rows = this.rows( opts ).nodes(), // Get all rows 9550 jqRows = $(rows); 9551 9552 return $( [].concat( 9553 jqRows.filter( selector ).toArray(), 9554 jqRows.find( selector ).toArray() 9555 ) ); 9556 } ); 9557 9558 9559 // jQuery functions to operate on the tables 9560 $.each( [ 'on', 'one', 'off' ], function (i, key) { 9561 _api_register( key+'()', function ( /* event, handler */ ) { 9562 var args = Array.prototype.slice.call(arguments); 9563 9564 // Add the `dt` namespace automatically if it isn't already present 9565 args[0] = $.map( args[0].split( /\s/ ), function ( e ) { 9566 return ! e.match(/\.dt\b/) ? 9567 e+'.dt' : 9568 e; 9569 } ).join( ' ' ); 9570 9571 var inst = $( this.tables().nodes() ); 9572 inst[key].apply( inst, args ); 9573 return this; 9574 } ); 9575 } ); 9576 9577 9578 _api_register( 'clear()', function () { 9579 return this.iterator( 'table', function ( settings ) { 9580 _fnClearTable( settings ); 9581 } ); 9582 } ); 9583 9584 9585 _api_register( 'settings()', function () { 9586 return new _Api( this.context, this.context ); 9587 } ); 9588 9589 9590 _api_register( 'init()', function () { 9591 var ctx = this.context; 9592 return ctx.length ? ctx[0].oInit : null; 9593 } ); 9594 9595 9596 _api_register( 'data()', function () { 9597 return this.iterator( 'table', function ( settings ) { 9598 return _pluck( settings.aoData, '_aData' ); 9599 } ).flatten(); 9600 } ); 9601 9602 9603 _api_register( 'destroy()', function ( remove ) { 9604 remove = remove || false; 9605 9606 return this.iterator( 'table', function ( settings ) { 9607 var classes = settings.oClasses; 9608 var table = settings.nTable; 9609 var tbody = settings.nTBody; 9610 var thead = settings.nTHead; 9611 var tfoot = settings.nTFoot; 9612 var jqTable = $(table); 9613 var jqTbody = $(tbody); 9614 var jqWrapper = $(settings.nTableWrapper); 9615 var rows = $.map( settings.aoData, function (r) { return r.nTr; } ); 9616 var i, ien; 9617 9618 // Flag to note that the table is currently being destroyed - no action 9619 // should be taken 9620 settings.bDestroying = true; 9621 9622 // Fire off the destroy callbacks for plug-ins etc 9623 _fnCallbackFire( settings, "aoDestroyCallback", "destroy", [settings] ); 9624 9625 // If not being removed from the document, make all columns visible 9626 if ( ! remove ) { 9627 new _Api( settings ).columns().visible( true ); 9628 } 9629 9630 // Blitz all `DT` namespaced events (these are internal events, the 9631 // lowercase, `dt` events are user subscribed and they are responsible 9632 // for removing them 9633 jqWrapper.off('.DT').find(':not(tbody *)').off('.DT'); 9634 $(window).off('.DT-'+settings.sInstance); 9635 9636 // When scrolling we had to break the table up - restore it 9637 if ( table != thead.parentNode ) { 9638 jqTable.children('thead').detach(); 9639 jqTable.append( thead ); 9640 } 9641 9642 if ( tfoot && table != tfoot.parentNode ) { 9643 jqTable.children('tfoot').detach(); 9644 jqTable.append( tfoot ); 9645 } 9646 9647 settings.aaSorting = []; 9648 settings.aaSortingFixed = []; 9649 _fnSortingClasses( settings ); 9650 9651 $( rows ).removeClass( settings.asStripeClasses.join(' ') ); 9652 9653 $('th, td', thead).removeClass( classes.sSortable+' '+ 9654 classes.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone 9655 ); 9656 9657 // Add the TR elements back into the table in their original order 9658 jqTbody.children().detach(); 9659 jqTbody.append( rows ); 9660 9661 var orig = settings.nTableWrapper.parentNode; 9662 9663 // Remove the DataTables generated nodes, events and classes 9664 var removedMethod = remove ? 'remove' : 'detach'; 9665 jqTable[ removedMethod ](); 9666 jqWrapper[ removedMethod ](); 9667 9668 // If we need to reattach the table to the document 9669 if ( ! remove && orig ) { 9670 // insertBefore acts like appendChild if !arg[1] 9671 orig.insertBefore( table, settings.nTableReinsertBefore ); 9672 9673 // Restore the width of the original table - was read from the style property, 9674 // so we can restore directly to that 9675 jqTable 9676 .css( 'width', settings.sDestroyWidth ) 9677 .removeClass( classes.sTable ); 9678 9679 // If the were originally stripe classes - then we add them back here. 9680 // Note this is not fool proof (for example if not all rows had stripe 9681 // classes - but it's a good effort without getting carried away 9682 ien = settings.asDestroyStripes.length; 9683 9684 if ( ien ) { 9685 jqTbody.children().each( function (i) { 9686 $(this).addClass( settings.asDestroyStripes[i % ien] ); 9687 } ); 9688 } 9689 } 9690 9691 /* Remove the settings object from the settings array */ 9692 var idx = $.inArray( settings, DataTable.settings ); 9693 if ( idx !== -1 ) { 9694 DataTable.settings.splice( idx, 1 ); 9695 } 9696 } ); 9697 } ); 9698 9699 9700 // Add the `every()` method for rows, columns and cells in a compact form 9701 $.each( [ 'column', 'row', 'cell' ], function ( i, type ) { 9702 _api_register( type+'s().every()', function ( fn ) { 9703 var opts = this.selector.opts; 9704 var api = this; 9705 9706 return this.iterator( type, function ( settings, arg1, arg2, arg3, arg4 ) { 9707 // Rows and columns: 9708 // arg1 - index 9709 // arg2 - table counter 9710 // arg3 - loop counter 9711 // arg4 - undefined 9712 // Cells: 9713 // arg1 - row index 9714 // arg2 - column index 9715 // arg3 - table counter 9716 // arg4 - loop counter 9717 fn.call( 9718 api[ type ]( 9719 arg1, 9720 type==='cell' ? arg2 : opts, 9721 type==='cell' ? opts : undefined 9722 ), 9723 arg1, arg2, arg3, arg4 9724 ); 9725 } ); 9726 } ); 9727 } ); 9728 9729 9730 // i18n method for extensions to be able to use the language object from the 9731 // DataTable 9732 _api_register( 'i18n()', function ( token, def, plural ) { 9733 var ctx = this.context[0]; 9734 var resolved = _fnGetObjectDataFn( token )( ctx.oLanguage ); 9735 9736 if ( resolved === undefined ) { 9737 resolved = def; 9738 } 9739 9740 if ( plural !== undefined && $.isPlainObject( resolved ) ) { 9741 resolved = resolved[ plural ] !== undefined ? 9742 resolved[ plural ] : 9743 resolved._; 9744 } 9745 9746 return
9746resolved.replace( '%d', plural ); // nb: plural might be undefined, 9747 } ); 9748 /** 9749 * Version string for plug-ins to check compatibility. Allowed format is 9750 * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used 9751 * only for non-release builds. See http://semver.org/ for more information. 9752 * @member 9753 * @type string 9754 * @default Version number 9755 */ 9756 DataTable.version = "1.13.4
vendor: 157,934 bytes, lines 9756-14898
9756"; 9757 9758 /** 9759 * Private data store, containing all of the settings objects that are 9760 * created for the tables on a given page. 9761 * 9762 * Note that the `DataTable.settings` object is aliased to 9763 * `jQuery.fn.dataTableExt` through which it may be accessed and 9764 * manipulated, or `jQuery.fn.dataTable.settings`. 9765 * @member 9766 * @type array 9767 * @default [] 9768 * @private 9769 */ 9770 DataTable.settings = []; 9771 9772 /** 9773 * Object models container, for the various models that DataTables has 9774 * available to it. These models define the objects that are used to hold 9775 * the active state and configuration of the table. 9776 * @namespace 9777 */ 9778 DataTable.models = {}; 9779 9780 9781 9782 /** 9783 * Template object for the way in which DataTables holds information about 9784 * search information for the global filter and individual column filters. 9785 * @namespace 9786 */ 9787 DataTable.models.oSearch = { 9788 /** 9789 * Flag to indicate if the filtering should be case insensitive or not 9790 * @type boolean 9791 * @default true 9792 */ 9793 "bCaseInsensitive": true, 9794 9795 /** 9796 * Applied search term 9797 * @type string 9798 * @default <i>Empty string</i> 9799 */ 9800 "sSearch": "", 9801 9802 /** 9803 * Flag to indicate if the search term should be interpreted as a 9804 * regular expression (true) or not (false) and therefore and special 9805 * regex characters escaped. 9806 * @type boolean 9807 * @default false 9808 */ 9809 "bRegex": false, 9810 9811 /** 9812 * Flag to indicate if DataTables is to use its smart filtering or not. 9813 * @type boolean 9814 * @default true 9815 */ 9816 "bSmart": true, 9817 9818 /** 9819 * Flag to indicate if DataTables should only trigger a search when 9820 * the return key is pressed. 9821 * @type boolean 9822 * @default false 9823 */ 9824 "return": false 9825 }; 9826 9827 9828 9829 9830 /** 9831 * Template object for the way in which DataTables holds information about 9832 * each individual row. This is the object format used for the settings 9833 * aoData array. 9834 * @namespace 9835 */ 9836 DataTable.models.oRow = { 9837 /** 9838 * TR element for the row 9839 * @type node 9840 * @default null 9841 */ 9842 "nTr": null, 9843 9844 /** 9845 * Array of TD elements for each row. This is null until the row has been 9846 * created. 9847 * @type array nodes 9848 * @default [] 9849 */ 9850 "anCells": null, 9851 9852 /** 9853 * Data object from the original data source for the row. This is either 9854 * an array if using the traditional form of DataTables, or an object if 9855 * using mData options. The exact type will depend on the passed in 9856 * data from the data source, or will be an array if using DOM a data 9857 * source. 9858 * @type array|object 9859 * @default [] 9860 */ 9861 "_aData": [], 9862 9863 /** 9864 * Sorting data cache - this array is ostensibly the same length as the 9865 * number of columns (although each index is generated only as it is 9866 * needed), and holds the data that is used for sorting each column in the 9867 * row. We do this cache generation at the start of the sort in order that 9868 * the formatting of the sort data need be done only once for each cell 9869 * per sort. This array should not be read from or written to by anything 9870 * other than the master sorting methods. 9871 * @type array 9872 * @default null 9873 * @private 9874 */ 9875 "_aSortData": null, 9876 9877 /** 9878 * Per cell filtering data cache. As per the sort data cache, used to 9879 * increase the performance of the filtering in DataTables 9880 * @type array 9881 * @default null 9882 * @private 9883 */ 9884 "_aFilterData": null, 9885 9886 /** 9887 * Filtering data cache. This is the same as the cell filtering cache, but 9888 * in this case a string rather than an array. This is easily computed with 9889 * a join on `_aFilterData`, but is provided as a cache so the join isn't 9890 * needed on every search (memory traded for performance) 9891 * @type array 9892 * @default null 9893 * @private 9894 */ 9895 "_sFilterRow": null, 9896 9897 /** 9898 * Cache of the class name that DataTables has applied to the row, so we 9899 * can quickly look at this variable rather than needing to do a DOM check 9900 * on className for the nTr property. 9901 * @type string 9902 * @default <i>Empty string</i> 9903 * @private 9904 */ 9905 "_sRowStripe": "", 9906 9907 /** 9908 * Denote if the original data source was from the DOM, or the data source 9909 * object. This is used for invalidating data, so DataTables can 9910 * automatically read data from the original source, unless uninstructed 9911 * otherwise. 9912 * @type string 9913 * @default null 9914 * @private 9915 */ 9916 "src": null, 9917 9918 /** 9919 * Index in the aoData array. This saves an indexOf lookup when we have the 9920 * object, but want to know the index 9921 * @type integer 9922 * @default -1 9923 * @private 9924 */ 9925 "idx": -1 9926 }; 9927 9928 9929 /** 9930 * Template object for the column information object in DataTables. This object 9931 * is held in the settings aoColumns array and contains all the information that 9932 * DataTables needs about each individual column. 9933 * 9934 * Note that this object is related to {@link DataTable.defaults.column} 9935 * but this one is the internal data store for DataTables's cache of columns. 9936 * It should NOT be manipulated outside of DataTables. Any configuration should 9937 * be done through the initialisation options. 9938 * @namespace 9939 */ 9940 DataTable.models.oColumn = { 9941 /** 9942 * Column index. This could be worked out on-the-fly with $.inArray, but it 9943 * is faster to just hold it as a variable 9944 * @type integer 9945 * @default null 9946 */ 9947 "idx": null, 9948 9949 /** 9950 * A list of the columns that sorting should occur on when this column 9951 * is sorted. That this property is an array allows multi-column sorting 9952 * to be defined for a column (for example first name / last name columns 9953 * would benefit from this). The values are integers pointing to the 9954 * columns to be sorted on (typically it will be a single integer pointing 9955 * at itself, but that doesn't need to be the case). 9956 * @type array 9957 */ 9958 "aDataSort": null, 9959 9960 /** 9961 * Define the sorting directions that are applied to the column, in sequence 9962 * as the column is repeatedly sorted upon - i.e. the first value is used 9963 * as the sorting direction when the column if first sorted (clicked on). 9964 * Sort it again (click again) and it will move on to the next index. 9965 * Repeat until loop. 9966 * @type array 9967 */ 9968 "asSorting": null, 9969 9970 /** 9971 * Flag to indicate if the column is searchable, and thus should be included 9972 * in the filtering or not. 9973 * @type boolean 9974 */ 9975 "bSearchable": null, 9976 9977 /** 9978 * Flag to indicate if the column is sortable or not. 9979 * @type boolean 9980 */ 9981 "bSortable": null, 9982 9983 /** 9984 * Flag to indicate if the column is currently visible in the table or not 9985 * @type boolean 9986 */ 9987 "bVisible": null, 9988 9989 /** 9990 * Store for manual type assignment using the `column.type` option. This 9991 * is held in store so we can manipulate the column's `sType` property. 9992 * @type string 9993 * @default null 9994 * @private 9995 */ 9996 "_sManualType": null, 9997 9998 /** 9999 * Flag to indicate if HTML5 data attributes should be used as the data 10000 * source for filtering or sorting. True is either are. 10001 * @type boolean 10002 * @default false 10003 * @private 10004 */ 10005 "_bAttrSrc": false, 10006 10007 /** 10008 * Developer definable function that is called whenever a cell is created (Ajax source, 10009 * etc) or processed for input (DOM source). This can be used as a compliment to mRender 10010 * allowing you to modify the DOM element (add background colour for example) when the 10011 * element is available. 10012 * @type function 10013 * @param {element} nTd The TD node that has been created 10014 * @param {*} sData The Data for the cell 10015 * @param {array|object} oData The data for the whole row 10016 * @param {int} iRow The row index for the aoData data store 10017 * @default null 10018 */ 10019 "fnCreatedCell": null, 10020 10021 /** 10022 * Function to get data from a cell in a column. You should <b>never</b> 10023 * access data directly through _aData internally in DataTables - always use 10024 * the method attached to this property. It allows mData to function as 10025 * required. This function is automatically assigned by the column 10026 * initialisation method 10027 * @type function 10028 * @param {array|object} oData The data array/object for the array 10029 * (i.e. aoData[]._aData) 10030 * @param {string} sSpecific The specific data type you want to get - 10031 * 'display', 'type' 'filter' 'sort' 10032 * @returns {*} The data for the cell from the given row's data 10033 * @default null 10034 */ 10035 "fnGetData": null, 10036 10037 /** 10038 * Function to set data for a cell in the column. You should <b>never</b> 10039 * set the data directly to _aData internally in DataTables - always use 10040 * this method. It allows mData to function as required. This function 10041 * is automatically assigned by the column initialisation method 10042 * @type function 10043 * @param {array|object} oData The data array/object for the array 10044 * (i.e. aoData[]._aData) 10045 * @param {*} sValue Value to set 10046 * @default null 10047 */ 10048 "fnSetData": null, 10049 10050 /** 10051 * Property to read the value for the cells in the column from the data 10052 * source array / object. If null, then the default content is used, if a 10053 * function is given then the return from the function is used. 10054 * @type function|int|string|null 10055 * @default null 10056 */ 10057 "mData": null, 10058 10059 /** 10060 * Partner property to mData which is used (only when defined) to get 10061 * the data - i.e. it is basically the same as mData, but without the 10062 * 'set' option, and also the data fed to it is the result from mData. 10063 * This is the rendering method to match the data method of mData. 10064 * @type function|int|string|null 10065 * @default null 10066 */ 10067 "mRender": null, 10068 10069 /** 10070 * Unique header TH/TD element for this column - this is what the sorting 10071 * listener is attached to (if sorting is enabled.) 10072 * @type node 10073 * @default null 10074 */ 10075 "nTh": null, 10076 10077 /** 10078 * Unique footer TH/TD element for this column (if there is one). Not used 10079 * in DataTables as such, but can be used for plug-ins to reference the 10080 * footer for each column. 10081 * @type node 10082 * @default null 10083 */ 10084 "nTf": null, 10085 10086 /** 10087 * The class to apply to all TD elements in the table's TBODY for the column 10088 * @type string 10089 * @default null 10090 */ 10091 "sClass": null, 10092 10093 /** 10094 * When DataTables calculates the column widths to assign to each column, 10095 * it finds the longest string in each column and then constructs a 10096 * temporary table and reads the widths from that. The problem with this 10097 * is that "mmm" is much wider then "iiii", but the latter is a longer 10098 * string - thus the calculation can go wrong (doing it properly and putting 10099 * it into an DOM object and measuring that is horribly(!) slow). Thus as 10100 * a "work around" we provide this option. It will append its value to the 10101 * text that is found to be the longest string for the column - i.e. padding. 10102 * @type string 10103 */ 10104 "sContentPadding": null, 10105 10106 /** 10107 * Allows a default value to be given for a column's data, and will be used 10108 * whenever a null data source is encountered (this can be because mData 10109 * is set to null, or because the data source itself is null). 10110 * @type string 10111 * @default null 10112 */ 10113 "sDefaultContent": null, 10114 10115 /** 10116 * Name for the column, allowing reference to the column by name as well as 10117 * by index (needs a lookup to work by name). 10118 * @type string 10119 */ 10120 "sName": null, 10121 10122 /** 10123 * Custom sorting data type - defines which of the available plug-ins in 10124 * afnSortData the custom sorting will use - if any is defined. 10125 * @type string 10126 * @default std 10127 */ 10128 "sSortDataType": 'std', 10129 10130 /** 10131 * Class to be applied to the header element when sorting on this column 10132 * @type string 10133 * @default null 10134 */ 10135 "sSortingClass": null, 10136 10137 /** 10138 * Class to be applied to the header element when sorting on this column - 10139 * when jQuery UI theming is used. 10140 * @type string 10141 * @default null 10142 */ 10143 "sSortingClassJUI": null, 10144 10145 /** 10146 * Title of the column - what is seen in the TH element (nTh). 10147 * @type string 10148 */ 10149 "sTitle": null, 10150 10151 /** 10152 * Column sorting and filtering type 10153 * @type string 10154 * @default null 10155 */ 10156 "sType": null, 10157 10158 /** 10159 * Width of the column 10160 * @type string 10161 * @default null 10162 */ 10163 "sWidth": null, 10164 10165 /** 10166 * Width of the column when it was first "encountered" 10167 * @type string 10168 * @default null 10169 */ 10170 "sWidthOrig": null 10171 }; 10172 10173 10174 /* 10175 * Developer note: The properties of the object below are given in Hungarian 10176 * notation, that was used as the interface for DataTables prior to v1.10, however 10177 * from v1.10 onwards the primary interface is camel case. In order to avoid 10178 * breaking backwards compatibility utterly with this change, the Hungarian 10179 * version is still, internally the primary interface, but is is not documented 10180 * - hence the @name tags in each doc comment. This allows a Javascript function 10181 * to create a map from Hungarian notation to camel case (going the other direction 10182 * would require each property to be listed, which would add around 3K to the size 10183 * of DataTables, while this method is about a 0.5K hit). 10184 * 10185 * Ultimately this does pave the way for Hungarian notation to be dropped 10186 * completely, but that is a massive amount of work and will break current 10187 * installs (therefore is on-hold until v2). 10188 */ 10189 10190 /** 10191 * Initialisation options that can be given to DataTables at initialisation 10192 * time. 10193 * @namespace 10194 */ 10195 DataTable.defaults = { 10196 /** 10197 * An array of data to use for the table, passed in at initialisation which 10198 * will be used in preference to any data which is already in the DOM. This is 10199 * particularly useful for constructing tables purely in Javascript, for 10200 * example with a custom Ajax call. 10201 * @type array 10202 * @default null 10203 * 10204 * @dtopt Option 10205 * @name DataTable.defaults.data 10206 * 10207 * @example 10208 * // Using a 2D array data source 10209 * $(document).ready( function () { 10210 * $('#example').dataTable( { 10211 * "data": [ 10212 * ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'], 10213 * ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'], 10214 * ], 10215 * "columns": [ 10216 * { "title": "Engine" }, 10217 * { "title": "Browser" }, 10218 * { "title": "Platform" }, 10219 * { "title": "Version" }, 10220 * { "title": "Grade" } 10221 * ] 10222 * } ); 10223 * } ); 10224 * 10225 * @example 10226 * // Using an array of objects as a data source (`data`) 10227 * $(document).ready( function () { 10228 * $('#example').dataTable( { 10229 * "data": [ 10230 * { 10231 * "engine": "Trident", 10232 * "browser": "Internet Explorer 4.0", 10233 * "platform": "Win 95+", 10234 * "version": 4, 10235 * "grade": "X" 10236 * }, 10237 * { 10238 * "engine": "Trident", 10239 * "browser": "Internet Explorer 5.0", 10240 * "platform": "Win 95+", 10241 * "version": 5, 10242 * "grade": "C" 10243 * } 10244 * ], 10245 * "columns": [ 10246 * { "title": "Engine", "data": "engine" }, 10247 * { "title": "Browser", "data": "browser" }, 10248 * { "title": "Platform", "data": "platform" }, 10249 * { "title": "Version", "data": "version" }, 10250 * { "title": "Grade", "data": "grade" } 10251 * ] 10252 * } ); 10253 * } ); 10254 */ 10255 "aaData": null, 10256 10257 10258 /** 10259 * If ordering is enabled, then DataTables will perform a first pass sort on 10260 * initialisation. You can define which column(s) the sort is performed 10261 * upon, and the sorting direction, with this variable. The `sorting` array 10262 * should contain an array for each column to be sorted initially containing 10263 * the column's index and a direction string ('asc' or 'desc'). 10264 * @type array 10265 * @default [[0,'asc']] 10266 * 10267 * @dtopt Option 10268 * @name DataTable.defaults.order 10269 * 10270 * @example 10271 * // Sort by 3rd column first, and then 4th column 10272 * $(document).ready( function() { 10273 * $('#example').dataTable( { 10274 * "order": [[2,'asc'], [3,'desc']] 10275 * } ); 10276 * } ); 10277 * 10278 * // No initial sorting 10279 * $(document).ready( function() { 10280 * $('#example').dataTable( { 10281 * "order": [] 10282 * } ); 10283 * } ); 10284 */ 10285 "aaSorting": [[0,'asc']], 10286 10287 10288 /** 10289 * This parameter is basically identical to the `sorting` parameter, but 10290 * cannot be overridden by user interaction with the table. What this means 10291 * is that you could have a column (visible or hidden) which the sorting 10292 * will always be forced on first - any sorting after that (from the user) 10293 * will then be performed as required. This can be useful for grouping rows 10294 * together. 10295 * @type array 10296 * @default null 10297 * 10298 * @dtopt Option 10299 * @name DataTable.defaults.orderFixed 10300 * 10301 * @example 10302 * $(document).ready( function() { 10303 * $('#example').dataTable( { 10304 * "orderFixed": [[0,'asc']] 10305 * } ); 10306 * } ) 10307 */ 10308 "aaSortingFixed": [], 10309 10310 10311 /** 10312 * DataTables can be instructed to load data to display in the table from a 10313 * Ajax source. This option defines how that Ajax call is made and where to. 10314 * 10315 * The `ajax` property has three different modes of operation, depending on 10316 * how it is defined. These are: 10317 * 10318 * * `string` - Set the URL from where the data should be loaded from. 10319 * * `object` - Define properties for `jQuery.ajax`. 10320 * * `function` - Custom data get function 10321 * 10322 * `string` 10323 * -------- 10324 * 10325 * As a string, the `ajax` property simply defines the URL from which 10326 * DataTables will load data. 10327 * 10328 * `object` 10329 * -------- 10330 * 10331 * As an object, the parameters in the object are passed to 10332 * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control 10333 * of the Ajax request. DataTables has a number of default parameters which 10334 * you can override using this option. Please refer to the jQuery 10335 * documentation for a full description of the options available, although 10336 * the following parameters provide additional options in DataTables or 10337 * require special consideration: 10338 * 10339 * * `data` - As with jQuery, `data` can be provided as an object, but it 10340 * can also be used as a function to manipulate the data DataTables sends 10341 * to the server. The function takes a single parameter, an object of 10342 * parameters with the values that DataTables has readied for sending. An 10343 * object may be returned which will be merged into the DataTables 10344 * defaults, or you can add the items to the object that was passed in and 10345 * not return anything from the function. This supersedes `fnServerParams` 10346 * from DataTables 1.9-. 10347 * 10348 * * `dataSrc` - By default DataTables will look for the property `data` (or 10349 * `aaData` for compatibility with DataTables 1.9-) when obtaining data 10350 * from an Ajax source or for server-side processing - this parameter 10351 * allows that property to be changed. You can use Javascript dotted 10352 * object notation to get a data source for multiple levels of nesting, or 10353 * it my be used as a function. As a function it takes a single parameter, 10354 * the JSON returned from the server, which can be manipulated as 10355 * required, with the returned value being that used by DataTables as the 10356 * data source for the table. This supersedes `sAjaxDataProp` from 10357 * DataTables 1.9-. 10358 * 10359 * * `success` - Should not be overridden it is used internally in 10360 * DataTables. To manipulate / transform the data returned by the server 10361 * use `ajax.dataSrc`, or use `ajax` as a function (see below). 10362 * 10363 * `function` 10364 * ---------- 10365 * 10366 * As a function, making the Ajax call is left up to yourself allowing 10367 * complete control of the Ajax request. Indeed, if desired, a method other 10368 * than Ajax could be used to obtain the required data, such as Web storage 10369 * or an AIR database. 10370 * 10371 * The function is given four parameters and no return is required. The 10372 * parameters are: 10373 * 10374 * 1. _object_ - Data to send to the server 10375 * 2. _function_ - Callback function that must be executed when the required 10376 * data has been obtained. That data should be passed into the callback 10377 * as the only parameter 10378 * 3. _object_ - DataTables settings object for the table 10379 * 10380 * Note that this supersedes `fnServerData` from DataTables 1.9-. 10381 * 10382 * @type string|object|function 10383 * @default null 10384 * 10385 * @dtopt Option 10386 * @name DataTable.defaults.ajax 10387 * @since 1.10.0 10388 * 10389 * @example 10390 * // Get JSON data from a file via Ajax. 10391 * // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default). 10392 * $('#example').dataTable( { 10393 * "ajax": "data.json" 10394 * } ); 10395 * 10396 * @example 10397 * // Get JSON data from a file via Ajax, using `dataSrc` to change 10398 * // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`) 10399 * $('#example').dataTable( { 10400 * "ajax": { 10401 * "url": "data.json", 10402 * "dataSrc": "tableData" 10403 * } 10404 * } ); 10405 * 10406 * @example 10407 * // Get JSON data from a file via Ajax, using `dataSrc` to read data 10408 * // from a plain array rather than an array in an object 10409 * $('#example').dataTable( { 10410 * "ajax": { 10411 * "url": "data.json", 10412 * "dataSrc": "" 10413 * } 10414 * } ); 10415 * 10416 * @example 10417 * // Manipulate the data returned from the server - add a link to data 10418 * // (note this can, should, be done using `render` for the column - this 10419 * // is just a simple example of how the data can be manipulated). 10420 * $('#example').dataTable( { 10421 * "ajax": { 10422 * "url": "data.json", 10423 * "dataSrc": function ( json ) { 10424 * for ( var i=0, ien=json.length ; i<ien ; i++ ) { 10425 * json[i][0] = '<a href="/message/'+json[i][0]+'>View message</a>'; 10426 * } 10427 * return json; 10428 * } 10429 * } 10430 * } ); 10431 * 10432 * @example 10433 * // Add data to the request 10434 * $('#example').dataTable( { 10435 * "ajax": { 10436 * "url": "data.json", 10437 * "data": function ( d ) { 10438 * return { 10439 * "extra_search": $('#extra').val() 10440 * }; 10441 * } 10442 * } 10443 * } ); 10444 * 10445 * @example 10446 * // Send request as POST 10447 * $('#example').dataTable( { 10448 * "ajax": { 10449 * "url": "data.json", 10450 * "type": "POST" 10451 * } 10452 * } ); 10453 * 10454 * @example 10455 * // Get the data from localStorage (could interface with a form for 10456 * // adding, editing and removing rows). 10457 * $('#example').dataTable( { 10458 * "ajax": function (data, callback, settings) { 10459 * callback( 10460 * JSON.parse( localStorage.getItem('dataTablesData') ) 10461 * ); 10462 * } 10463 * } ); 10464 */ 10465 "ajax": null, 10466 10467 10468 /** 10469 * This parameter allows you to readily specify the entries in the length drop 10470 * down menu that DataTables shows when pagination is enabled. It can be 10471 * either a 1D array of options which will be used for both the displayed 10472 * option and the value, or a 2D array which will use the array in the first 10473 * position as the value, and the array in the second position as the 10474 * displayed options (useful for language strings such as 'All'). 10475 * 10476 * Note that the `pageLength` property will be automatically set to the 10477 * first value given in this array, unless `pageLength` is also provided. 10478 * @type array 10479 * @default [ 10, 25, 50, 100 ] 10480 * 10481 * @dtopt Option 10482 * @name DataTable.defaults.lengthMenu 10483 * 10484 * @example 10485 * $(document).ready( function() { 10486 * $('#example').dataTable( { 10487 * "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]] 10488 * } ); 10489 * } ); 10490 */ 10491 "aLengthMenu": [ 10, 25, 50, 100 ], 10492 10493 10494 /** 10495 * The `columns` option in the initialisation parameter allows you to define 10496 * details about the way individual columns behave. For a full list of 10497 * column options that can be set, please see 10498 * {@link DataTable.defaults.column}. Note that if you use `columns` to 10499 * define your columns, you must have an entry in the array for every single 10500 * column that you have in your table (these can be null if you don't which 10501 * to specify any options). 10502 * @member 10503 * 10504 * @name DataTable.defaults.column 10505 */ 10506 "aoColumns": null, 10507 10508 /** 10509 * Very similar to `columns`, `columnDefs` allows you to target a specific 10510 * column, multiple columns, or all columns, using the `targets` property of 10511 * each object in the array. This allows great flexibility when creating 10512 * tables, as the `columnDefs` arrays can be of any length, targeting the 10513 * columns you specifically want. `columnDefs` may use any of the column 10514 * options available: {@link DataTable.defaults.column}, but it _must_ 10515 * have `targets` defined in each object in the array. Values in the `targets` 10516 * array may be: 10517 * <ul> 10518 * <li>a string - class name will be matched on the TH for the column</li> 10519 * <li>0 or a positive integer - column index counting from the left</li> 10520 * <li>a negative integer - column index counting from the right</li> 10521 * <li>the string "_all" - all columns (i.e. assign a default)</li> 10522 * </ul> 10523 * @member 10524 * 10525 * @name DataTable.defaults.columnDefs 10526 */ 10527 "aoColumnDefs": null, 10528 10529 10530 /** 10531 * Basically the same as `search`, this parameter defines the individual column 10532 * filtering state at initialisation time. The array must be of the same size 10533 * as the number of columns, and each element be an object with the parameters 10534 * `search` and `escapeRegex` (the latter is optional). 'null' is also 10535 * accepted and the default will be used. 10536 * @type array 10537 * @default [] 10538 * 10539 * @dtopt Option 10540 * @name DataTable.defaults.searchCols 10541 * 10542 * @example 10543 * $(document).ready( function() { 10544 * $('#example').dataTable( { 10545 * "searchCols": [ 10546 * null, 10547 * { "search": "My filter" }, 10548 * null, 10549 * { "search": "^[0-9]", "escapeRegex": false } 10550 * ] 10551 * } ); 10552 * } ) 10553 */ 10554 "aoSearchCols": [], 10555 10556 10557 /** 10558 * An array of CSS classes that should be applied to displayed rows. This 10559 * array may be of any length, and DataTables will apply each class 10560 * sequentially, looping when required. 10561 * @type array 10562 * @default null <i>Will take the values determined by the `oClasses.stripe*` 10563 * options</i> 10564 * 10565 * @dtopt Option 10566 * @name DataTable.defaults.stripeClasses 10567 * 10568 * @example 10569 * $(document).ready( function() { 10570 * $('#example').dataTable( { 10571 * "stripeClasses": [ 'strip1', 'strip2', 'strip3' ] 10572 * } ); 10573 * } ) 10574 */ 10575 "asStripeClasses": null, 10576 10577 10578 /** 10579 * Enable or disable automatic column width calculation. This can be disabled 10580 * as an optimisation (it takes some time to calculate the widths) if the 10581 * tables widths are passed in using `columns`. 10582 * @type boolean 10583 * @default true 10584 * 10585 * @dtopt Features 10586 * @name DataTable.defaults.autoWidth 10587 * 10588 * @example 10589 * $(document).ready( function () { 10590 * $('#example').dataTable( { 10591 * "autoWidth": false 10592 * } ); 10593 * } ); 10594 */ 10595 "bAutoWidth": true, 10596 10597 10598 /** 10599 * Deferred rendering can provide DataTables with a huge speed boost when you 10600 * are using an Ajax or JS data source for the table. This option, when set to 10601 * true, will cause DataTables to defer the creation of the table elements for 10602 * each row until they are needed for a draw - saving a significant amount of 10603 * time. 10604 * @type boolean 10605 * @default false 10606 * 10607 * @dtopt Features 10608 * @name DataTable.defaults.deferRender 10609 * 10610 * @example 10611 * $(document).ready( function() { 10612 * $('#example').dataTable( { 10613 * "ajax": "sources/arrays.txt", 10614 * "deferRender": true 10615 * } ); 10616 * } ); 10617 */ 10618 "bDeferRender": false, 10619 10620 10621 /** 10622 * Replace a DataTable which matches the given selector and replace it with 10623 * one which has the properties of the new initialisation object passed. If no 10624 * table matches the selector, then the new DataTable will be constructed as 10625 * per normal. 10626 * @type boolean 10627 * @default false 10628 * 10629 * @dtopt Options 10630 * @name DataTable.defaults.destroy 10631 * 10632 * @example 10633 * $(document).ready( function() { 10634 * $('#example').dataTable( { 10635 * "srollY": "200px", 10636 * "paginate": false 10637 * } ); 10638 * 10639 * // Some time later.... 10640 * $('#example').dataTable( { 10641 * "filter": false, 10642 * "destroy": true 10643 * } ); 10644 * } ); 10645 */ 10646 "bDestroy": false, 10647 10648 10649 /** 10650 * Enable or disable filtering of data. Filtering in DataTables is "smart" in 10651 * that it allows the end user to input multiple words (space separated) and 10652 * will match a row containing those words, even if not in the order that was 10653 * specified (this allow matching across multiple columns). Note that if you 10654 * wish to use filtering in DataTables this must remain 'true' - to remove the 10655 * default filtering input box and retain filtering abilities, please use 10656 * {@link DataTable.defaults.dom}. 10657 * @type boolean 10658 * @default true 10659 * 10660 * @dtopt Features 10661 * @name DataTable.defaults.searching 10662 * 10663 * @example 10664 * $(document).ready( function () { 10665 * $('#example').dataTable( { 10666 * "searching": false 10667 * } ); 10668 * } ); 10669 */ 10670 "bFilter": true, 10671 10672 10673 /** 10674 * Enable or disable the table information display. This shows information 10675 * about the data that is currently visible on the page, including information 10676 * about filtered data if that action is being performed. 10677 * @type boolean 10678 * @default true 10679 * 10680 * @dtopt Features 10681 * @name DataTable.defaults.info 10682 * 10683 * @example 10684 * $(document).ready( function () { 10685 * $('#example').dataTable( { 10686 * "info": false 10687 * } ); 10688 * } ); 10689 */ 10690 "bInfo": true, 10691 10692 10693 /** 10694 * Allows the end user to select the size of a formatted page from a select 10695 * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`). 10696 * @type boolean 10697 * @default true 10698 * 10699 * @dtopt Features 10700 * @name DataTable.defaults.lengthChange 10701 * 10702 * @example 10703 * $(document).ready( function () { 10704 * $('#example').dataTable( { 10705 * "lengthChange": false 10706 * } ); 10707 * } ); 10708 */ 10709 "bLengthChange": true, 10710 10711 10712 /** 10713 * Enable or disable pagination. 10714 * @type boolean 10715 * @default true 10716 * 10717 * @dtopt Features 10718 * @name DataTable.defaults.paging 10719 * 10720 * @example 10721 * $(document).ready( function () { 10722 * $('#example').dataTable( { 10723 * "paging": false 10724 * } ); 10725 * } ); 10726 */ 10727 "bPaginate": true, 10728 10729 10730 /** 10731 * Enable or disable the display of a 'processing' indicator when the table is 10732 * being processed (e.g. a sort). This is particularly useful for tables with 10733 * large amounts of data where it can take a noticeable amount of time to sort 10734 * the entries. 10735 * @type boolean 10736 * @default false 10737 * 10738 * @dtopt Features 10739 * @name DataTable.defaults.processing 10740 * 10741 * @example 10742 * $(document).ready( function () { 10743 * $('#example').dataTable( { 10744 * "processing": true 10745 * } ); 10746 * } ); 10747 */ 10748 "bProcessing": false, 10749 10750 10751 /** 10752 * Retrieve the DataTables object for the given selector. Note that if the 10753 * table has already been initialised, this parameter will cause DataTables 10754 * to simply return the object that has already been set up - it will not take 10755 * account of any changes you might have made to the initialisation object 10756 * passed to DataTables (setting this parameter to true is an acknowledgement 10757 * that you understand this). `destroy` can be used to reinitialise a table if 10758 * you need. 10759 * @type boolean 10760 * @default false 10761 * 10762 * @dtopt Options 10763 * @name DataTable.defaults.retrieve 10764 * 10765 * @example 10766 * $(document).ready( function() { 10767 * initTable(); 10768 * tableActions(); 10769 * } ); 10770 * 10771 * function initTable () 10772 * { 10773 * return $('#example').dataTable( { 10774 * "scrollY": "200px", 10775 * "paginate": false, 10776 * "retrieve": true 10777 * } ); 10778 * } 10779 * 10780 * function tableActions () 10781 * { 10782 * var table = initTable(); 10783 * // perform API operations with oTable 10784 * } 10785 */ 10786 "bRetrieve": false, 10787 10788 10789 /** 10790 * When vertical (y) scrolling is enabled, DataTables will force the height of 10791 * the table's viewport to the given height at all times (useful for layout). 10792 * However, this can look odd when filtering data down to a small data set, 10793 * and the footer is left "floating" further down. This parameter (when 10794 * enabled) will cause DataTables to collapse the table's viewport down when 10795 * the result set will fit within the given Y height. 10796 * @type boolean 10797 * @default false 10798 * 10799 * @dtopt Options 10800 * @name DataTable.defaults.scrollCollapse 10801 * 10802 * @example 10803 * $(document).ready( function() { 10804 * $('#example').dataTable( { 10805 * "scrollY": "200", 10806 * "scrollCollapse": true 10807 * } ); 10808 * } ); 10809 */ 10810 "bScrollCollapse": false, 10811 10812 10813 /** 10814 * Configure DataTables to use server-side processing. Note that the 10815 * `ajax` parameter must also be given in order to give DataTables a 10816 * source to obtain the required data for each draw. 10817 * @type boolean 10818 * @default false 10819 * 10820 * @dtopt Features 10821 * @dtopt Server-side 10822 * @name DataTable.defaults.serverSide 10823 * 10824 * @example 10825 * $(document).ready( function () { 10826 * $('#example').dataTable( { 10827 * "serverSide": true, 10828 * "ajax": "xhr.php" 10829 * } ); 10830 * } ); 10831 */ 10832 "bServerSide": false, 10833 10834 10835 /** 10836 * Enable or disable sorting of columns. Sorting of individual columns can be 10837 * disabled by the `sortable` option for each column. 10838 * @type boolean 10839 * @default true 10840 * 10841 * @dtopt Features 10842 * @name DataTable.defaults.ordering 10843 * 10844 * @example 10845 * $(document).ready( function () { 10846 * $('#example').dataTable( { 10847 * "ordering": false 10848 * } ); 10849 * } ); 10850 */ 10851 "bSort": true, 10852 10853 10854 /** 10855 * Enable or display DataTables' ability to sort multiple columns at the 10856 * same time (activated by shift-click by the user). 10857 * @type boolean 10858 * @default true 10859 * 10860 * @dtopt Options 10861 * @name DataTable.defaults.orderMulti 10862 * 10863 * @example 10864 * // Disable multiple column sorting ability 10865 * $(document).ready( function () { 10866 * $('#example').dataTable( { 10867 * "orderMulti": false 10868 * } ); 10869 * } ); 10870 */ 10871 "bSortMulti": true, 10872 10873 10874 /** 10875 * Allows control over whether DataTables should use the top (true) unique 10876 * cell that is found for a single column, or the bottom (false - default). 10877 * This is useful when using complex headers. 10878 * @type boolean 10879 * @default false 10880 * 10881 * @dtopt Options 10882 * @name DataTable.defaults.orderCellsTop 10883 * 10884 * @example 10885 * $(document).ready( function() { 10886 * $('#example').dataTable( { 10887 * "orderCellsTop": true 10888 * } ); 10889 * } ); 10890 */ 10891 "bSortCellsTop": false, 10892 10893 10894 /** 10895 * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and 10896 * `sorting\_3` to the columns which are currently being sorted on. This is 10897 * presented as a feature switch as it can increase processing time (while 10898 * classes are removed and added) so for large data sets you might want to 10899 * turn this off. 10900 * @type boolean 10901 * @default true 10902 * 10903 * @dtopt Features 10904 * @name DataTable.defaults.orderClasses 10905 * 10906 * @example 10907 * $(document).ready( function () { 10908 * $('#example').dataTable( { 10909 * "orderClasses": false 10910 * } ); 10911 * } ); 10912 */ 10913 "bSortClasses": true, 10914 10915 10916 /** 10917 * Enable or disable state saving. When enabled HTML5 `localStorage` will be 10918 * used to save table display information such as pagination information, 10919 * display length, filtering and sorting. As such when the end user reloads 10920 * the page the display display will match what thy had previously set up. 10921 * 10922 * Due to the use of `localStorage` the default state saving is not supported 10923 * in IE6 or 7. If state saving is required in those browsers, use 10924 * `stateSaveCallback` to provide a storage solution such as cookies. 10925 * @type boolean 10926 * @default false 10927 * 10928 * @dtopt Features 10929 * @name DataTable.defaults.stateSave 10930 * 10931 * @example 10932 * $(document).ready( function () { 10933 * $('#example').dataTable( { 10934 * "stateSave": true 10935 * } ); 10936 * } ); 10937 */ 10938 "bStateSave": false, 10939 10940 10941 /** 10942 * This function is called when a TR element is created (and all TD child 10943 * elements have been inserted), or registered if using a DOM source, allowing 10944 * manipulation of the TR element (adding classes etc). 10945 * @type function 10946 * @param {node} row "TR" element for the current row 10947 * @param {array} data Raw data array for this row 10948 * @param {int} dataIndex The index of this row in the internal aoData array 10949 * 10950 * @dtopt Callbacks 10951 * @name DataTable.defaults.createdRow 10952 * 10953 * @example 10954 * $(document).ready( function() { 10955 * $('#example').dataTable( { 10956 * "createdRow": function( row, data, dataIndex ) { 10957 * // Bold the grade for all 'A' grade browsers 10958 * if ( data[4] == "A" ) 10959 * { 10960 * $('td:eq(4)', row).html( '<b>A</b>' ); 10961 * } 10962 * } 10963 * } ); 10964 * } ); 10965 */ 10966 "fnCreatedRow": null, 10967 10968 10969 /** 10970 * This function is called on every 'draw' event, and allows you to 10971 * dynamically modify any aspect you want about the created DOM. 10972 * @type function 10973 * @param {object} settings DataTables settings object 10974 * 10975 * @dtopt Callbacks 10976 * @name DataTable.defaults.drawCallback 10977 * 10978 * @example 10979 * $(document).ready( function() { 10980 * $('#example').dataTable( { 10981 * "drawCallback": function( settings ) { 10982 * alert( 'DataTables has redrawn the table' ); 10983 * } 10984 * } ); 10985 * } ); 10986 */ 10987 "fnDrawCallback": null, 10988 10989 10990 /** 10991 * Identical to fnHeaderCallback() but for the table footer this function 10992 * allows you to modify the table footer on every 'draw' event. 10993 * @type function 10994 * @param {node} foot "TR" element for the footer 10995 * @param {array} data Full table data (as derived from the original HTML) 10996 * @param {int} start Index for the current display starting point in the 10997 * display array 10998 * @param {int} end Index for the current display ending point in the 10999 * display array 11000 * @param {array int} display Index array to translate the visual position 11001 * to the full data array 11002 * 11003 * @dtopt Callbacks 11004 * @name DataTable.defaults.footerCallback 11005 * 11006 * @example 11007 * $(document).ready( function() { 11008 * $('#example').dataTable( { 11009 * "footerCallback": function( tfoot, data, start, end, display ) { 11010 * tfoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+start; 11011 * } 11012 * } ); 11013 * } ) 11014 */ 11015 "fnFooterCallback": null, 11016 11017 11018 /** 11019 * When rendering large numbers in the information element for the table 11020 * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers 11021 * to have a comma separator for the 'thousands' units (e.g. 1 million is 11022 * rendered as "1,000,000") to help readability for the end user. This 11023 * function will override the default method DataTables uses. 11024 * @type function 11025 * @member 11026 * @param {int} toFormat number to be formatted 11027 * @returns {string} formatted string for DataTables to show the number 11028 * 11029 * @dtopt Callbacks 11030 * @name DataTable.defaults.formatNumber 11031 * 11032 * @example 11033 * // Format a number using a single quote for the separator (note that 11034 * // this can also be done with the language.thousands option) 11035 * $(document).ready( function() { 11036 * $('#example').dataTable( { 11037 * "formatNumber": function ( toFormat ) { 11038 * return toFormat.toString().replace( 11039 * /\B(?=(\d{3})+(?!\d))/g, "'" 11040 * ); 11041 * }; 11042 * } ); 11043 * } ); 11044 */ 11045 "fnFormatNumber": function ( toFormat ) { 11046 return toFormat.toString().replace( 11047 /\B(?=(\d{3})+(?!\d))/g, 11048 this.oLanguage.sThousands 11049 ); 11050 }, 11051 11052 11053 /** 11054 * This function is called on every 'draw' event, and allows you to 11055 * dynamically modify the header row. This can be used to calculate and 11056 * display useful information about the table. 11057 * @type function 11058 * @param {node} head "TR" element for the header 11059 * @param {array} data Full table data (as derived from the original HTML) 11060 * @param {int} start Index for the current display starting point in the 11061 * display array 11062 * @param {int} end Index for the current display ending point in the 11063 * display array 11064 * @param {array int} display Index array to translate the visual position 11065 * to the full data array 11066 * 11067 * @dtopt Callbacks 11068 * @name DataTable.defaults.headerCallback 11069 * 11070 * @example 11071 * $(document).ready( function() { 11072 * $('#example').dataTable( { 11073 * "fheaderCallback": function( head, data, start, end, display ) { 11074 * head.getElementsByTagName('th')[0].innerHTML = "Displaying "+(end-start)+" records"; 11075 * } 11076 * } ); 11077 * } ) 11078 */ 11079 "fnHeaderCallback": null, 11080 11081 11082 /** 11083 * The information element can be used to convey information about the current 11084 * state of the table. Although the internationalisation options presented by 11085 * DataTables are quite capable of dealing with most customisations, there may 11086 * be times where you wish to customise the string further. This callback 11087 * allows you to do exactly that. 11088 * @type function 11089 * @param {object} oSettings DataTables settings object 11090 * @param {int} start Starting position in data for the draw 11091 * @param {int} end End position in data for the draw 11092 * @param {int} max Total number of rows in the table (regardless of 11093 * filtering) 11094 * @param {int} total Total number of rows in the data set, after filtering 11095 * @param {string} pre The string that DataTables has formatted using it's 11096 * own rules 11097 * @returns {string} The string to be displayed in the information element. 11098 * 11099 * @dtopt Callbacks 11100 * @name DataTable.defaults.infoCallback 11101 * 11102 * @example 11103 * $('#example').dataTable( { 11104 * "infoCallback": function( settings, start, end, max, total, pre ) { 11105 * return start +" to "+ end; 11106 * } 11107 * } ); 11108 */ 11109 "fnInfoCallback": null, 11110 11111 11112 /** 11113 * Called when the table has been initialised. Normally DataTables will 11114 * initialise sequentially and there will be no need for this function, 11115 * however, this does not hold true when using external language information 11116 * since that is obtained using an async XHR call. 11117 * @type function 11118 * @param {object} settings DataTables settings object 11119 * @param {object} json The JSON object request from the server - only 11120 * present if client-side Ajax sourced data is used 11121 * 11122 * @dtopt Callbacks 11123 * @name DataTable.defaults.initComplete 11124 * 11125 * @example 11126 * $(document).ready( function() { 11127 * $('#example').dataTable( { 11128 * "initComplete": function(settings, json) { 11129 * alert( 'DataTables has finished its initialisation.' ); 11130 * } 11131 * } ); 11132 * } ) 11133 */ 11134 "fnInitComplete": null, 11135 11136 11137 /** 11138 * Called at the very start of each table draw and can be used to cancel the 11139 * draw by returning false, any other return (including undefined) results in 11140 * the full draw occurring). 11141 * @type function 11142 * @param {object} settings DataTables settings object 11143 * @returns {boolean} False will cancel the draw, anything else (including no 11144 * return) will allow it to complete. 11145 * 11146 * @dtopt Callbacks 11147 * @name DataTable.defaults.preDrawCallback 11148 * 11149 * @example 11150 * $(document).ready( function() { 11151 * $('#example').dataTable( { 11152 * "preDrawCallback": function( settings ) { 11153 * if ( $('#test').val() == 1 ) { 11154 * return false; 11155 * } 11156 * } 11157 * } ); 11158 * } ); 11159 */ 11160 "fnPreDrawCallback": null, 11161 11162 11163 /** 11164 * This function allows you to 'post process' each row after it have been 11165 * generated for each table draw, but before it is rendered on screen. This 11166 * function might be used for setting the row class name etc. 11167 * @type function 11168 * @param {node} row "TR" element for the current row 11169 * @param {array} data Raw data array for this row 11170 * @param {int} displayIndex The display index for the current table draw 11171 * @param {int} displayIndexFull The index of the data in the full list of 11172 * rows (after filtering) 11173 * 11174 * @dtopt Callbacks 11175 * @name DataTable.defaults.rowCallback 11176 * 11177 * @example 11178 * $(document).ready( function() { 11179 * $('#example').dataTable( { 11180 * "rowCallback": function( row, data, displayIndex, displayIndexFull ) { 11181 * // Bold the grade for all 'A' grade browsers 11182 * if ( data[4] == "A" ) { 11183 * $('td:eq(4)', row).html( '<b>A</b>' ); 11184 * } 11185 * } 11186 * } ); 11187 * } ); 11188 */ 11189 "fnRowCallback": null, 11190 11191 11192 /** 11193 * __Deprecated__ The functionality provided by this parameter has now been 11194 * superseded by that provided through `ajax`, which should be used instead. 11195 * 11196 * This parameter allows you to override the default function which obtains 11197 * the data from the server so something more suitable for your application. 11198 * For example you could use POST data, or pull information from a Gears or 11199 * AIR database. 11200 * @type function 11201 * @member 11202 * @param {string} source HTTP source to obtain the data from (`ajax`) 11203 * @param {array} data A key/value pair object containing the data to send 11204 * to the server 11205 * @param {function} callback to be called on completion of the data get 11206 * process that will draw the data on the page. 11207 * @param {object} settings DataTables settings object 11208 * 11209 * @dtopt Callbacks 11210 * @dtopt Server-side 11211 * @name DataTable.defaults.serverData 11212 * 11213 * @deprecated 1.10. Please use `ajax` for this functionality now. 11214 */ 11215 "fnServerData": null, 11216 11217 11218 /** 11219 * __Deprecated__ The functionality provided by this parameter has now been 11220 * superseded by that provided through `ajax`, which should be used instead. 11221 * 11222 * It is often useful to send extra data to the server when making an Ajax 11223 * request - for example custom filtering information, and this callback 11224 * function makes it trivial to send extra information to the server. The 11225 * passed in parameter is the data set that has been constructed by 11226 * DataTables, and you can add to this or modify it as you require. 11227 * @type function 11228 * @param {array} data Data array (array of objects which are name/value 11229 * pairs) that has been constructed by DataTables and will be sent to the 11230 * server. In the case of Ajax sourced data with server-side processing 11231 * this will be an empty array, for server-side processing there will be a 11232 * significant number of parameters! 11233 * @returns {undefined} Ensure that you modify the data array passed in, 11234 * as this is passed by reference. 11235 * 11236 * @dtopt Callbacks 11237 * @dtopt Server-side 11238 * @name DataTable.defaults.serverParams 11239 * 11240 * @deprecated 1.10. Please use `ajax` for this functionality now. 11241 */ 11242 "fnServerParams": null, 11243 11244 11245 /** 11246 * Load the table state. With this function you can define from where, and how, the 11247 * state of a table is loaded. By default DataTables will load from `localStorage` 11248 * but you might wish to use a server-side database or cookies. 11249 * @type function 11250 * @member 11251 * @param {object} settings DataTables settings object 11252 * @param {object} callback Callback that can be executed when done. It 11253 * should be passed the loaded state object. 11254 * @return {object} The DataTables state object to be loaded 11255 * 11256 * @dtopt Callbacks 11257 * @name DataTable.defaults.stateLoadCallback 11258 * 11259 * @example 11260 * $(document).ready( function() { 11261 * $('#example').dataTable( { 11262 * "stateSave": true, 11263 * "stateLoadCallback": function (settings, callback) { 11264 * $.ajax( { 11265 * "url": "/state_load", 11266 * "dataType": "json", 11267 * "success": function (json) { 11268 * callback( json ); 11269 * } 11270 * } ); 11271 * } 11272 * } ); 11273 * } ); 11274 */ 11275 "fnStateLoadCallback": function ( settings ) { 11276 try { 11277 return JSON.parse( 11278 (settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem( 11279 'DataTables_'+settings.sInstance+'_'+location.pathname 11280 ) 11281 ); 11282 } catch (e) { 11283 return {}; 11284 } 11285 }, 11286 11287 11288 /** 11289 * Callback which allows modification of the saved state prior to loading that state. 11290 * This callback is called when the table is loading state from the stored data, but 11291 * prior to the settings object being modified by the saved state. Note that for 11292 * plug-in authors, you should use the `stateLoadParams` event to load parameters for 11293 * a plug-in. 11294 * @type function 11295 * @param {object} settings DataTables settings object 11296 * @param {object} data The state object that is to be loaded 11297 * 11298 * @dtopt Callbacks 11299 * @name DataTable.defaults.stateLoadParams 11300 * 11301 * @example 11302 * // Remove a saved filter, so filtering is never loaded 11303 * $(document).ready( function() { 11304 * $('#example').dataTable( { 11305 * "stateSave": true, 11306 * "stateLoadParams": function (settings, data) { 11307 * data.oSearch.sSearch = ""; 11308 * } 11309 * } ); 11310 * } ); 11311 * 11312 * @example 11313 * // Disallow state loading by returning false 11314 * $(document).ready( function() { 11315 * $('#example').dataTable( { 11316 * "stateSave": true, 11317 * "stateLoadParams": function (settings, data) { 11318 * return false; 11319 * } 11320 * } ); 11321 * } ); 11322 */ 11323 "fnStateLoadParams": null, 11324 11325 11326 /** 11327 * Callback that is called when the state has been loaded from the state saving method 11328 * and the DataTables settings object has been modified as a result of the loaded state. 11329 * @type function 11330 * @param {object} settings DataTables settings object 11331 * @param {object} data The state object that was loaded 11332 * 11333 * @dtopt Callbacks 11334 * @name DataTable.defaults.stateLoaded 11335 * 11336 * @example 11337 * // Show an alert with the filtering value that was saved 11338 * $(document).ready( function() { 11339 * $('#example').dataTable( { 11340 * "stateSave": true, 11341 * "stateLoaded": function (settings, data) { 11342 * alert( 'Saved filter was: '+data.oSearch.sSearch ); 11343 * } 11344 * } ); 11345 * } ); 11346 */ 11347 "fnStateLoaded": null, 11348 11349 11350 /** 11351 * Save the table state. This function allows you to define where and how the state 11352 * information for the table is stored By default DataTables will use `localStorage` 11353 * but you might wish to use a server-side database or cookies. 11354 * @type function 11355 * @member 11356 * @param {object} settings DataTables settings object 11357 * @param {object} data The state object to be saved 11358 * 11359 * @dtopt Callbacks 11360 * @name DataTable.defaults.stateSaveCallback 11361 * 11362 * @example 11363 * $(document).ready( function() { 11364 * $('#example').dataTable( { 11365 * "stateSave": true, 11366 * "stateSaveCallback": function (settings, data) { 11367 * // Send an Ajax request to the server with the state object 11368 * $.ajax( { 11369 * "url": "/state_save", 11370 * "data": data, 11371 * "dataType": "json", 11372 * "method": "POST" 11373 * "success": function () {} 11374 * } ); 11375 * } 11376 * } ); 11377 * } ); 11378 */ 11379 "fnStateSaveCallback": function ( settings, data ) { 11380 try { 11381 (settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem( 11382 'DataTables_'+settings.sInstance+'_'+location.pathname, 11383 JSON.stringify( data ) 11384 ); 11385 } catch (e) {} 11386 }, 11387 11388 11389 /** 11390 * Callback which allows modification of the state to be saved. Called when the table 11391 * has changed state a new state save is required. This method allows modification of 11392 * the state saving object prior to actually doing the save, including addition or 11393 * other state properties or modification. Note that for plug-in authors, you should 11394 * use the `stateSaveParams` event to save parameters for a plug-in. 11395 * @type function 11396 * @param {object} settings DataTables settings object 11397 * @param {object} data The state object to be saved 11398 * 11399 * @dtopt Callbacks 11400 * @name DataTable.defaults.stateSaveParams 11401 * 11402 * @example 11403 * // Remove a saved filter, so filtering is never saved 11404 * $(document).ready( function() { 11405 * $('#example').dataTable( { 11406 * "stateSave": true, 11407 * "stateSaveParams": function (settings, data) { 11408 * data.oSearch.sSearch = ""; 11409 * } 11410 * } ); 11411 * } ); 11412 */ 11413 "fnStateSaveParams": null, 11414 11415 11416 /** 11417 * Duration for which the saved state information is considered valid. After this period 11418 * has elapsed the state will be returned to the default. 11419 * Value is given in seconds. 11420 * @type int 11421 * @default 7200 <i>(2 hours)</i> 11422 * 11423 * @dtopt Options 11424 * @name DataTable.defaults.stateDuration 11425 * 11426 * @example 11427 * $(document).ready( function() { 11428 * $('#example').dataTable( { 11429 * "stateDuration": 60*60*24; // 1 day 11430 * } ); 11431 * } ) 11432 */ 11433 "iStateDuration": 7200, 11434 11435 11436 /** 11437 * When enabled DataTables will not make a request to the server for the first 11438 * page draw - rather it will use the data already on the page (no sorting etc 11439 * will be applied to it), thus saving on an XHR at load time. `deferLoading` 11440 * is used to indicate that deferred loading is required, but it is also used 11441 * to tell DataTables how many records there are in the full table (allowing 11442 * the information element and pagination to be displayed correctly). In the case 11443 * where a filtering is applied to the table on initial load, this can be 11444 * indicated by giving the parameter as an array, where the first element is 11445 * the number of records available after filtering and the second element is the 11446 * number of records without filtering (allowing the table information element 11447 * to be shown correctly). 11448 * @type int | array 11449 * @default null 11450 * 11451 * @dtopt Options 11452 * @name DataTable.defaults.deferLoading 11453 * 11454 * @example 11455 * // 57 records available in the table, no filtering applied 11456 * $(document).ready( function() { 11457 * $('#example').dataTable( { 11458 * "serverSide": true, 11459 * "ajax": "scripts/server_processing.php", 11460 * "deferLoading": 57 11461 * } ); 11462 * } ); 11463 * 11464 * @example 11465 * // 57 records after filtering, 100 without filtering (an initial filter applied) 11466 * $(document).ready( function() { 11467 * $('#example').dataTable( { 11468 * "serverSide": true, 11469 * "ajax": "scripts/server_processing.php", 11470 * "deferLoading": [ 57, 100 ], 11471 * "search": { 11472 * "search": "my_filter" 11473 * } 11474 * } ); 11475 * } ); 11476 */ 11477 "iDeferLoading": null, 11478 11479 11480 /** 11481 * Number of rows to display on a single page when using pagination. If 11482 * feature enabled (`lengthChange`) then the end user will be able to override 11483 * this to a custom setting using a pop-up menu. 11484 * @type int 11485 * @default 10 11486 * 11487 * @dtopt Options 11488 * @name DataTable.defaults.pageLength 11489 * 11490 * @example 11491 * $(document).ready( function() { 11492 * $('#example').dataTable( { 11493 * "pageLength": 50 11494 * } ); 11495 * } ) 11496 */ 11497 "iDisplayLength": 10, 11498 11499 11500 /** 11501 * Define the starting point for data display when using DataTables with 11502 * pagination. Note that this parameter is the number of records, rather than 11503 * the page number, so if you have 10 records per page and want to start on 11504 * the third page, it should be "20". 11505 * @type int 11506 * @default 0 11507 * 11508 * @dtopt Options 11509 * @name DataTable.defaults.displayStart 11510 * 11511 * @example 11512 * $(document).ready( function() { 11513 * $('#example').dataTable( { 11514 * "displayStart": 20 11515 * } ); 11516 * } ) 11517 */ 11518 "iDisplayStart": 0, 11519 11520 11521 /** 11522 * By default DataTables allows keyboard navigation of the table (sorting, paging, 11523 * and filtering) by adding a `tabindex` attribute to the required elements. This 11524 * allows you to tab through the controls and press the enter key to activate them. 11525 * The tabindex is default 0, meaning that the tab follows the flow of the document. 11526 * You can overrule this using this parameter if you wish. Use a value of -1 to 11527 * disable built-in keyboard navigation. 11528 * @type int 11529 * @default 0 11530 * 11531 * @dtopt Options 11532 * @name DataTable.defaults.tabIndex 11533 * 11534 * @example 11535 * $(document).ready( function() { 11536 * $('#example').dataTable( { 11537 * "tabIndex": 1 11538 * } ); 11539 * } ); 11540 */ 11541 "iTabIndex": 0, 11542 11543 11544 /** 11545 * Classes that DataTables assigns to the various components and features 11546 * that it adds to the HTML table. This allows classes to be configured 11547 * during initialisation in addition to through the static 11548 * {@link DataTable.ext.oStdClasses} object). 11549 * @namespace 11550 * @name DataTable.defaults.classes 11551 */ 11552 "oClasses": {}, 11553 11554 11555 /** 11556 * All strings that DataTables uses in the user interface that it creates 11557 * are defined in this object, allowing you to modified them individually or 11558 * completely replace them all as required. 11559 * @namespace 11560 * @name DataTable.defaults.language 11561 */ 11562 "oLanguage": { 11563 /** 11564 * Strings that are used for WAI-ARIA labels and controls only (these are not 11565 * actually visible on the page, but will be read by screenreaders, and thus 11566 * must be internationalised as well). 11567 * @namespace 11568 * @name DataTable.defaults.language.aria 11569 */ 11570 "oAria": { 11571 /** 11572 * ARIA label that is added to the table headers when the column may be 11573 * sorted ascending by activing the column (click or return when focused). 11574 * Note that the column header is prefixed to this string. 11575 * @type string 11576 * @default : activate to sort column ascending 11577 * 11578 * @dtopt Language 11579 * @name DataTable.defaults.language.aria.sortAscending 11580 * 11581 * @example 11582 * $(document).ready( function() { 11583 * $('#example').dataTable( { 11584 * "language": { 11585 * "aria": { 11586 * "sortAscending": " - click/return to sort ascending" 11587 * } 11588 * } 11589 * } ); 11590 * } ); 11591 */ 11592 "sSortAscending": ": activate to sort column ascending", 11593 11594 /** 11595 * ARIA label that is added to the table headers when the column may be 11596 * sorted descending by activing the column (click or return when focused). 11597 * Note that the column header is prefixed to this string. 11598 * @type string 11599 * @default : activate to sort column ascending 11600 * 11601 * @dtopt Language 11602 * @name DataTable.defaults.language.aria.sortDescending 11603 * 11604 * @example 11605 * $(document).ready( function() { 11606 * $('#example').dataTable( { 11607 * "language": { 11608 * "aria": { 11609 * "sortDescending": " - click/return to sort descending" 11610 * } 11611 * } 11612 * } ); 11613 * } ); 11614 */ 11615 "sSortDescending": ": activate to sort column descending" 11616 }, 11617 11618 /** 11619 * Pagination string used by DataTables for the built-in pagination 11620 * control types. 11621 * @namespace 11622 * @name DataTable.defaults.language.paginate 11623 */ 11624 "oPaginate": { 11625 /** 11626 * Text to use when using the 'full_numbers' type of pagination for the 11627 * button to take the user to the first page. 11628 * @type string 11629 * @default First 11630 * 11631 * @dtopt Language 11632 * @name DataTable.defaults.language.paginate.first 11633 * 11634 * @example 11635 * $(document).ready( function() { 11636 * $('#example').dataTable( { 11637 * "language": { 11638 * "paginate": { 11639 * "first": "First page" 11640 * } 11641 * } 11642 * } ); 11643 * } ); 11644 */ 11645 "sFirst": "First", 11646 11647 11648 /** 11649 * Text to use when using the 'full_numbers' type of pagination for the 11650 * button to take the user to the last page. 11651 * @type string 11652 * @default Last 11653 * 11654 * @dtopt Language 11655 * @name DataTable.defaults.language.paginate.last 11656 * 11657 * @example 11658 * $(document).ready( function() { 11659 * $('#example').dataTable( { 11660 * "language": { 11661 * "paginate": { 11662 * "last": "Last page" 11663 * } 11664 * } 11665 * } ); 11666 * } ); 11667 */ 11668 "sLast": "Last", 11669 11670 11671 /** 11672 * Text to use for the 'next' pagination button (to take the user to the 11673 * next page). 11674 * @type string 11675 * @default Next 11676 * 11677 * @dtopt Language 11678 * @name DataTable.defaults.language.paginate.next 11679 * 11680 * @example 11681 * $(document).ready( function() { 11682 * $('#example').dataTable( { 11683 * "language": { 11684 * "paginate": { 11685 * "next": "Next page" 11686 * } 11687 * } 11688 * } ); 11689 * } ); 11690 */ 11691 "sNext": "Next", 11692 11693 11694 /** 11695 * Text to use for the 'previous' pagination button (to take the user to 11696 * the previous page). 11697 * @type string 11698 * @default Previous 11699 * 11700 * @dtopt Language 11701 * @name DataTable.defaults.language.paginate.previous 11702 * 11703 * @example 11704 * $(document).ready( function() { 11705 * $('#example').dataTable( { 11706 * "language": { 11707 * "paginate": { 11708 * "previous": "Previous page" 11709 * } 11710 * } 11711 * } ); 11712 * } ); 11713 */ 11714 "sPrevious": "Previous" 11715 }, 11716 11717 /** 11718 * This string is shown in preference to `zeroRecords` when the table is 11719 * empty of data (regardless of filtering). Note that this is an optional 11720 * parameter - if it is not given, the value of `zeroRecords` will be used 11721 * instead (either the default or given value). 11722 * @type string 11723 * @default No data available in table 11724 * 11725 * @dtopt Language 11726 * @name DataTable.defaults.language.emptyTable 11727 * 11728 * @example 11729 * $(document).ready( function() { 11730 * $('#example').dataTable( { 11731 * "language": { 11732 * "emptyTable": "No data available in table" 11733 * } 11734 * } ); 11735 * } ); 11736 */ 11737 "sEmptyTable": "No data available in table", 11738 11739 11740 /** 11741 * This string gives information to the end user about the information 11742 * that is current on display on the page. The following tokens can be 11743 * used in the string and will be dynamically replaced as the table 11744 * display updates. This tokens can be placed anywhere in the string, or 11745 * removed as needed by the language requires: 11746 * 11747 * * `\_START\_` - Display index of the first record on the current page 11748 * * `\_END\_` - Display index of the last record on the current page 11749 * * `\_TOTAL\_` - Number of records in the table after filtering 11750 * * `\_MAX\_` - Number of records in the table without filtering 11751 * * `\_PAGE\_` - Current page number 11752 * * `\_PAGES\_` - Total number of pages of data in the table 11753 * 11754 * @type string 11755 * @default Showing _START_ to _END_ of _TOTAL_ entries 11756 * 11757 * @dtopt Language 11758 * @name DataTable.defaults.language.info 11759 * 11760 * @example 11761 * $(document).ready( function() { 11762 * $('#example').dataTable( { 11763 * "language": { 11764 * "info": "Showing page _PAGE_ of _PAGES_" 11765 * } 11766 * } ); 11767 * } ); 11768 */ 11769 "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries", 11770 11771 11772 /** 11773 * Display information string for when the table is empty. Typically the 11774 * format of this string should match `info`. 11775 * @type string 11776 * @default Showing 0 to 0 of 0 entries 11777 * 11778 * @dtopt Language 11779 * @name DataTable.defaults.language.infoEmpty 11780 * 11781 * @example 11782 * $(document).ready( function() { 11783 * $('#example').dataTable( { 11784 * "language": { 11785 * "infoEmpty": "No entries to show" 11786 * } 11787 * } ); 11788 * } ); 11789 */ 11790 "sInfoEmpty": "Showing 0 to 0 of 0 entries", 11791 11792 11793 /** 11794 * When a user filters the information in a table, this string is appended 11795 * to the information (`info`) to give an idea of how strong the filtering 11796 * is. The variable _MAX_ is dynamically updated. 11797 * @type string 11798 * @default (filtered from _MAX_ total entries) 11799 * 11800 * @dtopt Language 11801 * @name DataTable.defaults.language.infoFiltered 11802 * 11803 * @example 11804 * $(document).ready( function() { 11805 * $('#example').dataTable( { 11806 * "language": { 11807 * "infoFiltered": " - filtering from _MAX_ records" 11808 * } 11809 * } ); 11810 * } ); 11811 */ 11812 "sInfoFiltered": "(filtered from _MAX_ total entries)", 11813 11814 11815 /** 11816 * If can be useful to append extra information to the info string at times, 11817 * and this variable does exactly that. This information will be appended to 11818 * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are 11819 * being used) at all times. 11820 * @type string 11821 * @default <i>Empty string</i> 11822 * 11823 * @dtopt Language 11824 * @name DataTable.defaults.language.infoPostFix 11825 * 11826 * @example 11827 * $(document).ready( function() { 11828 * $('#example').dataTable( { 11829 * "language": { 11830 * "infoPostFix": "All records shown are derived from real information." 11831 * } 11832 * } ); 11833 * } ); 11834 */ 11835 "sInfoPostFix": "", 11836 11837 11838 /** 11839 * This decimal place operator is a little different from the other 11840 * language options since DataTables doesn't output floating point 11841 * numbers, so it won't ever use this for display of a number. Rather, 11842 * what this parameter does is modify the sort methods of the table so 11843 * that numbers which are in a format which has a character other than 11844 * a period (`.`) as a decimal place will be sorted numerically. 11845 * 11846 * Note that numbers with different decimal places cannot be shown in 11847 * the same table and still be sortable, the table must be consistent. 11848 * However, multiple different tables on the page can use different 11849 * decimal place characters. 11850 * @type string 11851 * @default 11852 * 11853 * @dtopt Language 11854 * @name DataTable.defaults.language.decimal 11855 * 11856 * @example 11857 * $(document).ready( function() { 11858 * $('#example').dataTable( { 11859 * "language": { 11860 * "decimal": "," 11861 * "thousands": "." 11862 * } 11863 * } ); 11864 * } ); 11865 */ 11866 "sDecimal": "", 11867 11868 11869 /** 11870 * DataTables has a build in number formatter (`formatNumber`) which is 11871 * used to format large numbers that are used in the table information. 11872 * By default a comma is used, but this can be trivially changed to any 11873 * character you wish with this parameter. 11874 * @type string 11875 * @default , 11876 * 11877 * @dtopt Language 11878 * @name DataTable.defaults.language.thousands 11879 * 11880 * @example 11881 * $(document).ready( function() { 11882 * $('#example').dataTable( { 11883 * "language": { 11884 * "thousands": "'" 11885 * } 11886 * } ); 11887 * } ); 11888 */ 11889 "sThousands": ",", 11890 11891 11892 /** 11893 * Detail the action that will be taken when the drop down menu for the 11894 * pagination length option is changed. The '_MENU_' variable is replaced 11895 * with a default select list of 10, 25, 50 and 100, and can be replaced 11896 * with a custom select box if required. 11897 * @type string 11898 * @default Show _MENU_ entries 11899 * 11900 * @dtopt Language 11901 * @name DataTable.defaults.language.lengthMenu 11902 * 11903 * @example 11904 * // Language change only 11905 * $(document).ready( function() { 11906 * $('#example').dataTable( { 11907 * "language": { 11908 * "lengthMenu": "Display _MENU_ records" 11909 * } 11910 * } ); 11911 * } ); 11912 * 11913 * @example 11914 * // Language and options change 11915 * $(document).ready( function() { 11916 * $('#example').dataTable( { 11917 * "language": { 11918 * "lengthMenu": 'Display <select>'+ 11919 * '<option value="10">10</option>'+ 11920 * '<option value="20">20</option>'+ 11921 * '<option value="30">30</option>'+ 11922 * '<option value="40">40</option>'+ 11923 * '<option value="50">50</option>'+ 11924 * '<option value="-1">All</option>'+ 11925 * '</select> records' 11926 * } 11927 * } ); 11928 * } ); 11929 */ 11930 "sLengthMenu": "Show _MENU_ entries", 11931 11932 11933 /** 11934 * When using Ajax sourced data and during the first draw when DataTables is 11935 * gathering the data, this message is shown in an empty row in the table to 11936 * indicate to the end user the the data is being loaded. Note that this 11937 * parameter is not used when loading data by server-side processing, just 11938 * Ajax sourced data with client-side processing. 11939 * @type string 11940 * @default Loading... 11941 * 11942 * @dtopt Language 11943 * @name DataTable.defaults.language.loadingRecords 11944 * 11945 * @example 11946 * $(document).ready( function() { 11947 * $('#example').dataTable( { 11948 * "language": { 11949 * "loadingRecords": "Please wait - loading..." 11950 * } 11951 * } ); 11952 * } ); 11953 */ 11954 "sLoadingRecords": "Loading...", 11955 11956 11957 /** 11958 * Text which is displayed when the table is processing a user action 11959 * (usually a sort command or similar). 11960 * @type string 11961 * 11962 * @dtopt Language 11963 * @name DataTable.defaults.language.processing 11964 * 11965 * @example 11966 * $(document).ready( function() { 11967 * $('#example').dataTable( { 11968 * "language": { 11969 * "processing": "DataTables is currently busy" 11970 * } 11971 * } ); 11972 * } ); 11973 */ 11974 "sProcessing": "", 11975 11976 11977 /** 11978 * Details the actions that will be taken when the user types into the 11979 * filtering input text box. The variable "_INPUT_", if used in the string, 11980 * is replaced with the HTML text box for the filtering input allowing 11981 * control over where it appears in the string. If "_INPUT_" is not given 11982 * then the input box is appended to the string automatically. 11983 * @type string 11984 * @default Search: 11985 * 11986 * @dtopt Language 11987 * @name DataTable.defaults.language.search 11988 * 11989 * @example 11990 * // Input text box will be appended at the end automatically 11991 * $(document).ready( function() { 11992 * $('#example').dataTable( { 11993 * "language": { 11994 * "search": "Filter records:" 11995 * } 11996 * } ); 11997 * } ); 11998 * 11999 * @example 12000 * // Specify where the filter should appear 12001 * $(document).ready( function() { 12002 * $('#example').dataTable( { 12003 * "language": { 12004 * "search": "Apply filter _INPUT_ to table" 12005 * } 12006 * } ); 12007 * } ); 12008 */ 12009 "sSearch": "Search:", 12010 12011 12012 /** 12013 * Assign a `placeholder` attribute to the search `input` element 12014 * @type string 12015 * @default 12016 * 12017 * @dtopt Language 12018 * @name DataTable.defaults.language.searchPlaceholder 12019 */ 12020 "sSearchPlaceholder": "", 12021 12022 12023 /** 12024 * All of the language information can be stored in a file on the 12025 * server-side, which DataTables will look up if this parameter is passed. 12026 * It must store the URL of the language file, which is in a JSON format, 12027 * and the object has the same properties as the oLanguage object in the 12028 * initialiser object (i.e. the above parameters). Please refer to one of 12029 * the example language files to see how this works in action. 12030 * @type string 12031 * @default <i>Empty string - i.e. disabled</i> 12032 * 12033 * @dtopt Language 12034 * @name DataTable.defaults.language.url 12035 * 12036 * @example 12037 * $(document).ready( function() { 12038 * $('#example').dataTable( { 12039 * "language": { 12040 * "url": "http://www.sprymedia.co.uk/dataTables/lang.txt" 12041 * } 12042 * } ); 12043 * } ); 12044 */ 12045 "sUrl": "", 12046 12047 12048 /** 12049 * Text shown inside the table records when the is no information to be 12050 * displayed after filtering. `emptyTable` is shown when there is simply no 12051 * information in the table at all (regardless of filtering). 12052 * @type string 12053 * @default No matching records found 12054 * 12055 * @dtopt Language 12056 * @name DataTable.defaults.language.zeroRecords 12057 * 12058 * @example 12059 * $(document).ready( function() { 12060 * $('#example').dataTable( { 12061 * "language": { 12062 * "zeroRecords": "No records to display" 12063 * } 12064 * } ); 12065 * } ); 12066 */ 12067 "sZeroRecords": "No matching records found" 12068 }, 12069 12070 12071 /** 12072 * This parameter allows you to have define the global filtering state at 12073 * initialisation time. As an object the `search` parameter must be 12074 * defined, but all other parameters are optional. When `regex` is true, 12075 * the search string will be treated as a regular expression, when false 12076 * (default) it will be treated as a straight string. When `smart` 12077 * DataTables will use it's smart filtering methods (to word match at 12078 * any point in the data), when false this will not be done. 12079 * @namespace 12080 * @extends DataTable.models.oSearch 12081 * 12082 * @dtopt Options 12083 * @name DataTable.defaults.search 12084 * 12085 * @example 12086 * $(document).ready( function() { 12087 * $('#example').dataTable( { 12088 * "search": {"search": "Initial search"} 12089 * } ); 12090 * } ) 12091 */ 12092 "oSearch": $.extend( {}, DataTable.models.oSearch ), 12093 12094 12095 /** 12096 * __Deprecated__ The functionality provided by this parameter has now been 12097 * superseded by that provided through `ajax`, which should be used instead. 12098 * 12099 * By default DataTables will look for the property `data` (or `aaData` for 12100 * compatibility with DataTables 1.9-) when obtaining data from an Ajax 12101 * source or for server-side processing - this parameter allows that 12102 * property to be changed. You can use Javascript dotted object notation to 12103 * get a data source for multiple levels of nesting. 12104 * @type string 12105 * @default data 12106 * 12107 * @dtopt Options 12108 * @dtopt Server-side 12109 * @name DataTable.defaults.ajaxDataProp 12110 * 12111 * @deprecated 1.10. Please use `ajax` for this functionality now. 12112 */ 12113 "sAjaxDataProp": "data", 12114 12115 12116 /** 12117 * __Deprecated__ The functionality provided by this parameter has now been 12118 * superseded by that provided through `ajax`, which should be used instead. 12119 * 12120 * You can instruct DataTables to load data from an external 12121 * source using this parameter (use aData if you want to pass data in you 12122 * already have). Simply provide a url a JSON object can be obtained from. 12123 * @type string 12124 * @default null 12125 * 12126 * @dtopt Options 12127 * @dtopt Server-side 12128 * @name DataTable.defaults.ajaxSource 12129 * 12130 * @deprecated 1.10. Please use `ajax` for this functionality now. 12131 */ 12132 "sAjaxSource": null, 12133 12134 12135 /** 12136 * This initialisation variable allows you to specify exactly where in the 12137 * DOM you want DataTables to inject the various controls it adds to the page 12138 * (for example you might want the pagination controls at the top of the 12139 * table). DIV elements (with or without a custom class) can also be added to 12140 * aid styling. The follow syntax is used: 12141 * <ul> 12142 * <li>The following options are allowed: 12143 * <ul> 12144 * <li>'l' - Length changing</li> 12145 * <li>'f' - Filtering input</li> 12146 * <li>'t' - The table!</li> 12147 * <li>'i' - Information</li> 12148 * <li>'p' - Pagination</li> 12149 * <li>'r' - pRocessing</li> 12150 * </ul> 12151 * </li> 12152 * <li>The following constants are allowed: 12153 * <ul> 12154 * <li>'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li> 12155 * <li>'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li> 12156 * </ul> 12157 * </li> 12158 * <li>The following syntax is expected: 12159 * <ul> 12160 * <li>'<' and '>' - div elements</li> 12161 * <li>'<"class" and '>' - div with a class</li> 12162 * <li>'<"#id" and '>' - div with an ID</li> 12163 * </ul> 12164 * </li> 12165 * <li>Examples: 12166 * <ul> 12167 * <li>'<"wrapper"flipt>'</li> 12168 * <li>'<lf<t>ip>'</li> 12169 * </ul> 12170 * </li> 12171 * </ul> 12172 * @type string 12173 * @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b> 12174 * <"H"lfr>t<"F"ip> <i>(when `jQueryUI` is true)</i> 12175 * 12176 * @dtopt Options 12177 * @name DataTable.defaults.dom 12178 * 12179 * @example 12180 * $(document).ready( function() { 12181 * $('#example').dataTable( { 12182 * "dom": '<"top"i>rt<"bottom"flp><"clear">' 12183 * } ); 12184 * } ); 12185 */ 12186 "sDom": "lfrtip", 12187 12188 12189 /** 12190 * Search delay option. This will throttle full table searches that use the 12191 * DataTables provided search input element (it does not effect calls to 12192 * `dt-api search()`, providing a delay before the search is made. 12193 * @type integer 12194 * @default 0 12195 * 12196 * @dtopt Options 12197 * @name DataTable.defaults.searchDelay 12198 * 12199 * @example 12200 * $(document).ready( function() { 12201 * $('#example').dataTable( { 12202 * "searchDelay": 200 12203 * } ); 12204 * } ) 12205 */ 12206 "searchDelay": null, 12207 12208 12209 /** 12210 * DataTables features six different built-in options for the buttons to 12211 * display for pagination control: 12212 * 12213 * * `numbers` - Page number buttons only 12214 * * `simple` - 'Previous' and 'Next' buttons only 12215 * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers 12216 * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons 12217 * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus page numbers 12218 * * `first_last_numbers` - 'First' and 'Last' buttons, plus page numbers 12219 * 12220 * Further methods can be added using {@link DataTable.ext.oPagination}. 12221 * @type string 12222 * @default simple_numbers 12223 * 12224 * @dtopt Options 12225 * @name DataTable.defaults.pagingType 12226 * 12227 * @example 12228 * $(document).ready( function() { 12229 * $('#example').dataTable( { 12230 * "pagingType": "full_numbers" 12231 * } ); 12232 * } ) 12233 */ 12234 "sPaginationType": "simple_numbers", 12235 12236 12237 /** 12238 * Enable horizontal scrolling. When a table is too wide to fit into a 12239 * certain layout, or you have a large number of columns in the table, you 12240 * can enable x-scrolling to show the table in a viewport, which can be 12241 * scrolled. This property can be `true` which will allow the table to 12242 * scroll horizontally when needed, or any CSS unit, or a number (in which 12243 * case it will be treated as a pixel measurement). Setting as simply `true` 12244 * is recommended. 12245 * @type boolean|string 12246 * @default <i>blank string - i.e. disabled</i> 12247 * 12248 * @dtopt Features 12249 * @name DataTable.defaults.scrollX 12250 * 12251 * @example 12252 * $(document).ready( function() { 12253 * $('#example').dataTable( { 12254 * "scrollX": true, 12255 * "scrollCollapse": true 12256 * } ); 12257 * } ); 12258 */ 12259 "sScrollX": "", 12260 12261 12262 /** 12263 * This property can be used to force a DataTable to use more width than it 12264 * might otherwise do when x-scrolling is enabled. For example if you have a 12265 * table which requires to be well spaced, this parameter is useful for 12266 * "over-sizing" the table, and thus forcing scrolling. This property can by 12267 * any CSS unit, or a number (in which case it will be treated as a pixel 12268 * measurement). 12269 * @type string 12270 * @default <i>blank string - i.e. disabled</i> 12271 * 12272 * @dtopt Options 12273 * @name DataTable.defaults.scrollXInner 12274 * 12275 * @example 12276 * $(document).ready( function() { 12277 * $('#example').dataTable( { 12278 * "scrollX": "100%", 12279 * "scrollXInner": "110%" 12280 * } ); 12281 * } ); 12282 */ 12283 "sScrollXInner": "", 12284 12285 12286 /** 12287 * Enable vertical scrolling. Vertical scrolling will constrain the DataTable 12288 * to the given height, and enable scrolling for any data which overflows the 12289 * current viewport. This can be used as an alternative to paging to display 12290 * a lot of data in a small area (although paging and scrolling can both be 12291 * enabled at the same time). This property can be any CSS unit, or a number 12292 * (in which case it will be treated as a pixel measurement). 12293 * @type string 12294 * @default <i>blank string - i.e. disabled</i> 12295 * 12296 * @dtopt Features 12297 * @name DataTable.defaults.scrollY 12298 * 12299 * @example 12300 * $(document).ready( function() { 12301 * $('#example').dataTable( { 12302 * "scrollY": "200px", 12303 * "paginate": false 12304 * } ); 12305 * } ); 12306 */ 12307 "sScrollY": "", 12308 12309 12310 /** 12311 * __Deprecated__ The functionality provided by this parameter has now been 12312 * superseded by that provided through `ajax`, which should be used instead. 12313 * 12314 * Set the HTTP method that is used to make the Ajax call for server-side 12315 * processing or Ajax sourced data. 12316 * @type string 12317 * @default GET 12318 * 12319 * @dtopt Options 12320 * @dtopt Server-side 12321 * @name DataTable.defaults.serverMethod 12322 * 12323 * @deprecated 1.10. Please use `ajax` for this functionality now. 12324 */ 12325 "sServerMethod": "GET", 12326 12327 12328 /** 12329 * DataTables makes use of renderers when displaying HTML elements for 12330 * a table. These renderers can be added or modified by plug-ins to 12331 * generate suitable mark-up for a site. For example the Bootstrap 12332 * integration plug-in for DataTables uses a paging button renderer to 12333 * display pagination buttons in the mark-up required by Bootstrap. 12334 * 12335 * For further information about the renderers available see 12336 * DataTable.ext.renderer 12337 * @type string|object 12338 * @default null 12339 * 12340 * @name DataTable.defaults.renderer 12341 * 12342 */ 12343 "renderer": null, 12344 12345 12346 /** 12347 * Set the data property name that DataTables should use to get a row's id 12348 * to set as the `id` property in the node. 12349 * @type string 12350 * @default DT_RowId 12351 * 12352 * @name DataTable.defaults.rowId 12353 */ 12354 "rowId": "DT_RowId" 12355 }; 12356 12357 _fnHungarianMap( DataTable.defaults ); 12358 12359 12360 12361 /* 12362 * Developer note - See note in model.defaults.js about the use of Hungarian 12363 * notation and camel case. 12364 */ 12365 12366 /** 12367 * Column options that can be given to DataTables at initialisation time. 12368 * @namespace 12369 */ 12370 DataTable.defaults.column = { 12371 /** 12372 * Define which column(s) an order will occur on for this column. This 12373 * allows a column's ordering to take multiple columns into account when 12374 * doing a sort or use the data from a different column. For example first 12375 * name / last name columns make sense to do a multi-column sort over the 12376 * two columns. 12377 * @type array|int 12378 * @default null <i>Takes the value of the column index automatically</i> 12379 * 12380 * @name DataTable.defaults.column.orderData 12381 * @dtopt Columns 12382 * 12383 * @example 12384 * // Using `columnDefs` 12385 * $(document).ready( function() { 12386 * $('#example').dataTable( { 12387 * "columnDefs": [ 12388 * { "orderData": [ 0, 1 ], "targets": [ 0 ] }, 12389 * { "orderData": [ 1, 0 ], "targets": [ 1 ] }, 12390 * { "orderData": 2, "targets": [ 2 ] } 12391 * ] 12392 * } ); 12393 * } ); 12394 * 12395 * @example 12396 * // Using `columns` 12397 * $(document).ready( function() { 12398 * $('#example').dataTable( { 12399 * "columns": [ 12400 * { "orderData": [ 0, 1 ] }, 12401 * { "orderData": [ 1, 0 ] }, 12402 * { "orderData": 2 }, 12403 * null, 12404 * null 12405 * ] 12406 * } ); 12407 * } ); 12408 */ 12409 "aDataSort": null, 12410 "iDataSort": -1, 12411 12412 12413 /** 12414 * You can control the default ordering direction, and even alter the 12415 * behaviour of the sort handler (i.e. only allow ascending ordering etc) 12416 * using this parameter. 12417 * @type array 12418 * @default [ 'asc', 'desc' ] 12419 * 12420 * @name DataTable.defaults.column.orderSequence 12421 * @dtopt Columns 12422 * 12423 * @example 12424 * // Using `columnDefs` 12425 * $(document).ready( function() { 12426 * $('#example').dataTable( { 12427 * "columnDefs": [ 12428 * { "orderSequence": [ "asc" ], "targets": [ 1 ] }, 12429 * { "orderSequence": [ "desc", "asc", "asc" ], "targets": [ 2 ] }, 12430 * { "orderSequence": [ "desc" ], "targets": [ 3 ] } 12431 * ] 12432 * } ); 12433 * } ); 12434 * 12435 * @example 12436 * // Using `columns` 12437 * $(document).ready( function() { 12438 * $('#example').dataTable( { 12439 * "columns": [ 12440 * null, 12441 * { "orderSequence": [ "asc" ] }, 12442 * { "orderSequence": [ "desc", "asc", "asc" ] }, 12443 * { "orderSequence": [ "desc" ] }, 12444 * null 12445 * ] 12446 * } ); 12447 * } ); 12448 */ 12449 "asSorting": [ 'asc', 'desc' ], 12450 12451 12452 /** 12453 * Enable or disable filtering on the data in this column. 12454 * @type boolean 12455 * @default true 12456 * 12457 * @name DataTable.defaults.column.searchable 12458 * @dtopt Columns 12459 * 12460 * @example 12461 * // Using `columnDefs` 12462 * $(document).ready( function() { 12463 * $('#example').dataTable( { 12464 * "columnDefs": [ 12465 * { "searchable": false, "targets": [ 0 ] } 12466 * ] } ); 12467 * } ); 12468 * 12469 * @example 12470 * // Using `columns` 12471 * $(document).ready( function() { 12472 * $('#example').dataTable( { 12473 * "columns": [ 12474 * { "searchable": false }, 12475 * null, 12476 * null, 12477 * null, 12478 * null 12479 * ] } ); 12480 * } ); 12481 */ 12482 "bSearchable": true, 12483 12484 12485 /** 12486 * Enable or disable ordering on this column. 12487 * @type boolean 12488 * @default true 12489 * 12490 * @name DataTable.defaults.column.orderable 12491 * @dtopt Columns 12492 * 12493 * @example 12494 * // Using `columnDefs` 12495 * $(document).ready( function() { 12496 * $('#example').dataTable( { 12497 * "columnDefs": [ 12498 * { "orderable": false, "targets": [ 0 ] } 12499 * ] } ); 12500 * } ); 12501 * 12502 * @example 12503 * // Using `columns` 12504 * $(document).ready( function() { 12505 * $('#example').dataTable( { 12506 * "columns": [ 12507 * { "orderable": false }, 12508 * null, 12509 * null, 12510 * null, 12511 * null 12512 * ] } ); 12513 * } ); 12514 */ 12515 "bSortable": true, 12516 12517 12518 /** 12519 * Enable or disable the display of this column. 12520 * @type boolean 12521 * @default true 12522 * 12523 * @name DataTable.defaults.column.visible 12524 * @dtopt Columns 12525 * 12526 * @example 12527 * // Using `columnDefs` 12528 * $(document).ready( function() { 12529 * $('#example').dataTable( { 12530 * "columnDefs": [ 12531 * { "visible": false, "targets": [ 0 ] } 12532 * ] } ); 12533 * } ); 12534 * 12535 * @example 12536 * // Using `columns` 12537 * $(document).ready( function() { 12538 * $('#example').dataTable( { 12539 * "columns": [ 12540 * { "visible": false }, 12541 * null, 12542 * null, 12543 * null, 12544 * null 12545 * ] } ); 12546 * } ); 12547 */ 12548 "bVisible": true, 12549 12550 12551 /** 12552 * Developer definable function that is called whenever a cell is created (Ajax source, 12553 * etc) or processed for input (DOM source). This can be used as a compliment to mRender 12554 * allowing you to modify the DOM element (add background colour for example) when the 12555 * element is available. 12556 * @type function 12557 * @param {element} td The TD node that has been created 12558 * @param {*} cellData The Data for the cell 12559 * @param {array|object} rowData The data for the whole row 12560 * @param {int} row The row index for the aoData data store 12561 * @param {int} col The column index for aoColumns 12562 * 12563 * @name DataTable.defaults.column.createdCell 12564 * @dtopt Columns 12565 * 12566 * @example 12567 * $(document).ready( function() { 12568 * $('#example').dataTable( { 12569 * "columnDefs": [ { 12570 * "targets": [3], 12571 * "createdCell": function (td, cellData, rowData, row, col) { 12572 * if ( cellData == "1.7" ) { 12573 * $(td).css('color', 'blue') 12574 * } 12575 * } 12576 * } ] 12577 * }); 12578 * } ); 12579 */ 12580 "fnCreatedCell": null, 12581 12582 12583 /** 12584 * This parameter has been replaced by `data` in DataTables to ensure naming 12585 * consistency. `dataProp` can still be used, as there is backwards 12586 * compatibility in DataTables for this option, but it is strongly 12587 * recommended that you use `data` in preference to `dataProp`. 12588 * @name DataTable.defaults.column.dataProp 12589 */ 12590 12591 12592 /** 12593 * This property can be used to read data from any data source property, 12594 * including deeply nested objects / properties. `data` can be given in a 12595 * number of different ways which effect its behaviour: 12596 * 12597 * * `integer` - treated as an array index for the data source. This is the 12598 * default that DataTables uses (incrementally increased for each column). 12599 * * `string` - read an object property from the data source. There are 12600 * three 'special' options that can be used in the string to alter how 12601 * DataTables reads the data from the source object: 12602 * * `.` - Dotted Javascript notation. Just as you use a `.` in 12603 * Javascript to read from nested objects, so to can the options 12604 * specified in `data`. For example: `browser.version` or 12605 * `browser.name`. If your object parameter name contains a period, use 12606 * `\\` to escape it - i.e. `first\\.name`. 12607 * * `[]` - Array notation. DataTables can automatically combine data 12608 * from and array source, joining the data with the characters provided 12609 * between the two brackets. For example: `name[, ]` would provide a 12610 * comma-space separated list from the source array. If no characters 12611 * are provided between the brackets, the original array source is 12612 * returned. 12613 * * `()` - Function notation. Adding `()` to the end of a parameter will 12614 * execute a function of the name given. For example: `browser()` for a 12615 * simple function on the data source, `browser.version()` for a 12616 * function in a nested property or even `browser().version` to get an 12617 * object property if the function called returns an object. Note that 12618 * function notation is recommended for use in `render` rather than 12619 * `data` as it is much simpler to use as a renderer. 12620 * * `null` - use the original data source for the row rather than plucking 12621 * data directly from it. This action has effects on two other 12622 * initialisation options: 12623 * * `defaultContent` - When null is given as the `data` option and 12624 * `defaultContent` is specified for the column, the value defined by 12625 * `defaultContent` will be used for the cell. 12626 * * `render` - When null is used for the `data` option and the `render` 12627 * option is specified for the column, the whole data source for the 12628 * row is used for the renderer. 12629 * * `function` - the function given will be executed whenever DataTables 12630 * needs to set or get the data for a cell in the column. The function 12631 * takes three parameters: 12632 * * Parameters: 12633 * * `{array|object}` The data source for the row 12634 * * `{string}` The type call data requested - this will be 'set' when 12635 * setting data or 'filter', 'display', 'type', 'sort' or undefined 12636 * when gathering data. Note that when `undefined` is given for the 12637 * type DataTables expects to get the raw data for the object back< 12638 * * `{*}` Data to set when the second parameter is 'set'. 12639 * * Return: 12640 * * The return value from the function is not required when 'set' is 12641 * the type of call, but otherwise the return is what will be used 12642 * for the data requested. 12643 * 12644 * Note that `data` is a getter and setter option. If you just require 12645 * formatting of data for output, you will likely want to use `render` which 12646 * is simply a getter and thus simpler to use. 12647 * 12648 * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The 12649 * name change reflects the flexibility of this property and is consistent 12650 * with the naming of mRender. If 'mDataProp' is given, then it will still 12651 * be used by DataTables, as it automatically maps the old name to the new 12652 * if required. 12653 * 12654 * @type string|int|function|null 12655 * @default null <i>Use automatically calculated column index</i> 12656 * 12657 * @name DataTable.defaults.column.data 12658 * @dtopt Columns 12659 * 12660 * @example 12661 * // Read table data from objects 12662 * // JSON structure for each row: 12663 * // { 12664 * // "engine": {value}, 12665 * // "browser": {value}, 12666 * // "platform": {value}, 12667 * // "version": {value}, 12668 * // "grade": {value} 12669 * // } 12670 * $(document).ready( function() { 12671 * $('#example').dataTable( { 12672 * "ajaxSource": "sources/objects.txt", 12673 * "columns": [ 12674 * { "data": "engine" }, 12675 * { "data": "browser" }, 12676 * { "data": "platform" }, 12677 * { "data": "version" }, 12678 * { "data": "grade" } 12679 * ] 12680 * } ); 12681 * } ); 12682 * 12683 * @example 12684 * // Read information from deeply nested objects 12685 * // JSON structure for each row: 12686 * // { 12687 * // "engine": {value}, 12688 * // "browser": {value}, 12689 * // "platform": { 12690 * // "inner": {value} 12691 * // }, 12692 * // "details": [ 12693 * // {value}, {value} 12694 * // ] 12695 * // } 12696 * $(document).ready( function() { 12697 * $('#example').dataTable( { 12698 * "ajaxSource": "sources/deep.txt", 12699 * "columns": [ 12700 * { "data": "engine" }, 12701 * { "data": "browser" }, 12702 * { "data": "platform.inner" }, 12703 * { "data": "details.0" }, 12704 * { "data": "details.1" } 12705 * ] 12706 * } ); 12707 * } ); 12708 * 12709 * @example 12710 * // Using `data` as a function to provide different information for 12711 * // sorting, filtering and display. In this case, currency (price) 12712 * $(document).ready( function() { 12713 * $('#example').dataTable( { 12714 * "columnDefs": [ { 12715 * "targets": [ 0 ], 12716 * "data": function ( source, type, val ) { 12717 * if (type === 'set') { 12718 * source.price = val; 12719 * // Store the computed display and filter values for efficiency 12720 * source.price_display = val=="" ? "" : "$"+numberFormat(val); 12721 * source.price_filter = val=="" ? "" : "$"+numberFormat(val)+" "+val; 12722 * return; 12723 * } 12724 * else if (type === 'display') { 12725 * return source.price_display; 12726 * } 12727 * else if (type === 'filter') { 12728 * return source.price_filter; 12729 * } 12730 * // 'sort', 'type' and undefined all just use the integer 12731 * return source.price; 12732 * } 12733 * } ] 12734 * } ); 12735 * } ); 12736 * 12737 * @example 12738 * // Using default content 12739 * $(document).ready( function() { 12740 * $('#example').dataTable( { 12741 * "columnDefs": [ { 12742 * "targets": [ 0 ], 12743 * "data": null, 12744 * "defaultContent": "Click to edit" 12745 * } ] 12746 * } ); 12747 * } ); 12748 * 12749 * @example 12750 * // Using array notation - outputting a list from an array 12751 * $(document).ready( function() { 12752 * $('#example').dataTable( { 12753 * "columnDefs": [ { 12754 * "targets": [ 0 ], 12755 * "data": "name[, ]" 12756 * } ] 12757 * } ); 12758 * } ); 12759 * 12760 */ 12761 "mData": null, 12762 12763 12764 /** 12765 * This property is the rendering partner to `data` and it is suggested that 12766 * when you want to manipulate data for display (including filtering, 12767 * sorting etc) without altering the underlying data for the table, use this 12768 * property. `render` can be considered to be the the read only companion to 12769 * `data` which is read / write (then as such more complex). Like `data` 12770 * this option can be given in a number of different ways to effect its 12771 * behaviour: 12772 * 12773 * * `integer` - treated as an array index for the data source. This is the 12774 * default that DataTables uses (incrementally increased for each column). 12775 * * `string` - read an object property from the data source. There are 12776 * three 'special' options that can be used in the string to alter how 12777 * DataTables reads the data from the source object: 12778 * * `.` - Dotted Javascript notation. Just as you use a `.` in 12779 * Javascript to read from nested objects, so to can the options 12780 * specified in `data`. For example: `browser.version` or 12781 * `browser.name`. If your object parameter name contains a period, use 12782 * `\\` to escape it - i.e. `first\\.name`. 12783 * * `[]` - Array notation. DataTables can automatically combine data 12784 * from and array source, joining the data with the characters provided 12785 * between the two brackets. For example: `name[, ]` would provide a 12786 * comma-space separated list from the source array. If no characters 12787 * are provided between the brackets, the original array source is 12788 * returned. 12789 * * `()` - Function notation. Adding `()` to the end of a parameter will 12790 * execute a function of the name given. For example: `browser()` for a 12791 * simple function on the data source, `browser.version()` for a 12792 * function in a nested property or even `browser().version` to get an 12793 * object property if the function called returns an object. 12794 * * `object` - use different data for the different data types requested by 12795 * DataTables ('filter', 'display', 'type' or 'sort'). The property names 12796 * of the object is the data type the property refers to and the value can 12797 * defined using an integer, string or function using the same rules as 12798 * `render` normally does. Note that an `_` option _must_ be specified. 12799 * This is the default value to use if you haven't specified a value for 12800 * the data type requested by DataTables. 12801 * * `function` - the function given will be executed whenever DataTables 12802 * needs to set or get the data for a cell in the column. The function 12803 * takes three parameters: 12804 * * Parameters: 12805 * * {array|object} The data source for the row (based on `data`) 12806 * * {string} The type call data requested - this will be 'filter', 12807 * 'display', 'type' or 'sort'. 12808 * * {array|object} The full data source for the row (not based on 12809 * `data`) 12810 * * Return: 12811 * * The return value from the function is what will be used for the 12812 * data requested. 12813 * 12814 * @type string|int|function|object|null 12815 * @default null Use the data source value. 12816 * 12817 * @name DataTable.defaults.column.render 12818 * @dtopt Columns 12819 * 12820 * @example 12821 * // Create a comma separated list from an array of objects 12822 * $(document).ready( function() { 12823 * $('#example').dataTable( { 12824 * "ajaxSource": "sources/deep.txt", 12825 * "columns": [ 12826 * { "data": "engine" }, 12827 * { "data": "browser" }, 12828 * { 12829 * "data": "platform", 12830 * "render": "[, ].name" 12831 * } 12832 * ] 12833 * } ); 12834 * } ); 12835 * 12836 * @example 12837 * // Execute a function to obtain data 12838 * $(document).ready( function() { 12839 * $('#example').dataTable( { 12840 * "columnDefs": [ { 12841 * "targets": [ 0 ], 12842 * "data": null, // Use the full data source object for the renderer's source 12843 * "render": "browserName()" 12844 * } ] 12845 * } ); 12846 * } ); 12847 * 12848 * @example 12849 * // As an object, extracting different data for the different types 12850 * // This would be used with a data source such as: 12851 * // { "phone": 5552368, "phone_filter": "5552368 555-2368", "phone_display": "555-2368" } 12852 * // Here the `phone` integer is used for sorting and type detection, while `phone_filter` 12853 * // (which has both forms) is used for filtering for if a user inputs either format, while 12854 * // the formatted phone number is the one that is shown in the table. 12855 * $(document).ready( function() { 12856 * $('#example').dataTable( { 12857 * "columnDefs": [ { 12858 * "targets": [ 0 ], 12859 * "data": null, // Use the full data source object for the renderer's source 12860 * "render": { 12861 * "_": "phone", 12862 * "filter": "phone_filter", 12863 * "display": "phone_display" 12864 * } 12865 * } ] 12866 * } ); 12867 * } ); 12868 * 12869 * @example 12870 * // Use as a function to create a link from the data source 12871 * $(document).ready( function() { 12872 * $('#example').dataTable( { 12873 * "columnDefs": [ { 12874 * "targets": [ 0 ], 12875 * "data": "download_link", 12876 * "render": function ( data, type, full ) { 12877 * return '<a href="'+data+'">Download</a>'; 12878 * } 12879 * } ] 12880 * } ); 12881 * } ); 12882 */ 12883 "mRender": null, 12884 12885 12886 /** 12887 * Change the cell type created for the column - either TD cells or TH cells. This 12888 * can be useful as TH cells have semantic meaning in the table body, allowing them 12889 * to act as a header for a row (you may wish to add scope='row' to the TH elements). 12890 * @type string 12891 * @default td 12892 * 12893 * @name DataTable.defaults.column.cellType 12894 * @dtopt Columns 12895 * 12896 * @example 12897 * // Make the first column use TH cells 12898 * $(document).ready( function() { 12899 * $('#example').dataTable( { 12900 * "columnDefs": [ { 12901 * "targets": [ 0 ], 12902 * "cellType": "th" 12903 * } ] 12904 * } ); 12905 * } ); 12906 */ 12907 "sCellType": "td", 12908 12909 12910 /** 12911 * Class to give to each cell in this column. 12912 * @type string 12913 * @default <i>Empty string</i> 12914 * 12915 * @name DataTable.defaults.column.class 12916 * @dtopt Columns 12917 * 12918 * @example 12919 * // Using `columnDefs` 12920 * $(document).ready( function() { 12921 * $('#example').dataTable( { 12922 * "columnDefs": [ 12923 * { "class": "my_class", "targets": [ 0 ] } 12924 * ] 12925 * } ); 12926 * } ); 12927 * 12928 * @example 12929 * // Using `columns` 12930 * $(document).ready( function() { 12931 * $('#example').dataTable( { 12932 * "columns": [ 12933 * { "class": "my_class" }, 12934 * null, 12935 * null, 12936 * null, 12937 * null 12938 * ] 12939 * } ); 12940 * } ); 12941 */ 12942 "sClass": "", 12943 12944 /** 12945 * When DataTables calculates the column widths to assign to each column, 12946 * it finds the longest string in each column and then constructs a 12947 * temporary table and reads the widths from that. The problem with this 12948 * is that "mmm" is much wider then "iiii", but the latter is a longer 12949 * string - thus the calculation can go wrong (doing it properly and putting 12950 * it into an DOM object and measuring that is horribly(!) slow). Thus as 12951 * a "work around" we provide this option. It will append its value to the 12952 * text that is found to be the longest string for the column - i.e. padding. 12953 * Generally you shouldn't need this! 12954 * @type string 12955 * @default <i>Empty string<i> 12956 * 12957 * @name DataTable.defaults.column.contentPadding 12958 * @dtopt Columns 12959 * 12960 * @example 12961 * // Using `columns` 12962 * $(document).ready( function() { 12963 * $('#example').dataTable( { 12964 * "columns": [ 12965 * null, 12966 * null, 12967 * null, 12968 * { 12969 * "contentPadding": "mmm" 12970 * } 12971 * ] 12972 * } ); 12973 * } ); 12974 */ 12975 "sContentPadding": "", 12976 12977 12978 /** 12979 * Allows a default value to be given for a column's data, and will be used 12980 * whenever a null data source is encountered (this can be because `data` 12981 * is set to null, or because the data source itself is null). 12982 * @type string 12983 * @default null 12984 * 12985 * @name DataTable.defaults.column.defaultContent 12986 * @dtopt Columns 12987 * 12988 * @example 12989 * // Using `columnDefs` 12990 * $(document).ready( function() { 12991 * $('#example').dataTable( { 12992 * "columnDefs": [ 12993 * { 12994 * "data": null, 12995 * "defaultContent": "Edit", 12996 * "targets": [ -1 ] 12997 * } 12998 * ] 12999 * } ); 13000 * } ); 13001 * 13002 * @example 13003 * // Using `columns` 13004 * $(document).ready( function() { 13005 * $('#example').dataTable( { 13006 * "columns": [ 13007 * null, 13008 * null, 13009 * null, 13010 * { 13011 * "data": null, 13012 * "defaultContent": "Edit" 13013 * } 13014 * ] 13015 * } ); 13016 * } ); 13017 */ 13018 "sDefaultContent": null, 13019 13020 13021 /** 13022 * This parameter is only used in DataTables' server-side processing. It can 13023 * be exceptionally useful to know what columns are being displayed on the 13024 * client side, and to map these to database fields. When defined, the names 13025 * also allow DataTables to reorder information from the server if it comes 13026 * back in an unexpected order (i.e. if you switch your columns around on the 13027 * client-side, your server-side code does not also need updating). 13028 * @type string 13029 * @default <i>Empty string</i> 13030 * 13031 * @name DataTable.defaults.column.name 13032 * @dtopt Columns 13033 * 13034 * @example 13035 * // Using `columnDefs` 13036 * $(document).ready( function() { 13037 * $('#example').dataTable( { 13038 * "columnDefs": [ 13039 * { "name": "engine", "targets": [ 0 ] }, 13040 * { "name": "browser", "targets": [ 1 ] }, 13041 * { "name": "platform", "targets": [ 2 ] }, 13042 * { "name": "version", "targets": [ 3 ] }, 13043 * { "name": "grade", "targets": [ 4 ] } 13044 * ] 13045 * } ); 13046 * } ); 13047 * 13048 * @example 13049 * // Using `columns` 13050 * $(document).ready( function() { 13051 * $('#example').dataTable( { 13052 * "columns": [ 13053 * { "name": "engine" }, 13054 * { "name": "browser" }, 13055 * { "name": "platform" }, 13056 * { "name": "version" }, 13057 * { "name": "grade" } 13058 * ] 13059 * } ); 13060 * } ); 13061 */ 13062 "sName": "", 13063 13064 13065 /** 13066 * Defines a data source type for the ordering which can be used to read 13067 * real-time information from the table (updating the internally cached 13068 * version) prior to ordering. This allows ordering to occur on user 13069 * editable elements such as form inputs. 13070 * @type string 13071 * @default std 13072 * 13073 * @name DataTable.defaults.column.orderDataType 13074 * @dtopt Columns 13075 * 13076 * @example 13077 * // Using `columnDefs` 13078 * $(document).ready( function() { 13079 * $('#example').dataTable( { 13080 * "columnDefs": [ 13081 * { "orderDataType": "dom-text", "targets": [ 2, 3 ] }, 13082 * { "type": "numeric", "targets": [ 3 ] }, 13083 * { "orderDataType": "dom-select", "targets": [ 4 ] }, 13084 * { "orderDataType": "dom-checkbox", "targets": [ 5 ] } 13085 * ] 13086 * } ); 13087 * } ); 13088 * 13089 * @example 13090 * // Using `columns` 13091 * $(document).ready( function() { 13092 * $('#example').dataTable( { 13093 * "columns": [ 13094 * null, 13095 * null, 13096 * { "orderDataType": "dom-text" }, 13097 * { "orderDataType": "dom-text", "type": "numeric" }, 13098 * { "orderDataType": "dom-select" }, 13099 * { "orderDataType": "dom-checkbox" } 13100 * ] 13101 * } ); 13102 * } ); 13103 */ 13104 "sSortDataType": "std", 13105 13106 13107 /** 13108 * The title of this column. 13109 * @type string 13110 * @default null <i>Derived from the 'TH' value for this column in the 13111 * original HTML table.</i> 13112 * 13113 * @name DataTable.defaults.column.title 13114 * @dtopt Columns 13115 * 13116 * @example 13117 * // Using `columnDefs` 13118 * $(document).ready( function() { 13119 * $('#example').dataTable( { 13120 * "columnDefs": [ 13121 * { "title": "My column title", "targets": [ 0 ] } 13122 * ] 13123 * } ); 13124 * } ); 13125 * 13126 * @example 13127 * // Using `columns` 13128 * $(document).ready( function() { 13129 * $('#example').dataTable( { 13130 * "columns": [ 13131 * { "title": "My column title" }, 13132 * null, 13133 * null, 13134 * null, 13135 * null 13136 * ] 13137 * } ); 13138 * } ); 13139 */ 13140 "sTitle": null, 13141 13142 13143 /** 13144 * The type allows you to specify how the data for this column will be 13145 * ordered. Four types (string, numeric, date and html (which will strip 13146 * HTML tags before ordering)) are currently available. Note that only date 13147 * formats understood by Javascript's Date() object will be accepted as type 13148 * date. For example: "Mar 26, 2008 5:03 PM". May take the values: 'string', 13149 * 'numeric', 'date' or 'html' (by default). Further types can be adding 13150 * through plug-ins. 13151 * @type string 13152 * @default null <i>Auto-detected from raw data</i> 13153 * 13154 * @name DataTable.defaults.column.type 13155 * @dtopt Columns 13156 * 13157 * @example 13158 * // Using `columnDefs` 13159 * $(document).ready( function() { 13160 * $('#example').dataTable( { 13161 * "columnDefs": [ 13162 * { "type": "html", "targets": [ 0 ] } 13163 * ] 13164 * } ); 13165 * } ); 13166 * 13167 * @example 13168 * // Using `columns` 13169 * $(document).ready( function() { 13170 * $('#example').dataTable( { 13171 * "columns": [ 13172 * { "type": "html" }, 13173 * null, 13174 * null, 13175 * null, 13176 * null 13177 * ] 13178 * } ); 13179 * } ); 13180 */ 13181 "sType": null, 13182 13183 13184 /** 13185 * Defining the width of the column, this parameter may take any CSS value 13186 * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not 13187 * been given a specific width through this interface ensuring that the table 13188 * remains readable. 13189 * @type string 13190 * @default null <i>Automatic</i> 13191 * 13192 * @name DataTable.defaults.column.width 13193 * @dtopt Columns 13194 * 13195 * @example 13196 * // Using `columnDefs` 13197 * $(document).ready( function() { 13198 * $('#example').dataTable( { 13199 * "columnDefs": [ 13200 * { "width": "20%", "targets": [ 0 ] } 13201 * ] 13202 * } ); 13203 * } ); 13204 * 13205 * @example 13206 * // Using `columns` 13207 * $(document).ready( function() { 13208 * $('#example').dataTable( { 13209 * "columns": [ 13210 * { "width": "20%" }, 13211 * null, 13212 * null, 13213 * null, 13214 * null 13215 * ] 13216 * } ); 13217 * } ); 13218 */ 13219 "sWidth": null 13220 }; 13221 13222 _fnHungarianMap( DataTable.defaults.column ); 13223 13224 13225 13226 /** 13227 * DataTables settings object - this holds all the information needed for a 13228 * given table, including configuration, data and current application of the 13229 * table options. DataTables does not have a single instance for each DataTable 13230 * with the settings attached to that instance, but rather instances of the 13231 * DataTable "class" are created on-the-fly as needed (typically by a 13232 * $().dataTable() call) and the settings object is then applied to that 13233 * instance. 13234 * 13235 * Note that this object is related to {@link DataTable.defaults} but this 13236 * one is the internal data store for DataTables's cache of columns. It should 13237 * NOT be manipulated outside of DataTables. Any configuration should be done 13238 * through the initialisation options. 13239 * @namespace 13240 * @todo Really should attach the settings object to individual instances so we 13241 * don't need to create new instances on each $().dataTable() call (if the 13242 * table already exists). It would also save passing oSettings around and 13243 * into every single function. However, this is a very significant 13244 * architecture change for DataTables and will almost certainly break 13245 * backwards compatibility with older installations. This is something that 13246 * will be done in 2.0. 13247 */ 13248 DataTable.models.oSettings = { 13249 /** 13250 * Primary features of DataTables and their enablement state. 13251 * @namespace 13252 */ 13253 "oFeatures": { 13254 13255 /** 13256 * Flag to say if DataTables should automatically try to calculate the 13257 * optimum table and columns widths (true) or not (false). 13258 * Note that this parameter will be set by the initialisation routine. To 13259 * set a default use {@link DataTable.defaults}. 13260 * @type boolean 13261 */ 13262 "bAutoWidth": null, 13263 13264 /** 13265 * Delay the creation of TR and TD elements until they are actually 13266 * needed by a driven page draw. This can give a significant speed 13267 * increase for Ajax source and Javascript source data, but makes no 13268 * difference at all for DOM and server-side processing tables. 13269 * Note that this parameter will be set by the initialisation routine. To 13270 * set a default use {@link DataTable.defaults}. 13271 * @type boolean 13272 */ 13273 "bDeferRender": null, 13274 13275 /** 13276 * Enable filtering on the table or not. Note that if this is disabled 13277 * then there is no filtering at all on the table, including fnFilter. 13278 * To just remove the filtering input use sDom and remove the 'f' option. 13279 * Note that this parameter will be set by the initialisation routine. To 13280 * set a default use {@link DataTable.defaults}. 13281 * @type boolean 13282 */ 13283 "bFilter": null, 13284 13285 /** 13286 * Table information element (the 'Showing x of y records' div) enable 13287 * flag. 13288 * Note that this parameter will be set by the initialisation routine. To 13289 * set a default use {@link DataTable.defaults}. 13290 * @type boolean 13291 */ 13292 "bInfo": null, 13293 13294 /** 13295 * Present a user control allowing the end user to change the page size 13296 * when pagination is enabled. 13297 * Note that this parameter will be set by the initialisation routine. To 13298 * set a default use {@link DataTable.defaults}. 13299 * @type boolean 13300 */ 13301 "bLengthChange": null, 13302 13303 /** 13304 * Pagination enabled or not. Note that if this is disabled then length 13305 * changing must also be disabled. 13306 * Note that this parameter will be set by the initialisation routine. To 13307 * set a default use {@link DataTable.defaults}. 13308 * @type boolean 13309 */ 13310 "bPaginate": null, 13311 13312 /** 13313 * Processing indicator enable flag whenever DataTables is enacting a 13314 * user request - typically an Ajax request for server-side processing. 13315 * Note that this parameter will be set by the initialisation routine. To 13316 * set a default use {@link DataTable.defaults}. 13317 * @type boolean 13318 */ 13319 "bProcessing": null, 13320 13321 /** 13322 * Server-side processing enabled flag - when enabled DataTables will 13323 * get all data from the server for every draw - there is no filtering, 13324 * sorting or paging done on the client-side. 13325 * Note that this parameter will be set by the initialisation routine. To 13326 * set a default use {@link DataTable.defaults}. 13327 * @type boolean 13328 */ 13329 "bServerSide": null, 13330 13331 /** 13332 * Sorting enablement flag. 13333 * Note that this parameter will be set by the initialisation routine. To 13334 * set a default use {@link DataTable.defaults}. 13335 * @type boolean 13336 */ 13337 "bSort": null, 13338 13339 /** 13340 * Multi-column sorting 13341 * Note that this parameter will be set by the initialisation routine. To 13342 * set a default use {@link DataTable.defaults}. 13343 * @type boolean 13344 */ 13345 "bSortMulti": null, 13346 13347 /** 13348 * Apply a class to the columns which are being sorted to provide a 13349 * visual highlight or not. This can slow things down when enabled since 13350 * there is a lot of DOM interaction. 13351 * Note that this parameter will be set by the initialisation routine. To 13352 * set a default use {@link DataTable.defaults}. 13353 * @type boolean 13354 */ 13355 "bSortClasses": null, 13356 13357 /** 13358 * State saving enablement flag. 13359 * Note that this parameter will be set by the initialisation routine. To 13360 * set a default use {@link DataTable.defaults}. 13361 * @type boolean 13362 */ 13363 "bStateSave": null 13364 }, 13365 13366 13367 /** 13368 * Scrolling settings for a table. 13369 * @namespace 13370 */ 13371 "oScroll": { 13372 /** 13373 * When the table is shorter in height than sScrollY, collapse the 13374 * table container down to the height of the table (when true). 13375 * Note that this parameter will be set by the initialisation routine. To 13376 * set a default use {@link DataTable.defaults}. 13377 * @type boolean 13378 */ 13379 "bCollapse": null, 13380 13381 /** 13382 * Width of the scrollbar for the web-browser's platform. Calculated 13383 * during table initialisation. 13384 * @type int 13385 * @default 0 13386 */ 13387 "iBarWidth": 0, 13388 13389 /** 13390 * Viewport width for horizontal scrolling. Horizontal scrolling is 13391 * disabled if an empty string. 13392 * Note that this parameter will be set by the initialisation routine. To 13393 * set a default use {@link DataTable.defaults}. 13394 * @type string 13395 */ 13396 "sX": null, 13397 13398 /** 13399 * Width to expand the table to when using x-scrolling. Typically you 13400 * should not need to use this. 13401 * Note that this parameter will be set by the initialisation routine. To 13402 * set a default use {@link DataTable.defaults}. 13403 * @type string 13404 * @deprecated 13405 */ 13406 "sXInner": null, 13407 13408 /** 13409 * Viewport height for vertical scrolling. Vertical scrolling is disabled 13410 * if an empty string. 13411 * Note that this parameter will be set by the initialisation routine. To 13412 * set a default use {@link DataTable.defaults}. 13413 * @type string 13414 */ 13415 "sY": null 13416 }, 13417 13418 /** 13419 * Language information for the table. 13420 * @namespace 13421 * @extends DataTable.defaults.oLanguage 13422 */ 13423 "oLanguage": { 13424 /** 13425 * Information callback function. See 13426 * {@link DataTable.defaults.fnInfoCallback} 13427 * @type function 13428 * @default null 13429 */ 13430 "fnInfoCallback": null 13431 }, 13432 13433 /** 13434 * Browser support parameters 13435 * @namespace 13436 */ 13437 "oBrowser": { 13438 /** 13439 * Indicate if the browser incorrectly calculates width:100% inside a 13440 * scrolling element (IE6/7) 13441 * @type boolean 13442 * @default false 13443 */ 13444 "bScrollOversize": false, 13445 13446 /** 13447 * Determine if the vertical scrollbar is on the right or left of the 13448 * scrolling container - needed for rtl language layout, although not 13449 * all browsers move the scrollbar (Safari). 13450 * @type boolean 13451 * @default false 13452 */ 13453 "bScrollbarLeft": false, 13454 13455 /** 13456 * Flag for if `getBoundingClientRect` is fully supported or not 13457 * @type boolean 13458 * @default false 13459 */ 13460 "bBounding": false, 13461 13462 /** 13463 * Browser scrollbar width 13464 * @type integer 13465 * @default 0 13466 */ 13467 "barWidth": 0 13468 }, 13469 13470 13471 "ajax": null, 13472 13473 13474 /** 13475 * Array referencing the nodes which are used for the features. The 13476 * parameters of this object match what is allowed by sDom - i.e. 13477 * <ul> 13478 * <li>'l' - Length changing</li> 13479 * <li>'f' - Filtering input</li> 13480 * <li>'t' - The table!</li> 13481 * <li>'i' - Information</li> 13482 * <li>'p' - Pagination</li> 13483 * <li>'r' - pRocessing</li> 13484 * </ul> 13485 * @type array 13486 * @default [] 13487 */ 13488 "aanFeatures": [], 13489 13490 /** 13491 * Store data information - see {@link DataTable.models.oRow} for detailed 13492 * information. 13493 * @type array 13494 * @default [] 13495 */ 13496 "aoData": [], 13497 13498 /** 13499 * Array of indexes which are in the current display (after filtering etc) 13500 * @type array 13501 * @default [] 13502 */ 13503 "aiDisplay": [], 13504 13505 /** 13506 * Array of indexes for display - no filtering 13507 * @type array 13508 * @default [] 13509 */ 13510 "aiDisplayMaster": [], 13511 13512 /** 13513 * Map of row ids to data indexes 13514 * @type object 13515 * @default {} 13516 */ 13517 "aIds": {}, 13518 13519 /** 13520 * Store information about each column that is in use 13521 * @type array 13522 * @default [] 13523 */ 13524 "aoColumns": [], 13525 13526 /** 13527 * Store information about the table's header 13528 * @type array 13529 * @default [] 13530 */ 13531 "aoHeader": [], 13532 13533 /** 13534 * Store information about the table's footer 13535 * @type array 13536 * @default [] 13537 */ 13538 "aoFooter": [], 13539 13540 /** 13541 * Store the applied global search information in case we want to force a 13542 * research or compare the old search to a new one. 13543 * Note that this parameter will be set by the initialisation routine. To 13544 * set a default use {@link DataTable.defaults}. 13545 * @namespace 13546 * @extends DataTable.models.oSearch 13547 */ 13548 "oPreviousSearch": {}, 13549 13550 /** 13551 * Store the applied search for each column - see 13552 * {@link DataTable.models.oSearch} for the format that is used for the 13553 * filtering information for each column. 13554 * @type array 13555 * @default [] 13556 */ 13557 "aoPreSearchCols": [], 13558 13559 /** 13560 * Sorting that is applied to the table. Note that the inner arrays are 13561 * used in the following manner: 13562 * <ul> 13563 * <li>Index 0 - column number</li> 13564 * <li>Index 1 - current sorting direction</li> 13565 * </ul> 13566 * Note that this parameter will be set by the initialisation routine. To 13567 * set a default use {@link DataTable.defaults}. 13568 * @type array 13569 * @todo These inner arrays should really be objects 13570 */ 13571 "aaSorting": null, 13572 13573 /** 13574 * Sorting that is always applied to the table (i.e. prefixed in front of 13575 * aaSorting). 13576 * Note that this parameter will be set by the initialisation routine. To 13577 * set a default use {@link DataTable.defaults}. 13578 * @type array 13579 * @default [] 13580 */ 13581 "aaSortingFixed": [], 13582 13583 /** 13584 * Classes to use for the striping of a table. 13585 * Note that this parameter will be set by the initialisation routine. To 13586 * set a default use {@link DataTable.defaults}. 13587 * @type array 13588 * @default [] 13589 */ 13590 "asStripeClasses": null, 13591 13592 /** 13593 * If restoring a table - we should restore its striping classes as well 13594 * @type array 13595 * @default [] 13596 */ 13597 "asDestroyStripes": [], 13598 13599 /** 13600 * If restoring a table - we should restore its width 13601 * @type int 13602 * @default 0 13603 */ 13604 "sDestroyWidth": 0, 13605 13606 /** 13607 * Callback functions array for every time a row is inserted (i.e. on a draw). 13608 * @type array 13609 * @default [] 13610 */ 13611 "aoRowCallback": [], 13612 13613 /** 13614 * Callback functions for the header on each draw. 13615 * @type array 13616 * @default [] 13617 */ 13618 "aoHeaderCallback": [], 13619 13620 /** 13621 * Callback function for the footer on each draw. 13622 * @type array 13623 * @default [] 13624 */ 13625 "aoFooterCallback": [], 13626 13627 /** 13628 * Array of callback functions for draw callback functions 13629 * @type array 13630 * @default [] 13631 */ 13632 "aoDrawCallback": [], 13633 13634 /** 13635 * Array of callback functions for row created function 13636 * @type array 13637 * @default [] 13638 */ 13639 "aoRowCreatedCallback": [], 13640 13641 /** 13642 * Callback functions for just before the table is redrawn. A return of 13643 * false will be used to cancel the draw. 13644 * @type array 13645 * @default [] 13646 */ 13647 "aoPreDrawCallback": [], 13648 13649 /** 13650 * Callback functions for when the table has been initialised. 13651 * @type array 13652 * @default [] 13653 */ 13654 "aoInitComplete": [], 13655 13656 13657 /** 13658 * Callbacks for modifying the settings to be stored for state saving, prior to 13659 * saving state. 13660 * @type array 13661 * @default [] 13662 */ 13663 "aoStateSaveParams": [], 13664 13665 /** 13666 * Callbacks for modifying the settings that have been stored for state saving 13667 * prior to using the stored values to restore the state. 13668 * @type array 13669 * @default [] 13670 */ 13671 "aoStateLoadParams": [], 13672 13673 /** 13674 * Callbacks for operating on the settings object once the saved state has been 13675 * loaded 13676 * @type array 13677 * @default [] 13678 */ 13679 "aoStateLoaded": [], 13680 13681 /** 13682 * Cache the table ID for quick access 13683 * @type string 13684 * @default <i>Empty string</i> 13685 */ 13686 "sTableId": "", 13687 13688 /** 13689 * The TABLE node for the main table 13690 * @type node 13691 * @default null 13692 */ 13693 "nTable": null, 13694 13695 /** 13696 * Permanent ref to the thead element 13697 * @type node 13698 * @default null 13699 */ 13700 "nTHead": null, 13701 13702 /** 13703 * Permanent ref to the tfoot element - if it exists 13704 * @type node 13705 * @default null 13706 */ 13707 "nTFoot": null, 13708 13709 /** 13710 * Permanent ref to the tbody element 13711 * @type node 13712 * @default null 13713 */ 13714 "nTBody": null, 13715 13716 /** 13717 * Cache the wrapper node (contains all DataTables controlled elements) 13718 * @type node 13719 * @default null 13720 */ 13721 "nTableWrapper": null, 13722 13723 /** 13724 * Indicate if when using server-side processing the loading of data 13725 * should be deferred until the second draw. 13726 * Note that this parameter will be set by the initialisation routine. To 13727 * set a default use {@link DataTable.defaults}. 13728 * @type boolean 13729 * @default false 13730 */ 13731 "bDeferLoading": false, 13732 13733 /** 13734 * Indicate if all required information has been read in 13735 * @type boolean 13736 * @default false 13737 */ 13738 "bInitialised": false, 13739 13740 /** 13741 * Information about open rows. Each object in the array has the parameters 13742 * 'nTr' and 'nParent' 13743 * @type array 13744 * @default [] 13745 */ 13746 "aoOpenRows": [], 13747 13748 /** 13749 * Dictate the positioning of DataTables' control elements - see 13750 * {@link DataTable.model.oInit.sDom}. 13751 * Note that this parameter will be set by the initialisation routine. To 13752 * set a default use {@link DataTable.defaults}. 13753 * @type string 13754 * @default null 13755 */ 13756 "sDom": null, 13757 13758 /** 13759 * Search delay (in mS) 13760 * @type integer 13761 * @default null 13762 */ 13763 "searchDelay": null, 13764 13765 /** 13766 * Which type of pagination should be used. 13767 * Note that this parameter will be set by the initialisation routine. To 13768 * set a default use {@link DataTable.defaults}. 13769 * @type string 13770 * @default two_button 13771 */ 13772 "sPaginationType": "two_button", 13773 13774 /** 13775 * The state duration (for `stateSave`) in seconds. 13776 * Note that this parameter will be set by the initialisation routine. To 13777 * set a default use {@link DataTable.defaults}. 13778 * @type int 13779 * @default 0 13780 */ 13781 "iStateDuration": 0, 13782 13783 /** 13784 * Array of callback functions for state saving. Each array element is an 13785 * object with the following parameters: 13786 * <ul> 13787 * <li>function:fn - function to call. Takes two parameters, oSettings 13788 * and the JSON string to save that has been thus far created. Returns 13789 * a JSON string to be inserted into a json object 13790 * (i.e. '"param": [ 0, 1, 2]')</li> 13791 * <li>string:sName - name of callback</li> 13792 * </ul> 13793 * @type array 13794 * @default [] 13795 */ 13796 "aoStateSave": [], 13797 13798 /** 13799 * Array of callback functions for state loading. Each array element is an 13800 * object with the following parameters: 13801 * <ul> 13802 * <li>function:fn - function to call. Takes two parameters, oSettings 13803 * and the object stored. May return false to cancel state loading</li> 13804 * <li>string:sName - name of callback</li> 13805 * </ul> 13806 * @type array 13807 * @default [] 13808 */ 13809 "aoStateLoad": [], 13810 13811 /** 13812 * State that was saved. Useful for back reference 13813 * @type object 13814 * @default null 13815 */ 13816 "oSavedState": null, 13817 13818 /** 13819 * State that was loaded. Useful for back reference 13820 * @type object 13821 * @default null 13822 */ 13823 "oLoadedState": null, 13824 13825 /** 13826 * Source url for AJAX data for the table. 13827 * Note that this parameter will be set by the initialisation routine. To 13828 * set a default use {@link DataTable.defaults}. 13829 * @type string 13830 * @default null 13831 */ 13832 "sAjaxSource": null, 13833 13834 /** 13835 * Property from a given object from which to read the table data from. This 13836 * can be an empty string (when not server-side processing), in which case 13837 * it is assumed an an array is given directly. 13838 * Note that this parameter will be set by the initialisation routine. To 13839 * set a default use {@link DataTable.defaults}. 13840 * @type string 13841 */ 13842 "sAjaxDataProp": null, 13843 13844 /** 13845 * The last jQuery XHR object that was used for server-side data gathering. 13846 * This can be used for working with the XHR information in one of the 13847 * callbacks 13848 * @type object 13849 * @default null 13850 */ 13851 "jqXHR": null, 13852 13853 /** 13854 * JSON returned from the server in the last Ajax request 13855 * @type object 13856 * @default undefined 13857 */ 13858 "json": undefined, 13859 13860 /** 13861 * Data submitted as part of the last Ajax request 13862 * @type object 13863 * @default undefined 13864 */ 13865 "oAjaxData": undefined, 13866 13867 /** 13868 * Function to get the server-side data. 13869 * Note that this parameter will be set by the initialisation routine. To 13870 * set a default use {@link DataTable.defaults}. 13871 * @type function 13872 */ 13873 "fnServerData": null, 13874 13875 /** 13876 * Functions which are called prior to sending an Ajax request so extra 13877 * parameters can easily be sent to the server 13878 * @type array 13879 * @default [] 13880 */ 13881 "aoServerParams": [], 13882 13883 /** 13884 * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if 13885 * required). 13886 * Note that this parameter will be set by the initialisation routine. To 13887 * set a default use {@link DataTable.defaults}. 13888 * @type string 13889 */ 13890 "sServerMethod": null, 13891 13892 /** 13893 * Format numbers for display. 13894 * Note that this parameter will be set by the initialisation routine. To 13895 * set a default use {@link DataTable.defaults}. 13896 * @type function 13897 */ 13898 "fnFormatNumber": null, 13899 13900 /** 13901 * List of options that can be used for the user selectable length menu. 13902 * Note that this parameter will be set by the initialisation routine. To 13903 * set a default use {@link DataTable.defaults}. 13904 * @type array 13905 * @default [] 13906 */ 13907 "aLengthMenu": null, 13908 13909 /** 13910 * Counter for the draws that the table does. Also used as a tracker for 13911 * server-side processing 13912 * @type int 13913 * @default 0 13914 */ 13915 "iDraw": 0, 13916 13917 /** 13918 * Indicate if a redraw is being done - useful for Ajax 13919 * @type boolean 13920 * @default false 13921 */ 13922 "bDrawing": false, 13923 13924 /** 13925 * Draw index (iDraw) of the last error when parsing the returned data 13926 * @type int 13927 * @default -1 13928 */ 13929 "iDrawError": -1, 13930 13931 /** 13932 * Paging display length 13933 * @type int 13934 * @default 10 13935 */ 13936 "_iDisplayLength": 10, 13937 13938 /** 13939 * Paging start point - aiDisplay index 13940 * @type int 13941 * @default 0 13942 */ 13943 "_iDisplayStart": 0, 13944 13945 /** 13946 * Server-side processing - number of records in the result set 13947 * (i.e. before filtering), Use fnRecordsTotal rather than 13948 * this property to get the value of the number of records, regardless of 13949 * the server-side processing setting. 13950 * @type int 13951 * @default 0 13952 * @private 13953 */ 13954 "_iRecordsTotal": 0, 13955 13956 /** 13957 * Server-side processing - number of records in the current display set 13958 * (i.e. after filtering). Use fnRecordsDisplay rather than 13959 * this property to get the value of the number of records, regardless of 13960 * the server-side processing setting. 13961 * @type boolean 13962 * @default 0 13963 * @private 13964 */ 13965 "_iRecordsDisplay": 0, 13966 13967 /** 13968 * The classes to use for the table 13969 * @type object 13970 * @default {} 13971 */ 13972 "oClasses": {}, 13973 13974 /** 13975 * Flag attached to the settings object so you can check in the draw 13976 * callback if filtering has been done in the draw. Deprecated in favour of 13977 * events. 13978 * @type boolean 13979 * @default false 13980 * @deprecated 13981 */ 13982 "bFiltered": false, 13983 13984 /** 13985 * Flag attached to the settings object so you can check in the draw 13986 * callback if sorting has been done in the draw. Deprecated in favour of 13987 * events. 13988 * @type boolean 13989 * @default false 13990 * @deprecated 13991 */ 13992 "bSorted": false, 13993 13994 /** 13995 * Indicate that if multiple rows are in the header and there is more than 13996 * one unique cell per column, if the top one (true) or bottom one (false) 13997 * should be used for sorting / title by DataTables. 13998 * Note that this parameter will be set by the initialisation routine. To 13999 * set a default use {@link DataTable.defaults}. 14000 * @type boolean 14001 */ 14002 "bSortCellsTop": null, 14003 14004 /** 14005 * Initialisation object that is used for the table 14006 * @type object 14007 * @default null 14008 */ 14009 "oInit": null, 14010 14011 /** 14012 * Destroy callback functions - for plug-ins to attach themselves to the 14013 * destroy so they can clean up markup and events. 14014 * @type array 14015 * @default [] 14016 */ 14017 "aoDestroyCallback": [], 14018 14019 14020 /** 14021 * Get the number of records in the current record set, before filtering 14022 * @type function 14023 */ 14024 "fnRecordsTotal": function () 14025 { 14026 return _fnDataSource( this ) == 'ssp' ? 14027 this._iRecordsTotal * 1 : 14028 this.aiDisplayMaster.length; 14029 }, 14030 14031 /** 14032 * Get the number of records in the current record set, after filtering 14033 * @type function 14034 */ 14035 "fnRecordsDisplay": function () 14036 { 14037 return _fnDataSource( this ) == 'ssp' ? 14038 this._iRecordsDisplay * 1 : 14039 this.aiDisplay.length; 14040 }, 14041 14042 /** 14043 * Get the display end point - aiDisplay index 14044 * @type function 14045 */ 14046 "fnDisplayEnd": function () 14047 { 14048 var 14049 len = this._iDisplayLength, 14050 start = this._iDisplayStart, 14051 calc = start + len, 14052 records = this.aiDisplay.length, 14053 features = this.oFeatures, 14054 paginate = features.bPaginate; 14055 14056 if ( features.bServerSide ) { 14057 return paginate === false || len === -1 ? 14058 start + records : 14059 Math.min( start+len, this._iRecordsDisplay ); 14060 } 14061 else { 14062 return ! paginate || calc>records || len===-1 ? 14063 records : 14064 calc; 14065 } 14066 }, 14067 14068 /** 14069 * The DataTables object for this table 14070 * @type object 14071 * @default null 14072 */ 14073 "oInstance": null, 14074 14075 /** 14076 * Unique identifier for each instance of the DataTables object. If there 14077 * is an ID on the table node, then it takes that value, otherwise an 14078 * incrementing internal counter is used. 14079 * @type string 14080 * @default null 14081 */ 14082 "sInstance": null, 14083 14084 /** 14085 * tabindex attribute value that is added to DataTables control elements, allowing 14086 * keyboard navigation of the table and its controls. 14087 */ 14088 "iTabIndex": 0, 14089 14090 /** 14091 * DIV container for the footer scrolling table if scrolling 14092 */ 14093 "nScrollHead": null, 14094 14095 /** 14096 * DIV container for the footer scrolling table if scrolling 14097 */ 14098 "nScrollFoot": null, 14099 14100 /** 14101 * Last applied sort 14102 * @type array 14103 * @default [] 14104 */ 14105 "aLastSort": [], 14106 14107 /** 14108 * Stored plug-in instances 14109 * @type object 14110 * @default {} 14111 */ 14112 "oPlugins": {}, 14113 14114 /** 14115 * Function used to get a row's id from the row's data 14116 * @type function 14117 * @default null 14118 */ 14119 "rowIdFn": null, 14120 14121 /** 14122 * Data location where to store a row's id 14123 * @type string 14124 * @default null 14125 */ 14126 "rowId": null 14127 }; 14128 14129 /** 14130 * Extension object for DataTables that is used to provide all extension 14131 * options. 14132 * 14133 * Note that the `DataTable.ext` object is available through 14134 * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is 14135 * also aliased to `jQuery.fn.dataTableExt` for historic reasons. 14136 * @namespace 14137 * @extends DataTable.models.ext 14138 */ 14139 14140 14141 /** 14142 * DataTables extensions 14143 * 14144 * This namespace acts as a collection area for plug-ins that can be used to 14145 * extend DataTables capabilities. Indeed many of the build in methods 14146 * use this method to provide their own capabilities (sorting methods for 14147 * example). 14148 * 14149 * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy 14150 * reasons 14151 * 14152 * @namespace 14153 */ 14154 DataTable.ext = _ext = { 14155 /** 14156 * Buttons. For use with the Buttons extension for DataTables. This is 14157 * defined here so other extensions can define buttons regardless of load 14158 * order. It is _not_ used by DataTables core. 14159 * 14160 * @type object 14161 * @default {} 14162 */ 14163 buttons: {}, 14164 14165 14166 /** 14167 * Element class names 14168 * 14169 * @type object 14170 * @default {} 14171 */ 14172 classes: {}, 14173 14174 14175 /** 14176 * DataTables build type (expanded by the download builder) 14177 * 14178 * @type string 14179 */ 14180 builder: "-source-", 14181 14182 14183 /** 14184 * Error reporting. 14185 * 14186 * How should DataTables report an error. Can take the value 'alert', 14187 * 'throw', 'none' or a function. 14188 * 14189 * @type string|function 14190 * @default alert 14191 */ 14192 errMode: "alert", 14193 14194 14195 /** 14196 * Feature plug-ins. 14197 * 14198 * This is an array of objects which describe the feature plug-ins that are 14199 * available to DataTables. These feature plug-ins are then available for 14200 * use through the `dom` initialisation option. 14201 * 14202 * Each feature plug-in is described by an object which must have the 14203 * following properties: 14204 * 14205 * * `fnInit` - function that is used to initialise the plug-in, 14206 * * `cFeature` - a character so the feature can be enabled by the `dom` 14207 * instillation option. This is case sensitive. 14208 * 14209 * The `fnInit` function has the following input parameters: 14210 * 14211 * 1. `{object}` DataTables settings object: see 14212 * {@link DataTable.models.oSettings} 14213 * 14214 * And the following return is expected: 14215 * 14216 * * {node|null} The element which contains your feature. Note that the 14217 * return may also be void if your plug-in does not require to inject any 14218 * DOM elements into DataTables control (`dom`) - for example this might 14219 * be useful when developing a plug-in which allows table control via 14220 * keyboard entry 14221 * 14222 * @type array 14223 * 14224 * @example 14225 * $.fn.dataTable.ext.features.push( { 14226 * "fnInit": function( oSettings ) { 14227 * return new TableTools( { "oDTSettings": oSettings } ); 14228 * }, 14229 * "cFeature": "T" 14230 * } ); 14231 */ 14232 feature: [], 14233 14234 14235 /** 14236 * Row searching. 14237 * 14238 * This method of searching is complimentary to the default type based 14239 * searching, and a lot more comprehensive as it allows you complete control 14240 * over the searching logic. Each element in this array is a function 14241 * (parameters described below) that is called for every row in the table, 14242 * and your logic decides if it should be included in the searching data set 14243 * or not. 14244 * 14245 * Searching functions have the following input parameters: 14246 * 14247 * 1. `{object}` DataTables settings object: see 14248 * {@link DataTable.models.oSettings} 14249 * 2. `{array|object}` Data for the row to be processed (same as the 14250 * original format that was passed in as the data source, or an array 14251 * from a DOM data source 14252 * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which 14253 * can be useful to retrieve the `TR` element if you need DOM interaction. 14254 * 14255 * And the following return is expected: 14256 * 14257 * * {boolean} Include the row in the searched result set (true) or not 14258 * (false) 14259 * 14260 * Note that as with the main search ability in DataTables, technically this 14261 * is "filtering", since it is subtractive. However, for consistency in 14262 * naming we call it searching here. 14263 * 14264 * @type array 14265 * @default [] 14266 * 14267 * @example 14268 * // The following example shows custom search being applied to the 14269 * // fourth column (i.e. the data[3] index) based on two input values 14270 * // from the end-user, matching the data in a certain range. 14271 * $.fn.dataTable.ext.search.push( 14272 * function( settings, data, dataIndex ) { 14273 * var min = document.getElementById('min').value * 1; 14274 * var max = document.getElementById('max').value * 1; 14275 * var version = data[3] == "-" ? 0 : data[3]*1; 14276 * 14277 * if ( min == "" && max == "" ) { 14278 * return true; 14279 * } 14280 * else if ( min == "" && version < max ) { 14281 * return true; 14282 * } 14283 * else if ( min < version && "" == max ) { 14284 * return true; 14285 * } 14286 * else if ( min < version && version < max ) { 14287 * return true; 14288 * } 14289 * return false; 14290 * } 14291 * ); 14292 */ 14293 search: [], 14294 14295 14296 /** 14297 * Selector extensions 14298 * 14299 * The `selector` option can be used to extend the options available for the 14300 * selector modifier options (`selector-modifier` object data type) that 14301 * each of the three built in selector types offer (row, column and cell + 14302 * their plural counterparts). For example the Select extension uses this 14303 * mechanism to provide an option to select only rows, columns and cells 14304 * that have been marked as selected by the end user (`{selected: true}`), 14305 * which can be used in conjunction with the existing built in selector 14306 * options. 14307 * 14308 * Each property is an array to which functions can be pushed. The functions 14309 * take three attributes: 14310 * 14311 * * Settings object for the host table 14312 * * Options object (`selector-modifier` object type) 14313 * * Array of selected item indexes 14314 * 14315 * The return is an array of the resulting item indexes after the custom 14316 * selector has been applied. 14317 * 14318 * @type object 14319 */ 14320 selector: { 14321 cell: [], 14322 column: [], 14323 row: [] 14324 }, 14325 14326 14327 /** 14328 * Internal functions, exposed for used in plug-ins. 14329 * 14330 * Please note that you should not need to use the internal methods for 14331 * anything other than a plug-in (and even then, try to avoid if possible). 14332 * The internal function may change between releases. 14333 * 14334 * @type object 14335 * @default {} 14336 */ 14337 internal: {}, 14338 14339 14340 /** 14341 * Legacy configuration options. Enable and disable legacy options that 14342 * are available in DataTables. 14343 * 14344 * @type object 14345 */ 14346 legacy: { 14347 /** 14348 * Enable / disable DataTables 1.9 compatible server-side processing 14349 * requests 14350 * 14351 * @type boolean 14352 * @default null 14353 */ 14354 ajax: null 14355 }, 14356 14357 14358 /** 14359 * Pagination plug-in methods. 14360 * 14361 * Each entry in this object is a function and defines which buttons should 14362 * be shown by the pagination rendering method that is used for the table: 14363 * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the 14364 * buttons are displayed in the document, while the functions here tell it 14365 * what buttons to display. This is done by returning an array of button 14366 * descriptions (what each button will do). 14367 * 14368 * Pagination types (the four built in options and any additional plug-in 14369 * options defined here) can be used through the `paginationType` 14370 * initialisation parameter. 14371 * 14372 * The functions defined take two parameters: 14373 * 14374 * 1. `{int} page` The current page index 14375 * 2. `{int} pages` The number of pages in the table 14376 * 14377 * Each function is expected to return an array where each element of the 14378 * array can be one of: 14379 * 14380 * * `first` - Jump to first page when activated 14381 * * `last` - Jump to last page when activated 14382 * * `previous` - Show previous page when activated 14383 * * `next` - Show next page when activated 14384 * * `{int}` - Show page of the index given 14385 * * `{array}` - A nested array containing the above elements to add a 14386 * containing 'DIV' element (might be useful for styling). 14387 * 14388 * Note that DataTables v1.9- used this object slightly differently whereby 14389 * an object with two functions would be defined for each plug-in. That 14390 * ability is still supported by DataTables 1.10+ to provide backwards 14391 * compatibility, but this option of use is now decremented and no longer 14392 * documented in DataTables 1.10+. 14393 * 14394 * @type object 14395 * @default {} 14396 * 14397 * @example 14398 * // Show previous, next and current page buttons only 14399 * $.fn.dataTableExt.oPagination.current = function ( page, pages ) { 14400 * return [ 'previous', page, 'next' ]; 14401 * }; 14402 */ 14403 pager: {}, 14404 14405 14406 renderer: { 14407 pageButton: {}, 14408 header: {} 14409 }, 14410 14411 14412 /** 14413 * Ordering plug-ins - custom data source 14414 * 14415 * The extension options for ordering of data available here is complimentary 14416 * to the default type based ordering that DataTables typically uses. It 14417 * allows much greater control over the the data that is being used to 14418 * order a column, but is necessarily therefore more complex. 14419 * 14420 * This type of ordering is useful if you want to do ordering based on data 14421 * live from the DOM (for example the contents of an 'input' element) rather 14422 * than just the static string that DataTables knows of. 14423 * 14424 * The way these plug-ins work is that you create an array of the values you 14425 * wish to be ordering for the column in question and then return that 14426 * array. The data in the array much be in the index order of the rows in 14427 * the table (not the currently ordering order!). Which order data gathering 14428 * function is run here depends on the `dt-init columns.orderDataType` 14429 * parameter that is used for the column (if any). 14430 * 14431 * The functions defined take two parameters: 14432 * 14433 * 1. `{object}` DataTables settings object: see 14434 * {@link DataTable.models.oSettings} 14435 * 2. `{int}` Target column index 14436 * 14437 * Each function is expected to return an array: 14438 * 14439 * * `{array}` Data for the column to be ordering upon 14440 * 14441 * @type array 14442 * 14443 * @example 14444 * // Ordering using `input` node values 14445 * $.fn.dataTable.ext.order['dom-text'] = function ( settings, col ) 14446 * { 14447 * return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) { 14448 * return $('input', td).val(); 14449 * } ); 14450 * } 14451 */ 14452 order: {}, 14453 14454 14455 /** 14456 * Type based plug-ins. 14457 * 14458 * Each column in DataTables has a type assigned to it, either by automatic 14459 * detection or by direct assignment using the `type` option for the column. 14460 * The type of a column will effect how it is ordering and search (plug-ins 14461 * can also make use of the column type if required). 14462 * 14463 * @namespace 14464 */ 14465 type: { 14466 /** 14467 * Type detection functions. 14468 * 14469 * The functions defined in this object are used to automatically detect 14470 * a column's type, making initialisation of DataTables super easy, even 14471 * when complex data is in the table. 14472 * 14473 * The functions defined take two parameters: 14474 * 14475 * 1. `{*}` Data from the column cell to be analysed 14476 * 2. `{settings}` DataTables settings object. This can be used to 14477 * perform context specific type detection - for example detection 14478 * based on language settings such as using a comma for a decimal 14479 * place. Generally speaking the options from the settings will not 14480 * be required 14481 * 14482 * Each function is expected to return: 14483 * 14484 * * `{string|null}` Data type detected, or null if unknown (and thus 14485 * pass it on to the other type detection functions. 14486 * 14487 * @type array 14488 * 14489 * @example 14490 * // Currency type detection plug-in: 14491 * $.fn.dataTable.ext.type.detect.push( 14492 * function ( data, settings ) { 14493 * // Check the numeric part 14494 * if ( ! data.substring(1).match(/[0-9]/) ) { 14495 * return null; 14496 * } 14497 * 14498 * // Check prefixed by currency 14499 * if ( data.charAt(0) == '$' || data.charAt(0) == '£' ) { 14500 * return 'currency'; 14501 * } 14502 * return null; 14503 * } 14504 * ); 14505 */ 14506 detect: [], 14507 14508 14509 /** 14510 * Type based search formatting. 14511 * 14512 * The type based searching functions can be used to pre-format the 14513 * data to be search on. For example, it can be used to strip HTML 14514 * tags or to de-format telephone numbers for numeric only searching. 14515 * 14516 * Note that is a search is not defined for a column of a given type, 14517 * no search formatting will be performed. 14518 * 14519 * Pre-processing of searching data plug-ins - When you assign the sType 14520 * for a column (or have it automatically detected for you by DataTables 14521 * or a type detection plug-in), you will typically be using this for 14522 * custom sorting, but it can also be used to provide custom searching 14523 * by allowing you to pre-processing the data and returning the data in 14524 * the format that should be searched upon. This is done by adding 14525 * functions this object with a parameter name which matches the sType 14526 * for that target column. This is the corollary of <i>afnSortData</i> 14527 * for searching data. 14528 * 14529 * The functions defined take a single parameter: 14530 * 14531 * 1. `{*}` Data from the column cell to be prepared for searching 14532 * 14533 * Each function is expected to return: 14534 * 14535 * * `{string|null}` Formatted string that will be used for the searching. 14536 * 14537 * @type object 14538 * @default {} 14539 * 14540 * @example 14541 * $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) { 14542 * return d.replace(/\n/g," ").replace( /<.*?>/g, "" ); 14543 * } 14544 */ 14545 search: {}, 14546 14547 14548 /** 14549 * Type based ordering. 14550 * 14551 * The column type tells DataTables what ordering to apply to the table 14552 * when a column is sorted upon. The order for each type that is defined, 14553 * is defined by the functions available in this object. 14554 * 14555 * Each ordering option can be described by three properties added to 14556 * this object: 14557 * 14558 * * `{type}-pre` - Pre-formatting function 14559 * * `{type}-asc` - Ascending order function 14560 * * `{type}-desc` - Descending order function 14561 * 14562 * All three can be used together, only `{type}-pre` or only 14563 * `{type}-asc` and `{type}-desc` together. It is generally recommended 14564 * that only `{type}-pre` is used, as this provides the optimal 14565 * implementation in terms of speed, although the others are provided 14566 * for compatibility with existing Javascript sort functions. 14567 * 14568 * `{type}-pre`: Functions defined take a single parameter: 14569 * 14570 * 1. `{*}` Data from the column cell to be prepared for ordering 14571 * 14572 * And return: 14573 * 14574 * * `{*}` Data to be sorted upon 14575 * 14576 * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort 14577 * functions, taking two parameters: 14578 * 14579 * 1. `{*}` Data to compare to the second parameter 14580 * 2. `{*}` Data to compare to the first parameter 14581 * 14582 * And returning: 14583 * 14584 * * `{*}` Ordering match: <0 if first parameter should be sorted lower 14585 * than the second parameter, ===0 if the two parameters are equal and 14586 * >0 if the first parameter should be sorted height than the second 14587 * parameter. 14588 * 14589 * @type object 14590 * @default {} 14591 * 14592 * @example 14593 * // Numeric ordering of formatted numbers with a pre-formatter 14594 * $.extend( $.fn.dataTable.ext.type.order, { 14595 * "string-pre": function(x) { 14596 * a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" ); 14597 * return parseFloat( a ); 14598 * } 14599 * } ); 14600 * 14601 * @example 14602 * // Case-sensitive string ordering, with no pre-formatting method 14603 * $.extend( $.fn.dataTable.ext.order, { 14604 * "string-case-asc": function(x,y) { 14605 * return ((x < y) ? -1 : ((x > y) ? 1 : 0)); 14606 * }, 14607 * "string-case-desc": function(x,y) { 14608 * return ((x < y) ? 1 : ((x > y) ? -1 : 0)); 14609 * } 14610 * } ); 14611 */ 14612 order: {} 14613 }, 14614 14615 /** 14616 * Unique DataTables instance counter 14617 * 14618 * @type int 14619 * @private 14620 */ 14621 _unique: 0, 14622 14623 14624 // 14625 // Depreciated 14626 // The following properties are retained for backwards compatibility only. 14627 // The should not be used in new projects and will be removed in a future 14628 // version 14629 // 14630 14631 /** 14632 * Version check function. 14633 * @type function 14634 * @depreciated Since 1.10 14635 */ 14636 fnVersionCheck: DataTable.fnVersionCheck, 14637 14638 14639 /** 14640 * Index for what 'this' index API functions should use 14641 * @type int 14642 * @deprecated Since v1.10 14643 */ 14644 iApiIndex: 0, 14645 14646 14647 /** 14648 * jQuery UI class container 14649 * @type object 14650 * @deprecated Since v1.10 14651 */ 14652 oJUIClasses: {}, 14653 14654 14655 /** 14656 * Software version 14657 * @type string 14658 * @deprecated Since v1.10 14659 */ 14660 sVersion: DataTable.version 14661 }; 14662 14663 14664 // 14665 // Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts 14666 // 14667 $.extend( _ext, { 14668 afnFiltering: _ext.search, 14669 aTypes: _ext.type.detect, 14670 ofnSearch: _ext.type.search, 14671 oSort: _ext.type.order, 14672 afnSortData: _ext.order, 14673 aoFeatures: _ext.feature, 14674 oApi: _ext.internal, 14675 oStdClasses: _ext.classes, 14676 oPagination: _ext.pager 14677 } ); 14678 14679 14680 $.extend( DataTable.ext.classes, { 14681 "sTable": "dataTable", 14682 "sNoFooter": "no-footer", 14683 14684 /* Paging buttons */ 14685 "sPageButton": "paginate_button", 14686 "sPageButtonActive": "current", 14687 "sPageButtonDisabled": "disabled", 14688 14689 /* Striping classes */ 14690 "sStripeOdd": "odd", 14691 "sStripeEven": "even", 14692 14693 /* Empty row */ 14694 "sRowEmpty": "dataTables_empty", 14695 14696 /* Features */ 14697 "sWrapper": "dataTables_wrapper", 14698 "sFilter": "dataTables_filter", 14699 "sInfo": "dataTables_info", 14700 "sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */ 14701 "sLength": "dataTables_length", 14702 "sProcessing": "dataTables_processing", 14703 14704 /* Sorting */ 14705 "sSortAsc": "sorting_asc", 14706 "sSortDesc": "sorting_desc", 14707 "sSortable": "sorting", /* Sortable in both directions */ 14708 "sSortableAsc": "sorting_desc_disabled", 14709 "sSortableDesc": "sorting_asc_disabled", 14710 "sSortableNone": "sorting_disabled", 14711 "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */ 14712 14713 /* Filtering */ 14714 "sFilterInput": "", 14715 14716 /* Page length */ 14717 "sLengthSelect": "", 14718 14719 /* Scrolling */ 14720 "sScrollWrapper": "dataTables_scroll", 14721 "sScrollHead": "dataTables_scrollHead", 14722 "sScrollHeadInner": "dataTables_scrollHeadInner", 14723 "sScrollBody": "dataTables_scrollBody", 14724 "sScrollFoot": "dataTables_scrollFoot", 14725 "sScrollFootInner": "dataTables_scrollFootInner", 14726 14727 /* Misc */ 14728 "sHeaderTH": "", 14729 "sFooterTH": "", 14730 14731 // Deprecated 14732 "sSortJUIAsc": "", 14733 "sSortJUIDesc": "", 14734 "sSortJUI": "", 14735 "sSortJUIAscAllowed": "", 14736 "sSortJUIDescAllowed": "", 14737 "sSortJUIWrapper": "", 14738 "sSortIcon": "", 14739 "sJUIHeader": "", 14740 "sJUIFooter": "" 14741 } ); 14742 14743 14744 var extPagination = DataTable.ext.pager; 14745 14746 function _numbers ( page, pages ) { 14747 var 14748 numbers = [], 14749 buttons = extPagination.numbers_length, 14750 half = Math.floor( buttons / 2 ), 14751 i = 1; 14752 14753 if ( pages <= buttons ) { 14754 numbers = _range( 0, pages ); 14755 } 14756 else if ( page <= half ) { 14757 numbers = _range( 0, buttons-2 ); 14758 numbers.push( 'ellipsis' ); 14759 numbers.push( pages-1 ); 14760 } 14761 else if ( page >= pages - 1 - half ) { 14762 numbers = _range( pages-(buttons-2), pages ); 14763 numbers.splice( 0, 0, 'ellipsis' ); // no unshift in ie6 14764 numbers.splice( 0, 0, 0 ); 14765 } 14766 else { 14767 numbers = _range( page-half+2, page+half-1 ); 14768 numbers.push( 'ellipsis' ); 14769 numbers.push( pages-1 ); 14770 numbers.splice( 0, 0, 'ellipsis' ); 14771 numbers.splice( 0, 0, 0 ); 14772 } 14773 14774 numbers.DT_el = 'span'; 14775 return numbers; 14776 } 14777 14778 14779 $.extend( extPagination, { 14780 simple: function ( page, pages ) { 14781 return [ 'previous', 'next' ]; 14782 }, 14783 14784 full: function ( page, pages ) { 14785 return [ 'first', 'previous', 'next', 'last' ]; 14786 }, 14787 14788 numbers: function ( page, pages ) { 14789 return [ _numbers(page, pages) ]; 14790 }, 14791 14792 simple_numbers: function ( page, pages ) { 14793 return [ 'previous', _numbers(page, pages), 'next' ]; 14794 }, 14795 14796 full_numbers: function ( page, pages ) { 14797 return [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ]; 14798 }, 14799 14800 first_last_numbers: function (page, pages) { 14801 return ['first', _numbers(page, pages), 'last']; 14802 }, 14803 14804 // For testing and plug-ins to use 14805 _numbers: _numbers, 14806 14807 // Number of number buttons (including ellipsis) to show. _Must be odd!_ 14808 numbers_length: 7 14809 } ); 14810 14811 14812 $.extend( true, DataTable.ext.renderer, { 14813 pageButton: { 14814 _: function ( settings, host, idx, buttons, page, pages ) { 14815 var classes = settings.oClasses; 14816 var lang = settings.oLanguage.oPaginate; 14817 var aria = settings.oLanguage.oAria.paginate || {}; 14818 var btnDisplay, btnClass; 14819 14820 var attach = function( container, buttons ) { 14821 var i, ien, node, button, tabIndex; 14822 var disabledClass = classes.sPageButtonDisabled; 14823 var clickHandler = function ( e ) { 14824 _fnPageChange( settings, e.data.action, true ); 14825 }; 14826 14827 for ( i=0, ien=buttons.length ; i<ien ; i++ ) { 14828 button = buttons[i]; 14829 14830 if ( Array.isArray( button ) ) { 14831 var inner = $( '<'+(button.DT_el || 'div')+'/>' ) 14832 .appendTo( container ); 14833 attach( inner, button ); 14834 } 14835 else { 14836 btnDisplay = null; 14837 btnClass = button; 14838 tabIndex = settings.iTabIndex; 14839 14840 switch ( button ) { 14841 case 'ellipsis': 14842 container.append('<span class="ellipsis">…</span>'); 14843 break; 14844 14845 case 'first': 14846 btnDisplay = lang.sFirst; 14847 14848 if ( page === 0 ) { 14849 tabIndex = -1; 14850 btnClass += ' ' + disabledClass; 14851 } 14852 break; 14853 14854 case 'previous': 14855 btnDisplay = lang.sPrevious; 14856 14857 if ( page === 0 ) { 14858 tabIndex = -1; 14859 btnClass += ' ' + disabledClass; 14860 } 14861 break; 14862 14863 case 'next': 14864 btnDisplay = lang.sNext; 14865 14866 if ( pages === 0 || page === pages-1 ) { 14867 tabIndex = -1; 14868 btnClass += ' ' + disabledClass; 14869 } 14870 break; 14871 14872 case 'last': 14873 btnDisplay = lang.sLast; 14874 14875 if ( pages === 0 || page === pages-1 ) { 14876 tabIndex = -1; 14877 btnClass += ' ' + disabledClass; 14878 } 14879 break; 14880 14881 default: 14882 btnDisplay = settings.fnFormatNumber( button + 1 ); 14883 btnClass = page === button ? 14884 classes.sPageButtonActive : ''; 14885 break; 14886 } 14887 14888 if ( btnDisplay !== null ) { 14889 var tag = settings.oInit.pagingTag || 'a'; 14890 var disabled = btnClass.indexOf(disabledClass) !== -1; 14891 14892 14893 node = $('<'+tag+'>', { 14894 'class': classes.sPageButton+' '+btnClass, 14895 'aria-controls': settings.sTableId, 14896 'aria-disabled': disabled ? 'true' : null, 14897 'aria-label': aria[ button ], 14898 '
14898aria-role': 'link', 14899 'aria-current': btnClass === classes.sPageButtonActive ? 'page' : null, 14900 'data-dt-idx': button, 14901 'tabindex': tabIndex, 14902 'id': idx === 0 && typeof button === 'string' ? 14903 settings.sTableId +'_'+ button : 14904 null 14905 } ) 14906 .html( btnDisplay ) 14907 .appendTo( container ); 14908 14909 _fnBindAction( 14910 node, {action: button}, clickHandler 14911 ); 14912 } 14913 } 14914 } 14915 }; 14916 14917 // IE9 throws an 'unknown error' if document.activeElement is used 14918 // inside an iframe or frame. Try / catch the error. Not good for 14919 // accessibility, but neither are frames. 14920 var activeEl; 14921
vendor: 2,993 bytes, lines 14922-15032
14922 try { 14923 // Because this approach is destroying and recreating the paging 14924 // elements, focus is lost on the select button which is bad for 14925 // accessibility. So we want to restore focus once the draw has 14926 // completed 14927 activeEl = $(host).find(document.activeElement).data('dt-idx'); 14928 } 14929 catch (e) {} 14930 14931 attach( $(host).empty(), buttons ); 14932 14933 if ( activeEl !== undefined ) { 14934 $(host).find( '[data-dt-idx='+activeEl+']' ).trigger('focus'); 14935 } 14936 } 14937 } 14938 } ); 14939 14940 14941 14942 // Built in type detection. See model.ext.aTypes for information about 14943 // what is required from this methods. 14944 $.extend( DataTable.ext.type.detect, [ 14945 // Plain numbers - first since V8 detects some plain numbers as dates 14946 // e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...). 14947 function ( d, settings ) 14948 { 14949 var decimal = settings.oLanguage.sDecimal; 14950 return _isNumber( d, decimal ) ? 'num'+decimal : null; 14951 }, 14952 14953 // Dates (only those recognised by the browser's Date.parse) 14954 function ( d, settings ) 14955 { 14956 // V8 tries _very_ hard to make a string passed into `Date.parse()` 14957 // valid, so we need to use a regex to restrict date formats. Use a 14958 // plug-in for anything other than ISO8601 style strings 14959 if ( d && !(d instanceof Date) && ! _re_date.test(d) ) { 14960 return null; 14961 } 14962 var parsed = Date.parse(d); 14963 return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null; 14964 }, 14965 14966 // Formatted numbers 14967 function ( d, settings ) 14968 { 14969 var decimal = settings.oLanguage.sDecimal; 14970 return _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null; 14971 }, 14972 14973 // HTML numeric 14974 function ( d, settings ) 14975 { 14976 var decimal = settings.oLanguage.sDecimal; 14977 return _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null; 14978 }, 14979 14980 // HTML numeric, formatted 14981 function ( d, settings ) 14982 { 14983 var decimal = settings.oLanguage.sDecimal; 14984 return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null; 14985 }, 14986 14987 // HTML (this is strict checking - there must be html) 14988 function ( d, settings ) 14989 { 14990 return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ? 14991 'html' : null; 14992 } 14993 ] ); 14994 14995 14996 14997 // Filter formatting functions. See model.ext.ofnSearch for information about 14998 // what is required from these methods. 14999 // 15000 // Note that additional search methods are added for the html numbers and 15001 // html formatted numbers by `_addNumericSort()` when we know what the decimal 15002 // place is 15003 15004 15005 $.extend( DataTable.ext.type.search, { 15006 html: function ( data ) { 15007 return _empty(data) ? 15008 data : 15009 typeof data === 'string' ? 15010 data 15011 .replace( _re_new_lines, " " ) 15012 .replace( _re_html, "" ) : 15013 ''; 15014 }, 15015 15016 string: function ( data ) { 15017 return _empty(data) ? 15018 data : 15019 typeof data === 'string' ? 15020 data.replace( _re_new_lines, " " ) : 15021 data; 15022 } 15023 } ); 15024 15025 15026 15027 var __numericReplace = function ( d, decimalPlace, re1, re2 ) { 15028 if ( d !== 0 && (!d || d === '-') ) { 15029 return -Infinity; 15030 } 15031 15032 let
vendor: 9,520 bytes, lines 15032-15406
15032 type = typeof d; 15033 15034 if (type === 'number' || type === 'bigint') { 15035 return d; 15036 } 15037 15038 // If a decimal place other than `.` is used, it needs to be given to the 15039 // function so we can detect it and replace with a `.` which is the only 15040 // decimal place Javascript recognises - it is not locale aware. 15041 if ( decimalPlace ) { 15042 d = _numToDecimal( d, decimalPlace ); 15043 } 15044 15045 if ( d.replace ) { 15046 if ( re1 ) { 15047 d = d.replace( re1, '' ); 15048 } 15049 15050 if ( re2 ) { 15051 d = d.replace( re2, '' ); 15052 } 15053 } 15054 15055 return d * 1; 15056 }; 15057 15058 15059 // Add the numeric 'deformatting' functions for sorting and search. This is done 15060 // in a function to provide an easy ability for the language options to add 15061 // additional methods if a non-period decimal place is used. 15062 function _addNumericSort ( decimalPlace ) { 15063 $.each( 15064 { 15065 // Plain numbers 15066 "num": function ( d ) { 15067 return __numericReplace( d, decimalPlace ); 15068 }, 15069 15070 // Formatted numbers 15071 "num-fmt": function ( d ) { 15072 return __numericReplace( d, decimalPlace, _re_formatted_numeric ); 15073 }, 15074 15075 // HTML numeric 15076 "html-num": function ( d ) { 15077 return __numericReplace( d, decimalPlace, _re_html ); 15078 }, 15079 15080 // HTML numeric, formatted 15081 "html-num-fmt": function ( d ) { 15082 return __numericReplace( d, decimalPlace, _re_html, _re_formatted_numeric ); 15083 } 15084 }, 15085 function ( key, fn ) { 15086 // Add the ordering method 15087 _ext.type.order[ key+decimalPlace+'-pre' ] = fn; 15088 15089 // For HTML types add a search formatter that will strip the HTML 15090 if ( key.match(/^html\-/) ) { 15091 _ext.type.search[ key+decimalPlace ] = _ext.type.search.html; 15092 } 15093 } 15094 ); 15095 } 15096 15097 15098 // Default sort methods 15099 $.extend( _ext.type.order, { 15100 // Dates 15101 "date-pre": function ( d ) { 15102 var ts = Date.parse( d ); 15103 return isNaN(ts) ? -Infinity : ts; 15104 }, 15105 15106 // html 15107 "html-pre": function ( a ) { 15108 return _empty(a) ? 15109 '' : 15110 a.replace ? 15111 a.replace( /<.*?>/g, "" ).toLowerCase() : 15112 a+''; 15113 }, 15114 15115 // string 15116 "string-pre": function ( a ) { 15117 // This is a little complex, but faster than always calling toString, 15118 // http://jsperf.com/tostring-v-check 15119 return _empty(a) ? 15120 '' : 15121 typeof a === 'string' ? 15122 a.toLowerCase() : 15123 ! a.toString ? 15124 '' : 15125 a.toString(); 15126 }, 15127 15128 // string-asc and -desc are retained only for compatibility with the old 15129 // sort methods 15130 "string-asc": function ( x, y ) { 15131 return ((x < y) ? -1 : ((x > y) ? 1 : 0)); 15132 }, 15133 15134 "string-desc": function ( x, y ) { 15135 return ((x < y) ? 1 : ((x > y) ? -1 : 0)); 15136 } 15137 } ); 15138 15139 15140 // Numeric sorting types - order doesn't matter here 15141 _addNumericSort( '' ); 15142 15143 15144 $.extend( true, DataTable.ext.renderer, { 15145 header: { 15146 _: function ( settings, cell, column, classes ) { 15147 // No additional mark-up required 15148 // Attach a sort listener to update on sort - note that using the 15149 // `DT` namespace will allow the event to be removed automatically 15150 // on destroy, while the `dt` namespaced event is the one we are 15151 // listening for 15152 $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) { 15153 if ( settings !== ctx ) { // need to check this this is the host 15154 return; // table, not a nested one 15155 } 15156 15157 var colIdx = column.idx; 15158 15159 cell 15160 .removeClass( 15161 classes.sSortAsc +' '+ 15162 classes.sSortDesc 15163 ) 15164 .addClass( columns[ colIdx ] == 'asc' ? 15165 classes.sSortAsc : columns[ colIdx ] == 'desc' ? 15166 classes.sSortDesc : 15167 column.sSortingClass 15168 ); 15169 } ); 15170 }, 15171 15172 jqueryui: function ( settings, cell, column, classes ) { 15173 $('<div/>') 15174 .addClass( classes.sSortJUIWrapper ) 15175 .append( cell.contents() ) 15176 .append( $('<span/>') 15177 .addClass( classes.sSortIcon+' '+column.sSortingClassJUI ) 15178 ) 15179 .appendTo( cell ); 15180 15181 // Attach a sort listener to update on sort 15182 $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) { 15183 if ( settings !== ctx ) { 15184 return; 15185 } 15186 15187 var colIdx = column.idx; 15188 15189 cell 15190 .removeClass( classes.sSortAsc +" "+classes.sSortDesc ) 15191 .addClass( columns[ colIdx ] == 'asc' ? 15192 classes.sSortAsc : columns[ colIdx ] == 'desc' ? 15193 classes.sSortDesc : 15194 column.sSortingClass 15195 ); 15196 15197 cell 15198 .find( 'span.'+classes.sSortIcon ) 15199 .removeClass( 15200 classes.sSortJUIAsc +" "+ 15201 classes.sSortJUIDesc +" "+ 15202 classes.sSortJUI +" "+ 15203 classes.sSortJUIAscAllowed +" "+ 15204 classes.sSortJUIDescAllowed 15205 ) 15206 .addClass( columns[ colIdx ] == 'asc' ? 15207 classes.sSortJUIAsc : columns[ colIdx ] == 'desc' ? 15208 classes.sSortJUIDesc : 15209 column.sSortingClassJUI 15210 ); 15211 } ); 15212 } 15213 } 15214 } ); 15215 15216 /* 15217 * Public helper functions. These aren't used internally by DataTables, or 15218 * called by any of the options passed into DataTables, but they can be used 15219 * externally by developers working with DataTables. They are helper functions 15220 * to make working with DataTables a little bit easier. 15221 */ 15222 15223 var __htmlEscapeEntities = function ( d ) { 15224 if (Array.isArray(d)) { 15225 d = d.join(','); 15226 } 15227 15228 return typeof d === 'string' ? 15229 d 15230 .replace(/&/g, '&') 15231 .replace(/</g, '<') 15232 .replace(/>/g, '>') 15233 .replace(/"/g, '"') : 15234 d; 15235 }; 15236 15237 // Common logic for moment, luxon or a date action 15238 function __mld( dt, momentFn, luxonFn, dateFn, arg1 ) { 15239 if (window.moment) { 15240 return dt[momentFn]( arg1 ); 15241 } 15242 else if (window.luxon) { 15243 return dt[luxonFn]( arg1 ); 15244 } 15245 15246 return dateFn ? dt[dateFn]( arg1 ) : dt; 15247 } 15248 15249 15250 var __mlWarning = false; 15251 function __mldObj (d, format, locale) { 15252 var dt; 15253 15254 if (window.moment) { 15255 dt = window.moment.utc( d, format, locale, true ); 15256 15257 if (! dt.isValid()) { 15258 return null; 15259 } 15260 } 15261 else if (window.luxon) { 15262 dt = format && typeof d === 'string' 15263 ? window.luxon.DateTime.fromFormat( d, format ) 15264 : window.luxon.DateTime.fromISO( d ); 15265 15266 if (! dt.isValid) { 15267 return null; 15268 } 15269 15270 dt.setLocale(locale); 15271 } 15272 else if (! format) { 15273 // No format given, must be ISO 15274 dt = new Date(d); 15275 } 15276 else { 15277 if (! __mlWarning) { 15278 alert('DataTables warning: Formatted date without Moment.js or Luxon - https://datatables.net/tn/17'); 15279 } 15280 15281 __mlWarning = true; 15282 } 15283 15284 return dt; 15285 } 15286 15287 // Wrapper for date, datetime and time which all operate the same way with the exception of 15288 // the output string for auto locale support 15289 function __mlHelper (localeString) { 15290 return function ( from, to, locale, def ) { 15291 // Luxon and Moment support 15292 // Argument shifting 15293 if ( arguments.length === 0 ) { 15294 locale = 'en'; 15295 to = null; // means toLocaleString 15296 from = null; // means iso8601 15297 } 15298 else if ( arguments.length === 1 ) { 15299 locale = 'en'; 15300 to = from; 15301 from = null; 15302 } 15303 else if ( arguments.length === 2 ) { 15304 locale = to; 15305 to = from; 15306 from = null; 15307 } 15308 15309 var typeName = 'datetime-' + to; 15310 15311 // Add type detection and sorting specific to this date format - we need to be able to identify 15312 // date type columns as such, rather than as numbers in extensions. Hence the need for this. 15313 if (! DataTable.ext.type.order[typeName]) { 15314 // The renderer will give the value to type detect as the type! 15315 DataTable.ext.type.detect.unshift(function (d) { 15316 return d === typeName ? typeName : false; 15317 }); 15318 15319 // The renderer gives us Moment, Luxon or Date obects for the sorting, all of which have a 15320 // `valueOf` which gives milliseconds epoch 15321 DataTable.ext.type.order[typeName + '-asc'] = function (a, b) { 15322 var x = a.valueOf(); 15323 var y = b.valueOf(); 15324 15325 return x === y 15326 ? 0 15327 : x < y 15328 ? -1 15329 : 1; 15330 } 15331 15332 DataTable.ext.type.order[typeName + '-desc'] = function (a, b) { 15333 var x = a.valueOf(); 15334 var y = b.valueOf(); 15335 15336 return x === y 15337 ? 0 15338 : x > y 15339 ? -1 15340 : 1; 15341 } 15342 } 15343 15344 return function ( d, type ) { 15345 // Allow for a default value 15346 if (d === null || d === undefined) { 15347 if (def === '--now') { 15348 // We treat everything as UTC further down, so no changes are 15349 // made, as such need to get the local date / time as if it were 15350 // UTC 15351 var local = new Date(); 15352 d = new Date( Date.UTC( 15353 local.getFullYear(), local.getMonth(), local.getDate(), 15354 local.getHours(), local.getMinutes(), local.getSeconds() 15355 ) ); 15356 } 15357 else { 15358 d = ''; 15359 } 15360 } 15361 15362 if (type === 'type') { 15363 // Typing uses the type name for fast matching 15364 return typeName; 15365 } 15366 15367 if (d === '') { 15368 return type !== 'sort' 15369 ? '' 15370 : __mldObj('0000-01-01 00:00:00', null, locale); 15371 } 15372 15373 // Shortcut. If `from` and `to` are the same, we are using the renderer to 15374 // format for ordering, not display - its already in the display format. 15375 if ( to !== null && from === to && type !== 'sort' && type !== 'type' && ! (d instanceof Date) ) { 15376 return d; 15377 } 15378 15379 var dt = __mldObj(d, from, locale); 15380 15381 if (dt === null) { 15382 return d; 15383 } 15384 15385 if (type === 'sort') { 15386 return dt; 15387 } 15388 15389 var formatted = to === null 15390 ? __mld(dt, 'toDate', 'toJSDate', '')[localeString]() 15391 : __mld(dt, 'format', 'toFormat', 'toISOString', to); 15392 15393 // XSS protection 15394 return type === 'display' ? 15395 __htmlEscapeEntities( formatted ) : 15396 formatted; 15397 }; 15398 } 15399 } 15400 15401 // Based on locale, determine standard number formatting 15402 // Fallback for legacy browsers is US English 15403 var __thousands = ','; 15404 var __decimal = '.'; 15405 15406 if (
vendor: 8,417 bytes, lines 15406-15686
15406Intl) { 15407 try { 15408 var num = new Intl.NumberFormat().formatToParts(100000.1); 15409 15410 for (var i=0 ; i<num.length ; i++) { 15411 if (num[i].type === 'group') { 15412 __thousands = num[i].value; 15413 } 15414 else if (num[i].type === 'decimal') { 15415 __decimal = num[i].value; 15416 } 15417 } 15418 } 15419 catch (e) { 15420 // noop 15421 } 15422 } 15423 15424 // Formatted date time detection - use by declaring the formats you are going to use 15425 DataTable.datetime = function ( format, locale ) { 15426 var typeName = 'datetime-detect-' + format; 15427 15428 if (! locale) { 15429 locale = 'en'; 15430 } 15431 15432 if (! DataTable.ext.type.order[typeName]) { 15433 DataTable.ext.type.detect.unshift(function (d) { 15434 var dt = __mldObj(d, format, locale); 15435 return d === '' || dt ? typeName : false; 15436 }); 15437 15438 DataTable.ext.type.order[typeName + '-pre'] = function (d) { 15439 return __mldObj(d, format, locale) || 0; 15440 } 15441 } 15442 } 15443 15444 /** 15445 * Helpers for `columns.render`. 15446 * 15447 * The options defined here can be used with the `columns.render` initialisation 15448 * option to provide a display renderer. The following functions are defined: 15449 * 15450 * * `number` - Will format numeric data (defined by `columns.data`) for 15451 * display, retaining the original unformatted data for sorting and filtering. 15452 * It takes 5 parameters: 15453 * * `string` - Thousands grouping separator 15454 * * `string` - Decimal point indicator 15455 * * `integer` - Number of decimal points to show 15456 * * `string` (optional) - Prefix. 15457 * * `string` (optional) - Postfix (/suffix). 15458 * * `text` - Escape HTML to help prevent XSS attacks. It has no optional 15459 * parameters. 15460 * 15461 * @example 15462 * // Column definition using the number renderer 15463 * { 15464 * data: "salary", 15465 * render: $.fn.dataTable.render.number( '\'', '.', 0, '$' ) 15466 * } 15467 * 15468 * @namespace 15469 */ 15470 DataTable.render = { 15471 date: __mlHelper('toLocaleDateString'), 15472 datetime: __mlHelper('toLocaleString'), 15473 time: __mlHelper('toLocaleTimeString'), 15474 number: function ( thousands, decimal, precision, prefix, postfix ) { 15475 // Auto locale detection 15476 if (thousands === null || thousands === undefined) { 15477 thousands = __thousands; 15478 } 15479 15480 if (decimal === null || decimal === undefined) { 15481 decimal = __decimal; 15482 } 15483 15484 return { 15485 display: function ( d ) { 15486 if ( typeof d !== 'number' && typeof d !== 'string' ) { 15487 return d; 15488 } 15489 15490 if (d === '' || d === null) { 15491 return d; 15492 } 15493 15494 var negative = d < 0 ? '-' : ''; 15495 var flo = parseFloat( d ); 15496 15497 // If NaN then there isn't much formatting that we can do - just 15498 // return immediately, escaping any HTML (this was supposed to 15499 // be a number after all) 15500 if ( isNaN( flo ) ) { 15501 return __htmlEscapeEntities( d ); 15502 } 15503 15504 flo = flo.toFixed( precision ); 15505 d = Math.abs( flo ); 15506 15507 var intPart = parseInt( d, 10 ); 15508 var floatPart = precision ? 15509 decimal+(d - intPart).toFixed( precision ).substring( 2 ): 15510 ''; 15511 15512 // If zero, then can't have a negative prefix 15513 if (intPart === 0 && parseFloat(floatPart) === 0) { 15514 negative = ''; 15515 } 15516 15517 return negative + (prefix||'') + 15518 intPart.toString().replace( 15519 /\B(?=(\d{3})+(?!\d))/g, thousands 15520 ) + 15521 floatPart + 15522 (postfix||''); 15523 } 15524 }; 15525 }, 15526 15527 text: function () { 15528 return { 15529 display: __htmlEscapeEntities, 15530 filter: __htmlEscapeEntities 15531 }; 15532 } 15533 }; 15534 15535 15536 /* 15537 * This is really a good bit rubbish this method of exposing the internal methods 15538 * publicly... - To be fixed in 2.0 using methods on the prototype 15539 */ 15540 15541 15542 /** 15543 * Create a wrapper function for exporting an internal functions to an external API. 15544 * @param {string} fn API function name 15545 * @returns {function} wrapped function 15546 * @memberof DataTable#internal 15547 */ 15548 function _fnExternApiFunc (fn) 15549 { 15550 return function() { 15551 var args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat( 15552 Array.prototype.slice.call(arguments) 15553 ); 15554 return DataTable.ext.internal[fn].apply( this, args ); 15555 }; 15556 } 15557 15558 15559 /** 15560 * Reference to internal functions for use by plug-in developers. Note that 15561 * these methods are references to internal functions and are considered to be 15562 * private. If you use these methods, be aware that they are liable to change 15563 * between versions. 15564 * @namespace 15565 */ 15566 $.extend( DataTable.ext.internal, { 15567 _fnExternApiFunc: _fnExternApiFunc, 15568 _fnBuildAjax: _fnBuildAjax, 15569 _fnAjaxUpdate: _fnAjaxUpdate, 15570 _fnAjaxParameters: _fnAjaxParameters, 15571 _fnAjaxUpdateDraw: _fnAjaxUpdateDraw, 15572 _fnAjaxDataSrc: _fnAjaxDataSrc, 15573 _fnAddColumn: _fnAddColumn, 15574 _fnColumnOptions: _fnColumnOptions, 15575 _fnAdjustColumnSizing: _fnAdjustColumnSizing, 15576 _fnVisibleToColumnIndex: _fnVisibleToColumnIndex, 15577 _fnColumnIndexToVisible: _fnColumnIndexToVisible, 15578 _fnVisbleColumns: _fnVisbleColumns, 15579 _fnGetColumns: _fnGetColumns, 15580 _fnColumnTypes: _fnColumnTypes, 15581 _fnApplyColumnDefs: _fnApplyColumnDefs, 15582 _fnHungarianMap: _fnHungarianMap, 15583 _fnCamelToHungarian: _fnCamelToHungarian, 15584 _fnLanguageCompat: _fnLanguageCompat, 15585 _fnBrowserDetect: _fnBrowserDetect, 15586 _fnAddData: _fnAddData, 15587 _fnAddTr: _fnAddTr, 15588 _fnNodeToDataIndex: _fnNodeToDataIndex, 15589 _fnNodeToColumnIndex: _fnNodeToColumnIndex, 15590 _fnGetCellData: _fnGetCellData, 15591 _fnSetCellData: _fnSetCellData, 15592 _fnSplitObjNotation: _fnSplitObjNotation, 15593 _fnGetObjectDataFn: _fnGetObjectDataFn, 15594 _fnSetObjectDataFn: _fnSetObjectDataFn, 15595 _fnGetDataMaster: _fnGetDataMaster, 15596 _fnClearTable: _fnClearTable, 15597 _fnDeleteIndex: _fnDeleteIndex, 15598 _fnInvalidate: _fnInvalidate, 15599 _fnGetRowElements: _fnGetRowElements, 15600 _fnCreateTr: _fnCreateTr, 15601 _fnBuildHead: _fnBuildHead, 15602 _fnDrawHead: _fnDrawHead, 15603 _fnDraw: _fnDraw, 15604 _fnReDraw: _fnReDraw, 15605 _fnAddOptionsHtml: _fnAddOptionsHtml, 15606 _fnDetectHeader: _fnDetectHeader, 15607 _fnGetUniqueThs: _fnGetUniqueThs, 15608 _fnFeatureHtmlFilter: _fnFeatureHtmlFilter, 15609 _fnFilterComplete: _fnFilterComplete, 15610 _fnFilterCustom: _fnFilterCustom, 15611 _fnFilterColumn: _fnFilterColumn, 15612 _fnFilter: _fnFilter, 15613 _fnFilterCreateSearch: _fnFilterCreateSearch, 15614 _fnEscapeRegex: _fnEscapeRegex, 15615 _fnFilterData: _fnFilterData, 15616 _fnFeatureHtmlInfo: _fnFeatureHtmlInfo, 15617 _fnUpdateInfo: _fnUpdateInfo, 15618 _fnInfoMacros: _fnInfoMacros, 15619 _fnInitialise: _fnInitialise, 15620 _fnInitComplete: _fnInitComplete, 15621 _fnLengthChange: _fnLengthChange, 15622 _fnFeatureHtmlLength: _fnFeatureHtmlLength, 15623 _fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate, 15624 _fnPageChange: _fnPageChange, 15625 _fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing, 15626 _fnProcessingDisplay: _fnProcessingDisplay, 15627 _fnFeatureHtmlTable: _fnFeatureHtmlTable, 15628 _fnScrollDraw: _fnScrollDraw, 15629 _fnApplyToChildren: _fnApplyToChildren, 15630 _fnCalculateColumnWidths: _fnCalculateColumnWidths, 15631 _fnThrottle: _fnThrottle, 15632 _fnConvertToWidth: _fnConvertToWidth, 15633 _fnGetWidestNode: _fnGetWidestNode, 15634 _fnGetMaxLenString: _fnGetMaxLenString, 15635 _fnStringToCss: _fnStringToCss, 15636 _fnSortFlatten: _fnSortFlatten, 15637 _fnSort: _fnSort, 15638 _fnSortAria: _fnSortAria, 15639 _fnSortListener: _fnSortListener, 15640 _fnSortAttachListener: _fnSortAttachListener, 15641 _fnSortingClasses: _fnSortingClasses, 15642 _fnSortData: _fnSortData, 15643 _fnSaveState: _fnSaveState, 15644 _fnLoadState: _fnLoadState, 15645 _fnImplementState: _fnImplementState, 15646 _fnSettingsFromNode: _fnSettingsFromNode, 15647 _fnLog: _fnLog, 15648 _fnMap: _fnMap, 15649 _fnBindAction: _fnBindAction, 15650 _fnCallbackReg: _fnCallbackReg, 15651 _fnCallbackFire: _fnCallbackFire, 15652 _fnLengthOverflow: _fnLengthOverflow, 15653 _fnRenderer: _fnRenderer, 15654 _fnDataSource: _fnDataSource, 15655 _fnRowAttributes: _fnRowAttributes, 15656 _fnExtend: _fnExtend, 15657 _fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant 15658 // in 1.10, so this dead-end function is 15659 // added to prevent errors 15660 } ); 15661 15662 15663 // jQuery access 15664 $.fn.dataTable = DataTable; 15665 15666 // Provide access to the host jQuery object (circular reference) 15667 DataTable.$ = $; 15668 15669 // Legacy aliases 15670 $.fn.dataTableSettings = DataTable.settings; 15671 $.fn.dataTableExt = DataTable.ext; 15672 15673 // With a capital `D` we return a DataTables API instance rather than a 15674 // jQuery object 15675 $.fn.DataTable = function ( opts ) { 15676 return $(this).dataTable( opts ).api(); 15677 }; 15678 15679 // All properties that are available to $.fn.dataTable should also be 15680 // available on $.fn.DataTable 15681 $.each( DataTable, function ( prop, val ) { 15682 $.fn.DataTable[ prop ] = val; 15683 } ); 15684 15685 return DataTable; 15686}));
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.