1/*! DataTables 1.13.11 2 * ©2008-2024 SpryMedia Ltd - datatables.net/license 3 */ 4 5/** 6 * @summary DataTables 7 * @description Paginate, search and order HTML tables 8 * @version 1.13.11 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 - https://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: https://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 module.exports =
vendor: 41,972 bytes, lines 57-1348
57 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
1348s
vendor: 27,673 bytes, lines 1348-2347
1348://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 var 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 1522 .replace( _re_html, '' ) // Complete tags 1523 .replace(/<script/i, ''); // Safety for incomplete script tag 1524 }; 1525 1526 1527 /** 1528 * Determine if all values in the array are unique. This means we can short 1529 * cut the _unique method at the cost of a single loop. A sorted array is used 1530 * to easily check the values. 1531 * 1532 * @param {array} src Source array 1533 * @return {boolean} true if all unique, false otherwise 1534 * @ignore 1535 */ 1536 var _areAllUnique = function ( src ) { 1537 if ( src.length < 2 ) { 1538 return true; 1539 } 1540 1541 var sorted = src.slice().sort(); 1542 var last = sorted[0]; 1543 1544 for ( var i=1, ien=sorted.length ; i<ien ; i++ ) { 1545 if ( sorted[i] === last ) { 1546 return false; 1547 } 1548 1549 last = sorted[i]; 1550 } 1551 1552 return true; 1553 }; 1554 1555 1556 /** 1557 * Find the unique elements in a source array. 1558 * 1559 * @param {array} src Source array 1560 * @return {array} Array of unique items 1561 * @ignore 1562 */ 1563 var _unique = function ( src ) 1564 { 1565 if ( _areAllUnique( src ) ) { 1566 return src.slice(); 1567 } 1568 1569 // A faster unique method is to use object keys to identify used values, 1570 // but this doesn't work with arrays or objects, which we must also 1571 // consider. See jsperf.com/compare-array-unique-versions/4 for more 1572 // information. 1573 var 1574 out = [], 1575 val, 1576 i, ien=src.length, 1577 j, k=0; 1578 1579 again: for ( i=0 ; i<ien ; i++ ) { 1580 val = src[i]; 1581 1582 for ( j=0 ; j<k ; j++ ) { 1583 if ( out[j] === val ) { 1584 continue again; 1585 } 1586 } 1587 1588 out.push( val ); 1589 k++; 1590 } 1591 1592 return out; 1593 }; 1594 1595 // Surprisingly this is faster than [].concat.apply 1596 // https://jsperf.com/flatten-an-array-loop-vs-reduce/2 1597 var _flatten = function (out, val) { 1598 if (Array.isArray(val)) { 1599 for (var i=0 ; i<val.length ; i++) { 1600 _flatten(out, val[i]); 1601 } 1602 } 1603 else { 1604 out.push(val); 1605 } 1606 1607 return out; 1608 } 1609 1610 var _includes = function (search, start) { 1611 if (start === undefined) { 1612 start = 0; 1613 } 1614 1615 return this.indexOf(search, start) !== -1; 1616 }; 1617 1618 // Array.isArray polyfill. 1619 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray 1620 if (! Array.isArray) { 1621 Array.isArray = function(arg) { 1622 return Object.prototype.toString.call(arg) === '[object Array]'; 1623 }; 1624 } 1625 1626 if (! Array.prototype.includes) { 1627 Array.prototype.includes = _includes; 1628 } 1629 1630 // .trim() polyfill 1631 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/trim 1632 if (!String.prototype.trim) { 1633 String.prototype.trim = function () { 1634 return this.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ''); 1635 }; 1636 } 1637 1638 if (! String.prototype.includes) { 1639 String.prototype.includes = _includes; 1640 } 1641 1642 /** 1643 * DataTables utility methods 1644 * 1645 * This namespace provides helper methods that DataTables uses internally to 1646 * create a DataTable, but which are not exclusively used only for DataTables. 1647 * These methods can be used by extension authors to save the duplication of 1648 * code. 1649 * 1650 * @namespace 1651 */ 1652 DataTable.util = { 1653 /** 1654 * Throttle the calls to a function. Arguments and context are maintained 1655 * for the throttled function. 1656 * 1657 * @param {function} fn Function to be called 1658 * @param {integer} freq Call frequency in mS 1659 * @return {function} Wrapped function 1660 */ 1661 throttle: function ( fn, freq ) { 1662 var 1663 frequency = freq !== undefined ? freq : 200, 1664 last, 1665 timer; 1666 1667 return function () { 1668 var 1669 that = this, 1670 now = +new Date(), 1671 args = arguments; 1672 1673 if ( last && now < last + frequency ) { 1674 clearTimeout( timer ); 1675 1676 timer = setTimeout( function () { 1677 last = undefined; 1678 fn.apply( that, args ); 1679 }, frequency ); 1680 } 1681 else { 1682 last = now; 1683 fn.apply( that, args ); 1684 } 1685 }; 1686 }, 1687 1688 1689 /** 1690 * Escape a string such that it can be used in a regular expression 1691 * 1692 * @param {string} val string to escape 1693 * @returns {string} escaped string 1694 */ 1695 escapeRegex: function ( val ) { 1696 return val.replace( _re_escape_regex, '\\$1' ); 1697 }, 1698 1699 /** 1700 * Create a function that will write to a nested object or array 1701 * @param {*} source JSON notation string 1702 * @returns Write function 1703 */ 1704 set: function ( source ) { 1705 if ( $.isPlainObject( source ) ) { 1706 /* Unlike get, only the underscore (global) option is used for for 1707 * setting data since we don't know the type here. This is why an object 1708 * option is not documented for `mData` (which is read/write), but it is 1709 * for `mRender` which is read only. 1710 */ 1711 return DataTable.util.set( source._ ); 1712 } 1713 else if ( source === null ) { 1714 // Nothing to do when the data source is null 1715 return function () {}; 1716 } 1717 else if ( typeof source === 'function' ) { 1718 return function (data, val, meta) { 1719 source( data, 'set', val, meta ); 1720 }; 1721 } 1722 else if ( typeof source === 'string' && (source.indexOf('.') !== -1 || 1723 source.indexOf('[') !== -1 || source.indexOf('(') !== -1) ) 1724 { 1725 // Like the get, we need to get data from a nested object 1726 var setData = function (data, val, src) { 1727 var a = _fnSplitObjNotation( src ), b; 1728 var aLast = a[a.length-1]; 1729 var arrayNotation, funcNotation, o, innerSrc; 1730 1731 for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ ) { 1732 // Protect against prototype pollution 1733 if (a[i] === '__proto__' || a[i] === 'constructor') { 1734 throw new Error('Cannot set prototype values'); 1735 } 1736 1737 // Check if we are dealing with an array notation request 1738 arrayNotation = a[i].match(__reArray); 1739 funcNotation = a[i].match(__reFn); 1740 1741 if ( arrayNotation ) { 1742 a[i] = a[i].replace(__reArray, ''); 1743 data[ a[i] ] = []; 1744 1745 // Get the remainder of the nested object to set so we can recurse 1746 b = a.slice(); 1747 b.splice( 0, i+1 ); 1748 innerSrc = b.join('.'); 1749 1750 // Traverse each entry in the array setting the properties requested 1751 if ( Array.isArray( val ) ) { 1752 for ( var j=0, jLen=val.length ; j<jLen ; j++ ) { 1753 o = {}; 1754 setData( o, val[j], innerSrc ); 1755 data[ a[i] ].push( o ); 1756 } 1757 } 1758 else { 1759 // We've been asked to save data to an array, but it 1760 // isn't array data to be saved. Best that can be done 1761 // is to just save the value. 1762 data[ a[i] ] = val; 1763 } 1764 1765 // The inner call to setData has already traversed through the remainder 1766 // of the source and has set the data, thus we can exit here 1767 return; 1768 } 1769 else if ( funcNotation ) { 1770 // Function call 1771 a[i] = a[i].replace(__reFn, ''); 1772 data = data[ a[i] ]( val ); 1773 } 1774 1775 // If the nested object doesn't currently exist - since we are 1776 // trying to set the value - create it 1777 if ( data[ a[i] ] === null || data[ a[i] ] === undefined ) { 1778 data[ a[i] ] = {}; 1779 } 1780 data = data[ a[i] ]; 1781 } 1782 1783 // Last item in the input - i.e, the actual set 1784 if ( aLast.match(__reFn ) ) { 1785 // Function call 1786 data = data[ aLast.replace(__reFn, '') ]( val ); 1787 } 1788 else { 1789 // If array notation is used, we just want to strip it and use the property name 1790 // and assign the value. If it isn't used, then we get the result we want anyway 1791 data[ aLast.replace(__reArray, '') ] = val; 1792 } 1793 }; 1794 1795 return function (data, val) { // meta is also passed in, but not used 1796 return setData( data, val, source ); 1797 }; 1798 } 1799 else { 1800 // Array or flat object mapping 1801 return function (data, val) { // meta is also passed in, but not used 1802 data[source] = val; 1803 }; 1804 } 1805 }, 1806 1807 /** 1808 * Create a function that will read nested objects from arrays, based on JSON notation 1809 * @param {*} source JSON notation string 1810 * @returns Value read 1811 */ 1812 get: function ( source ) { 1813 if ( $.isPlainObject( source ) ) { 1814 // Build an object of get functions, and wrap them in a single call 1815 var o = {}; 1816 $.each( source, function (key, val) { 1817 if ( val ) { 1818 o[key] = DataTable.util.get( val ); 1819 } 1820 } ); 1821 1822 return function (data, type, row, meta) { 1823 var t = o[type] || o._; 1824 return t !== undefined ? 1825 t(data, type, row, meta) : 1826 data; 1827 }; 1828 } 1829 else if ( source === null ) { 1830 // Give an empty string for rendering / sorting etc 1831 return function (data) { // type, row and meta also passed, but not used 1832 return data; 1833 }; 1834 } 1835 else if ( typeof source === 'function' ) { 1836 return function (data, type, row, meta) { 1837 return source( data, type, row, meta ); 1838 }; 1839 } 1840 else if ( typeof source === 'string' && (source.indexOf('.') !== -1 || 1841 source.indexOf('[') !== -1 || source.indexOf('(') !== -1) ) 1842 { 1843 /* If there is a . in the source string then the data source is in a 1844 * nested object so we loop over the data for each level to get the next 1845 * level down. On each loop we test for undefined, and if found immediately 1846 * return. This allows entire objects to be missing and sDefaultContent to 1847 * be used if defined, rather than throwing an error 1848 */ 1849 var fetchData = function (data, type, src) { 1850 var arrayNotation, funcNotation, out, innerSrc; 1851 1852 if ( src !== "" ) { 1853 var a = _fnSplitObjNotation( src ); 1854 1855 for ( var i=0, iLen=a.length ; i<iLen ; i++ ) { 1856 // Check if we are dealing with special notation 1857 arrayNotation = a[i].match(__reArray); 1858 funcNotation = a[i].match(__reFn); 1859 1860 if ( arrayNotation ) { 1861 // Array notation 1862 a[i] = a[i].replace(__reArray, ''); 1863 1864 // Condition allows simply [] to be passed in 1865 if ( a[i] !== "" ) { 1866 data = data[ a[i] ]; 1867 } 1868 out = []; 1869 1870 // Get the remainder of the nested object to get 1871 a.splice( 0, i+1 ); 1872 innerSrc = a.join('.'); 1873 1874 // Traverse each entry in the array getting the properties requested 1875 if ( Array.isArray( data ) ) { 1876 for ( var j=0, jLen=data.length ; j<jLen ; j++ ) { 1877 out.push( fetchData( data[j], type, innerSrc ) ); 1878 } 1879 } 1880 1881 // If a string is given in between the array notation indicators, that 1882 // is used to join the strings together, otherwise an array is returned 1883 var join = arrayNotation[0].substring(1, arrayNotation[0].length-1); 1884 data = (join==="") ? out : out.join(join); 1885 1886 // The inner call to fetchData has already traversed through the remainder 1887 // of the source requested, so we exit from the loop 1888 break; 1889 } 1890 else if ( funcNotation ) { 1891 // Function call 1892 a[i] = a[i].replace(__reFn, ''); 1893 data = data[ a[i] ](); 1894 continue; 1895 } 1896 1897 if (data === null || data[ a[i] ] === null) { 1898 return null; 1899 } 1900 else if ( data === undefined || data[ a[i] ] === undefined ) { 1901 return undefined; 1902 } 1903 1904 data = data[ a[i] ]; 1905 } 1906 } 1907 1908 return data; 1909 }; 1910 1911 return function (data, type) { // row and meta also passed, but not used 1912 return fetchData( data, type, source ); 1913 }; 1914 } 1915 else { 1916 // Array or flat object mapping 1917 return function (data, type) { // row and meta also passed, but not used 1918 return data[source]; 1919 }; 1920 } 1921 } 1922 }; 1923 1924 1925 1926 /** 1927 * Create a mapping object that allows camel case parameters to be looked up 1928 * for their Hungarian counterparts. The mapping is stored in a private 1929 * parameter called `_hungarianMap` which can be accessed on the source object. 1930 * @param {object} o 1931 * @memberof DataTable#oApi 1932 */ 1933 function _fnHungarianMap ( o ) 1934 { 1935 var 1936 hungarian = 'a aa ai ao as b fn i m o s ', 1937 match, 1938 newKey, 1939 map = {}; 1940 1941 $.each( o, function (key, val) { 1942 match = key.match(/^([^A-Z]+?)([A-Z])/); 1943 1944 if ( match && hungarian.indexOf(match[1]+' ') !== -1 ) 1945 { 1946 newKey = key.replace( match[0], match[2].toLowerCase() ); 1947 map[ newKey ] = key; 1948 1949 if ( match[1] === 'o' ) 1950 { 1951 _fnHungarianMap( o[key] ); 1952 } 1953 } 1954 } ); 1955 1956 o._hungarianMap = map; 1957 } 1958 1959 1960 /** 1961 * Convert from camel case parameters to Hungarian, based on a Hungarian map 1962 * created by _fnHungarianMap. 1963 * @param {object} src The model object which holds all parameters that can be 1964 * mapped. 1965 * @param {object} user The object to convert from camel case to Hungarian. 1966 * @param {boolean} force When set to `true`, properties which already have a 1967 * Hungarian value in the `user` object will be overwritten. Otherwise they 1968 * won't be. 1969 * @memberof DataTable#oApi 1970 */ 1971 function _fnCamelToHungarian ( src, user, force ) 1972 { 1973 if ( ! src._hungarianMap ) { 1974 _fnHungarianMap( src ); 1975 } 1976 1977 var hungarianKey; 1978 1979 $.each( user, function (key, val) { 1980 hungarianKey = src._hungarianMap[ key ]; 1981 1982 if ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) ) 1983 { 1984 // For objects, we need to buzz down into the object to copy parameters 1985 if ( hungarianKey.charAt(0) === 'o' ) 1986 { 1987 // Copy the camelCase options over to the hungarian 1988 if ( ! user[ hungarianKey ] ) { 1989 user[ hungarianKey ] = {}; 1990 } 1991 $.extend( true, user[hungarianKey], user[key] ); 1992 1993 _fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force ); 1994 } 1995 else { 1996 user[hungarianKey] = user[ key ]; 1997 } 1998 } 1999 } ); 2000 } 2001 2002 2003 /** 2004 * Language compatibility - when certain options are given, and others aren't, we 2005 * need to duplicate the values over, in order to provide backwards compatibility 2006 * with older language files. 2007 * @param {object} oSettings dataTables settings object 2008 * @memberof DataTable#oApi 2009 */ 2010 function _fnLanguageCompat( lang ) 2011 { 2012 // Note the use of the Hungarian notation for the parameters in this method as 2013 // this is called after the mapping of camelCase to Hungarian 2014 var defaults = DataTable.defaults.oLanguage; 2015 2016 // Default mapping 2017 var defaultDecimal = defaults.sDecimal; 2018 if ( defaultDecimal ) { 2019 _addNumericSort( defaultDecimal ); 2020 } 2021 2022 if ( lang ) { 2023 var zeroRecords = lang.sZeroRecords; 2024 2025 // Backwards compatibility - if there is no sEmptyTable given, then use the same as 2026 // sZeroRecords - assuming that is given. 2027 if ( ! lang.sEmptyTable && zeroRecords && 2028 defaults.sEmptyTable === "No data available in table" ) 2029 { 2030 _fnMap( lang, lang, 'sZeroRecords', 'sEmptyTable' ); 2031 } 2032 2033 // Likewise with loading records 2034 if ( ! lang.sLoadingRecords && zeroRecords && 2035 defaults.sLoadingRecords === "Loading..." ) 2036 { 2037 _fnMap( lang, lang, 'sZeroRecords', 'sLoadingRecords' ); 2038 } 2039 2040 // Old parameter name of the thousands separator mapped onto the new 2041 if ( lang.sInfoThousands ) { 2042 lang.sThousands = lang.sInfoThousands; 2043 } 2044 2045 var decimal = lang.sDecimal; 2046 if ( decimal && defaultDecimal !== decimal ) { 2047 _addNumericSort( decimal ); 2048 } 2049 } 2050 } 2051 2052 2053 /** 2054 * Map one parameter onto another 2055 * @param {object} o Object to map 2056 * @param {*} knew The new parameter name 2057 * @param {*} old The old parameter name 2058 */ 2059 var _fnCompatMap = function ( o, knew, old ) { 2060 if ( o[ knew ] !== undefined ) { 2061 o[ old ] = o[ knew ]; 2062 } 2063 }; 2064 2065 2066 /** 2067 * Provide backwards compatibility for the main DT options. Note that the new 2068 * options are mapped onto the old parameters, so this is an external interface 2069 * change only. 2070 * @param {object} init Object to map 2071 */ 2072 function _fnCompatOpts ( init ) 2073 { 2074 _fnCompatMap( init, 'ordering', 'bSort' ); 2075 _fnCompatMap( init, 'orderMulti', 'bSortMulti' ); 2076 _fnCompatMap( init, 'orderClasses', 'bSortClasses' ); 2077 _fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' ); 2078 _fnCompatMap( init, 'order', 'aaSorting' ); 2079 _fnCompatMap( init, 'orderFixed', 'aaSortingFixed' ); 2080 _fnCompatMap( init, 'paging', 'bPaginate' ); 2081 _fnCompatMap( init, 'pagingType', 'sPaginationType' ); 2082 _fnCompatMap( init, 'pageLength', 'iDisplayLength' ); 2083 _fnCompatMap( init, 'searching', 'bFilter' ); 2084 2085 // Boolean initialisation of x-scrolling 2086 if ( typeof init.sScrollX === 'boolean' ) { 2087 init.sScrollX = init.sScrollX ? '100%' : ''; 2088 } 2089 if ( typeof init.scrollX === 'boolean' ) { 2090 init.scrollX = init.scrollX ? '100%' : ''; 2091 } 2092 2093 // Column search objects are in an array, so it needs to be converted 2094 // element by element 2095 var searchCols = init.aoSearchCols; 2096 2097 if ( searchCols ) { 2098 for ( var i=0, ien=searchCols.length ; i<ien ; i++ ) { 2099 if ( searchCols[i] ) { 2100 _fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] ); 2101 } 2102 } 2103 } 2104 } 2105 2106 2107 /** 2108 * Provide backwards compatibility for column options. Note that the new options 2109 * are mapped onto the old parameters, so this is an external interface change 2110 * only. 2111 * @param {object} init Object to map 2112 */ 2113 function _fnCompatCols ( init ) 2114 { 2115 _fnCompatMap( init, 'orderable', 'bSortable' ); 2116 _fnCompatMap( init, 'orderData', 'aDataSort' ); 2117 _fnCompatMap( init, 'orderSequence', 'asSorting' ); 2118 _fnCompatMap( init, 'orderDataType', 'sortDataType' ); 2119 2120 // orderData can be given as an integer 2121 var dataSort = init.aDataSort; 2122 if ( typeof dataSort === 'number' && ! Array.isArray( dataSort ) ) { 2123 init.aDataSort = [ dataSort ]; 2124 } 2125 } 2126 2127 2128 /** 2129 * Browser feature detection for capabilities, quirks 2130 * @param {object} settings dataTables settings object 2131 * @memberof DataTable#oApi 2132 */ 2133 function _fnBrowserDetect( settings ) 2134 { 2135 // We don't need to do this every time DataTables is constructed, the values 2136 // calculated are specific to the browser and OS configuration which we 2137 // don't expect to change between initialisations 2138 if ( ! DataTable.__browser ) { 2139 var browser = {}; 2140 DataTable.__browser = browser; 2141 2142 // Scrolling feature / quirks detection 2143 var n = $('<div/>') 2144 .css( { 2145 position: 'fixed', 2146 top: 0, 2147 left: $(window).scrollLeft()*-1, // allow for scrolling 2148 height: 1, 2149 width: 1, 2150 overflow: 'hidden' 2151 } ) 2152 .append( 2153 $('<div/>') 2154 .css( { 2155 position: 'absolute', 2156 top: 1, 2157 left: 1, 2158 width: 100, 2159 overflow: 'scroll' 2160 } ) 2161 .append( 2162 $('<div/>') 2163 .css( { 2164 width: '100%', 2165 height: 10 2166 } ) 2167 ) 2168 ) 2169 .appendTo( 'body' ); 2170 2171 var outer = n.children(); 2172 var inner = outer.children(); 2173 2174 // Numbers below, in order, are: 2175 // inner.offsetWidth, inner.clientWidth, outer.offsetWidth, outer.clientWidth 2176 // 2177 // IE6 XP: 100 100 100 83 2178 // IE7 Vista: 100 100 100 83 2179 // IE 8+ Windows: 83 83 100 83 2180 // Evergreen Windows: 83 83 100 83 2181 // Evergreen Mac with scrollbars: 85 85 100 85 2182 // Evergreen Mac without scrollbars: 100 100 100 100 2183 2184 // Get scrollbar width 2185 browser.barWidth = outer[0].offsetWidth - outer[0].clientWidth; 2186 2187 // IE6/7 will oversize a width 100% element inside a scrolling element, to 2188 // include the width of the scrollbar, while other browsers ensure the inner 2189 // element is contained without forcing scrolling 2190 browser.bScrollOversize = inner[0].offsetWidth === 100 && outer[0].clientWidth !== 100; 2191 2192 // In rtl text layout, some browsers (most, but not all) will place the 2193 // scrollbar on the left, rather than the right. 2194 browser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1; 2195 2196 // IE8- don't provide height and width for getBoundingClientRect 2197 browser.bBounding = n[0].getBoundingClientRect().width ? true : false; 2198 2199 n.remove(); 2200 } 2201 2202 $.extend( settings.oBrowser, DataTable.__browser ); 2203 settings.oScroll.iBarWidth = DataTable.__browser.barWidth; 2204 } 2205 2206 2207 /** 2208 * Array.prototype reduce[Right] method, used for browsers which don't support 2209 * JS 1.6. Done this way to reduce code size, since we iterate either way 2210 * @param {object} settings dataTables settings object 2211 * @memberof DataTable#oApi 2212 */ 2213 function _fnReduce ( that, fn, init, start, end, inc ) 2214 { 2215 var 2216 i = start, 2217 value, 2218 isSet = false; 2219 2220 if ( init !== undefined ) { 2221 value = init; 2222 isSet = true; 2223 } 2224 2225 while ( i !== end ) { 2226 if ( ! that.hasOwnProperty(i) ) { 2227 continue; 2228 } 2229 2230 value = isSet ? 2231 fn( value, that[i], i, that ) : 2232 that[i]; 2233 2234 isSet = true; 2235 i += inc; 2236 } 2237 2238 return value; 2239 } 2240 2241 /** 2242 * Add a column to the list used for the table with default values 2243 * @param {object} oSettings dataTables settings object 2244 * @param {node} nTh The th element for this column 2245 * @memberof DataTable#oApi 2246 */ 2247 function _fnAddColumn( oSettings, nTh ) 2248 { 2249 // Add column to aoColumns array 2250 var oDefaults = DataTable.defaults.column; 2251 var iCol = oSettings.aoColumns.length; 2252 var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, { 2253 "nTh": nTh ? nTh : document.createElement('th'), 2254 "sTitle": oDefaults.sTitle ? oDefaults.sTitle : nTh ? nTh.innerHTML : '', 2255 "aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol], 2256 "mData": oDefaults.mData ? oDefaults.mData : iCol, 2257 idx: iCol 2258 } ); 2259 oSettings.aoColumns.push( oCol ); 2260 2261 // Add search object for column specific search. Note that the `searchCols[ iCol ]` 2262 // passed into extend can be undefined. This allows the user to give a default 2263 // with only some of the parameters defined, and also not give a default 2264 var searchCols = oSettings.aoPreSearchCols; 2265 searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] ); 2266 2267 // Use the default column options function to initialise classes etc 2268 _fnColumnOptions( oSettings, iCol, $(nTh).data() ); 2269 } 2270 2271 2272 /** 2273 * Apply options for a column 2274 * @param {object} oSettings dataTables settings object 2275 * @param {int} iCol column index to consider 2276 * @param {object} oOptions object with sType, bVisible and bSearchable etc 2277 * @memberof DataTable#oApi 2278 */ 2279 function _fnColumnOptions( oSettings, iCol, oOptions ) 2280 { 2281 var oCol = oSettings.aoColumns[ iCol ]; 2282 var oClasses = oSettings.oClasses; 2283 var th = $(oCol.nTh); 2284 2285 // Try to get width information from the DOM. We can't get it from CSS 2286 // as we'd need to parse the CSS stylesheet. `width` option can override 2287 if ( ! oCol.sWidthOrig ) { 2288 // Width attribute 2289 oCol.sWidthOrig = th.attr('width') || null; 2290 2291 // Style attribute 2292 var t = (th.attr('style') || '').match(/width:\s*(\d+[pxem%]+)/); 2293 if ( t ) { 2294 oCol.sWidthOrig = t[1]; 2295 } 2296 } 2297 2298 /* User specified column options */ 2299 if ( oOptions !== undefined && oOptions !== null ) 2300 { 2301 // Backwards compatibility 2302 _fnCompatCols( oOptions ); 2303 2304 // Map camel case parameters to their Hungarian counterparts 2305 _fnCamelToHungarian( DataTable.defaults.column, oOptions, true ); 2306 2307 /* Backwards compatibility for mDataProp */ 2308 if ( oOptions.mDataProp !== undefined && !oOptions.mData ) 2309 { 2310 oOptions.mData = oOptions.mDataProp; 2311 } 2312 2313 if ( oOptions.sType ) 2314 { 2315 oCol._sManualType = oOptions.sType; 2316 } 2317 2318 // `class` is a reserved word in Javascript, so we need to provide 2319 // the ability to use a valid name for the camel case input 2320 if ( oOptions.className && ! oOptions.sClass ) 2321 { 2322 oOptions.sClass = oOptions.className; 2323 } 2324 if ( oOptions.sClass ) { 2325 th.addClass( oOptions.sClass ); 2326 } 2327 2328 var origClass = oCol.sClass; 2329 2330 $.extend( oCol, oOptions ); 2331 _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" ); 2332 2333 // Merge class from previously defined classes with this one, rather than just 2334 // overwriting it in the extend above 2335 if (origClass !== oCol.sClass) { 2336 oCol.sClass = origClass + ' ' + oCol.sClass; 2337 } 2338 2339 /* iDataSort to be applied (backwards compatibility), but aDataSort will take 2340 * priority if defined 2341 */ 2342 if ( oOptions.iDataSort !== undefined ) 2343 { 2344 oCol.aDataSort = [ oOptions.iDataSort ]; 2345 } 2346 _fnMap( oCol, oOptions, "aDataSort" ); 2347
2347 2348 // Fall back to the aria-label attribute on the table header if no ariaTitle is 2349 // provided. 2350 if (! oCol.ariaTitle) { 2351 oCol.ariaTitle = th.attr("aria-label"); 2352 }
vendor: 54,944 bytes, lines 2352-4316
2352 2353 } 2354 2355 /* Cache the data get and set functions for speed */ 2356 var mDataSrc = oCol.mData; 2357 var mData = _fnGetObjectDataFn( mDataSrc ); 2358 var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null; 2359 2360 var attrTest = function( src ) { 2361 return typeof src === 'string' && src.indexOf('@') !== -1; 2362 }; 2363 oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && ( 2364 attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter) 2365 ); 2366 oCol._setter = null; 2367 2368 oCol.fnGetData = function (rowData, type, meta) { 2369 var innerData = mData( rowData, type, undefined, meta ); 2370 2371 return mRender && type ? 2372 mRender( innerData, type, rowData, meta ) : 2373 innerData; 2374 }; 2375 oCol.fnSetData = function ( rowData, val, meta ) { 2376 return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta ); 2377 }; 2378 2379 // Indicate if DataTables should read DOM data as an object or array 2380 // Used in _fnGetRowElements 2381 if ( typeof mDataSrc !== 'number' && ! oCol._isArrayHost ) { 2382 oSettings._rowReadObject = true; 2383 } 2384 2385 /* Feature sorting overrides column specific when off */ 2386 if ( !oSettings.oFeatures.bSort ) 2387 { 2388 oCol.bSortable = false; 2389 th.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called 2390 } 2391 2392 /* Check that the class assignment is correct for sorting */ 2393 var bAsc = $.inArray('asc', oCol.asSorting) !== -1; 2394 var bDesc = $.inArray('desc', oCol.asSorting) !== -1; 2395 if ( !oCol.bSortable || (!bAsc && !bDesc) ) 2396 { 2397 oCol.sSortingClass = oClasses.sSortableNone; 2398 oCol.sSortingClassJUI = ""; 2399 } 2400 else if ( bAsc && !bDesc ) 2401 { 2402 oCol.sSortingClass = oClasses.sSortableAsc; 2403 oCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed; 2404 } 2405 else if ( !bAsc && bDesc ) 2406 { 2407 oCol.sSortingClass = oClasses.sSortableDesc; 2408 oCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed; 2409 } 2410 else 2411 { 2412 oCol.sSortingClass = oClasses.sSortable; 2413 oCol.sSortingClassJUI = oClasses.sSortJUI; 2414 } 2415 } 2416 2417 2418 /** 2419 * Adjust the table column widths for new data. Note: you would probably want to 2420 * do a redraw after calling this function! 2421 * @param {object} settings dataTables settings object 2422 * @memberof DataTable#oApi 2423 */ 2424 function _fnAdjustColumnSizing ( settings ) 2425 { 2426 /* Not interested in doing column width calculation if auto-width is disabled */ 2427 if ( settings.oFeatures.bAutoWidth !== false ) 2428 { 2429 var columns = settings.aoColumns; 2430 2431 _fnCalculateColumnWidths( settings ); 2432 for ( var i=0 , iLen=columns.length ; i<iLen ; i++ ) 2433 { 2434 columns[i].nTh.style.width = columns[i].sWidth; 2435 } 2436 } 2437 2438 var scroll = settings.oScroll; 2439 if ( scroll.sY !== '' || scroll.sX !== '') 2440 { 2441 _fnScrollDraw( settings ); 2442 } 2443 2444 _fnCallbackFire( settings, null, 'column-sizing', [settings] ); 2445 } 2446 2447 2448 /** 2449 * Convert the index of a visible column to the index in the data array (take account 2450 * of hidden columns) 2451 * @param {object} oSettings dataTables settings object 2452 * @param {int} iMatch Visible column index to lookup 2453 * @returns {int} i the data index 2454 * @memberof DataTable#oApi 2455 */ 2456 function _fnVisibleToColumnIndex( oSettings, iMatch ) 2457 { 2458 var aiVis = _fnGetColumns( oSettings, 'bVisible' ); 2459 2460 return typeof aiVis[iMatch] === 'number' ? 2461 aiVis[iMatch] : 2462 null; 2463 } 2464 2465 2466 /** 2467 * Convert the index of an index in the data array and convert it to the visible 2468 * column index (take account of hidden columns) 2469 * @param {int} iMatch Column index to lookup 2470 * @param {object} oSettings dataTables settings object 2471 * @returns {int} i the data index 2472 * @memberof DataTable#oApi 2473 */ 2474 function _fnColumnIndexToVisible( oSettings, iMatch ) 2475 { 2476 var aiVis = _fnGetColumns( oSettings, 'bVisible' ); 2477 var iPos = $.inArray( iMatch, aiVis ); 2478 2479 return iPos !== -1 ? iPos : null; 2480 } 2481 2482 2483 /** 2484 * Get the number of visible columns 2485 * @param {object} oSettings dataTables settings object 2486 * @returns {int} i the number of visible columns 2487 * @memberof DataTable#oApi 2488 */ 2489 function _fnVisbleColumns( oSettings ) 2490 { 2491 var vis = 0; 2492 2493 // No reduce in IE8, use a loop for now 2494 $.each( oSettings.aoColumns, function ( i, col ) { 2495 if ( col.bVisible && $(col.nTh).css('display') !== 'none' ) { 2496 vis++; 2497 } 2498 } ); 2499 2500 return vis; 2501 } 2502 2503 2504 /** 2505 * Get an array of column indexes that match a given property 2506 * @param {object} oSettings dataTables settings object 2507 * @param {string} sParam Parameter in aoColumns to look for - typically 2508 * bVisible or bSearchable 2509 * @returns {array} Array of indexes with matched properties 2510 * @memberof DataTable#oApi 2511 */ 2512 function _fnGetColumns( oSettings, sParam ) 2513 { 2514 var a = []; 2515 2516 $.map( oSettings.aoColumns, function(val, i) { 2517 if ( val[sParam] ) { 2518 a.push( i ); 2519 } 2520 } ); 2521 2522 return a; 2523 } 2524 2525 2526 /** 2527 * Calculate the 'type' of a column 2528 * @param {object} settings dataTables settings object 2529 * @memberof DataTable#oApi 2530 */ 2531 function _fnColumnTypes ( settings ) 2532 { 2533 var columns = settings.aoColumns; 2534 var data = settings.aoData; 2535 var types = DataTable.ext.type.detect; 2536 var i, ien, j, jen, k, ken; 2537 var col, cell, detectedType, cache; 2538 2539 // For each column, spin over the 2540 for ( i=0, ien=columns.length ; i<ien ; i++ ) { 2541 col = columns[i]; 2542 cache = []; 2543 2544 if ( ! col.sType && col._sManualType ) { 2545 col.sType = col._sManualType; 2546 } 2547 else if ( ! col.sType ) { 2548 for ( j=0, jen=types.length ; j<jen ; j++ ) { 2549 for ( k=0, ken=data.length ; k<ken ; k++ ) { 2550 // Use a cache array so we only need to get the type data 2551 // from the formatter once (when using multiple detectors) 2552 if ( cache[k] === undefined ) { 2553 cache[k] = _fnGetCellData( settings, k, i, 'type' ); 2554 } 2555 2556 detectedType = types[j]( cache[k], settings ); 2557 2558 // If null, then this type can't apply to this column, so 2559 // rather than testing all cells, break out. There is an 2560 // exception for the last type which is `html`. We need to 2561 // scan all rows since it is possible to mix string and HTML 2562 // types 2563 if ( ! detectedType && j !== types.length-1 ) { 2564 break; 2565 } 2566 2567 // Only a single match is needed for html type since it is 2568 // bottom of the pile and very similar to string - but it 2569 // must not be empty 2570 if ( detectedType === 'html' && ! _empty(cache[k]) ) { 2571 break; 2572 } 2573 } 2574 2575 // Type is valid for all data points in the column - use this 2576 // type 2577 if ( detectedType ) { 2578 col.sType = detectedType; 2579 break; 2580 } 2581 } 2582 2583 // Fall back - if no type was detected, always use string 2584 if ( ! col.sType ) { 2585 col.sType = 'string'; 2586 } 2587 } 2588 } 2589 } 2590 2591 2592 /** 2593 * Take the column definitions and static columns arrays and calculate how 2594 * they relate to column indexes. The callback function will then apply the 2595 * definition found for a column to a suitable configuration object. 2596 * @param {object} oSettings dataTables settings object 2597 * @param {array} aoColDefs The aoColumnDefs array that is to be applied 2598 * @param {array} aoCols The aoColumns array that defines columns individually 2599 * @param {function} fn Callback function - takes two parameters, the calculated 2600 * column index and the definition for that column. 2601 * @memberof DataTable#oApi 2602 */ 2603 function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn ) 2604 { 2605 var i, iLen, j, jLen, k, kLen, def; 2606 var columns = oSettings.aoColumns; 2607 2608 // Column definitions with aTargets 2609 if ( aoColDefs ) 2610 { 2611 /* Loop over the definitions array - loop in reverse so first instance has priority */ 2612 for ( i=aoColDefs.length-1 ; i>=0 ; i-- ) 2613 { 2614 def = aoColDefs[i]; 2615 2616 /* Each definition can target multiple columns, as it is an array */ 2617 var aTargets = def.target !== undefined 2618 ? def.target 2619 : def.targets !== undefined 2620 ? def.targets 2621 : def.aTargets; 2622 2623 if ( ! Array.isArray( aTargets ) ) 2624 { 2625 aTargets = [ aTargets ]; 2626 } 2627 2628 for ( j=0, jLen=aTargets.length ; j<jLen ; j++ ) 2629 { 2630 if ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 ) 2631 { 2632 /* Add columns that we don't yet know about */ 2633 while( columns.length <= aTargets[j] ) 2634 { 2635 _fnAddColumn( oSettings ); 2636 } 2637 2638 /* Integer, basic index */ 2639 fn( aTargets[j], def ); 2640 } 2641 else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 ) 2642 { 2643 /* Negative integer, right to left column counting */ 2644 fn( columns.length+aTargets[j], def ); 2645 } 2646 else if ( typeof aTargets[j] === 'string' ) 2647 { 2648 /* Class name matching on TH element */ 2649 for ( k=0, kLen=columns.length ; k<kLen ; k++ ) 2650 { 2651 if ( aTargets[j] == "_all" || 2652 $(columns[k].nTh).hasClass( aTargets[j] ) ) 2653 { 2654 fn( k, def ); 2655 } 2656 } 2657 } 2658 } 2659 } 2660 } 2661 2662 // Statically defined columns array 2663 if ( aoCols ) 2664 { 2665 for ( i=0, iLen=aoCols.length ; i<iLen ; i++ ) 2666 { 2667 fn( i, aoCols[i] ); 2668 } 2669 } 2670 } 2671 2672 /** 2673 * Add a data array to the table, creating DOM node etc. This is the parallel to 2674 * _fnGatherData, but for adding rows from a Javascript source, rather than a 2675 * DOM source. 2676 * @param {object} oSettings dataTables settings object 2677 * @param {array} aData data array to be added 2678 * @param {node} [nTr] TR element to add to the table - optional. If not given, 2679 * DataTables will create a row automatically 2680 * @param {array} [anTds] Array of TD|TH elements for the row - must be given 2681 * if nTr is. 2682 * @returns {int} >=0 if successful (index of new aoData entry), -1 if failed 2683 * @memberof DataTable#oApi 2684 */ 2685 function _fnAddData ( oSettings, aDataIn, nTr, anTds ) 2686 { 2687 /* Create the object for storing information about this new row */ 2688 var iRow = oSettings.aoData.length; 2689 var oData = $.extend( true, {}, DataTable.models.oRow, { 2690 src: nTr ? 'dom' : 'data', 2691 idx: iRow 2692 } ); 2693 2694 oData._aData = aDataIn; 2695 oSettings.aoData.push( oData ); 2696 2697 /* Create the cells */ 2698 var nTd, sThisType; 2699 var columns = oSettings.aoColumns; 2700 2701 // Invalidate the column types as the new data needs to be revalidated 2702 for ( var i=0, iLen=columns.length ; i<iLen ; i++ ) 2703 { 2704 columns[i].sType = null; 2705 } 2706 2707 /* Add to the display array */ 2708 oSettings.aiDisplayMaster.push( iRow ); 2709 2710 var id = oSettings.rowIdFn( aDataIn ); 2711 if ( id !== undefined ) { 2712 oSettings.aIds[ id ] = oData; 2713 } 2714 2715 /* Create the DOM information, or register it if already present */ 2716 if ( nTr || ! oSettings.oFeatures.bDeferRender ) 2717 { 2718 _fnCreateTr( oSettings, iRow, nTr, anTds ); 2719 } 2720 2721 return iRow; 2722 } 2723 2724 2725 /** 2726 * Add one or more TR elements to the table. Generally we'd expect to 2727 * use this for reading data from a DOM sourced table, but it could be 2728 * used for an TR element. Note that if a TR is given, it is used (i.e. 2729 * it is not cloned). 2730 * @param {object} settings dataTables settings object 2731 * @param {array|node|jQuery} trs The TR element(s) to add to the table 2732 * @returns {array} Array of indexes for the added rows 2733 * @memberof DataTable#oApi 2734 */ 2735 function _fnAddTr( settings, trs ) 2736 { 2737 var row; 2738 2739 // Allow an individual node to be passed in 2740 if ( ! (trs instanceof $) ) { 2741 trs = $(trs); 2742 } 2743 2744 return trs.map( function (i, el) { 2745 row = _fnGetRowElements( settings, el ); 2746 return _fnAddData( settings, row.data, el, row.cells ); 2747 } ); 2748 } 2749 2750 2751 /** 2752 * Take a TR element and convert it to an index in aoData 2753 * @param {object} oSettings dataTables settings object 2754 * @param {node} n the TR element to find 2755 * @returns {int} index if the node is found, null if not 2756 * @memberof DataTable#oApi 2757 */ 2758 function _fnNodeToDataIndex( oSettings, n ) 2759 { 2760 return (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null; 2761 } 2762 2763 2764 /** 2765 * Take a TD element and convert it into a column data index (not the visible index) 2766 * @param {object} oSettings dataTables settings object 2767 * @param {int} iRow The row number the TD/TH can be found in 2768 * @param {node} n The TD/TH element to find 2769 * @returns {int} index if the node is found, -1 if not 2770 * @memberof DataTable#oApi 2771 */ 2772 function _fnNodeToColumnIndex( oSettings, iRow, n ) 2773 { 2774 return $.inArray( n, oSettings.aoData[ iRow ].anCells ); 2775 } 2776 2777 2778 /** 2779 * Get the data for a given cell from the internal cache, taking into account data mapping 2780 * @param {object} settings dataTables settings object 2781 * @param {int} rowIdx aoData row id 2782 * @param {int} colIdx Column index 2783 * @param {string} type data get type ('display', 'type' 'filter|search' 'sort|order') 2784 * @returns {*} Cell data 2785 * @memberof DataTable#oApi 2786 */ 2787 function _fnGetCellData( settings, rowIdx, colIdx, type ) 2788 { 2789 if (type === 'search') { 2790 type = 'filter'; 2791 } 2792 else if (type === 'order') { 2793 type = 'sort'; 2794 } 2795 2796 var draw = settings.iDraw; 2797 var col = settings.aoColumns[colIdx]; 2798 var rowData = settings.aoData[rowIdx]._aData; 2799 var defaultContent = col.sDefaultContent; 2800 var cellData = col.fnGetData( rowData, type, { 2801 settings: settings, 2802 row: rowIdx, 2803 col: colIdx 2804 } ); 2805 2806 if ( cellData === undefined ) { 2807 if ( settings.iDrawError != draw && defaultContent === null ) { 2808 _fnLog( settings, 0, "Requested unknown parameter "+ 2809 (typeof col.mData=='function' ? '{function}' : "'"+col.mData+"'")+ 2810 " for row "+rowIdx+", column "+colIdx, 4 ); 2811 settings.iDrawError = draw; 2812 } 2813 return defaultContent; 2814 } 2815 2816 // When the data source is null and a specific data type is requested (i.e. 2817 // not the original data), we can use default column data 2818 if ( (cellData === rowData || cellData === null) && defaultContent !== null && type !== undefined ) { 2819 cellData = defaultContent; 2820 } 2821 else if ( typeof cellData === 'function' ) { 2822 // If the data source is a function, then we run it and use the return, 2823 // executing in the scope of the data object (for instances) 2824 return cellData.call( rowData ); 2825 } 2826 2827 if ( cellData === null && type === 'display' ) { 2828 return ''; 2829 } 2830 2831 if ( type === 'filter' ) { 2832 var fomatters = DataTable.ext.type.search; 2833 2834 if ( fomatters[ col.sType ] ) { 2835 cellData = fomatters[ col.sType ]( cellData ); 2836 } 2837 } 2838 2839 return cellData; 2840 } 2841 2842 2843 /** 2844 * Set the value for a specific cell, into the internal data cache 2845 * @param {object} settings dataTables settings object 2846 * @param {int} rowIdx aoData row id 2847 * @param {int} colIdx Column index 2848 * @param {*} val Value to set 2849 * @memberof DataTable#oApi 2850 */ 2851 function _fnSetCellData( settings, rowIdx, colIdx, val ) 2852 { 2853 var col = settings.aoColumns[colIdx]; 2854 var rowData = settings.aoData[rowIdx]._aData; 2855 2856 col.fnSetData( rowData, val, { 2857 settings: settings, 2858 row: rowIdx, 2859 col: colIdx 2860 } ); 2861 } 2862 2863 2864 // Private variable that is used to match action syntax in the data property object 2865 var __reArray = /\[.*?\]$/; 2866 var __reFn = /\(\)$/; 2867 2868 /** 2869 * Split string on periods, taking into account escaped periods 2870 * @param {string} str String to split 2871 * @return {array} Split string 2872 */ 2873 function _fnSplitObjNotation( str ) 2874 { 2875 return $.map( str.match(/(\\.|[^\.])+/g) || [''], function ( s ) { 2876 return s.replace(/\\\./g, '.'); 2877 } ); 2878 } 2879 2880 2881 /** 2882 * Return a function that can be used to get data from a source object, taking 2883 * into account the ability to use nested objects as a source 2884 * @param {string|int|function} mSource The data source for the object 2885 * @returns {function} Data get function 2886 * @memberof DataTable#oApi 2887 */ 2888 var _fnGetObjectDataFn = DataTable.util.get; 2889 2890 2891 /** 2892 * Return a function that can be used to set data from a source object, taking 2893 * into account the ability to use nested objects as a source 2894 * @param {string|int|function} mSource The data source for the object 2895 * @returns {function} Data set function 2896 * @memberof DataTable#oApi 2897 */ 2898 var _fnSetObjectDataFn = DataTable.util.set; 2899 2900 2901 /** 2902 * Return an array with the full table data 2903 * @param {object} oSettings dataTables settings object 2904 * @returns array {array} aData Master data array 2905 * @memberof DataTable#oApi 2906 */ 2907 function _fnGetDataMaster ( settings ) 2908 { 2909 return _pluck( settings.aoData, '_aData' ); 2910 } 2911 2912 2913 /** 2914 * Nuke the table 2915 * @param {object} oSettings dataTables settings object 2916 * @memberof DataTable#oApi 2917 */ 2918 function _fnClearTable( settings ) 2919 { 2920 settings.aoData.length = 0; 2921 settings.aiDisplayMaster.length = 0; 2922 settings.aiDisplay.length = 0; 2923 settings.aIds = {}; 2924 } 2925 2926 2927 /** 2928 * Take an array of integers (index array) and remove a target integer (value - not 2929 * the key!) 2930 * @param {array} a Index array to target 2931 * @param {int} iTarget value to find 2932 * @memberof DataTable#oApi 2933 */ 2934 function _fnDeleteIndex( a, iTarget, splice ) 2935 { 2936 var iTargetIndex = -1; 2937 2938 for ( var i=0, iLen=a.length ; i<iLen ; i++ ) 2939 { 2940 if ( a[i] == iTarget ) 2941 { 2942 iTargetIndex = i; 2943 } 2944 else if ( a[i] > iTarget ) 2945 { 2946 a[i]--; 2947 } 2948 } 2949 2950 if ( iTargetIndex != -1 && splice === undefined ) 2951 { 2952 a.splice( iTargetIndex, 1 ); 2953 } 2954 } 2955 2956 2957 /** 2958 * Mark cached data as invalid such that a re-read of the data will occur when 2959 * the cached data is next requested. Also update from the data source object. 2960 * 2961 * @param {object} settings DataTables settings object 2962 * @param {int} rowIdx Row index to invalidate 2963 * @param {string} [src] Source to invalidate from: undefined, 'auto', 'dom' 2964 * or 'data' 2965 * @param {int} [colIdx] Column index to invalidate. If undefined the whole 2966 * row will be invalidated 2967 * @memberof DataTable#oApi 2968 * 2969 * @todo For the modularisation of v1.11 this will need to become a callback, so 2970 * the sort and filter methods can subscribe to it. That will required 2971 * initialisation options for sorting, which is why it is not already baked in 2972 */ 2973 function _fnInvalidate( settings, rowIdx, src, colIdx ) 2974 { 2975 var row = settings.aoData[ rowIdx ]; 2976 var i, ien; 2977 var cellWrite = function ( cell, col ) { 2978 // This is very frustrating, but in IE if you just write directly 2979 // to innerHTML, and elements that are overwritten are GC'ed, 2980 // even if there is a reference to them elsewhere 2981 while ( cell.childNodes.length ) { 2982 cell.removeChild( cell.firstChild ); 2983 } 2984 2985 cell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' ); 2986 }; 2987 2988 // Are we reading last data from DOM or the data object? 2989 if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) { 2990 // Read the data from the DOM 2991 row._aData = _fnGetRowElements( 2992 settings, row, colIdx, colIdx === undefined ? undefined : row._aData 2993 ) 2994 .data; 2995 } 2996 else { 2997 // Reading from data object, update the DOM 2998 var cells = row.anCells; 2999 3000 if ( cells ) { 3001 if ( colIdx !== undefined ) { 3002 cellWrite( cells[colIdx], colIdx ); 3003 } 3004 else { 3005 for ( i=0, ien=cells.length ; i<ien ; i++ ) { 3006 cellWrite( cells[i], i ); 3007 } 3008 } 3009 } 3010 } 3011 3012 // For both row and cell invalidation, the cached data for sorting and 3013 // filtering is nulled out 3014 row._aSortData = null; 3015 row._aFilterData = null; 3016 3017 // Invalidate the type for a specific column (if given) or all columns since 3018 // the data might have changed 3019 var cols = settings.aoColumns; 3020 if ( colIdx !== undefined ) { 3021 cols[ colIdx ].sType = null; 3022 } 3023 else { 3024 for ( i=0, ien=cols.length ; i<ien ; i++ ) { 3025 cols[i].sType = null; 3026 } 3027 3028 // Update DataTables special `DT_*` attributes for the row 3029 _fnRowAttributes( settings, row ); 3030 } 3031 } 3032 3033 3034 /** 3035 * Build a data source object from an HTML row, reading the contents of the 3036 * cells that are in the row. 3037 * 3038 * @param {object} settings DataTables settings object 3039 * @param {node|object} TR element from which to read data or existing row 3040 * object from which to re-read the data from the cells 3041 * @param {int} [colIdx] Optional column index 3042 * @param {array|object} [d] Data source object. If `colIdx` is given then this 3043 * parameter should also be given and will be used to write the data into. 3044 * Only the column in question will be written 3045 * @returns {object} Object with two parameters: `data` the data read, in 3046 * document order, and `cells` and array of nodes (they can be useful to the 3047 * caller, so rather than needing a second traversal to get them, just return 3048 * them from here). 3049 * @memberof DataTable#oApi 3050 */ 3051 function _fnGetRowElements( settings, row, colIdx, d ) 3052 { 3053 var 3054 tds = [], 3055 td = row.firstChild, 3056 name, col, o, i=0, contents, 3057 columns = settings.aoColumns, 3058 objectRead = settings._rowReadObject; 3059 3060 // Allow the data object to be passed in, or construct 3061 d = d !== undefined ? 3062 d : 3063 objectRead ? 3064 {} : 3065 []; 3066 3067 var attr = function ( str, td ) { 3068 if ( typeof str === 'string' ) { 3069 var idx = str.indexOf('@'); 3070 3071 if ( idx !== -1 ) { 3072 var attr = str.substring( idx+1 ); 3073 var setter = _fnSetObjectDataFn( str ); 3074 setter( d, td.getAttribute( attr ) ); 3075 } 3076 } 3077 }; 3078 3079 // Read data from a cell and store into the data object 3080 var cellProcess = function ( cell ) { 3081 if ( colIdx === undefined || colIdx === i ) { 3082 col = columns[i]; 3083 contents = (cell.innerHTML).trim(); 3084 3085 if ( col && col._bAttrSrc ) { 3086 var setter = _fnSetObjectDataFn( col.mData._ ); 3087 setter( d, contents ); 3088 3089 attr( col.mData.sort, cell ); 3090 attr( col.mData.type, cell ); 3091 attr( col.mData.filter, cell ); 3092 } 3093 else { 3094 // Depending on the `data` option for the columns the data can 3095 // be read to either an object or an array. 3096 if ( objectRead ) { 3097 if ( ! col._setter ) { 3098 // Cache the setter function 3099 col._setter = _fnSetObjectDataFn( col.mData ); 3100 } 3101 col._setter( d, contents ); 3102 } 3103 else { 3104 d[i] = contents; 3105 } 3106 } 3107 } 3108 3109 i++; 3110 }; 3111 3112 if ( td ) { 3113 // `tr` element was passed in 3114 while ( td ) { 3115 name = td.nodeName.toUpperCase(); 3116 3117 if ( name == "TD" || name == "TH" ) { 3118 cellProcess( td ); 3119 tds.push( td ); 3120 } 3121 3122 td = td.nextSibling; 3123 } 3124 } 3125 else { 3126 // Existing row object passed in 3127 tds = row.anCells; 3128 3129 for ( var j=0, jen=tds.length ; j<jen ; j++ ) { 3130 cellProcess( tds[j] ); 3131 } 3132 } 3133 3134 // Read the ID from the DOM if present 3135 var rowNode = row.firstChild ? row : row.nTr; 3136 3137 if ( rowNode ) { 3138 var id = rowNode.getAttribute( 'id' ); 3139 3140 if ( id ) { 3141 _fnSetObjectDataFn( settings.rowId )( d, id ); 3142 } 3143 } 3144 3145 return { 3146 data: d, 3147 cells: tds 3148 }; 3149 } 3150 /** 3151 * Create a new TR element (and it's TD children) for a row 3152 * @param {object} oSettings dataTables settings object 3153 * @param {int} iRow Row to consider 3154 * @param {node} [nTrIn] TR element to add to the table - optional. If not given, 3155 * DataTables will create a row automatically 3156 * @param {array} [anTds] Array of TD|TH elements for the row - must be given 3157 * if nTr is. 3158 * @memberof DataTable#oApi 3159 */ 3160 function _fnCreateTr ( oSettings, iRow, nTrIn, anTds ) 3161 { 3162 var 3163 row = oSettings.aoData[iRow], 3164 rowData = row._aData, 3165 cells = [], 3166 nTr, nTd, oCol, 3167 i, iLen, create; 3168 3169 if ( row.nTr === null ) 3170 { 3171 nTr = nTrIn || document.createElement('tr'); 3172 3173 row.nTr = nTr; 3174 row.anCells = cells; 3175 3176 /* Use a private property on the node to allow reserve mapping from the node 3177 * to the aoData array for fast look up 3178 */ 3179 nTr._DT_RowIndex = iRow; 3180 3181 /* Special parameters can be given by the data source to be used on the row */ 3182 _fnRowAttributes( oSettings, row ); 3183 3184 /* Process each column */ 3185 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ ) 3186 { 3187 oCol = oSettings.aoColumns[i]; 3188 create = nTrIn ? false : true; 3189 3190 nTd = create ? document.createElement( oCol.sCellType ) : anTds[i]; 3191 3192 if (! nTd) { 3193 _fnLog( oSettings, 0, 'Incorrect column count', 18 ); 3194 } 3195 3196 nTd._DT_CellIndex = { 3197 row: iRow, 3198 column: i 3199 }; 3200 3201 cells.push( nTd ); 3202 3203 // Need to create the HTML if new, or if a rendering function is defined 3204 if ( create || ((oCol.mRender || oCol.mData !== i) && 3205 (!$.isPlainObject(oCol.mData) || oCol.mData._ !== i+'.display') 3206 )) { 3207 nTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' ); 3208 } 3209 3210 /* Add user defined class */ 3211 if ( oCol.sClass ) 3212 { 3213 nTd.className += ' '+oCol.sClass; 3214 } 3215 3216 // Visibility - add or remove as required 3217 if ( oCol.bVisible && ! nTrIn ) 3218 { 3219 nTr.appendChild( nTd ); 3220 } 3221 else if ( ! oCol.bVisible && nTrIn ) 3222 { 3223 nTd.parentNode.removeChild( nTd ); 3224 } 3225 3226 if ( oCol.fnCreatedCell ) 3227 { 3228 oCol.fnCreatedCell.call( oSettings.oInstance, 3229 nTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i 3230 ); 3231 } 3232 } 3233 3234 _fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [nTr, rowData, iRow, cells] ); 3235 } 3236 } 3237 3238 3239 /** 3240 * Add attributes to a row based on the special `DT_*` parameters in a data 3241 * source object. 3242 * @param {object} settings DataTables settings object 3243 * @param {object} DataTables row object for the row to be modified 3244 * @memberof DataTable#oApi 3245 */ 3246 function _fnRowAttributes( settings, row ) 3247 { 3248 var tr = row.nTr; 3249 var data = row._aData; 3250 3251 if ( tr ) { 3252 var id = settings.rowIdFn( data ); 3253 3254 if ( id ) { 3255 tr.id = id; 3256 } 3257 3258 if ( data.DT_RowClass ) { 3259 // Remove any classes added by DT_RowClass before 3260 var a = data.DT_RowClass.split(' '); 3261 row.__rowc = row.__rowc ? 3262 _unique( row.__rowc.concat( a ) ) : 3263 a; 3264 3265 $(tr) 3266 .removeClass( row.__rowc.join(' ') ) 3267 .addClass( data.DT_RowClass ); 3268 } 3269 3270 if ( data.DT_RowAttr ) { 3271 $(tr).attr( data.DT_RowAttr ); 3272 } 3273 3274 if ( data.DT_RowData ) { 3275 $(tr).data( data.DT_RowData ); 3276 } 3277 } 3278 } 3279 3280 3281 /** 3282 * Create the HTML header for the table 3283 * @param {object} oSettings dataTables settings object 3284 * @memberof DataTable#oApi 3285 */ 3286 function _fnBuildHead( oSettings ) 3287 { 3288 var i, ien, cell, row, column; 3289 var thead = oSettings.nTHead; 3290 var tfoot = oSettings.nTFoot; 3291 var createHeader = $('th, td', thead).length === 0; 3292 var classes = oSettings.oClasses; 3293 var columns = oSettings.aoColumns; 3294 3295 if ( createHeader ) { 3296 row = $('<tr/>').appendTo( thead ); 3297 } 3298 3299 for ( i=0, ien=columns.length ; i<ien ; i++ ) { 3300 column = columns[i]; 3301 cell = $( column.nTh ).addClass( column.sClass ); 3302 3303 if ( createHeader ) { 3304 cell.appendTo( row ); 3305 } 3306 3307 // 1.11 move into sorting 3308 if ( oSettings.oFeatures.bSort ) { 3309 cell.addClass( column.sSortingClass ); 3310 3311 if ( column.bSortable !== false ) { 3312 cell 3313 .attr( 'tabindex', oSettings.iTabIndex ) 3314 .attr( 'aria-controls', oSettings.sTableId ); 3315 3316 _fnSortAttachListener( oSettings, column.nTh, i ); 3317 } 3318 } 3319 3320 if ( column.sTitle != cell[0].innerHTML ) { 3321 cell.html( column.sTitle ); 3322 } 3323 3324 _fnRenderer( oSettings, 'header' )( 3325 oSettings, cell, column, classes 3326 ); 3327 } 3328 3329 if ( createHeader ) { 3330 _fnDetectHeader( oSettings.aoHeader, thead ); 3331 } 3332 3333 /* Deal with the footer - add classes if required */ 3334 $(thead).children('tr').children('th, td').addClass( classes.sHeaderTH ); 3335 $(tfoot).children('tr').children('th, td').addClass( classes.sFooterTH ); 3336 3337 // Cache the footer cells. Note that we only take the cells from the first 3338 // row in the footer. If there is more than one row the user wants to 3339 // interact with, they need to use the table().foot() method. Note also this 3340 // allows cells to be used for multiple columns using colspan 3341 if ( tfoot !== null ) { 3342 var cells = oSettings.aoFooter[0]; 3343 3344 for ( i=0, ien=cells.length ; i<ien ; i++ ) { 3345 column = columns[i]; 3346 3347 if (column) { 3348 column.nTf = cells[i].cell; 3349 3350 if ( column.sClass ) { 3351 $(column.nTf).addClass( column.sClass ); 3352 } 3353 } 3354 else { 3355 _fnLog( oSettings, 0, 'Incorrect column count', 18 ); 3356 } 3357 } 3358 } 3359 } 3360 3361 3362 /** 3363 * Draw the header (or footer) element based on the column visibility states. The 3364 * methodology here is to use the layout array from _fnDetectHeader, modified for 3365 * the instantaneous column visibility, to construct the new layout. The grid is 3366 * traversed over cell at a time in a rows x columns grid fashion, although each 3367 * cell insert can cover multiple elements in the grid - which is tracks using the 3368 * aApplied array. Cell inserts in the grid will only occur where there isn't 3369 * already a cell in that position. 3370 * @param {object} oSettings dataTables settings object 3371 * @param array {objects} aoSource Layout array from _fnDetectHeader 3372 * @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc, 3373 * @memberof DataTable#oApi 3374 */ 3375 function _fnDrawHead( oSettings, aoSource, bIncludeHidden ) 3376 { 3377 var i, iLen, j, jLen, k, kLen, n, nLocalTr; 3378 var aoLocal = []; 3379 var aApplied = []; 3380 var iColumns = oSettings.aoColumns.length; 3381 var iRowspan, iColspan; 3382 3383 if ( ! aoSource ) 3384 { 3385 return; 3386 } 3387 3388 if ( bIncludeHidden === undefined ) 3389 { 3390 bIncludeHidden = false; 3391 } 3392 3393 /* Make a copy of the master layout array, but without the visible columns in it */ 3394 for ( i=0, iLen=aoSource.length ; i<iLen ; i++ ) 3395 { 3396 aoLocal[i] = aoSource[i].slice(); 3397 aoLocal[i].nTr = aoSource[i].nTr; 3398 3399 /* Remove any columns which are currently hidden */ 3400 for ( j=iColumns-1 ; j>=0 ; j-- ) 3401 { 3402 if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden ) 3403 { 3404 aoLocal[i].splice( j, 1 ); 3405 } 3406 } 3407 3408 /* Prep the applied array - it needs an element for each row */ 3409 aApplied.push( [] ); 3410 } 3411 3412 for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ ) 3413 { 3414 nLocalTr = aoLocal[i].nTr; 3415 3416 /* All cells are going to be replaced, so empty out the row */ 3417 if ( nLocalTr ) 3418 { 3419 while( (n = nLocalTr.firstChild) ) 3420 { 3421 nLocalTr.removeChild( n ); 3422 } 3423 } 3424 3425 for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ ) 3426 { 3427 iRowspan = 1; 3428 iColspan = 1; 3429 3430 /* Check to see if there is already a cell (row/colspan) covering our target 3431 * insert point. If there is, then there is nothing to do. 3432 */ 3433 if ( aApplied[i][j] === undefined ) 3434 { 3435 nLocalTr.appendChild( aoLocal[i][j].cell ); 3436 aApplied[i][j] = 1; 3437 3438 /* Expand the cell to cover as many rows as needed */ 3439 while ( aoLocal[i+iRowspan] !== undefined && 3440 aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell ) 3441 { 3442 aApplied[i+iRowspan][j] = 1; 3443 iRowspan++; 3444 } 3445 3446 /* Expand the cell to cover as many columns as needed */ 3447 while ( aoLocal[i][j+iColspan] !== undefined && 3448 aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell ) 3449 { 3450 /* Must update the applied array over the rows for the columns */ 3451 for ( k=0 ; k<iRowspan ; k++ ) 3452 { 3453 aApplied[i+k][j+iColspan] = 1; 3454 } 3455 iColspan++; 3456 } 3457 3458 /* Do the actual expansion in the DOM */ 3459 $(aoLocal[i][j].cell) 3460 .attr('rowspan', iRowspan) 3461 .attr('colspan', iColspan); 3462 } 3463 } 3464 } 3465 } 3466 3467 3468 /** 3469 * Insert the required TR nodes into the table for display 3470 * @param {object} oSettings dataTables settings object 3471 * @param ajaxComplete true after ajax call to complete rendering 3472 * @memberof DataTable#oApi 3473 */ 3474 function _fnDraw( oSettings, ajaxComplete ) 3475 { 3476 // Allow for state saving and a custom start position 3477 _fnStart( oSettings ); 3478 3479 /* Provide a pre-callback function which can be used to cancel the draw is false is returned */ 3480 var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] ); 3481 if ( $.inArray( false, aPreDraw ) !== -1 ) 3482 { 3483 _fnProcessingDisplay( oSettings, false ); 3484 return; 3485 } 3486 3487 var anRows = []; 3488 var iRowCount = 0; 3489 var asStripeClasses = oSettings.asStripeClasses; 3490 var iStripes = asStripeClasses.length; 3491 var oLang = oSettings.oLanguage; 3492 var bServerSide = _fnDataSource( oSettings ) == 'ssp'; 3493 var aiDisplay = oSettings.aiDisplay; 3494 var iDisplayStart = oSettings._iDisplayStart; 3495 var iDisplayEnd = oSettings.fnDisplayEnd(); 3496 3497 oSettings.bDrawing = true; 3498 3499 /* Server-side processing draw intercept */ 3500 if ( oSettings.bDeferLoading ) 3501 { 3502 oSettings.bDeferLoading = false; 3503 oSettings.iDraw++; 3504 _fnProcessingDisplay( oSettings, false ); 3505 } 3506 else if ( !bServerSide ) 3507 { 3508 oSettings.iDraw++; 3509 } 3510 else if ( !oSettings.bDestroying && !ajaxComplete) 3511 { 3512 _fnAjaxUpdate( oSettings ); 3513 return; 3514 } 3515 3516 if ( aiDisplay.length !== 0 ) 3517 { 3518 var iStart = bServerSide ? 0 : iDisplayStart; 3519 var iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd; 3520 3521 for ( var j=iStart ; j<iEnd ; j++ ) 3522 { 3523 var iDataIndex = aiDisplay[j]; 3524 var aoData = oSettings.aoData[ iDataIndex ]; 3525 if ( aoData.nTr === null ) 3526 { 3527 _fnCreateTr( oSettings, iDataIndex ); 3528 } 3529 3530 var nRow = aoData.nTr; 3531 3532 /* Remove the old striping classes and then add the new one */ 3533 if ( iStripes !== 0 ) 3534 { 3535 var sStripe = asStripeClasses[ iRowCount % iStripes ]; 3536 if ( aoData._sRowStripe != sStripe ) 3537 { 3538 $(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe ); 3539 aoData._sRowStripe = sStripe; 3540 } 3541 } 3542 3543 // Row callback functions - might want to manipulate the row 3544 // iRowCount and j are not currently documented. Are they at all 3545 // useful? 3546 _fnCallbackFire( oSettings, 'aoRowCallback', null, 3547 [nRow, aoData._aData, iRowCount, j, iDataIndex] ); 3548 3549 anRows.push( nRow ); 3550 iRowCount++; 3551 } 3552 } 3553 else 3554 { 3555 /* Table is empty - create a row with an empty message in it */ 3556 var sZero = oLang.sZeroRecords; 3557 if ( oSettings.iDraw == 1 && _fnDataSource( oSettings ) == 'ajax' ) 3558 { 3559 sZero = oLang.sLoadingRecords; 3560 } 3561 else if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 ) 3562 { 3563 sZero = oLang.sEmptyTable; 3564 } 3565 3566 anRows[ 0 ] = $( '<tr/>', { 'class': iStripes ? asStripeClasses[0] : '' } ) 3567 .append( $('<td />', { 3568 'valign': 'top', 3569 'colSpan': _fnVisbleColumns( oSettings ), 3570 'class': oSettings.oClasses.sRowEmpty 3571 } ).html( sZero ) )[0]; 3572 } 3573 3574 /* Header and footer callbacks */ 3575 _fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0], 3576 _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] ); 3577 3578 _fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0], 3579 _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] ); 3580 3581 var body = $(oSettings.nTBody); 3582 3583 body.children().detach(); 3584 body.append( $(anRows) ); 3585 3586 /* Call all required callback functions for the end of a draw */ 3587 _fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] ); 3588 3589 /* Draw is complete, sorting and filtering must be as well */ 3590 oSettings.bSorted = false; 3591 oSettings.bFiltered = false; 3592 oSettings.bDrawing = false; 3593 } 3594 3595 3596 /** 3597 * Redraw the table - taking account of the various features which are enabled 3598 * @param {object} oSettings dataTables settings object 3599 * @param {boolean} [holdPosition] Keep the current paging position. By default 3600 * the paging is reset to the first page 3601 * @memberof DataTable#oApi 3602 */ 3603 function _fnReDraw( settings, holdPosition ) 3604 { 3605 var 3606 features = settings.oFeatures, 3607 sort = features.bSort, 3608 filter = features.bFilter; 3609 3610 if ( sort ) { 3611 _fnSort( settings ); 3612 } 3613 3614 if ( filter ) { 3615 _fnFilterComplete( settings, settings.oPreviousSearch ); 3616 } 3617 else { 3618 // No filtering, so we want to just use the display master 3619 settings.aiDisplay = settings.aiDisplayMaster.slice(); 3620 } 3621 3622 if ( holdPosition !== true ) { 3623 settings._iDisplayStart = 0; 3624 } 3625 3626 // Let any modules know about the draw hold position state (used by 3627 // scrolling internally) 3628 settings._drawHold = holdPosition; 3629 3630 _fnDraw( settings ); 3631 3632 settings._drawHold = false; 3633 } 3634 3635 3636 /** 3637 * Add the options to the page HTML for the table 3638 * @param {object} oSettings dataTables settings object 3639 * @memberof DataTable#oApi 3640 */ 3641 function _fnAddOptionsHtml ( oSettings ) 3642 { 3643 var classes = oSettings.oClasses; 3644 var table = $(oSettings.nTable); 3645 var holding = $('<div/>').insertBefore( table ); // Holding element for speed 3646 var features = oSettings.oFeatures; 3647 3648 // All DataTables are wrapped in a div 3649 var insert = $('<div/>', { 3650 id: oSettings.sTableId+'_wrapper', 3651 'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter) 3652 } ); 3653 3654 oSettings.nHolding = holding[0]; 3655 oSettings.nTableWrapper = insert[0]; 3656 oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling; 3657 3658 /* Loop over the user set positioning and place the elements as needed */ 3659 var aDom = oSettings.sDom.split(''); 3660 var featureNode, cOption, nNewNode, cNext, sAttr, j; 3661 for ( var i=0 ; i<aDom.length ; i++ ) 3662 { 3663 featureNode = null; 3664 cOption = aDom[i]; 3665 3666 if ( cOption == '<' ) 3667 { 3668 /* New container div */ 3669 nNewNode = $('<div/>')[0]; 3670 3671 /* Check to see if we should append an id and/or a class name to the container */ 3672 cNext = aDom[i+1]; 3673 if ( cNext == "'" || cNext == '"' ) 3674 { 3675 sAttr = ""; 3676 j = 2; 3677 while ( aDom[i+j] != cNext ) 3678 { 3679 sAttr += aDom[i+j]; 3680 j++; 3681 } 3682 3683 /* Replace jQuery UI constants @todo depreciated */ 3684 if ( sAttr == "H" ) 3685 { 3686 sAttr = classes.sJUIHeader; 3687 } 3688 else if ( sAttr == "F" ) 3689 { 3690 sAttr = classes.sJUIFooter; 3691 } 3692 3693 /* The attribute can be in the format of "#id.class", "#id" or "class" This logic 3694 * breaks the string into parts and applies them as needed 3695 */ 3696 if ( sAttr.indexOf('.') != -1 ) 3697 { 3698 var aSplit = sAttr.split('.'); 3699 nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1); 3700 nNewNode.className = aSplit[1]; 3701 } 3702 else if ( sAttr.charAt(0) == "#" ) 3703 { 3704 nNewNode.id = sAttr.substr(1, sAttr.length-1); 3705 } 3706 else 3707 { 3708 nNewNode.className = sAttr; 3709 } 3710 3711 i += j; /* Move along the position array */ 3712 } 3713 3714 insert.append( nNewNode ); 3715 insert = $(nNewNode); 3716 } 3717 else if ( cOption == '>' ) 3718 { 3719 /* End container div */ 3720 insert = insert.parent(); 3721 } 3722 // @todo Move options into their own plugins? 3723 else if ( cOption == 'l' && features.bPaginate && features.bLengthChange ) 3724 { 3725 /* Length */ 3726 featureNode = _fnFeatureHtmlLength( oSettings ); 3727 } 3728 else if ( cOption == 'f' && features.bFilter ) 3729 { 3730 /* Filter */ 3731 featureNode = _fnFeatureHtmlFilter( oSettings ); 3732 } 3733 else if ( cOption == 'r' && features.bProcessing ) 3734 { 3735 /* pRocessing */ 3736 featureNode = _fnFeatureHtmlProcessing( oSettings ); 3737 } 3738 else if ( cOption == 't' ) 3739 { 3740 /* Table */ 3741 featureNode = _fnFeatureHtmlTable( oSettings ); 3742 } 3743 else if ( cOption == 'i' && features.bInfo ) 3744 { 3745 /* Info */ 3746 featureNode = _fnFeatureHtmlInfo( oSettings ); 3747 } 3748 else if ( cOption == 'p' && features.bPaginate ) 3749 { 3750 /* Pagination */ 3751 featureNode = _fnFeatureHtmlPaginate( oSettings ); 3752 } 3753 else if ( DataTable.ext.feature.length !== 0 ) 3754 { 3755 /* Plug-in features */ 3756 var aoFeatures = DataTable.ext.feature; 3757 for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ ) 3758 { 3759 if ( cOption == aoFeatures[k].cFeature ) 3760 { 3761 featureNode = aoFeatures[k].fnInit( oSettings ); 3762 break; 3763 } 3764 } 3765 } 3766 3767 /* Add to the 2D features array */ 3768 if ( featureNode ) 3769 { 3770 var aanFeatures = oSettings.aanFeatures; 3771 3772 if ( ! aanFeatures[cOption] ) 3773 { 3774 aanFeatures[cOption] = []; 3775 } 3776 3777 aanFeatures[cOption].push( featureNode ); 3778 insert.append( featureNode ); 3779 } 3780 } 3781 3782 /* Built our DOM structure - replace the holding div with what we want */ 3783 holding.replaceWith( insert ); 3784 oSettings.nHolding = null; 3785 } 3786 3787 3788 /** 3789 * Use the DOM source to create up an array of header cells. The idea here is to 3790 * create a layout grid (array) of rows x columns, which contains a reference 3791 * to the cell that that point in the grid (regardless of col/rowspan), such that 3792 * any column / row could be removed and the new grid constructed 3793 * @param array {object} aLayout Array to store the calculated layout in 3794 * @param {node} nThead The header/footer element for the table 3795 * @memberof DataTable#oApi 3796 */ 3797 function _fnDetectHeader ( aLayout, nThead ) 3798 { 3799 var nTrs = $(nThead).children('tr'); 3800 var nTr, nCell; 3801 var i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan; 3802 var bUnique; 3803 var fnShiftCol = function ( a, i, j ) { 3804 var k = a[i]; 3805 while ( k[j] ) { 3806 j++; 3807 } 3808 return j; 3809 }; 3810 3811 aLayout.splice( 0, aLayout.length ); 3812 3813 /* We know how many rows there are in the layout - so prep it */ 3814 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ ) 3815 { 3816 aLayout.push( [] ); 3817 } 3818 3819 /* Calculate a layout array */ 3820 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ ) 3821 { 3822 nTr = nTrs[i]; 3823 iColumn = 0; 3824 3825 /* For every cell in the row... */ 3826 nCell = nTr.firstChild; 3827 while ( nCell ) { 3828 if ( nCell.nodeName.toUpperCase() == "TD" || 3829 nCell.nodeName.toUpperCase() == "TH" ) 3830 { 3831 /* Get the col and rowspan attributes from the DOM and sanitise them */ 3832 iColspan = nCell.getAttribute('colspan') * 1; 3833 iRowspan = nCell.getAttribute('rowspan') * 1; 3834 iColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan; 3835 iRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan; 3836 3837 /* There might be colspan cells already in this row, so shift our target 3838 * accordingly 3839 */ 3840 iColShifted = fnShiftCol( aLayout, i, iColumn ); 3841 3842 /* Cache calculation for unique columns */ 3843 bUnique = iColspan === 1 ? true : false; 3844 3845 /* If there is col / rowspan, copy the information into the layout grid */ 3846 for ( l=0 ; l<iColspan ; l++ ) 3847 { 3848 for ( k=0 ; k<iRowspan ; k++ ) 3849 { 3850 aLayout[i+k][iColShifted+l] = { 3851 "cell": nCell, 3852 "unique": bUnique 3853 }; 3854 aLayout[i+k].nTr = nTr; 3855 } 3856 } 3857 } 3858 nCell = nCell.nextSibling; 3859 } 3860 } 3861 } 3862 3863 3864 /** 3865 * Get an array of unique th elements, one for each column 3866 * @param {object} oSettings dataTables settings object 3867 * @param {node} nHeader automatically detect the layout from this node - optional 3868 * @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional 3869 * @returns array {node} aReturn list of unique th's 3870 * @memberof DataTable#oApi 3871 */ 3872 function _fnGetUniqueThs ( oSettings, nHeader, aLayout ) 3873 { 3874 var aReturn = []; 3875 if ( !aLayout ) 3876 { 3877 aLayout = oSettings.aoHeader; 3878 if ( nHeader ) 3879 { 3880 aLayout = []; 3881 _fnDetectHeader( aLayout, nHeader ); 3882 } 3883 } 3884 3885 for ( var i=0, iLen=aLayout.length ; i<iLen ; i++ ) 3886 { 3887 for ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ ) 3888 { 3889 if ( aLayout[i][j].unique && 3890 (!aReturn[j] || !oSettings.bSortCellsTop) ) 3891 { 3892 aReturn[j] = aLayout[i][j].cell; 3893 } 3894 } 3895 } 3896 3897 return aReturn; 3898 } 3899 3900 /** 3901 * Set the start position for draw 3902 * @param {object} oSettings dataTables settings object 3903 */ 3904 function _fnStart( oSettings ) 3905 { 3906 var bServerSide = _fnDataSource( oSettings ) == 'ssp'; 3907 var iInitDisplayStart = oSettings.iInitDisplayStart; 3908 3909 // Check and see if we have an initial draw position from state saving 3910 if ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 ) 3911 { 3912 oSettings._iDisplayStart = bServerSide ? 3913 iInitDisplayStart : 3914 iInitDisplayStart >= oSettings.fnRecordsDisplay() ? 3915 0 : 3916 iInitDisplayStart; 3917 3918 oSettings.iInitDisplayStart = -1; 3919 } 3920 } 3921 3922 /** 3923 * Create an Ajax call based on the table's settings, taking into account that 3924 * parameters can have multiple forms, and backwards compatibility. 3925 * 3926 * @param {object} oSettings dataTables settings object 3927 * @param {array} data Data to send to the server, required by 3928 * DataTables - may be augmented by developer callbacks 3929 * @param {function} fn Callback function to run when data is obtained 3930 */ 3931 function _fnBuildAjax( oSettings, data, fn ) 3932 { 3933 // Compatibility with 1.9-, allow fnServerData and event to manipulate 3934 _fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] ); 3935 3936 // Convert to object based for 1.10+ if using the old array scheme which can 3937 // come from server-side processing or serverParams 3938 if ( data && Array.isArray(data) ) { 3939 var tmp = {}; 3940 var rbracket = /(.*?)\[\]$/; 3941 3942 $.each( data, function (key, val) { 3943 var match = val.name.match(rbracket); 3944 3945 if ( match ) { 3946 // Support for arrays 3947 var name = match[0]; 3948 3949 if ( ! tmp[ name ] ) { 3950 tmp[ name ] = []; 3951 } 3952 tmp[ name ].push( val.value ); 3953 } 3954 else { 3955 tmp[val.name] = val.value; 3956 } 3957 } ); 3958 data = tmp; 3959 } 3960 3961 var ajaxData; 3962 var ajax = oSettings.ajax; 3963 var instance = oSettings.oInstance; 3964 var callback = function ( json ) { 3965 var status = oSettings.jqXHR 3966 ? oSettings.jqXHR.status 3967 : null; 3968 3969 if ( json === null || (typeof status === 'number' && status == 204 ) ) { 3970 json = {}; 3971 _fnAjaxDataSrc( oSettings, json, [] ); 3972 } 3973 3974 var error = json.error || json.sError; 3975 if ( error ) { 3976 _fnLog( oSettings, 0, error ); 3977 } 3978 3979 oSettings.json = json; 3980 3981 _fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR] ); 3982 fn( json ); 3983 }; 3984 3985 if ( $.isPlainObject( ajax ) && ajax.data ) 3986 { 3987 ajaxData = ajax.data; 3988 3989 var newData = typeof ajaxData === 'function' ? 3990 ajaxData( data, oSettings ) : // fn can manipulate data or return 3991 ajaxData; // an object object or array to merge 3992 3993 // If the function returned something, use that alone 3994 data = typeof ajaxData === 'function' && newData ? 3995 newData : 3996 $.extend( true, data, newData ); 3997 3998 // Remove the data property as we've resolved it already and don't want 3999 // jQuery to do it again (it is restored at the end of the function) 4000 delete ajax.data; 4001 } 4002 4003 var baseAjax = { 4004 "data": data, 4005 "success": callback, 4006 "dataType": "json", 4007 "cache": false, 4008 "type": oSettings.sServerMethod, 4009 "error": function (xhr, error, thrown) { 4010 var ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR] ); 4011 4012 if ( $.inArray( true, ret ) === -1 ) { 4013 if ( error == "parsererror" ) { 4014 _fnLog( oSettings, 0, 'Invalid JSON response', 1 ); 4015 } 4016 else if ( xhr.readyState === 4 ) { 4017 _fnLog( oSettings, 0, 'Ajax error', 7 ); 4018 } 4019 } 4020 4021 _fnProcessingDisplay( oSettings, false ); 4022 } 4023 }; 4024 4025 // Store the data submitted for the API 4026 oSettings.oAjaxData = data; 4027 4028 // Allow plug-ins and external processes to modify the data 4029 _fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data] ); 4030 4031 if ( oSettings.fnServerData ) 4032 { 4033 // DataTables 1.9- compatibility 4034 oSettings.fnServerData.call( instance, 4035 oSettings.sAjaxSource, 4036 $.map( data, function (val, key) { // Need to convert back to 1.9 trad format 4037 return { name: key, value: val }; 4038 } ), 4039 callback, 4040 oSettings 4041 ); 4042 } 4043 else if ( oSettings.sAjaxSource || typeof ajax === 'string' ) 4044 { 4045 // DataTables 1.9- compatibility 4046 oSettings.jqXHR = $.ajax( $.extend( baseAjax, { 4047 url: ajax || oSettings.sAjaxSource 4048 } ) ); 4049 } 4050 else if ( typeof ajax === 'function' ) 4051 { 4052 // Is a function - let the caller define what needs to be done 4053 oSettings.jqXHR = ajax.call( instance, data, callback, oSettings ); 4054 } 4055 else 4056 { 4057 // Object to extend the base settings 4058 oSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) ); 4059 4060 // Restore for next time around 4061 ajax.data = ajaxData; 4062 } 4063 } 4064 4065 4066 /** 4067 * Update the table using an Ajax call 4068 * @param {object} settings dataTables settings object 4069 * @returns {boolean} Block the table drawing or not 4070 * @memberof DataTable#oApi 4071 */ 4072 function _fnAjaxUpdate( settings ) 4073 { 4074 settings.iDraw++; 4075 _fnProcessingDisplay( settings, true ); 4076 4077 // Keep track of drawHold state to handle scrolling after the Ajax call 4078 var drawHold = settings._drawHold; 4079 4080 _fnBuildAjax( 4081 settings, 4082 _fnAjaxParameters( settings ), 4083 function(json) { 4084 settings._drawHold = drawHold; 4085 _fnAjaxUpdateDraw( settings, json ); 4086 settings._drawHold = false; 4087 } 4088 ); 4089 } 4090 4091 4092 /** 4093 * Build up the parameters in an object needed for a server-side processing 4094 * request. Note that this is basically done twice, is different ways - a modern 4095 * method which is used by default in DataTables 1.10 which uses objects and 4096 * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if 4097 * the sAjaxSource option is used in the initialisation, or the legacyAjax 4098 * option is set. 4099 * @param {object} oSettings dataTables settings object 4100 * @returns {bool} block the table drawing or not 4101 * @memberof DataTable#oApi 4102 */ 4103 function _fnAjaxParameters( settings ) 4104 { 4105 var 4106 columns = settings.aoColumns, 4107 columnCount = columns.length, 4108 features = settings.oFeatures, 4109 preSearch = settings.oPreviousSearch, 4110 preColSearch = settings.aoPreSearchCols, 4111 i, data = [], dataProp, column, columnSearch, 4112 sort = _fnSortFlatten( settings ), 4113 displayStart = settings._iDisplayStart, 4114 displayLength = features.bPaginate !== false ? 4115 settings._iDisplayLength : 4116 -1; 4117 4118 var param = function ( name, value ) { 4119 data.push( { 'name': name, 'value': value } ); 4120 }; 4121 4122 // DataTables 1.9- compatible method 4123 param( 'sEcho', settings.iDraw ); 4124 param( 'iColumns', columnCount ); 4125 param( 'sColumns', _pluck( columns, 'sName' ).join(',') ); 4126 param( 'iDisplayStart', displayStart ); 4127 param( 'iDisplayLength', displayLength ); 4128 4129 // DataTables 1.10+ method 4130 var d = { 4131 draw: settings.iDraw, 4132 columns: [], 4133 order: [], 4134 start: displayStart, 4135 length: displayLength, 4136 search: { 4137 value: preSearch.sSearch, 4138 regex: preSearch.bRegex 4139 } 4140 }; 4141 4142 for ( i=0 ; i<columnCount ; i++ ) { 4143 column = columns[i]; 4144 columnSearch = preColSearch[i]; 4145 dataProp = typeof column.mData=="function" ? 'function' : column.mData ; 4146 4147 d.columns.push( { 4148 data: dataProp, 4149 name: column.sName, 4150 searchable: column.bSearchable, 4151 orderable: column.bSortable, 4152 search: { 4153 value: columnSearch.sSearch, 4154 regex: columnSearch.bRegex 4155 } 4156 } ); 4157 4158 param( "mDataProp_"+i, dataProp ); 4159 4160 if ( features.bFilter ) { 4161 param( 'sSearch_'+i, columnSearch.sSearch ); 4162 param( 'bRegex_'+i, columnSearch.bRegex ); 4163 param( 'bSearchable_'+i, column.bSearchable ); 4164 } 4165 4166 if ( features.bSort ) { 4167 param( 'bSortable_'+i, column.bSortable ); 4168 } 4169 } 4170 4171 if ( features.bFilter ) { 4172 param( 'sSearch', preSearch.sSearch ); 4173 param( 'bRegex', preSearch.bRegex ); 4174 } 4175 4176 if ( features.bSort ) { 4177 $.each( sort, function ( i, val ) { 4178 d.order.push( { column: val.col, dir: val.dir } ); 4179 4180 param( 'iSortCol_'+i, val.col ); 4181 param( 'sSortDir_'+i, val.dir ); 4182 } ); 4183 4184 param( 'iSortingCols', sort.length ); 4185 } 4186 4187 // If the legacy.ajax parameter is null, then we automatically decide which 4188 // form to use, based on sAjaxSource 4189 var legacy = DataTable.ext.legacy.ajax; 4190 if ( legacy === null ) { 4191 return settings.sAjaxSource ? data : d; 4192 } 4193 4194 // Otherwise, if legacy has been specified then we use that to decide on the 4195 // form 4196 return legacy ? data : d; 4197 } 4198 4199 4200 /** 4201 * Data the data from the server (nuking the old) and redraw the table 4202 * @param {object} oSettings dataTables settings object 4203 * @param {object} json json data return from the server. 4204 * @param {string} json.sEcho Tracking flag for DataTables to match requests 4205 * @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering 4206 * @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering 4207 * @param {array} json.aaData The data to display on this page 4208 * @param {string} [json.sColumns] Column ordering (sName, comma separated) 4209 * @memberof DataTable#oApi 4210 */ 4211 function _fnAjaxUpdateDraw ( settings, json ) 4212 { 4213 // v1.10 uses camelCase variables, while 1.9 uses Hungarian notation. 4214 // Support both 4215 var compat = function ( old, modern ) { 4216 return json[old] !== undefined ? json[old] : json[modern]; 4217 }; 4218 4219 var data = _fnAjaxDataSrc( settings, json ); 4220 var draw = compat( 'sEcho', 'draw' ); 4221 var recordsTotal = compat( 'iTotalRecords', 'recordsTotal' ); 4222 var recordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' ); 4223 4224 if ( draw !== undefined ) { 4225 // Protect against out of sequence returns 4226 if ( draw*1 < settings.iDraw ) { 4227 return; 4228 } 4229 settings.iDraw = draw * 1; 4230 } 4231 4232 // No data in returned object, so rather than an array, we show an empty table 4233 if ( ! data ) { 4234 data = []; 4235 } 4236 4237 _fnClearTable( settings ); 4238 settings._iRecordsTotal = parseInt(recordsTotal, 10); 4239 settings._iRecordsDisplay = parseInt(recordsFiltered, 10); 4240 4241 for ( var i=0, ien=data.length ; i<ien ; i++ ) { 4242 _fnAddData( settings, data[i] ); 4243 } 4244 settings.aiDisplay = settings.aiDisplayMaster.slice(); 4245 4246 _fnDraw( settings, true ); 4247 4248 if ( ! settings._bInitComplete ) { 4249 _fnInitComplete( settings, json ); 4250 } 4251 4252 _fnProcessingDisplay( settings, false ); 4253 } 4254 4255 4256 /** 4257 * Get the data from the JSON data source to use for drawing a table. Using 4258 * `_fnGetObjectDataFn` allows the data to be sourced from a property of the 4259 * source object, or from a processing function. 4260 * @param {object} oSettings dataTables settings object 4261 * @param {object} json Data source object / array from the server 4262 * @return {array} Array of data to use 4263 */ 4264 function _fnAjaxDataSrc ( oSettings, json, write ) 4265 { 4266 var dataSrc = $.isPlainObject( oSettings.ajax ) && oSettings.ajax.dataSrc !== undefined ? 4267 oSettings.ajax.dataSrc : 4268 oSettings.sAjaxDataProp; // Compatibility with 1.9-. 4269 4270 if ( ! write ) { 4271 if ( dataSrc === 'data' ) { 4272 // If the default, then we still want to support the old style, and safely ignore 4273 // it if possible 4274 return json.aaData || json[dataSrc]; 4275 } 4276 4277 return dataSrc !== "" ? 4278 _fnGetObjectDataFn( dataSrc )( json ) : 4279 json; 4280 } 4281 4282 // set 4283 _fnSetObjectDataFn( dataSrc )( json, write ); 4284 } 4285 4286 /** 4287 * Generate the node required for filtering text 4288 * @returns {node} Filter control element 4289 * @param {object} oSettings dataTables settings object 4290 * @memberof DataTable#oApi 4291 */ 4292 function _fnFeatureHtmlFilter ( settings ) 4293 { 4294 var classes = settings.oClasses; 4295 var tableId = settings.sTableId; 4296 var language = settings.oLanguage; 4297 var previousSearch = settings.oPreviousSearch; 4298 var features = settings.aanFeatures; 4299 var input = '<input type="search" class="'+classes.sFilterInput+'"/>'; 4300 4301 var str = language.sSearch; 4302 str = str.match(/_INPUT_/) ? 4303 str.replace('_INPUT_', input) : 4304 str+input; 4305 4306 var filter = $('<div/>', { 4307 'id': ! features.f ? tableId+'_filter' : null, 4308 'class': classes.sFilter 4309 } ) 4310 .append( $('<label/>' ).append( str ) ); 4311 4312 var searchFn = function(event) { 4313 /* Update all other filter input elements for the new display */ 4314 var n = features.f; 4315 var val = !this.value ? "" : this.value; // mental IE8 fix :-( 4316 if(previousSearch
vendor: 10,320 bytes, lines 4316-4653
4316['return'] && event.key !== "Enter") { 4317 return; 4318 } 4319 /* Now do the filter */ 4320 if ( val != previousSearch.sSearch ) { 4321 _fnFilterComplete( settings, { 4322 "sSearch": val, 4323 "bRegex": previousSearch.bRegex, 4324 "bSmart": previousSearch.bSmart , 4325 "bCaseInsensitive": previousSearch.bCaseInsensitive, 4326 "return": previousSearch['return'] 4327 } ); 4328 4329 // Need to redraw, without resorting 4330 settings._iDisplayStart = 0; 4331 _fnDraw( settings ); 4332 } 4333 }; 4334 4335 var searchDelay = settings.searchDelay !== null ? 4336 settings.searchDelay : 4337 _fnDataSource( settings ) === 'ssp' ? 4338 400 : 4339 0; 4340 4341 var jqFilter = $('input', filter) 4342 .val( previousSearch.sSearch ) 4343 .attr( 'placeholder', language.sSearchPlaceholder ) 4344 .on( 4345 'keyup.DT search.DT input.DT paste.DT cut.DT', 4346 searchDelay ? 4347 _fnThrottle( searchFn, searchDelay ) : 4348 searchFn 4349 ) 4350 .on( 'mouseup.DT', function(e) { 4351 // Edge fix! Edge 17 does not trigger anything other than mouse events when clicking 4352 // on the clear icon (Edge bug 17584515). This is safe in other browsers as `searchFn` 4353 // checks the value to see if it has changed. In other browsers it won't have. 4354 setTimeout( function () { 4355 searchFn.call(jqFilter[0], e); 4356 }, 10); 4357 } ) 4358 .on( 'keypress.DT', function(e) { 4359 /* Prevent form submission */ 4360 if ( e.keyCode == 13 ) { 4361 return false; 4362 } 4363 } ) 4364 .attr('aria-controls', tableId); 4365 4366 // Update the input elements whenever the table is filtered 4367 $(settings.nTable).on( 'search.dt.DT', function ( ev, s ) { 4368 if ( settings === s ) { 4369 // IE9 throws an 'unknown error' if document.activeElement is used 4370 // inside an iframe or frame... 4371 try { 4372 if ( jqFilter[0] !== document.activeElement ) { 4373 jqFilter.val( previousSearch.sSearch ); 4374 } 4375 } 4376 catch ( e ) {} 4377 } 4378 } ); 4379 4380 return filter[0]; 4381 } 4382 4383 4384 /** 4385 * Filter the table using both the global filter and column based filtering 4386 * @param {object} oSettings dataTables settings object 4387 * @param {object} oSearch search information 4388 * @param {int} [iForce] force a research of the master array (1) or not (undefined or 0) 4389 * @memberof DataTable#oApi 4390 */ 4391 function _fnFilterComplete ( oSettings, oInput, iForce ) 4392 { 4393 var oPrevSearch = oSettings.oPreviousSearch; 4394 var aoPrevSearch = oSettings.aoPreSearchCols; 4395 var fnSaveFilter = function ( oFilter ) { 4396 /* Save the filtering values */ 4397 oPrevSearch.sSearch = oFilter.sSearch; 4398 oPrevSearch.bRegex = oFilter.bRegex; 4399 oPrevSearch.bSmart = oFilter.bSmart; 4400 oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive; 4401 oPrevSearch['return'] = oFilter['return']; 4402 }; 4403 var fnRegex = function ( o ) { 4404 // Backwards compatibility with the bEscapeRegex option 4405 return o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex; 4406 }; 4407 4408 // Resolve any column types that are unknown due to addition or invalidation 4409 // @todo As per sort - can this be moved into an event handler? 4410 _fnColumnTypes( oSettings ); 4411 4412 /* In server-side processing all filtering is done by the server, so no point hanging around here */ 4413 if ( _fnDataSource( oSettings ) != 'ssp' ) 4414 { 4415 /* Global filter */ 4416 _fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive ); 4417 fnSaveFilter( oInput ); 4418 4419 /* Now do the individual column filter */ 4420 for ( var i=0 ; i<aoPrevSearch.length ; i++ ) 4421 { 4422 _fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, fnRegex(aoPrevSearch[i]), 4423 aoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive ); 4424 } 4425 4426 /* Custom filtering */ 4427 _fnFilterCustom( oSettings ); 4428 } 4429 else 4430 { 4431 fnSaveFilter( oInput ); 4432 } 4433 4434 /* Tell the draw function we have been filtering */ 4435 oSettings.bFiltered = true; 4436 _fnCallbackFire( oSettings, null, 'search', [oSettings] ); 4437 } 4438 4439 4440 /** 4441 * Apply custom filtering functions 4442 * @param {object} oSettings dataTables settings object 4443 * @memberof DataTable#oApi 4444 */ 4445 function _fnFilterCustom( settings ) 4446 { 4447 var filters = DataTable.ext.search; 4448 var displayRows = settings.aiDisplay; 4449 var row, rowIdx; 4450 4451 for ( var i=0, ien=filters.length ; i<ien ; i++ ) { 4452 var rows = []; 4453 4454 // Loop over each row and see if it should be included 4455 for ( var j=0, jen=displayRows.length ; j<jen ; j++ ) { 4456 rowIdx = displayRows[ j ]; 4457 row = settings.aoData[ rowIdx ]; 4458 4459 if ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) { 4460 rows.push( rowIdx ); 4461 } 4462 } 4463 4464 // So the array reference doesn't break set the results into the 4465 // existing array 4466 displayRows.length = 0; 4467 $.merge( displayRows, rows ); 4468 } 4469 } 4470 4471 4472 /** 4473 * Filter the table on a per-column basis 4474 * @param {object} oSettings dataTables settings object 4475 * @param {string} sInput string to filter on 4476 * @param {int} iColumn column to filter 4477 * @param {bool} bRegex treat search string as a regular expression or not 4478 * @param {bool} bSmart use smart filtering or not 4479 * @param {bool} bCaseInsensitive Do case insensitive matching or not 4480 * @memberof DataTable#oApi 4481 */ 4482 function _fnFilterColumn ( settings, searchStr, colIdx, regex, smart, caseInsensitive ) 4483 { 4484 if ( searchStr === '' ) { 4485 return; 4486 } 4487 4488 var data; 4489 var out = []; 4490 var display = settings.aiDisplay; 4491 var rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive ); 4492 4493 for ( var i=0 ; i<display.length ; i++ ) { 4494 data = settings.aoData[ display[i] ]._aFilterData[ colIdx ]; 4495 4496 if ( rpSearch.test( data ) ) { 4497 out.push( display[i] ); 4498 } 4499 } 4500 4501 settings.aiDisplay = out; 4502 } 4503 4504 4505 /** 4506 * Filter the data table based on user input and draw the table 4507 * @param {object} settings dataTables settings object 4508 * @param {string} input string to filter on 4509 * @param {int} force optional - force a research of the master array (1) or not (undefined or 0) 4510 * @param {bool} regex treat as a regular expression or not 4511 * @param {bool} smart perform smart filtering or not 4512 * @param {bool} caseInsensitive Do case insensitive matching or not 4513 * @memberof DataTable#oApi 4514 */ 4515 function _fnFilter( settings, input, force, regex, smart, caseInsensitive ) 4516 { 4517 var rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive ); 4518 var prevSearch = settings.oPreviousSearch.sSearch; 4519 var displayMaster = settings.aiDisplayMaster; 4520 var display, invalidated, i; 4521 var filtered = []; 4522 4523 // Need to take account of custom filtering functions - always filter 4524 if ( DataTable.ext.search.length !== 0 ) { 4525 force = true; 4526 } 4527 4528 // Check if any of the rows were invalidated 4529 invalidated = _fnFilterData( settings ); 4530 4531 // If the input is blank - we just want the full data set 4532 if ( input.length <= 0 ) { 4533 settings.aiDisplay = displayMaster.slice(); 4534 } 4535 else { 4536 // New search - start from the master array 4537 if ( invalidated || 4538 force || 4539 regex || 4540 prevSearch.length > input.length || 4541 input.indexOf(prevSearch) !== 0 || 4542 settings.bSorted // On resort, the display master needs to be 4543 // re-filtered since indexes will have changed 4544 ) { 4545 settings.aiDisplay = displayMaster.slice(); 4546 } 4547 4548 // Search the display array 4549 display = settings.aiDisplay; 4550 4551 for ( i=0 ; i<display.length ; i++ ) { 4552 if ( rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) { 4553 filtered.push( display[i] ); 4554 } 4555 } 4556 4557 settings.aiDisplay = filtered; 4558 } 4559 } 4560 4561 4562 /** 4563 * Build a regular expression object suitable for searching a table 4564 * @param {string} sSearch string to search for 4565 * @param {bool} bRegex treat as a regular expression or not 4566 * @param {bool} bSmart perform smart filtering or not 4567 * @param {bool} bCaseInsensitive Do case insensitive matching or not 4568 * @returns {RegExp} constructed object 4569 * @memberof DataTable#oApi 4570 */ 4571 function _fnFilterCreateSearch( search, regex, smart, caseInsensitive ) 4572 { 4573 search = regex ? 4574 search : 4575 _fnEscapeRegex( search ); 4576 4577 if ( smart ) { 4578 /* For smart filtering we want to allow the search to work regardless of 4579 * word order. We also want double quoted text to be preserved, so word 4580 * order is important - a la google. So this is what we want to 4581 * generate: 4582 * 4583 * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$ 4584 */ 4585 var a = $.map( search.match( /["\u201C][^"\u201D]+["\u201D]|[^ ]+/g ) || [''], function ( word ) { 4586 if ( word.charAt(0) === '"' ) { 4587 var m = word.match( /^"(.*)"$/ ); 4588 word = m ? m[1] : word; 4589 } 4590 else if ( word.charAt(0) === '\u201C' ) { 4591 var m = word.match( /^\u201C(.*)\u201D$/ ); 4592 word = m ? m[1] : word; 4593 } 4594 4595 return word.replace('"', ''); 4596 } ); 4597 4598 search = '^(?=.*?'+a.join( ')(?=.*?' )+').*$'; 4599 } 4600 4601 return new RegExp( search, caseInsensitive ? 'i' : '' ); 4602 } 4603 4604 4605 /** 4606 * Escape a string such that it can be used in a regular expression 4607 * @param {string} sVal string to escape 4608 * @returns {string} escaped string 4609 * @memberof DataTable#oApi 4610 */ 4611 var _fnEscapeRegex = DataTable.util.escapeRegex; 4612 4613 var __filter_div = $('<div>')[0]; 4614 var __filter_div_textContent = __filter_div.textContent !== undefined; 4615 4616 // Update the filtering data for each row if needed (by invalidation or first run) 4617 function _fnFilterData ( settings ) 4618 { 4619 var columns = settings.aoColumns; 4620 var column; 4621 var i, j, ien, jen, filterData, cellData, row; 4622 var wasInvalidated = false; 4623 4624 for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) { 4625 row = settings.aoData[i]; 4626 4627 if ( ! row._aFilterData ) { 4628 filterData = []; 4629 4630 for ( j=0, jen=columns.length ; j<jen ; j++ ) { 4631 column = columns[j]; 4632 4633 if ( column.bSearchable ) { 4634 cellData = _fnGetCellData( settings, i, j, 'filter' ); 4635 4636 // Search in DataTables 1.10 is string based. In 1.11 this 4637 // should be altered to also allow strict type checking. 4638 if ( cellData === null ) { 4639 cellData = ''; 4640 } 4641 4642 if ( typeof cellData !== 'string' && cellData.toString ) { 4643 cellData = cellData.toString(); 4644 } 4645 } 4646 else { 4647 cellData = ''; 4648 } 4649 4650 // If it looks like there is an HTML entity in the string, 4651 // attempt to decode it so sorting works as expected. Note that 4652 // we could use a single line of jQuery to do this, but the DOM 4653 // method used here is much faster https
vendor: 28,961 bytes, lines 4653-5678
4653://jsperf.com/html-decode 4654 if ( cellData.indexOf && cellData.indexOf('&') !== -1 ) { 4655 __filter_div.innerHTML = cellData; 4656 cellData = __filter_div_textContent ? 4657 __filter_div.textContent : 4658 __filter_div.innerText; 4659 } 4660 4661 if ( cellData.replace ) { 4662 cellData = cellData.replace(/[\r\n\u2028]/g, ''); 4663 } 4664 4665 filterData.push( cellData ); 4666 } 4667 4668 row._aFilterData = filterData; 4669 row._sFilterRow = filterData.join(' '); 4670 wasInvalidated = true; 4671 } 4672 } 4673 4674 return wasInvalidated; 4675 } 4676 4677 4678 /** 4679 * Convert from the internal Hungarian notation to camelCase for external 4680 * interaction 4681 * @param {object} obj Object to convert 4682 * @returns {object} Inverted object 4683 * @memberof DataTable#oApi 4684 */ 4685 function _fnSearchToCamel ( obj ) 4686 { 4687 return { 4688 search: obj.sSearch, 4689 smart: obj.bSmart, 4690 regex: obj.bRegex, 4691 caseInsensitive: obj.bCaseInsensitive 4692 }; 4693 } 4694 4695 4696 4697 /** 4698 * Convert from camelCase notation to the internal Hungarian. We could use the 4699 * Hungarian convert function here, but this is cleaner 4700 * @param {object} obj Object to convert 4701 * @returns {object} Inverted object 4702 * @memberof DataTable#oApi 4703 */ 4704 function _fnSearchToHung ( obj ) 4705 { 4706 return { 4707 sSearch: obj.search, 4708 bSmart: obj.smart, 4709 bRegex: obj.regex, 4710 bCaseInsensitive: obj.caseInsensitive 4711 }; 4712 } 4713 4714 /** 4715 * Generate the node required for the info display 4716 * @param {object} oSettings dataTables settings object 4717 * @returns {node} Information element 4718 * @memberof DataTable#oApi 4719 */ 4720 function _fnFeatureHtmlInfo ( settings ) 4721 { 4722 var 4723 tid = settings.sTableId, 4724 nodes = settings.aanFeatures.i, 4725 n = $('<div/>', { 4726 'class': settings.oClasses.sInfo, 4727 'id': ! nodes ? tid+'_info' : null 4728 } ); 4729 4730 if ( ! nodes ) { 4731 // Update display on each draw 4732 settings.aoDrawCallback.push( { 4733 "fn": _fnUpdateInfo, 4734 "sName": "information" 4735 } ); 4736 4737 n 4738 .attr( 'role', 'status' ) 4739 .attr( 'aria-live', 'polite' ); 4740 4741 // Table is described by our info div 4742 $(settings.nTable).attr( 'aria-describedby', tid+'_info' ); 4743 } 4744 4745 return n[0]; 4746 } 4747 4748 4749 /** 4750 * Update the information elements in the display 4751 * @param {object} settings dataTables settings object 4752 * @memberof DataTable#oApi 4753 */ 4754 function _fnUpdateInfo ( settings ) 4755 { 4756 /* Show information about the table */ 4757 var nodes = settings.aanFeatures.i; 4758 if ( nodes.length === 0 ) { 4759 return; 4760 } 4761 4762 var 4763 lang = settings.oLanguage, 4764 start = settings._iDisplayStart+1, 4765 end = settings.fnDisplayEnd(), 4766 max = settings.fnRecordsTotal(), 4767 total = settings.fnRecordsDisplay(), 4768 out = total ? 4769 lang.sInfo : 4770 lang.sInfoEmpty; 4771 4772 if ( total !== max ) { 4773 /* Record set after filtering */ 4774 out += ' ' + lang.sInfoFiltered; 4775 } 4776 4777 // Convert the macros 4778 out += lang.sInfoPostFix; 4779 out = _fnInfoMacros( settings, out ); 4780 4781 var callback = lang.fnInfoCallback; 4782 if ( callback !== null ) { 4783 out = callback.call( settings.oInstance, 4784 settings, start, end, max, total, out 4785 ); 4786 } 4787 4788 $(nodes).html( out ); 4789 } 4790 4791 4792 function _fnInfoMacros ( settings, str ) 4793 { 4794 // When infinite scrolling, we are always starting at 1. _iDisplayStart is used only 4795 // internally 4796 var 4797 formatter = settings.fnFormatNumber, 4798 start = settings._iDisplayStart+1, 4799 len = settings._iDisplayLength, 4800 vis = settings.fnRecordsDisplay(), 4801 all = len === -1; 4802 4803 return str. 4804 replace(/_START_/g, formatter.call( settings, start ) ). 4805 replace(/_END_/g, formatter.call( settings, settings.fnDisplayEnd() ) ). 4806 replace(/_MAX_/g, formatter.call( settings, settings.fnRecordsTotal() ) ). 4807 replace(/_TOTAL_/g, formatter.call( settings, vis ) ). 4808 replace(/_PAGE_/g, formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ). 4809 replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) ); 4810 } 4811 4812 4813 4814 /** 4815 * Draw the table for the first time, adding all required features 4816 * @param {object} settings dataTables settings object 4817 * @memberof DataTable#oApi 4818 */ 4819 function _fnInitialise ( settings ) 4820 { 4821 var i, iLen, iAjaxStart=settings.iInitDisplayStart; 4822 var columns = settings.aoColumns, column; 4823 var features = settings.oFeatures; 4824 var deferLoading = settings.bDeferLoading; // value modified by the draw 4825 4826 /* Ensure that the table data is fully initialised */ 4827 if ( ! settings.bInitialised ) { 4828 setTimeout( function(){ _fnInitialise( settings ); }, 200 ); 4829 return; 4830 } 4831 4832 /* Show the display HTML options */ 4833 _fnAddOptionsHtml( settings ); 4834 4835 /* Build and draw the header / footer for the table */ 4836 _fnBuildHead( settings ); 4837 _fnDrawHead( settings, settings.aoHeader ); 4838 _fnDrawHead( settings, settings.aoFooter ); 4839 4840 /* Okay to show that something is going on now */ 4841 _fnProcessingDisplay( settings, true ); 4842 4843 /* Calculate sizes for columns */ 4844 if ( features.bAutoWidth ) { 4845 _fnCalculateColumnWidths( settings ); 4846 } 4847 4848 for ( i=0, iLen=columns.length ; i<iLen ; i++ ) { 4849 column = columns[i]; 4850 4851 if ( column.sWidth ) { 4852 column.nTh.style.width = _fnStringToCss( column.sWidth ); 4853 } 4854 } 4855 4856 _fnCallbackFire( settings, null, 'preInit', [settings] ); 4857 4858 // If there is default sorting required - let's do it. The sort function 4859 // will do the drawing for us. Otherwise we draw the table regardless of the 4860 // Ajax source - this allows the table to look initialised for Ajax sourcing 4861 // data (show 'loading' message possibly) 4862 _fnReDraw( settings ); 4863 4864 // Server-side processing init complete is done by _fnAjaxUpdateDraw 4865 var dataSrc = _fnDataSource( settings ); 4866 if ( dataSrc != 'ssp' || deferLoading ) { 4867 // if there is an ajax source load the data 4868 if ( dataSrc == 'ajax' ) { 4869 _fnBuildAjax( settings, [], function(json) { 4870 var aData = _fnAjaxDataSrc( settings, json ); 4871 4872 // Got the data - add it to the table 4873 for ( i=0 ; i<aData.length ; i++ ) { 4874 _fnAddData( settings, aData[i] ); 4875 } 4876 4877 // Reset the init display for cookie saving. We've already done 4878 // a filter, and therefore cleared it before. So we need to make 4879 // it appear 'fresh' 4880 settings.iInitDisplayStart = iAjaxStart; 4881 4882 _fnReDraw( settings ); 4883 4884 _fnProcessingDisplay( settings, false ); 4885 _fnInitComplete( settings, json ); 4886 }, settings ); 4887 } 4888 else { 4889 _fnProcessingDisplay( settings, false ); 4890 _fnInitComplete( settings ); 4891 } 4892 } 4893 } 4894 4895 4896 /** 4897 * Draw the table for the first time, adding all required features 4898 * @param {object} oSettings dataTables settings object 4899 * @param {object} [json] JSON from the server that completed the table, if using Ajax source 4900 * with client-side processing (optional) 4901 * @memberof DataTable#oApi 4902 */ 4903 function _fnInitComplete ( settings, json ) 4904 { 4905 settings._bInitComplete = true; 4906 4907 // When data was added after the initialisation (data or Ajax) we need to 4908 // calculate the column sizing 4909 if ( json || settings.oInit.aaData ) { 4910 _fnAdjustColumnSizing( settings ); 4911 } 4912 4913 _fnCallbackFire( settings, null, 'plugin-init', [settings, json] ); 4914 _fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] ); 4915 } 4916 4917 4918 function _fnLengthChange ( settings, val ) 4919 { 4920 var len = parseInt( val, 10 ); 4921 settings._iDisplayLength = len; 4922 4923 _fnLengthOverflow( settings ); 4924 4925 // Fire length change event 4926 _fnCallbackFire( settings, null, 'length', [settings, len] ); 4927 } 4928 4929 4930 /** 4931 * Generate the node required for user display length changing 4932 * @param {object} settings dataTables settings object 4933 * @returns {node} Display length feature node 4934 * @memberof DataTable#oApi 4935 */ 4936 function _fnFeatureHtmlLength ( settings ) 4937 { 4938 var 4939 classes = settings.oClasses, 4940 tableId = settings.sTableId, 4941 menu = settings.aLengthMenu, 4942 d2 = Array.isArray( menu[0] ), 4943 lengths = d2 ? menu[0] : menu, 4944 language = d2 ? menu[1] : menu; 4945 4946 var select = $('<select/>', { 4947 'name': tableId+'_length', 4948 'aria-controls': tableId, 4949 'class': classes.sLengthSelect 4950 } ); 4951 4952 for ( var i=0, ien=lengths.length ; i<ien ; i++ ) { 4953 select[0][ i ] = new Option( 4954 typeof language[i] === 'number' ? 4955 settings.fnFormatNumber( language[i] ) : 4956 language[i], 4957 lengths[i] 4958 ); 4959 } 4960 4961 var div = $('<div><label/></div>').addClass( classes.sLength ); 4962 if ( ! settings.aanFeatures.l ) { 4963 div[0].id = tableId+'_length'; 4964 } 4965 4966 div.children().append( 4967 settings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML ) 4968 ); 4969 4970 // Can't use `select` variable as user might provide their own and the 4971 // reference is broken by the use of outerHTML 4972 $('select', div) 4973 .val( settings._iDisplayLength ) 4974 .on( 'change.DT', function(e) { 4975 _fnLengthChange( settings, $(this).val() ); 4976 _fnDraw( settings ); 4977 } ); 4978 4979 // Update node value whenever anything changes the table's length 4980 $(settings.nTable).on( 'length.dt.DT', function (e, s, len) { 4981 if ( settings === s ) { 4982 $('select', div).val( len ); 4983 } 4984 } ); 4985 4986 return div[0]; 4987 } 4988 4989 4990 4991 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 4992 * Note that most of the paging logic is done in 4993 * DataTable.ext.pager 4994 */ 4995 4996 /** 4997 * Generate the node required for default pagination 4998 * @param {object} oSettings dataTables settings object 4999 * @returns {node} Pagination feature node 5000 * @memberof DataTable#oApi 5001 */ 5002 function _fnFeatureHtmlPaginate ( settings ) 5003 { 5004 var 5005 type = settings.sPaginationType, 5006 plugin = DataTable.ext.pager[ type ], 5007 modern = typeof plugin === 'function', 5008 redraw = function( settings ) { 5009 _fnDraw( settings ); 5010 }, 5011 node = $('<div/>').addClass( settings.oClasses.sPaging + type )[0], 5012 features = settings.aanFeatures; 5013 5014 if ( ! modern ) { 5015 plugin.fnInit( settings, node, redraw ); 5016 } 5017 5018 /* Add a draw callback for the pagination on first instance, to update the paging display */ 5019 if ( ! features.p ) 5020 { 5021 node.id = settings.sTableId+'_paginate'; 5022 5023 settings.aoDrawCallback.push( { 5024 "fn": function( settings ) { 5025 if ( modern ) { 5026 var 5027 start = settings._iDisplayStart, 5028 len = settings._iDisplayLength, 5029 visRecords = settings.fnRecordsDisplay(), 5030 all = len === -1, 5031 page = all ? 0 : Math.ceil( start / len ), 5032 pages = all ? 1 : Math.ceil( visRecords / len ), 5033 buttons = plugin(page, pages), 5034 i, ien; 5035 5036 for ( i=0, ien=features.p.length ; i<ien ; i++ ) { 5037 _fnRenderer( settings, 'pageButton' )( 5038 settings, features.p[i], i, buttons, page, pages 5039 ); 5040 } 5041 } 5042 else { 5043 plugin.fnUpdate( settings, redraw ); 5044 } 5045 }, 5046 "sName": "pagination" 5047 } ); 5048 } 5049 5050 return node; 5051 } 5052 5053 5054 /** 5055 * Alter the display settings to change the page 5056 * @param {object} settings DataTables settings object 5057 * @param {string|int} action Paging action to take: "first", "previous", 5058 * "next" or "last" or page number to jump to (integer) 5059 * @param [bool] redraw Automatically draw the update or not 5060 * @returns {bool} true page has changed, false - no change 5061 * @memberof DataTable#oApi 5062 */ 5063 function _fnPageChange ( settings, action, redraw ) 5064 { 5065 var 5066 start = settings._iDisplayStart, 5067 len = settings._iDisplayLength, 5068 records = settings.fnRecordsDisplay(); 5069 5070 if ( records === 0 || len === -1 ) 5071 { 5072 start = 0; 5073 } 5074 else if ( typeof action === "number" ) 5075 { 5076 start = action * len; 5077 5078 if ( start > records ) 5079 { 5080 start = 0; 5081 } 5082 } 5083 else if ( action == "first" ) 5084 { 5085 start = 0; 5086 } 5087 else if ( action == "previous" ) 5088 { 5089 start = len >= 0 ? 5090 start - len : 5091 0; 5092 5093 if ( start < 0 ) 5094 { 5095 start = 0; 5096 } 5097 } 5098 else if ( action == "next" ) 5099 { 5100 if ( start + len < records ) 5101 { 5102 start += len; 5103 } 5104 } 5105 else if ( action == "last" ) 5106 { 5107 start = Math.floor( (records-1) / len) * len; 5108 } 5109 else 5110 { 5111 _fnLog( settings, 0, "Unknown paging action: "+action, 5 ); 5112 } 5113 5114 var changed = settings._iDisplayStart !== start; 5115 settings._iDisplayStart = start; 5116 5117 if ( changed ) { 5118 _fnCallbackFire( settings, null, 'page', [settings] ); 5119 5120 if ( redraw ) { 5121 _fnDraw( settings ); 5122 } 5123 } 5124 else { 5125 // No change event - paging was called, but no change 5126 _fnCallbackFire( settings, null, 'page-nc', [settings] ); 5127 } 5128 5129 return changed; 5130 } 5131 5132 5133 5134 /** 5135 * Generate the node required for the processing node 5136 * @param {object} settings dataTables settings object 5137 * @returns {node} Processing element 5138 * @memberof DataTable#oApi 5139 */ 5140 function _fnFeatureHtmlProcessing ( settings ) 5141 { 5142 return $('<div/>', { 5143 'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null, 5144 'class': settings.oClasses.sProcessing, 5145 'role': 'status' 5146 } ) 5147 .html( settings.oLanguage.sProcessing ) 5148 .append('<div><div></div><div></div><div></div><div></div></div>') 5149 .insertBefore( settings.nTable )[0]; 5150 } 5151 5152 5153 /** 5154 * Display or hide the processing indicator 5155 * @param {object} settings dataTables settings object 5156 * @param {bool} show Show the processing indicator (true) or not (false) 5157 * @memberof DataTable#oApi 5158 */ 5159 function _fnProcessingDisplay ( settings, show ) 5160 { 5161 if ( settings.oFeatures.bProcessing ) { 5162 $(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' ); 5163 } 5164 5165 _fnCallbackFire( settings, null, 'processing', [settings, show] ); 5166 } 5167 5168 /** 5169 * Add any control elements for the table - specifically scrolling 5170 * @param {object} settings dataTables settings object 5171 * @returns {node} Node to add to the DOM 5172 * @memberof DataTable#oApi 5173 */ 5174 function _fnFeatureHtmlTable ( settings ) 5175 { 5176 var table = $(settings.nTable); 5177 5178 // Scrolling from here on in 5179 var scroll = settings.oScroll; 5180 5181 if ( scroll.sX === '' && scroll.sY === '' ) { 5182 return settings.nTable; 5183 } 5184 5185 var scrollX = scroll.sX; 5186 var scrollY = scroll.sY; 5187 var classes = settings.oClasses; 5188 var caption = table.children('caption'); 5189 var captionSide = caption.length ? caption[0]._captionSide : null; 5190 var headerClone = $( table[0].cloneNode(false) ); 5191 var footerClone = $( table[0].cloneNode(false) ); 5192 var footer = table.children('tfoot'); 5193 var _div = '<div/>'; 5194 var size = function ( s ) { 5195 return !s ? null : _fnStringToCss( s ); 5196 }; 5197 5198 if ( ! footer.length ) { 5199 footer = null; 5200 } 5201 5202 /* 5203 * The HTML structure that we want to generate in this function is: 5204 * div - scroller 5205 * div - scroll head 5206 * div - scroll head inner 5207 * table - scroll head table 5208 * thead - thead 5209 * div - scroll body 5210 * table - table (master table) 5211 * thead - thead clone for sizing 5212 * tbody - tbody 5213 * div - scroll foot 5214 * div - scroll foot inner 5215 * table - scroll foot table 5216 * tfoot - tfoot 5217 */ 5218 var scroller = $( _div, { 'class': classes.sScrollWrapper } ) 5219 .append( 5220 $(_div, { 'class': classes.sScrollHead } ) 5221 .css( { 5222 overflow: 'hidden', 5223 position: 'relative', 5224 border: 0, 5225 width: scrollX ? size(scrollX) : '100%' 5226 } ) 5227 .append( 5228 $(_div, { 'class': classes.sScrollHeadInner } ) 5229 .css( { 5230 'box-sizing': 'content-box', 5231 width: scroll.sXInner || '100%' 5232 } ) 5233 .append( 5234 headerClone 5235 .removeAttr('id') 5236 .css( 'margin-left', 0 ) 5237 .append( captionSide === 'top' ? caption : null ) 5238 .append( 5239 table.children('thead') 5240 ) 5241 ) 5242 ) 5243 ) 5244 .append( 5245 $(_div, { 'class': classes.sScrollBody } ) 5246 .css( { 5247 position: 'relative', 5248 overflow: 'auto', 5249 width: size( scrollX ) 5250 } ) 5251 .append( table ) 5252 ); 5253 5254 if ( footer ) { 5255 scroller.append( 5256 $(_div, { 'class': classes.sScrollFoot } ) 5257 .css( { 5258 overflow: 'hidden', 5259 border: 0, 5260 width: scrollX ? size(scrollX) : '100%' 5261 } ) 5262 .append( 5263 $(_div, { 'class': classes.sScrollFootInner } ) 5264 .append( 5265 footerClone 5266 .removeAttr('id') 5267 .css( 'margin-left', 0 ) 5268 .append( captionSide === 'bottom' ? caption : null ) 5269 .append( 5270 table.children('tfoot') 5271 ) 5272 ) 5273 ) 5274 ); 5275 } 5276 5277 var children = scroller.children(); 5278 var scrollHead = children[0]; 5279 var scrollBody = children[1]; 5280 var scrollFoot = footer ? children[2] : null; 5281 5282 // When the body is scrolled, then we also want to scroll the headers 5283 if ( scrollX ) { 5284 $(scrollBody).on( 'scroll.DT', function (e) { 5285 var scrollLeft = this.scrollLeft; 5286 5287 scrollHead.scrollLeft = scrollLeft; 5288 5289 if ( footer ) { 5290 scrollFoot.scrollLeft = scrollLeft; 5291 } 5292 } ); 5293 } 5294 5295 $(scrollBody).css('max-height', scrollY); 5296 if (! scroll.bCollapse) { 5297 $(scrollBody).css('height', scrollY); 5298 } 5299 5300 settings.nScrollHead = scrollHead; 5301 settings.nScrollBody = scrollBody; 5302 settings.nScrollFoot = scrollFoot; 5303 5304 // On redraw - align columns 5305 settings.aoDrawCallback.push( { 5306 "fn": _fnScrollDraw, 5307 "sName": "scrolling" 5308 } ); 5309 5310 return scroller[0]; 5311 } 5312 5313 5314 5315 /** 5316 * Update the header, footer and body tables for resizing - i.e. column 5317 * alignment. 5318 * 5319 * Welcome to the most horrible function DataTables. The process that this 5320 * function follows is basically: 5321 * 1. Re-create the table inside the scrolling div 5322 * 2. Take live measurements from the DOM 5323 * 3. Apply the measurements to align the columns 5324 * 4. Clean up 5325 * 5326 * @param {object} settings dataTables settings object 5327 * @memberof DataTable#oApi 5328 */ 5329 function _fnScrollDraw ( settings ) 5330 { 5331 // Given that this is such a monster function, a lot of variables are use 5332 // to try and keep the minimised size as small as possible 5333 var 5334 scroll = settings.oScroll, 5335 scrollX = scroll.sX, 5336 scrollXInner = scroll.sXInner, 5337 scrollY = scroll.sY, 5338 barWidth = scroll.iBarWidth, 5339 divHeader = $(settings.nScrollHead), 5340 divHeaderStyle = divHeader[0].style, 5341 divHeaderInner = divHeader.children('div'), 5342 divHeaderInnerStyle = divHeaderInner[0].style, 5343 divHeaderTable = divHeaderInner.children('table'), 5344 divBodyEl = settings.nScrollBody, 5345 divBody = $(divBodyEl), 5346 divBodyStyle = divBodyEl.style, 5347 divFooter = $(settings.nScrollFoot), 5348 divFooterInner = divFooter.children('div'), 5349 divFooterTable = divFooterInner.children('table'), 5350 header = $(settings.nTHead), 5351 table = $(settings.nTable), 5352 tableEl = table[0], 5353 tableStyle = tableEl.style, 5354 footer = settings.nTFoot ? $(settings.nTFoot) : null, 5355 browser = settings.oBrowser, 5356 ie67 = browser.bScrollOversize, 5357 dtHeaderCells = _pluck( settings.aoColumns, 'nTh' ), 5358 headerTrgEls, footerTrgEls, 5359 headerSrcEls, footerSrcEls, 5360 headerCopy, footerCopy, 5361 headerWidths=[], footerWidths=[], 5362 headerContent=[], footerContent=[], 5363 idx, correction, sanityWidth, 5364 zeroOut = function(nSizer) { 5365 var style = nSizer.style; 5366 style.paddingTop = "0"; 5367 style.paddingBottom = "0"; 5368 style.borderTopWidth = "0"; 5369 style.borderBottomWidth = "0"; 5370 style.height = 0; 5371 }; 5372 5373 // If the scrollbar visibility has changed from the last draw, we need to 5374 // adjust the column sizes as the table width will have changed to account 5375 // for the scrollbar 5376 var scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight; 5377 5378 if ( settings.scrollBarVis !== scrollBarVis && settings.scrollBarVis !== undefined ) { 5379 settings.scrollBarVis = scrollBarVis; 5380 _fnAdjustColumnSizing( settings ); 5381 return; // adjust column sizing will call this function again 5382 } 5383 else { 5384 settings.scrollBarVis = scrollBarVis; 5385 } 5386 5387 /* 5388 * 1. Re-create the table inside the scrolling div 5389 */ 5390 5391 // Remove the old minimised thead and tfoot elements in the inner table 5392 table.children('thead, tfoot').remove(); 5393 5394 if ( footer ) { 5395 footerCopy = footer.clone().prependTo( table ); 5396 footerTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized 5397 footerSrcEls = footerCopy.find('tr'); 5398 footerCopy.find('[id]').removeAttr('id'); 5399 } 5400 5401 // Clone the current header and footer elements and then place it into the inner table 5402 headerCopy = header.clone().prependTo( table ); 5403 headerTrgEls = header.find('tr'); // original header is in its own table 5404 headerSrcEls = headerCopy.find('tr'); 5405 headerCopy.find('th, td').removeAttr('tabindex'); 5406 headerCopy.find('[id]').removeAttr('id'); 5407 5408 5409 /* 5410 * 2. Take live measurements from the DOM - do not alter the DOM itself! 5411 */ 5412 5413 // Remove old sizing and apply the calculated column widths 5414 // Get the unique column headers in the newly created (cloned) header. We want to apply the 5415 // calculated sizes to this header 5416 if ( ! scrollX ) 5417 { 5418 divBodyStyle.width = '100%'; 5419 divHeader[0].style.width = '100%'; 5420 } 5421 5422 $.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) { 5423 idx = _fnVisibleToColumnIndex( settings, i ); 5424 el.style.width = settings.aoColumns[idx].sWidth; 5425 } ); 5426 5427 if ( footer ) { 5428 _fnApplyToChildren( function(n) { 5429 n.style.width = ""; 5430 }, footerSrcEls ); 5431 } 5432 5433 // Size the table as a whole 5434 sanityWidth = table.outerWidth(); 5435 if ( scrollX === "" ) { 5436 // No x scrolling 5437 tableStyle.width = "100%"; 5438 5439 // IE7 will make the width of the table when 100% include the scrollbar 5440 // - which is shouldn't. When there is a scrollbar we need to take this 5441 // into account. 5442 if ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight || 5443 divBody.css('overflow-y') == "scroll") 5444 ) { 5445 tableStyle.width = _fnStringToCss( table.outerWidth() - barWidth); 5446 } 5447 5448 // Recalculate the sanity width 5449 sanityWidth = table.outerWidth(); 5450 } 5451 else if ( scrollXInner !== "" ) { 5452 // legacy x scroll inner has been given - use it 5453 tableStyle.width = _fnStringToCss(scrollXInner); 5454 5455 // Recalculate the sanity width 5456 sanityWidth = table.outerWidth(); 5457 } 5458 5459 // Hidden header should have zero height, so remove padding and borders. Then 5460 // set the width based on the real headers 5461 5462 // Apply all styles in one pass 5463 _fnApplyToChildren( zeroOut, headerSrcEls ); 5464 5465 // Read all widths in next pass 5466 _fnApplyToChildren( function(nSizer) { 5467 var style = window.getComputedStyle ? 5468 window.getComputedStyle(nSizer).width : 5469 _fnStringToCss( $(nSizer).width() ); 5470 5471 headerContent.push( nSizer.innerHTML ); 5472 headerWidths.push( style ); 5473 }, headerSrcEls ); 5474 5475 // Apply all widths in final pass 5476 _fnApplyToChildren( function(nToSize, i) { 5477 nToSize.style.width = headerWidths[i]; 5478 }, headerTrgEls ); 5479 5480 $(headerSrcEls).css('height', 0); 5481 5482 /* Same again with the footer if we have one */ 5483 if ( footer ) 5484 { 5485 _fnApplyToChildren( zeroOut, footerSrcEls ); 5486 5487 _fnApplyToChildren( function(nSizer) { 5488 footerContent.push( nSizer.innerHTML ); 5489 footerWidths.push( _fnStringToCss( $(nSizer).css('width') ) ); 5490 }, footerSrcEls ); 5491 5492 _fnApplyToChildren( function(nToSize, i) { 5493 nToSize.style.width = footerWidths[i]; 5494 }, footerTrgEls ); 5495 5496 $(footerSrcEls).height(0); 5497 } 5498 5499 5500 /* 5501 * 3. Apply the measurements 5502 */ 5503 5504 // "Hide" the header and footer that we used for the sizing. We need to keep 5505 // the content of the cell so that the width applied to the header and body 5506 // both match, but we want to hide it completely. We want to also fix their 5507 // width to what they currently are 5508 _fnApplyToChildren( function(nSizer, i) { 5509 nSizer.innerHTML = '<div class="dataTables_sizing">'+headerContent[i]+'</div>'; 5510 nSizer.childNodes[0].style.height = "0"; 5511 nSizer.childNodes[0].style.overflow = "hidden"; 5512 nSizer.style.width = headerWidths[i]; 5513 }, headerSrcEls ); 5514 5515 if ( footer ) 5516 { 5517 _fnApplyToChildren( function(nSizer, i) { 5518 nSizer.innerHTML = '<div class="dataTables_sizing">'+footerContent[i]+'</div>'; 5519 nSizer.childNodes[0].style.height = "0"; 5520 nSizer.childNodes[0].style.overflow = "hidden"; 5521 nSizer.style.width = footerWidths[i]; 5522 }, footerSrcEls ); 5523 } 5524 5525 // Sanity check that the table is of a sensible width. If not then we are going to get 5526 // misalignment - try to prevent this by not allowing the table to shrink below its min width 5527 if ( Math.round(table.outerWidth()) < Math.round(sanityWidth) ) 5528 { 5529 // The min width depends upon if we have a vertical scrollbar visible or not */ 5530 correction = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight || 5531 divBody.css('overflow-y') == "scroll")) ? 5532 sanityWidth+barWidth : 5533 sanityWidth; 5534 5535 // IE6/7 are a law unto themselves... 5536 if ( ie67 && (divBodyEl.scrollHeight > 5537 divBodyEl.offsetHeight || divBody.css('overflow-y') == "scroll") 5538 ) { 5539 tableStyle.width = _fnStringToCss( correction-barWidth ); 5540 } 5541 5542 // And give the user a warning that we've stopped the table getting too small 5543 if ( scrollX === "" || scrollXInner !== "" ) { 5544 _fnLog( settings, 1, 'Possible column misalignment', 6 ); 5545 } 5546 } 5547 else 5548 { 5549 correction = '100%'; 5550 } 5551 5552 // Apply to the container elements 5553 divBodyStyle.width = _fnStringToCss( correction ); 5554 divHeaderStyle.width = _fnStringToCss( correction ); 5555 5556 if ( footer ) { 5557 settings.nScrollFoot.style.width = _fnStringToCss( correction ); 5558 } 5559 5560 5561 /* 5562 * 4. Clean up 5563 */ 5564 if ( ! scrollY ) { 5565 /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting 5566 * the scrollbar height from the visible display, rather than adding it on. We need to 5567 * set the height in order to sort this. Don't want to do it in any other browsers. 5568 */ 5569 if ( ie67 ) { 5570 divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth ); 5571 } 5572 } 5573 5574 /* Finally set the width's of the header and footer tables */ 5575 var iOuterWidth = table.outerWidth(); 5576 divHeaderTable[0].style.width = _fnStringToCss( iOuterWidth ); 5577 divHeaderInnerStyle.width = _fnStringToCss( iOuterWidth ); 5578 5579 // Figure out if there are scrollbar present - if so then we need a the header and footer to 5580 // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar) 5581 var bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll"; 5582 var padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' ); 5583 divHeaderInnerStyle[ padding ] = bScrolling ? barWidth+"px" : "0px"; 5584 5585 if ( footer ) { 5586 divFooterTable[0].style.width = _fnStringToCss( iOuterWidth ); 5587 divFooterInner[0].style.width = _fnStringToCss( iOuterWidth ); 5588 divFooterInner[0].style[padding] = bScrolling ? barWidth+"px" : "0px"; 5589 } 5590 5591 // Correct DOM ordering for colgroup - comes before the thead 5592 table.children('colgroup').insertBefore( table.children('thead') ); 5593 5594 /* Adjust the position of the header in case we loose the y-scrollbar */ 5595 divBody.trigger('scroll'); 5596 5597 // If sorting or filtering has occurred, jump the scrolling back to the top 5598 // only if we aren't holding the position 5599 if ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) { 5600 divBodyEl.scrollTop = 0; 5601 } 5602 } 5603 5604 5605 5606 /** 5607 * Apply a given function to the display child nodes of an element array (typically 5608 * TD children of TR rows 5609 * @param {function} fn Method to apply to the objects 5610 * @param array {nodes} an1 List of elements to look through for display children 5611 * @param array {nodes} an2 Another list (identical structure to the first) - optional 5612 * @memberof DataTable#oApi 5613 */ 5614 function _fnApplyToChildren( fn, an1, an2 ) 5615 { 5616 var index=0, i=0, iLen=an1.length; 5617 var nNode1, nNode2; 5618 5619 while ( i < iLen ) { 5620 nNode1 = an1[i].firstChild; 5621 nNode2 = an2 ? an2[i].firstChild : null; 5622 5623 while ( nNode1 ) { 5624 if ( nNode1.nodeType === 1 ) { 5625 if ( an2 ) { 5626 fn( nNode1, nNode2, index ); 5627 } 5628 else { 5629 fn( nNode1, index ); 5630 } 5631 5632 index++; 5633 } 5634 5635 nNode1 = nNode1.nextSibling; 5636 nNode2 = an2 ? nNode2.nextSibling : null; 5637 } 5638 5639 i++; 5640 } 5641 } 5642 5643 5644 5645 var __re_html_remove = /<.*?>/g; 5646 5647 5648 /** 5649 * Calculate the width of columns for the table 5650 * @param {object} oSettings dataTables settings object 5651 * @memberof DataTable#oApi 5652 */ 5653 function _fnCalculateColumnWidths ( oSettings ) 5654 { 5655 var 5656 table = oSettings.nTable, 5657 columns = oSettings.aoColumns, 5658 scroll = oSettings.oScroll, 5659 scrollY = scroll.sY, 5660 scrollX = scroll.sX, 5661 scrollXInner = scroll.sXInner, 5662 columnCount = columns.length, 5663 visibleColumns = _fnGetColumns( oSettings, 'bVisible' ), 5664 headerCells = $('th', oSettings.nTHead), 5665 tableWidthAttr = table.getAttribute('width'), // from DOM element 5666 tableContainer = table.parentNode, 5667 userInputs = false, 5668 i, column, columnIdx, width, outerWidth, 5669 browser = oSettings.oBrowser, 5670 ie67 = browser.bScrollOversize; 5671 5672 var styleWidth = table.style.width; 5673 if ( styleWidth && styleWidth.indexOf('%') !== -1 ) { 5674 tableWidthAttr = styleWidth; 5675 } 5676 5677 /* Convert any user input sizes into pixel sizes */ 5678
5678var sizes = _fnConvertToWidth(_pluck(columns, 'sWidthOrig'), tableContainer); 5679 5680 for ( i=0 ; i<visibleColumns.length ; i++ ) { 5681 column = columns[ visibleColumns[i] ]; 5682 5683 if ( column.sWidth !== null ) { 5684 column.sWidth = sizes[i]
vendor: 6,819 bytes, lines 5684-5887
5684; 5685 5686 userInputs = true; 5687 } 5688 } 5689 5690 /* If the number of columns in the DOM equals the number that we have to 5691 * process in DataTables, then we can use the offsets that are created by 5692 * the web- browser. No custom sizes can be set in order for this to happen, 5693 * nor scrolling used 5694 */ 5695 if ( ie67 || ! userInputs && ! scrollX && ! scrollY && 5696 columnCount == _fnVisbleColumns( oSettings ) && 5697 columnCount == headerCells.length 5698 ) { 5699 for ( i=0 ; i<columnCount ; i++ ) { 5700 var colIdx = _fnVisibleToColumnIndex( oSettings, i ); 5701 5702 if ( colIdx !== null ) { 5703 columns[ colIdx ].sWidth = _fnStringToCss( headerCells.eq(i).width() ); 5704 } 5705 } 5706 } 5707 else 5708 { 5709 // Otherwise construct a single row, worst case, table with the widest 5710 // node in the data, assign any user defined widths, then insert it into 5711 // the DOM and allow the browser to do all the hard work of calculating 5712 // table widths 5713 var tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table 5714 .css( 'visibility', 'hidden' ) 5715 .removeAttr( 'id' ); 5716 5717 // Clean up the table body 5718 tmpTable.find('tbody tr').remove(); 5719 var tr = $('<tr/>').appendTo( tmpTable.find('tbody') ); 5720 5721 // Clone the table header and footer - we can't use the header / footer 5722 // from the cloned table, since if scrolling is active, the table's 5723 // real header and footer are contained in different table tags 5724 tmpTable.find('thead, tfoot').remove(); 5725 tmpTable 5726 .append( $(oSettings.nTHead).clone() ) 5727 .append( $(oSettings.nTFoot).clone() ); 5728 5729 // Remove any assigned widths from the footer (from scrolling) 5730 tmpTable.find('tfoot th, tfoot td').css('width', ''); 5731 5732 // Apply custom sizing to the cloned header 5733 headerCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] ); 5734 5735 for ( i=0 ; i<visibleColumns.length ; i++ ) { 5736 column = columns[ visibleColumns[i] ]; 5737 5738 headerCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ? 5739 _fnStringToCss( column.sWidthOrig ) : 5740 ''; 5741 5742 // For scrollX we need to force the column width otherwise the 5743 // browser will collapse it. If this width is smaller than the 5744 // width the column requires, then it will have no effect 5745 if ( column.sWidthOrig && scrollX ) { 5746 $( headerCells[i] ).append( $('<div/>').css( { 5747 width: column.sWidthOrig, 5748 margin: 0, 5749 padding: 0, 5750 border: 0, 5751 height: 1 5752 } ) ); 5753 } 5754 } 5755 5756 // Find the widest cell for each column and put it into the table 5757 if ( oSettings.aoData.length ) { 5758 for ( i=0 ; i<visibleColumns.length ; i++ ) { 5759 columnIdx = visibleColumns[i]; 5760 column = columns[ columnIdx ]; 5761 5762 $( _fnGetWidestNode( oSettings, columnIdx ) ) 5763 .clone( false ) 5764 .append( column.sContentPadding ) 5765 .appendTo( tr ); 5766 } 5767 } 5768 5769 // Tidy the temporary table - remove name attributes so there aren't 5770 // duplicated in the dom (radio elements for example) 5771 $('[name]', tmpTable).removeAttr('name'); 5772 5773 // Table has been built, attach to the document so we can work with it. 5774 // A holding element is used, positioned at the top of the container 5775 // with minimal height, so it has no effect on if the container scrolls 5776 // or not. Otherwise it might trigger scrolling when it actually isn't 5777 // needed 5778 var holder = $('<div/>').css( scrollX || scrollY ? 5779 { 5780 position: 'absolute', 5781 top: 0, 5782 left: 0, 5783 height: 1, 5784 right: 0, 5785 overflow: 'hidden' 5786 } : 5787 {} 5788 ) 5789 .append( tmpTable ) 5790 .appendTo( tableContainer ); 5791 5792 // When scrolling (X or Y) we want to set the width of the table as 5793 // appropriate. However, when not scrolling leave the table width as it 5794 // is. This results in slightly different, but I think correct behaviour 5795 if ( scrollX && scrollXInner ) { 5796 tmpTable.width( scrollXInner ); 5797 } 5798 else if ( scrollX ) { 5799 tmpTable.css( 'width', 'auto' ); 5800 tmpTable.removeAttr('width'); 5801 5802 // If there is no width attribute or style, then allow the table to 5803 // collapse 5804 if ( tmpTable.width() < tableContainer.clientWidth && tableWidthAttr ) { 5805 tmpTable.width( tableContainer.clientWidth ); 5806 } 5807 } 5808 else if ( scrollY ) { 5809 tmpTable.width( tableContainer.clientWidth ); 5810 } 5811 else if ( tableWidthAttr ) { 5812 tmpTable.width( tableWidthAttr ); 5813 } 5814 5815 // Get the width of each column in the constructed table - we need to 5816 // know the inner width (so it can be assigned to the other table's 5817 // cells) and the outer width so we can calculate the full width of the 5818 // table. This is safe since DataTables requires a unique cell for each 5819 // column, but if ever a header can span multiple columns, this will 5820 // need to be modified. 5821 var total = 0; 5822 for ( i=0 ; i<visibleColumns.length ; i++ ) { 5823 var cell = $(headerCells[i]); 5824 var border = cell.outerWidth() - cell.width(); 5825 5826 // Use getBounding... where possible (not IE8-) because it can give 5827 // sub-pixel accuracy, which we then want to round up! 5828 var bounding = browser.bBounding ? 5829 Math.ceil( headerCells[i].getBoundingClientRect().width ) : 5830 cell.outerWidth(); 5831 5832 // Total is tracked to remove any sub-pixel errors as the outerWidth 5833 // of the table might not equal the total given here (IE!). 5834 total += bounding; 5835 5836 // Width for each column to use 5837 columns[ visibleColumns[i] ].sWidth = _fnStringToCss( bounding - border ); 5838 } 5839 5840 table.style.width = _fnStringToCss( total ); 5841 5842 // Finished with the table - ditch it 5843 holder.remove(); 5844 } 5845 5846 // If there is a width attr, we want to attach an event listener which 5847 // allows the table sizing to automatically adjust when the window is 5848 // resized. Use the width attr rather than CSS, since we can't know if the 5849 // CSS is a relative value or absolute - DOM read is always px. 5850 if ( tableWidthAttr ) { 5851 table.style.width = _fnStringToCss( tableWidthAttr ); 5852 } 5853 5854 if ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) { 5855 var bindResize = function () { 5856 $(window).on('resize.DT-'+oSettings.sInstance, _fnThrottle( function () { 5857 _fnAdjustColumnSizing( oSettings ); 5858 } ) ); 5859 }; 5860 5861 // IE6/7 will crash if we bind a resize event handler on page load. 5862 // To be removed in 1.11 which drops IE6/7 support 5863 if ( ie67 ) { 5864 setTimeout( bindResize, 1000 ); 5865 } 5866 else { 5867 bindResize(); 5868 } 5869 5870 oSettings._reszEvt = true; 5871 } 5872 } 5873 5874 5875 /** 5876 * Throttle the calls to a function. Arguments and context are maintained for 5877 * the throttled function 5878 * @param {function} fn Function to be called 5879 * @param {int} [freq=200] call frequency in mS 5880 * @returns {function} wrapped function 5881 * @memberof DataTable#oApi 5882 */ 5883 var _fnThrottle = DataTable.util.throttle; 5884 5885 5886 /** 5887 * Convert a
5887set of CSS units width to pixels (e.g. 2em) 5888 * @param {string[]} widths widths to be converted 5889 * @param {node} parent parent to get the with for (required for relative widths) - optional 5890 * @returns {int[]} widths in pixels 5891 * @memberof DataTable#oApi 5892 */ 5893 function _fnConvertToWidth ( widths, parent ) 5894 { 5895 var els = []; 5896 var results = []; 5897 5898 // Add the elements in a single loop so we only need to reflow once 5899 for (var i=0 ; i<widths.length ; i++) { 5900 if (widths[i]) { 5901 els.push( 5902 $('<div/>') 5903 .css( 'width', _fnStringToCss( widths[i] ) ) 5904 .appendTo( parent || document.body ) 5905 ) 5906 } 5907 else { 5908 els.push(null); 5909 } 5910 } 5911 5912 // Get the sizes (will reflow once) 5913 for (var i=0 ; i<widths.length ; i++) { 5914 results.push(els[i] ? els[i][0].offsetWidth : null); 5915 } 5916 5917 // Tidy 5918 $(els).remove(); 5919 5920 return results
vendor: 19,949 bytes, lines 5920-6655
5920; 5921 } 5922 5923 5924 /** 5925 * Get the widest node 5926 * @param {object} settings dataTables settings object 5927 * @param {int} colIdx column of interest 5928 * @returns {node} widest table node 5929 * @memberof DataTable#oApi 5930 */ 5931 function _fnGetWidestNode( settings, colIdx ) 5932 { 5933 var idx = _fnGetMaxLenString( settings, colIdx ); 5934 if ( idx < 0 ) { 5935 return null; 5936 } 5937 5938 var data = settings.aoData[ idx ]; 5939 return ! data.nTr ? // Might not have been created when deferred rendering 5940 $('<td/>').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] : 5941 data.anCells[ colIdx ]; 5942 } 5943 5944 5945 /** 5946 * Get the maximum strlen for each data column 5947 * @param {object} settings dataTables settings object 5948 * @param {int} colIdx column of interest 5949 * @returns {string} max string length for each column 5950 * @memberof DataTable#oApi 5951 */ 5952 function _fnGetMaxLenString( settings, colIdx ) 5953 { 5954 var s, max=-1, maxIdx = -1; 5955 5956 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) { 5957 s = _fnGetCellData( settings, i, colIdx, 'display' )+''; 5958 s = s.replace( __re_html_remove, '' ); 5959 s = s.replace( / /g, ' ' ); 5960 5961 if ( s.length > max ) { 5962 max = s.length; 5963 maxIdx = i; 5964 } 5965 } 5966 5967 return maxIdx; 5968 } 5969 5970 5971 /** 5972 * Append a CSS unit (only if required) to a string 5973 * @param {string} value to css-ify 5974 * @returns {string} value with css unit 5975 * @memberof DataTable#oApi 5976 */ 5977 function _fnStringToCss( s ) 5978 { 5979 if ( s === null ) { 5980 return '0px'; 5981 } 5982 5983 if ( typeof s == 'number' ) { 5984 return s < 0 ? 5985 '0px' : 5986 s+'px'; 5987 } 5988 5989 // Check it has a unit character already 5990 return s.match(/\d$/) ? 5991 s+'px' : 5992 s; 5993 } 5994 5995 5996 5997 function _fnSortFlatten ( settings ) 5998 { 5999 var 6000 i, iLen, k, kLen, 6001 aSort = [], 6002 aiOrig = [], 6003 aoColumns = settings.aoColumns, 6004 aDataSort, iCol, sType, srcCol, 6005 fixed = settings.aaSortingFixed, 6006 fixedObj = $.isPlainObject( fixed ), 6007 nestedSort = [], 6008 add = function ( a ) { 6009 if ( a.length && ! Array.isArray( a[0] ) ) { 6010 // 1D array 6011 nestedSort.push( a ); 6012 } 6013 else { 6014 // 2D array 6015 $.merge( nestedSort, a ); 6016 } 6017 }; 6018 6019 // Build the sort array, with pre-fix and post-fix options if they have been 6020 // specified 6021 if ( Array.isArray( fixed ) ) { 6022 add( fixed ); 6023 } 6024 6025 if ( fixedObj && fixed.pre ) { 6026 add( fixed.pre ); 6027 } 6028 6029 add( settings.aaSorting ); 6030 6031 if (fixedObj && fixed.post ) { 6032 add( fixed.post ); 6033 } 6034 6035 for ( i=0 ; i<nestedSort.length ; i++ ) 6036 { 6037 srcCol = nestedSort[i][0]; 6038 aDataSort = aoColumns[ srcCol ].aDataSort; 6039 6040 for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ ) 6041 { 6042 iCol = aDataSort[k]; 6043 sType = aoColumns[ iCol ].sType || 'string'; 6044 6045 if ( nestedSort[i]._idx === undefined ) { 6046 nestedSort[i]._idx = $.inArray( nestedSort[i][1], aoColumns[iCol].asSorting ); 6047 } 6048 6049 aSort.push( { 6050 src: srcCol, 6051 col: iCol, 6052 dir: nestedSort[i][1], 6053 index: nestedSort[i]._idx, 6054 type: sType, 6055 formatter: DataTable.ext.type.order[ sType+"-pre" ] 6056 } ); 6057 } 6058 } 6059 6060 return aSort; 6061 } 6062 6063 /** 6064 * Change the order of the table 6065 * @param {object} oSettings dataTables settings object 6066 * @memberof DataTable#oApi 6067 * @todo This really needs split up! 6068 */ 6069 function _fnSort ( oSettings ) 6070 { 6071 var 6072 i, ien, iLen, j, jLen, k, kLen, 6073 sDataType, nTh, 6074 aiOrig = [], 6075 oExtSort = DataTable.ext.type.order, 6076 aoData = oSettings.aoData, 6077 aoColumns = oSettings.aoColumns, 6078 aDataSort, data, iCol, sType, oSort, 6079 formatters = 0, 6080 sortCol, 6081 displayMaster = oSettings.aiDisplayMaster, 6082 aSort; 6083 6084 // Resolve any column types that are unknown due to addition or invalidation 6085 // @todo Can this be moved into a 'data-ready' handler which is called when 6086 // data is going to be used in the table? 6087 _fnColumnTypes( oSettings ); 6088 6089 aSort = _fnSortFlatten( oSettings ); 6090 6091 for ( i=0, ien=aSort.length ; i<ien ; i++ ) { 6092 sortCol = aSort[i]; 6093 6094 // Track if we can use the fast sort algorithm 6095 if ( sortCol.formatter ) { 6096 formatters++; 6097 } 6098 6099 // Load the data needed for the sort, for each cell 6100 _fnSortData( oSettings, sortCol.col ); 6101 } 6102 6103 /* No sorting required if server-side or no sorting array */ 6104 if ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 ) 6105 { 6106 // Create a value - key array of the current row positions such that we can use their 6107 // current position during the sort, if values match, in order to perform stable sorting 6108 for ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) { 6109 aiOrig[ displayMaster[i] ] = i; 6110 } 6111 6112 /* Do the sort - here we want multi-column sorting based on a given data source (column) 6113 * and sorting function (from oSort) in a certain direction. It's reasonably complex to 6114 * follow on it's own, but this is what we want (example two column sorting): 6115 * fnLocalSorting = function(a,b){ 6116 * var iTest; 6117 * iTest = oSort['string-asc']('data11', 'data12'); 6118 * if (iTest !== 0) 6119 * return iTest; 6120 * iTest = oSort['numeric-desc']('data21', 'data22'); 6121 * if (iTest !== 0) 6122 * return iTest; 6123 * return oSort['numeric-asc']( aiOrig[a], aiOrig[b] ); 6124 * } 6125 * Basically we have a test for each sorting column, if the data in that column is equal, 6126 * test the next column. If all columns match, then we use a numeric sort on the row 6127 * positions in the original data array to provide a stable sort. 6128 * 6129 * Note - I know it seems excessive to have two sorting methods, but the first is around 6130 * 15% faster, so the second is only maintained for backwards compatibility with sorting 6131 * methods which do not have a pre-sort formatting function. 6132 */ 6133 if ( formatters === aSort.length ) { 6134 // All sort types have formatting functions 6135 displayMaster.sort( function ( a, b ) { 6136 var 6137 x, y, k, test, sort, 6138 len=aSort.length, 6139 dataA = aoData[a]._aSortData, 6140 dataB = aoData[b]._aSortData; 6141 6142 for ( k=0 ; k<len ; k++ ) { 6143 sort = aSort[k]; 6144 6145 x = dataA[ sort.col ]; 6146 y = dataB[ sort.col ]; 6147 6148 test = x<y ? -1 : x>y ? 1 : 0; 6149 if ( test !== 0 ) { 6150 return sort.dir === 'asc' ? test : -test; 6151 } 6152 } 6153 6154 x = aiOrig[a]; 6155 y = aiOrig[b]; 6156 return x<y ? -1 : x>y ? 1 : 0; 6157 } ); 6158 } 6159 else { 6160 // Depreciated - remove in 1.11 (providing a plug-in option) 6161 // Not all sort types have formatting methods, so we have to call their sorting 6162 // methods. 6163 displayMaster.sort( function ( a, b ) { 6164 var 6165 x, y, k, l, test, sort, fn, 6166 len=aSort.length, 6167 dataA = aoData[a]._aSortData, 6168 dataB = aoData[b]._aSortData; 6169 6170 for ( k=0 ; k<len ; k++ ) { 6171 sort = aSort[k]; 6172 6173 x = dataA[ sort.col ]; 6174 y = dataB[ sort.col ]; 6175 6176 fn = oExtSort[ sort.type+"-"+sort.dir ] || oExtSort[ "string-"+sort.dir ]; 6177 test = fn( x, y ); 6178 if ( test !== 0 ) { 6179 return test; 6180 } 6181 } 6182 6183 x = aiOrig[a]; 6184 y = aiOrig[b]; 6185 return x<y ? -1 : x>y ? 1 : 0; 6186 } ); 6187 } 6188 } 6189 6190 /* Tell the draw function that we have sorted the data */ 6191 oSettings.bSorted = true; 6192 } 6193 6194 6195 function _fnSortAria ( settings ) 6196 { 6197 var label; 6198 var nextSort; 6199 var columns = settings.aoColumns; 6200 var aSort = _fnSortFlatten( settings ); 6201 var oAria = settings.oLanguage.oAria; 6202 6203 // ARIA attributes - need to loop all columns, to update all (removing old 6204 // attributes as needed) 6205 for ( var i=0, iLen=columns.length ; i<iLen ; i++ ) 6206 { 6207 var col = columns[i]; 6208 var asSorting = col.asSorting; 6209 var sTitle = col.ariaTitle || col.sTitle.replace( /<.*?>/g, "" ); 6210 var th = col.nTh; 6211 6212 // IE7 is throwing an error when setting these properties with jQuery's 6213 // attr() and removeAttr() methods... 6214 th.removeAttribute('aria-sort'); 6215 6216 /* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */ 6217 if ( col.bSortable ) { 6218 if ( aSort.length > 0 && aSort[0].col == i ) { 6219 th.setAttribute('aria-sort', aSort[0].dir=="asc" ? "ascending" : "descending" ); 6220 nextSort = asSorting[ aSort[0].index+1 ] || asSorting[0]; 6221 } 6222 else { 6223 nextSort = asSorting[0]; 6224 } 6225 6226 label = sTitle + ( nextSort === "asc" ? 6227 oAria.sSortAscending : 6228 oAria.sSortDescending 6229 ); 6230 } 6231 else { 6232 label = sTitle; 6233 } 6234 6235 th.setAttribute('aria-label', label); 6236 } 6237 } 6238 6239 6240 /** 6241 * Function to run on user sort request 6242 * @param {object} settings dataTables settings object 6243 * @param {node} attachTo node to attach the handler to 6244 * @param {int} colIdx column sorting index 6245 * @param {boolean} [append=false] Append the requested sort to the existing 6246 * sort if true (i.e. multi-column sort) 6247 * @param {function} [callback] callback function 6248 * @memberof DataTable#oApi 6249 */ 6250 function _fnSortListener ( settings, colIdx, append, callback ) 6251 { 6252 var col = settings.aoColumns[ colIdx ]; 6253 var sorting = settings.aaSorting; 6254 var asSorting = col.asSorting; 6255 var nextSortIdx; 6256 var next = function ( a, overflow ) { 6257 var idx = a._idx; 6258 if ( idx === undefined ) { 6259 idx = $.inArray( a[1], asSorting ); 6260 } 6261 6262 return idx+1 < asSorting.length ? 6263 idx+1 : 6264 overflow ? 6265 null : 6266 0; 6267 }; 6268 6269 // Convert to 2D array if needed 6270 if ( typeof sorting[0] === 'number' ) { 6271 sorting = settings.aaSorting = [ sorting ]; 6272 } 6273 6274 // If appending the sort then we are multi-column sorting 6275 if ( append && settings.oFeatures.bSortMulti ) { 6276 // Are we already doing some kind of sort on this column? 6277 var sortIdx = $.inArray( colIdx, _pluck(sorting, '0') ); 6278 6279 if ( sortIdx !== -1 ) { 6280 // Yes, modify the sort 6281 nextSortIdx = next( sorting[sortIdx], true ); 6282 6283 if ( nextSortIdx === null && sorting.length === 1 ) { 6284 nextSortIdx = 0; // can't remove sorting completely 6285 } 6286 6287 if ( nextSortIdx === null ) { 6288 sorting.splice( sortIdx, 1 ); 6289 } 6290 else { 6291 sorting[sortIdx][1] = asSorting[ nextSortIdx ]; 6292 sorting[sortIdx]._idx = nextSortIdx; 6293 } 6294 } 6295 else { 6296 // No sort on this column yet 6297 sorting.push( [ colIdx, asSorting[0], 0 ] ); 6298 sorting[sorting.length-1]._idx = 0; 6299 } 6300 } 6301 else if ( sorting.length && sorting[0][0] == colIdx ) { 6302 // Single column - already sorting on this column, modify the sort 6303 nextSortIdx = next( sorting[0] ); 6304 6305 sorting.length = 1; 6306 sorting[0][1] = asSorting[ nextSortIdx ]; 6307 sorting[0]._idx = nextSortIdx; 6308 } 6309 else { 6310 // Single column - sort only on this column 6311 sorting.length = 0; 6312 sorting.push( [ colIdx, asSorting[0] ] ); 6313 sorting[0]._idx = 0; 6314 } 6315 6316 // Run the sort by calling a full redraw 6317 _fnReDraw( settings ); 6318 6319 // callback used for async user interaction 6320 if ( typeof callback == 'function' ) { 6321 callback( settings ); 6322 } 6323 } 6324 6325 6326 /** 6327 * Attach a sort handler (click) to a node 6328 * @param {object} settings dataTables settings object 6329 * @param {node} attachTo node to attach the handler to 6330 * @param {int} colIdx column sorting index 6331 * @param {function} [callback] callback function 6332 * @memberof DataTable#oApi 6333 */ 6334 function _fnSortAttachListener ( settings, attachTo, colIdx, callback ) 6335 { 6336 var col = settings.aoColumns[ colIdx ]; 6337 6338 _fnBindAction( attachTo, {}, function (e) { 6339 /* If the column is not sortable - don't to anything */ 6340 if ( col.bSortable === false ) { 6341 return; 6342 } 6343 6344 // If processing is enabled use a timeout to allow the processing 6345 // display to be shown - otherwise to it synchronously 6346 if ( settings.oFeatures.bProcessing ) { 6347 _fnProcessingDisplay( settings, true ); 6348 6349 setTimeout( function() { 6350 _fnSortListener( settings, colIdx, e.shiftKey, callback ); 6351 6352 // In server-side processing, the draw callback will remove the 6353 // processing display 6354 if ( _fnDataSource( settings ) !== 'ssp' ) { 6355 _fnProcessingDisplay( settings, false ); 6356 } 6357 }, 0 ); 6358 } 6359 else { 6360 _fnSortListener( settings, colIdx, e.shiftKey, callback ); 6361 } 6362 } ); 6363 } 6364 6365 6366 /** 6367 * Set the sorting classes on table's body, Note: it is safe to call this function 6368 * when bSort and bSortClasses are false 6369 * @param {object} oSettings dataTables settings object 6370 * @memberof DataTable#oApi 6371 */ 6372 function _fnSortingClasses( settings ) 6373 { 6374 var oldSort = settings.aLastSort; 6375 var sortClass = settings.oClasses.sSortColumn; 6376 var sort = _fnSortFlatten( settings ); 6377 var features = settings.oFeatures; 6378 var i, ien, colIdx; 6379 6380 if ( features.bSort && features.bSortClasses ) { 6381 // Remove old sorting classes 6382 for ( i=0, ien=oldSort.length ; i<ien ; i++ ) { 6383 colIdx = oldSort[i].src; 6384 6385 // Remove column sorting 6386 $( _pluck( settings.aoData, 'anCells', colIdx ) ) 6387 .removeClass( sortClass + (i<2 ? i+1 : 3) ); 6388 } 6389 6390 // Add new column sorting 6391 for ( i=0, ien=sort.length ; i<ien ; i++ ) { 6392 colIdx = sort[i].src; 6393 6394 $( _pluck( settings.aoData, 'anCells', colIdx ) ) 6395 .addClass( sortClass + (i<2 ? i+1 : 3) ); 6396 } 6397 } 6398 6399 settings.aLastSort = sort; 6400 } 6401 6402 6403 // Get the data to sort a column, be it from cache, fresh (populating the 6404 // cache), or from a sort formatter 6405 function _fnSortData( settings, idx ) 6406 { 6407 // Custom sorting function - provided by the sort data type 6408 var column = settings.aoColumns[ idx ]; 6409 var customSort = DataTable.ext.order[ column.sSortDataType ]; 6410 var customData; 6411 6412 if ( customSort ) { 6413 customData = customSort.call( settings.oInstance, settings, idx, 6414 _fnColumnIndexToVisible( settings, idx ) 6415 ); 6416 } 6417 6418 // Use / populate cache 6419 var row, cellData; 6420 var formatter = DataTable.ext.type.order[ column.sType+"-pre" ]; 6421 6422 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) { 6423 row = settings.aoData[i]; 6424 6425 if ( ! row._aSortData ) { 6426 row._aSortData = []; 6427 } 6428 6429 if ( ! row._aSortData[idx] || customSort ) { 6430 cellData = customSort ? 6431 customData[i] : // If there was a custom sort function, use data from there 6432 _fnGetCellData( settings, i, idx, 'sort' ); 6433 6434 row._aSortData[ idx ] = formatter ? 6435 formatter( cellData ) : 6436 cellData; 6437 } 6438 } 6439 } 6440 6441 6442 6443 /** 6444 * Save the state of a table 6445 * @param {object} oSettings dataTables settings object 6446 * @memberof DataTable#oApi 6447 */ 6448 function _fnSaveState ( settings ) 6449 { 6450 if (settings._bLoadingState) { 6451 return; 6452 } 6453 6454 /* Store the interesting variables */ 6455 var state = { 6456 time: +new Date(), 6457 start: settings._iDisplayStart, 6458 length: settings._iDisplayLength, 6459 order: $.extend( true, [], settings.aaSorting ), 6460 search: _fnSearchToCamel( settings.oPreviousSearch ), 6461 columns: $.map( settings.aoColumns, function ( col, i ) { 6462 return { 6463 visible: col.bVisible, 6464 search: _fnSearchToCamel( settings.aoPreSearchCols[i] ) 6465 }; 6466 } ) 6467 }; 6468 6469 settings.oSavedState = state; 6470 _fnCallbackFire( settings, "aoStateSaveParams", 'stateSaveParams', [settings, state] ); 6471 6472 if ( settings.oFeatures.bStateSave && !settings.bDestroying ) 6473 { 6474 settings.fnStateSaveCallback.call( settings.oInstance, settings, state ); 6475 } 6476 } 6477 6478 6479 /** 6480 * Attempt to load a saved table state 6481 * @param {object} oSettings dataTables settings object 6482 * @param {object} oInit DataTables init object so we can override settings 6483 * @param {function} callback Callback to execute when the state has been loaded 6484 * @memberof DataTable#oApi 6485 */ 6486 function _fnLoadState ( settings, oInit, callback ) 6487 { 6488 if ( ! settings.oFeatures.bStateSave ) { 6489 callback(); 6490 return; 6491 } 6492 6493 var loaded = function(state) { 6494 _fnImplementState(settings, state, callback); 6495 } 6496 6497 var state = settings.fnStateLoadCallback.call( settings.oInstance, settings, loaded ); 6498 6499 if ( state !== undefined ) { 6500 _fnImplementState( settings, state, callback ); 6501 } 6502 // otherwise, wait for the loaded callback to be executed 6503 6504 return true; 6505 } 6506 6507 function _fnImplementState ( settings, s, callback) { 6508 var i, ien; 6509 var columns = settings.aoColumns; 6510 settings._bLoadingState = true; 6511 6512 // When StateRestore was introduced the state could now be implemented at any time 6513 // Not just initialisation. To do this an api instance is required in some places 6514 var api = settings._bInitComplete ? new DataTable.Api(settings) : null; 6515 6516 if ( ! s || ! s.time ) { 6517 settings._bLoadingState = false; 6518 callback(); 6519 return; 6520 } 6521 6522 // Allow custom and plug-in manipulation functions to alter the saved data set and 6523 // cancelling of loading by returning false 6524 var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, s] ); 6525 if ( $.inArray( false, abStateLoad ) !== -1 ) { 6526 settings._bLoadingState = false; 6527 callback(); 6528 return; 6529 } 6530 6531 // Reject old data 6532 var duration = settings.iStateDuration; 6533 if ( duration > 0 && s.time < +new Date() - (duration*1000) ) { 6534 settings._bLoadingState = false; 6535 callback(); 6536 return; 6537 } 6538 6539 // Number of columns have changed - all bets are off, no restore of settings 6540 if ( s.columns && columns.length !== s.columns.length ) { 6541 settings._bLoadingState = false; 6542 callback(); 6543 return; 6544 } 6545 6546 // Store the saved state so it might be accessed at any time 6547 settings.oLoadedState = $.extend( true, {}, s ); 6548 6549 // Page Length 6550 if ( s.length !== undefined ) { 6551 // If already initialised just set the value directly so that the select element is also updated 6552 if (api) { 6553 api.page.len(s.length) 6554 } 6555 else { 6556 settings._iDisplayLength = s.length; 6557 } 6558 } 6559 6560 // Restore key features - todo - for 1.11 this needs to be done by 6561 // subscribed events 6562 if ( s.start !== undefined ) { 6563 if(api === null) { 6564 settings._iDisplayStart = s.start; 6565 settings.iInitDisplayStart = s.start; 6566 } 6567 else { 6568 _fnPageChange(settings, s.start/settings._iDisplayLength); 6569 } 6570 } 6571 6572 // Order 6573 if ( s.order !== undefined ) { 6574 settings.aaSorting = []; 6575 $.each( s.order, function ( i, col ) { 6576 settings.aaSorting.push( col[0] >= columns.length ? 6577 [ 0, col[1] ] : 6578 col 6579 ); 6580 } ); 6581 } 6582 6583 // Search 6584 if ( s.search !== undefined ) { 6585 $.extend( settings.oPreviousSearch, _fnSearchToHung( s.search ) ); 6586 } 6587 6588 // Columns 6589 if ( s.columns ) { 6590 for ( i=0, ien=s.columns.length ; i<ien ; i++ ) { 6591 var col = s.columns[i]; 6592 6593 // Visibility 6594 if ( col.visible !== undefined ) { 6595 // If the api is defined, the table has been initialised so we need to use it rather than internal settings 6596 if (api) { 6597 // Don't redraw the columns on every iteration of this loop, we will do this at the end instead 6598 api.column(i).visible(col.visible, false); 6599 } 6600 else { 6601 columns[i].bVisible = col.visible; 6602 } 6603 } 6604 6605 // Search 6606 if ( col.search !== undefined ) { 6607 $.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) ); 6608 } 6609 } 6610 6611 // If the api is defined then we need to adjust the columns once the visibility has been changed 6612 if (api) { 6613 api.columns.adjust(); 6614 } 6615 } 6616 6617 settings._bLoadingState = false; 6618 _fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, s] ); 6619 callback(); 6620 }; 6621 6622 6623 /** 6624 * Return the settings object for a particular table 6625 * @param {node} table table we are using as a dataTable 6626 * @returns {object} Settings object - or null if not found 6627 * @memberof DataTable#oApi 6628 */ 6629 function _fnSettingsFromNode ( table ) 6630 { 6631 var settings = DataTable.settings; 6632 var idx = $.inArray( table, _pluck( settings, 'nTable' ) ); 6633 6634 return idx !== -1 ? 6635 settings[ idx ] : 6636 null; 6637 } 6638 6639 6640 /** 6641 * Log an error message 6642 * @param {object} settings dataTables settings object 6643 * @param {int} level log error messages, or display them to the user 6644 * @param {string} msg error message 6645 * @param {int} tn Technical note id to get more information about the error. 6646 * @memberof DataTable#oApi 6647 */ 6648 function _fnLog( settings, level, msg, tn ) 6649 { 6650 msg = 'DataTables warning: '+ 6651 (settings ? 'table id='+settings.sTableId+' - ' : '')+msg; 6652 6653 if ( tn ) { 6654 msg += '. For more information about this error, please see '+ 6655 'http
6655s
vendor: 50,097 bytes, lines 6655-8586
6655://datatables.net/tn/'+tn; 6656 } 6657 6658 if ( ! level ) { 6659 // Backwards compatibility pre 1.10 6660 var ext = DataTable.ext; 6661 var type = ext.sErrMode || ext.errMode; 6662 6663 if ( settings ) { 6664 _fnCallbackFire( settings, null, 'error', [ settings, tn, msg ] ); 6665 } 6666 6667 if ( type == 'alert' ) { 6668 alert( msg ); 6669 } 6670 else if ( type == 'throw' ) { 6671 throw new Error(msg); 6672 } 6673 else if ( typeof type == 'function' ) { 6674 type( settings, tn, msg ); 6675 } 6676 } 6677 else if ( window.console && console.log ) { 6678 console.log( msg ); 6679 } 6680 } 6681 6682 6683 /** 6684 * See if a property is defined on one object, if so assign it to the other object 6685 * @param {object} ret target object 6686 * @param {object} src source object 6687 * @param {string} name property 6688 * @param {string} [mappedName] name to map too - optional, name used if not given 6689 * @memberof DataTable#oApi 6690 */ 6691 function _fnMap( ret, src, name, mappedName ) 6692 { 6693 if ( Array.isArray( name ) ) { 6694 $.each( name, function (i, val) { 6695 if ( Array.isArray( val ) ) { 6696 _fnMap( ret, src, val[0], val[1] ); 6697 } 6698 else { 6699 _fnMap( ret, src, val ); 6700 } 6701 } ); 6702 6703 return; 6704 } 6705 6706 if ( mappedName === undefined ) { 6707 mappedName = name; 6708 } 6709 6710 if ( src[name] !== undefined ) { 6711 ret[mappedName] = src[name]; 6712 } 6713 } 6714 6715 6716 /** 6717 * Extend objects - very similar to jQuery.extend, but deep copy objects, and 6718 * shallow copy arrays. The reason we need to do this, is that we don't want to 6719 * deep copy array init values (such as aaSorting) since the dev wouldn't be 6720 * able to override them, but we do want to deep copy arrays. 6721 * @param {object} out Object to extend 6722 * @param {object} extender Object from which the properties will be applied to 6723 * out 6724 * @param {boolean} breakRefs If true, then arrays will be sliced to take an 6725 * independent copy with the exception of the `data` or `aaData` parameters 6726 * if they are present. This is so you can pass in a collection to 6727 * DataTables and have that used as your data source without breaking the 6728 * references 6729 * @returns {object} out Reference, just for convenience - out === the return. 6730 * @memberof DataTable#oApi 6731 * @todo This doesn't take account of arrays inside the deep copied objects. 6732 */ 6733 function _fnExtend( out, extender, breakRefs ) 6734 { 6735 var val; 6736 6737 for ( var prop in extender ) { 6738 if ( extender.hasOwnProperty(prop) ) { 6739 val = extender[prop]; 6740 6741 if ( $.isPlainObject( val ) ) { 6742 if ( ! $.isPlainObject( out[prop] ) ) { 6743 out[prop] = {}; 6744 } 6745 $.extend( true, out[prop], val ); 6746 } 6747 else if ( breakRefs && prop !== 'data' && prop !== 'aaData' && Array.isArray(val) ) { 6748 out[prop] = val.slice(); 6749 } 6750 else { 6751 out[prop] = val; 6752 } 6753 } 6754 } 6755 6756 return out; 6757 } 6758 6759 6760 /** 6761 * Bind an event handers to allow a click or return key to activate the callback. 6762 * This is good for accessibility since a return on the keyboard will have the 6763 * same effect as a click, if the element has focus. 6764 * @param {element} n Element to bind the action to 6765 * @param {object} oData Data object to pass to the triggered function 6766 * @param {function} fn Callback function for when the event is triggered 6767 * @memberof DataTable#oApi 6768 */ 6769 function _fnBindAction( n, oData, fn ) 6770 { 6771 $(n) 6772 .on( 'click.DT', oData, function (e) { 6773 $(n).trigger('blur'); // Remove focus outline for mouse users 6774 fn(e); 6775 } ) 6776 .on( 'keypress.DT', oData, function (e){ 6777 if ( e.which === 13 ) { 6778 e.preventDefault(); 6779 fn(e); 6780 } 6781 } ) 6782 .on( 'selectstart.DT', function () { 6783 /* Take the brutal approach to cancelling text selection */ 6784 return false; 6785 } ); 6786 } 6787 6788 6789 /** 6790 * Register a callback function. Easily allows a callback function to be added to 6791 * an array store of callback functions that can then all be called together. 6792 * @param {object} oSettings dataTables settings object 6793 * @param {string} sStore Name of the array storage for the callbacks in oSettings 6794 * @param {function} fn Function to be called back 6795 * @param {string} sName Identifying name for the callback (i.e. a label) 6796 * @memberof DataTable#oApi 6797 */ 6798 function _fnCallbackReg( oSettings, sStore, fn, sName ) 6799 { 6800 if ( fn ) 6801 { 6802 oSettings[sStore].push( { 6803 "fn": fn, 6804 "sName": sName 6805 } ); 6806 } 6807 } 6808 6809 6810 /** 6811 * Fire callback functions and trigger events. Note that the loop over the 6812 * callback array store is done backwards! Further note that you do not want to 6813 * fire off triggers in time sensitive applications (for example cell creation) 6814 * as its slow. 6815 * @param {object} settings dataTables settings object 6816 * @param {string} callbackArr Name of the array storage for the callbacks in 6817 * oSettings 6818 * @param {string} eventName Name of the jQuery custom event to trigger. If 6819 * null no trigger is fired 6820 * @param {array} args Array of arguments to pass to the callback function / 6821 * trigger 6822 * @memberof DataTable#oApi 6823 */ 6824 function _fnCallbackFire( settings, callbackArr, eventName, args ) 6825 { 6826 var ret = []; 6827 6828 if ( callbackArr ) { 6829 ret = $.map( settings[callbackArr].slice().reverse(), function (val, i) { 6830 return val.fn.apply( settings.oInstance, args ); 6831 } ); 6832 } 6833 6834 if ( eventName !== null ) { 6835 var e = $.Event( eventName+'.dt' ); 6836 var table = $(settings.nTable); 6837 6838 table.trigger( e, args ); 6839 6840 // If not yet attached to the document, trigger the event 6841 // on the body directly to sort of simulate the bubble 6842 if (table.parents('body').length === 0) { 6843 $('body').trigger( e, args ); 6844 } 6845 6846 ret.push( e.result ); 6847 } 6848 6849 return ret; 6850 } 6851 6852 6853 function _fnLengthOverflow ( settings ) 6854 { 6855 var 6856 start = settings._iDisplayStart, 6857 end = settings.fnDisplayEnd(), 6858 len = settings._iDisplayLength; 6859 6860 /* If we have space to show extra rows (backing up from the end point - then do so */ 6861 if ( start >= end ) 6862 { 6863 start = end - len; 6864 } 6865 6866 // Keep the start record on the current page 6867 start -= (start % len); 6868 6869 if ( len === -1 || start < 0 ) 6870 { 6871 start = 0; 6872 } 6873 6874 settings._iDisplayStart = start; 6875 } 6876 6877 6878 function _fnRenderer( settings, type ) 6879 { 6880 var renderer = settings.renderer; 6881 var host = DataTable.ext.renderer[type]; 6882 6883 if ( $.isPlainObject( renderer ) && renderer[type] ) { 6884 // Specific renderer for this type. If available use it, otherwise use 6885 // the default. 6886 return host[renderer[type]] || host._; 6887 } 6888 else if ( typeof renderer === 'string' ) { 6889 // Common renderer - if there is one available for this type use it, 6890 // otherwise use the default 6891 return host[renderer] || host._; 6892 } 6893 6894 // Use the default 6895 return host._; 6896 } 6897 6898 6899 /** 6900 * Detect the data source being used for the table. Used to simplify the code 6901 * a little (ajax) and to make it compress a little smaller. 6902 * 6903 * @param {object} settings dataTables settings object 6904 * @returns {string} Data source 6905 * @memberof DataTable#oApi 6906 */ 6907 function _fnDataSource ( settings ) 6908 { 6909 if ( settings.oFeatures.bServerSide ) { 6910 return 'ssp'; 6911 } 6912 else if ( settings.ajax || settings.sAjaxSource ) { 6913 return 'ajax'; 6914 } 6915 return 'dom'; 6916 } 6917 6918 6919 6920 6921 /** 6922 * Computed structure of the DataTables API, defined by the options passed to 6923 * `DataTable.Api.register()` when building the API. 6924 * 6925 * The structure is built in order to speed creation and extension of the Api 6926 * objects since the extensions are effectively pre-parsed. 6927 * 6928 * The array is an array of objects with the following structure, where this 6929 * base array represents the Api prototype base: 6930 * 6931 * [ 6932 * { 6933 * name: 'data' -- string - Property name 6934 * val: function () {}, -- function - Api method (or undefined if just an object 6935 * methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result 6936 * propExt: [ ... ] -- array - Array of Api object definitions to extend the property 6937 * }, 6938 * { 6939 * name: 'row' 6940 * val: {}, 6941 * methodExt: [ ... ], 6942 * propExt: [ 6943 * { 6944 * name: 'data' 6945 * val: function () {}, 6946 * methodExt: [ ... ], 6947 * propExt: [ ... ] 6948 * }, 6949 * ... 6950 * ] 6951 * } 6952 * ] 6953 * 6954 * @type {Array} 6955 * @ignore 6956 */ 6957 var __apiStruct = []; 6958 6959 6960 /** 6961 * `Array.prototype` reference. 6962 * 6963 * @type object 6964 * @ignore 6965 */ 6966 var __arrayProto = Array.prototype; 6967 6968 6969 /** 6970 * Abstraction for `context` parameter of the `Api` constructor to allow it to 6971 * take several different forms for ease of use. 6972 * 6973 * Each of the input parameter types will be converted to a DataTables settings 6974 * object where possible. 6975 * 6976 * @param {string|node|jQuery|object} mixed DataTable identifier. Can be one 6977 * of: 6978 * 6979 * * `string` - jQuery selector. Any DataTables' matching the given selector 6980 * with be found and used. 6981 * * `node` - `TABLE` node which has already been formed into a DataTable. 6982 * * `jQuery` - A jQuery object of `TABLE` nodes. 6983 * * `object` - DataTables settings object 6984 * * `DataTables.Api` - API instance 6985 * @return {array|null} Matching DataTables settings objects. `null` or 6986 * `undefined` is returned if no matching DataTable is found. 6987 * @ignore 6988 */ 6989 var _toSettings = function ( mixed ) 6990 { 6991 var idx, jq; 6992 var settings = DataTable.settings; 6993 var tables = $.map( settings, function (el, i) { 6994 return el.nTable; 6995 } ); 6996 6997 if ( ! mixed ) { 6998 return []; 6999 } 7000 else if ( mixed.nTable && mixed.oApi ) { 7001 // DataTables settings object 7002 return [ mixed ]; 7003 } 7004 else if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) { 7005 // Table node 7006 idx = $.inArray( mixed, tables ); 7007 return idx !== -1 ? [ settings[idx] ] : null; 7008 } 7009 else if ( mixed && typeof mixed.settings === 'function' ) { 7010 return mixed.settings().toArray(); 7011 } 7012 else if ( typeof mixed === 'string' ) { 7013 // jQuery selector 7014 jq = $(mixed); 7015 } 7016 else if ( mixed instanceof $ ) { 7017 // jQuery object (also DataTables instance) 7018 jq = mixed; 7019 } 7020 7021 if ( jq ) { 7022 return jq.map( function(i) { 7023 idx = $.inArray( this, tables ); 7024 return idx !== -1 ? settings[idx] : null; 7025 } ).toArray(); 7026 } 7027 }; 7028 7029 7030 /** 7031 * DataTables API class - used to control and interface with one or more 7032 * DataTables enhanced tables. 7033 * 7034 * The API class is heavily based on jQuery, presenting a chainable interface 7035 * that you can use to interact with tables. Each instance of the API class has 7036 * a "context" - i.e. the tables that it will operate on. This could be a single 7037 * table, all tables on a page or a sub-set thereof. 7038 * 7039 * Additionally the API is designed to allow you to easily work with the data in 7040 * the tables, retrieving and manipulating it as required. This is done by 7041 * presenting the API class as an array like interface. The contents of the 7042 * array depend upon the actions requested by each method (for example 7043 * `rows().nodes()` will return an array of nodes, while `rows().data()` will 7044 * return an array of objects or arrays depending upon your table's 7045 * configuration). The API object has a number of array like methods (`push`, 7046 * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`, 7047 * `unique` etc) to assist your working with the data held in a table. 7048 * 7049 * Most methods (those which return an Api instance) are chainable, which means 7050 * the return from a method call also has all of the methods available that the 7051 * top level object had. For example, these two calls are equivalent: 7052 * 7053 * // Not chained 7054 * api.row.add( {...} ); 7055 * api.draw(); 7056 * 7057 * // Chained 7058 * api.row.add( {...} ).draw(); 7059 * 7060 * @class DataTable.Api 7061 * @param {array|object|string|jQuery} context DataTable identifier. This is 7062 * used to define which DataTables enhanced tables this API will operate on. 7063 * Can be one of: 7064 * 7065 * * `string` - jQuery selector. Any DataTables' matching the given selector 7066 * with be found and used. 7067 * * `node` - `TABLE` node which has already been formed into a DataTable. 7068 * * `jQuery` - A jQuery object of `TABLE` nodes. 7069 * * `object` - DataTables settings object 7070 * @param {array} [data] Data to initialise the Api instance with. 7071 * 7072 * @example 7073 * // Direct initialisation during DataTables construction 7074 * var api = $('#example').DataTable(); 7075 * 7076 * @example 7077 * // Initialisation using a DataTables jQuery object 7078 * var api = $('#example').dataTable().api(); 7079 * 7080 * @example 7081 * // Initialisation as a constructor 7082 * var api = new $.fn.DataTable.Api( 'table.dataTable' ); 7083 */ 7084 _Api = function ( context, data ) 7085 { 7086 if ( ! (this instanceof _Api) ) { 7087 return new _Api( context, data ); 7088 } 7089 7090 var settings = []; 7091 var ctxSettings = function ( o ) { 7092 var a = _toSettings( o ); 7093 if ( a ) { 7094 settings.push.apply( settings, a ); 7095 } 7096 }; 7097 7098 if ( Array.isArray( context ) ) { 7099 for ( var i=0, ien=context.length ; i<ien ; i++ ) { 7100 ctxSettings( context[i] ); 7101 } 7102 } 7103 else { 7104 ctxSettings( context ); 7105 } 7106 7107 // Remove duplicates 7108 this.context = _unique( settings ); 7109 7110 // Initial data 7111 if ( data ) { 7112 $.merge( this, data ); 7113 } 7114 7115 // selector 7116 this.selector = { 7117 rows: null, 7118 cols: null, 7119 opts: null 7120 }; 7121 7122 _Api.extend( this, this, __apiStruct ); 7123 }; 7124 7125 DataTable.Api = _Api; 7126 7127 // Don't destroy the existing prototype, just extend it. Required for jQuery 2's 7128 // isPlainObject. 7129 $.extend( _Api.prototype, { 7130 any: function () 7131 { 7132 return this.count() !== 0; 7133 }, 7134 7135 7136 concat: __arrayProto.concat, 7137 7138 7139 context: [], // array of table settings objects 7140 7141 7142 count: function () 7143 { 7144 return this.flatten().length; 7145 }, 7146 7147 7148 each: function ( fn ) 7149 { 7150 for ( var i=0, ien=this.length ; i<ien; i++ ) { 7151 fn.call( this, this[i], i, this ); 7152 } 7153 7154 return this; 7155 }, 7156 7157 7158 eq: function ( idx ) 7159 { 7160 var ctx = this.context; 7161 7162 return ctx.length > idx ? 7163 new _Api( ctx[idx], this[idx] ) : 7164 null; 7165 }, 7166 7167 7168 filter: function ( fn ) 7169 { 7170 var a = []; 7171 7172 if ( __arrayProto.filter ) { 7173 a = __arrayProto.filter.call( this, fn, this ); 7174 } 7175 else { 7176 // Compatibility for browsers without EMCA-252-5 (JS 1.6) 7177 for ( var i=0, ien=this.length ; i<ien ; i++ ) { 7178 if ( fn.call( this, this[i], i, this ) ) { 7179 a.push( this[i] ); 7180 } 7181 } 7182 } 7183 7184 return new _Api( this.context, a ); 7185 }, 7186 7187 7188 flatten: function () 7189 { 7190 var a = []; 7191 return new _Api( this.context, a.concat.apply( a, this.toArray() ) ); 7192 }, 7193 7194 7195 join: __arrayProto.join, 7196 7197 7198 indexOf: __arrayProto.indexOf || function (obj, start) 7199 { 7200 for ( var i=(start || 0), ien=this.length ; i<ien ; i++ ) { 7201 if ( this[i] === obj ) { 7202 return i; 7203 } 7204 } 7205 return -1; 7206 }, 7207 7208 iterator: function ( flatten, type, fn, alwaysNew ) { 7209 var 7210 a = [], ret, 7211 i, ien, j, jen, 7212 context = this.context, 7213 rows, items, item, 7214 selector = this.selector; 7215 7216 // Argument shifting 7217 if ( typeof flatten === 'string' ) { 7218 alwaysNew = fn; 7219 fn = type; 7220 type = flatten; 7221 flatten = false; 7222 } 7223 7224 for ( i=0, ien=context.length ; i<ien ; i++ ) { 7225 var apiInst = new _Api( context[i] ); 7226 7227 if ( type === 'table' ) { 7228 ret = fn.call( apiInst, context[i], i ); 7229 7230 if ( ret !== undefined ) { 7231 a.push( ret ); 7232 } 7233 } 7234 else if ( type === 'columns' || type === 'rows' ) { 7235 // this has same length as context - one entry for each table 7236 ret = fn.call( apiInst, context[i], this[i], i ); 7237 7238 if ( ret !== undefined ) { 7239 a.push( ret ); 7240 } 7241 } 7242 else if ( type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) { 7243 // columns and rows share the same structure. 7244 // 'this' is an array of column indexes for each context 7245 items = this[i]; 7246 7247 if ( type === 'column-rows' ) { 7248 rows = _selector_row_indexes( context[i], selector.opts ); 7249 } 7250 7251 for ( j=0, jen=items.length ; j<jen ; j++ ) { 7252 item = items[j]; 7253 7254 if ( type === 'cell' ) { 7255 ret = fn.call( apiInst, context[i], item.row, item.column, i, j ); 7256 } 7257 else { 7258 ret = fn.call( apiInst, context[i], item, i, j, rows ); 7259 } 7260 7261 if ( ret !== undefined ) { 7262 a.push( ret ); 7263 } 7264 } 7265 } 7266 } 7267 7268 if ( a.length || alwaysNew ) { 7269 var api = new _Api( context, flatten ? a.concat.apply( [], a ) : a ); 7270 var apiSelector = api.selector; 7271 apiSelector.rows = selector.rows; 7272 apiSelector.cols = selector.cols; 7273 apiSelector.opts = selector.opts; 7274 return api; 7275 } 7276 return this; 7277 }, 7278 7279 7280 lastIndexOf: __arrayProto.lastIndexOf || function (obj, start) 7281 { 7282 // Bit cheeky... 7283 return this.indexOf.apply( this.toArray.reverse(), arguments ); 7284 }, 7285 7286 7287 length: 0, 7288 7289 7290 map: function ( fn ) 7291 { 7292 var a = []; 7293 7294 if ( __arrayProto.map ) { 7295 a = __arrayProto.map.call( this, fn, this ); 7296 } 7297 else { 7298 // Compatibility for browsers without EMCA-252-5 (JS 1.6) 7299 for ( var i=0, ien=this.length ; i<ien ; i++ ) { 7300 a.push( fn.call( this, this[i], i ) ); 7301 } 7302 } 7303 7304 return new _Api( this.context, a ); 7305 }, 7306 7307 7308 pluck: function ( prop ) 7309 { 7310 var fn = DataTable.util.get(prop); 7311 7312 return this.map( function ( el ) { 7313 return fn(el); 7314 } ); 7315 }, 7316 7317 pop: __arrayProto.pop, 7318 7319 7320 push: __arrayProto.push, 7321 7322 7323 // Does not return an API instance 7324 reduce: __arrayProto.reduce || function ( fn, init ) 7325 { 7326 return _fnReduce( this, fn, init, 0, this.length, 1 ); 7327 }, 7328 7329 7330 reduceRight: __arrayProto.reduceRight || function ( fn, init ) 7331 { 7332 return _fnReduce( this, fn, init, this.length-1, -1, -1 ); 7333 }, 7334 7335 7336 reverse: __arrayProto.reverse, 7337 7338 7339 // Object with rows, columns and opts 7340 selector: null, 7341 7342 7343 shift: __arrayProto.shift, 7344 7345 7346 slice: function () { 7347 return new _Api( this.context, this ); 7348 }, 7349 7350 7351 sort: __arrayProto.sort, // ? name - order? 7352 7353 7354 splice: __arrayProto.splice, 7355 7356 7357 toArray: function () 7358 { 7359 return __arrayProto.slice.call( this ); 7360 }, 7361 7362 7363 to$: function () 7364 { 7365 return $( this ); 7366 }, 7367 7368 7369 toJQuery: function () 7370 { 7371 return $( this ); 7372 }, 7373 7374 7375 unique: function () 7376 { 7377 return new _Api( this.context, _unique(this) ); 7378 }, 7379 7380 7381 unshift: __arrayProto.unshift 7382 } ); 7383 7384 7385 _Api.extend = function ( scope, obj, ext ) 7386 { 7387 // Only extend API instances and static properties of the API 7388 if ( ! ext.length || ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) { 7389 return; 7390 } 7391 7392 var 7393 i, ien, 7394 struct, 7395 methodScoping = function ( scope, fn, struc ) { 7396 return function () { 7397 var ret = fn.apply( scope, arguments ); 7398 7399 // Method extension 7400 _Api.extend( ret, ret, struc.methodExt ); 7401 return ret; 7402 }; 7403 }; 7404 7405 for ( i=0, ien=ext.length ; i<ien ; i++ ) { 7406 struct = ext[i]; 7407 7408 // Value 7409 obj[ struct.name ] = struct.type === 'function' ? 7410 methodScoping( scope, struct.val, struct ) : 7411 struct.type === 'object' ? 7412 {} : 7413 struct.val; 7414 7415 obj[ struct.name ].__dt_wrapper = true; 7416 7417 // Property extension 7418 _Api.extend( scope, obj[ struct.name ], struct.propExt ); 7419 } 7420 }; 7421 7422 7423 // @todo - Is there need for an augment function? 7424 // _Api.augment = function ( inst, name ) 7425 // { 7426 // // Find src object in the structure from the name 7427 // var parts = name.split('.'); 7428 7429 // _Api.extend( inst, obj ); 7430 // }; 7431 7432 7433 // [ 7434 // { 7435 // name: 'data' -- string - Property name 7436 // val: function () {}, -- function - Api method (or undefined if just an object 7437 // methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result 7438 // propExt: [ ... ] -- array - Array of Api object definitions to extend the property 7439 // }, 7440 // { 7441 // name: 'row' 7442 // val: {}, 7443 // methodExt: [ ... ], 7444 // propExt: [ 7445 // { 7446 // name: 'data' 7447 // val: function () {}, 7448 // methodExt: [ ... ], 7449 // propExt: [ ... ] 7450 // }, 7451 // ... 7452 // ] 7453 // } 7454 // ] 7455 7456 _Api.register = _api_register = function ( name, val ) 7457 { 7458 if ( Array.isArray( name ) ) { 7459 for ( var j=0, jen=name.length ; j<jen ; j++ ) { 7460 _Api.register( name[j], val ); 7461 } 7462 return; 7463 } 7464 7465 var 7466 i, ien, 7467 heir = name.split('.'), 7468 struct = __apiStruct, 7469 key, method; 7470 7471 var find = function ( src, name ) { 7472 for ( var i=0, ien=src.length ; i<ien ; i++ ) { 7473 if ( src[i].name === name ) { 7474 return src[i]; 7475 } 7476 } 7477 return null; 7478 }; 7479 7480 for ( i=0, ien=heir.length ; i<ien ; i++ ) { 7481 method = heir[i].indexOf('()') !== -1; 7482 key = method ? 7483 heir[i].replace('()', '') : 7484 heir[i]; 7485 7486 var src = find( struct, key ); 7487 if ( ! src ) { 7488 src = { 7489 name: key, 7490 val: {}, 7491 methodExt: [], 7492 propExt: [], 7493 type: 'object' 7494 }; 7495 struct.push( src ); 7496 } 7497 7498 if ( i === ien-1 ) { 7499 src.val = val; 7500 src.type = typeof val === 'function' ? 7501 'function' : 7502 $.isPlainObject( val ) ? 7503 'object' : 7504 'other'; 7505 } 7506 else { 7507 struct = method ? 7508 src.methodExt : 7509 src.propExt; 7510 } 7511 } 7512 }; 7513 7514 _Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) { 7515 _Api.register( pluralName, val ); 7516 7517 _Api.register( singularName, function () { 7518 var ret = val.apply( this, arguments ); 7519 7520 if ( ret === this ) { 7521 // Returned item is the API instance that was passed in, return it 7522 return this; 7523 } 7524 else if ( ret instanceof _Api ) { 7525 // New API instance returned, want the value from the first item 7526 // in the returned array for the singular result. 7527 return ret.length ? 7528 Array.isArray( ret[0] ) ? 7529 new _Api( ret.context, ret[0] ) : // Array results are 'enhanced' 7530 ret[0] : 7531 undefined; 7532 } 7533 7534 // Non-API return - just fire it back 7535 return ret; 7536 } ); 7537 }; 7538 7539 7540 /** 7541 * Selector for HTML tables. Apply the given selector to the give array of 7542 * DataTables settings objects. 7543 * 7544 * @param {string|integer} [selector] jQuery selector string or integer 7545 * @param {array} Array of DataTables settings objects to be filtered 7546 * @return {array} 7547 * @ignore 7548 */ 7549 var __table_selector = function ( selector, a ) 7550 { 7551 if ( Array.isArray(selector) ) { 7552 return $.map( selector, function (item) { 7553 return __table_selector(item, a); 7554 } ); 7555 } 7556 7557 // Integer is used to pick out a table by index 7558 if ( typeof selector === 'number' ) { 7559 return [ a[ selector ] ]; 7560 } 7561 7562 // Perform a jQuery selector on the table nodes 7563 var nodes = $.map( a, function (el, i) { 7564 return el.nTable; 7565 } ); 7566 7567 return $(nodes) 7568 .filter( selector ) 7569 .map( function (i) { 7570 // Need to translate back from the table node to the settings 7571 var idx = $.inArray( this, nodes ); 7572 return a[ idx ]; 7573 } ) 7574 .toArray(); 7575 }; 7576 7577 7578 7579 /** 7580 * Context selector for the API's context (i.e. the tables the API instance 7581 * refers to. 7582 * 7583 * @name DataTable.Api#tables 7584 * @param {string|integer} [selector] Selector to pick which tables the iterator 7585 * should operate on. If not given, all tables in the current context are 7586 * used. This can be given as a jQuery selector (for example `':gt(0)'`) to 7587 * select multiple tables or as an integer to select a single table. 7588 * @returns {DataTable.Api} Returns a new API instance if a selector is given. 7589 */ 7590 _api_register( 'tables()', function ( selector ) { 7591 // A new instance is created if there was a selector specified 7592 return selector !== undefined && selector !== null ? 7593 new _Api( __table_selector( selector, this.context ) ) : 7594 this; 7595 } ); 7596 7597 7598 _api_register( 'table()', function ( selector ) { 7599 var tables = this.tables( selector ); 7600 var ctx = tables.context; 7601 7602 // Truncate to the first matched table 7603 return ctx.length ? 7604 new _Api( ctx[0] ) : 7605 tables; 7606 } ); 7607 7608 7609 _api_registerPlural( 'tables().nodes()', 'table().node()' , function () { 7610 return this.iterator( 'table', function ( ctx ) { 7611 return ctx.nTable; 7612 }, 1 ); 7613 } ); 7614 7615 7616 _api_registerPlural( 'tables().body()', 'table().body()' , function () { 7617 return this.iterator( 'table', function ( ctx ) { 7618 return ctx.nTBody; 7619 }, 1 ); 7620 } ); 7621 7622 7623 _api_registerPlural( 'tables().header()', 'table().header()' , function () { 7624 return this.iterator( 'table', function ( ctx ) { 7625 return ctx.nTHead; 7626 }, 1 ); 7627 } ); 7628 7629 7630 _api_registerPlural( 'tables().footer()', 'table().footer()' , function () { 7631 return this.iterator( 'table', function ( ctx ) { 7632 return ctx.nTFoot; 7633 }, 1 ); 7634 } ); 7635 7636 7637 _api_registerPlural( 'tables().containers()', 'table().container()' , function () { 7638 return this.iterator( 'table', function ( ctx ) { 7639 return ctx.nTableWrapper; 7640 }, 1 ); 7641 } ); 7642 7643 7644 7645 /** 7646 * Redraw the tables in the current context. 7647 */ 7648 _api_register( 'draw()', function ( paging ) { 7649 return this.iterator( 'table', function ( settings ) { 7650 if ( paging === 'page' ) { 7651 _fnDraw( settings ); 7652 } 7653 else { 7654 if ( typeof paging === 'string' ) { 7655 paging = paging === 'full-hold' ? 7656 false : 7657 true; 7658 } 7659 7660 _fnReDraw( settings, paging===false ); 7661 } 7662 } ); 7663 } ); 7664 7665 7666 7667 /** 7668 * Get the current page index. 7669 * 7670 * @return {integer} Current page index (zero based) 7671 *//** 7672 * Set the current page. 7673 * 7674 * Note that if you attempt to show a page which does not exist, DataTables will 7675 * not throw an error, but rather reset the paging. 7676 * 7677 * @param {integer|string} action The paging action to take. This can be one of: 7678 * * `integer` - The page index to jump to 7679 * * `string` - An action to take: 7680 * * `first` - Jump to first page. 7681 * * `next` - Jump to the next page 7682 * * `previous` - Jump to previous page 7683 * * `last` - Jump to the last page. 7684 * @returns {DataTables.Api} this 7685 */ 7686 _api_register( 'page()', function ( action ) { 7687 if ( action === undefined ) { 7688 return this.page.info().page; // not an expensive call 7689 } 7690 7691 // else, have an action to take on all tables 7692 return this.iterator( 'table', function ( settings ) { 7693 _fnPageChange( settings, action ); 7694 } ); 7695 } ); 7696 7697 7698 /** 7699 * Paging information for the first table in the current context. 7700 * 7701 * If you require paging information for another table, use the `table()` method 7702 * with a suitable selector. 7703 * 7704 * @return {object} Object with the following properties set: 7705 * * `page` - Current page index (zero based - i.e. the first page is `0`) 7706 * * `pages` - Total number of pages 7707 * * `start` - Display index for the first record shown on the current page 7708 * * `end` - Display index for the last record shown on the current page 7709 * * `length` - Display length (number of records). Note that generally `start 7710 * + length = end`, but this is not always true, for example if there are 7711 * only 2 records to show on the final page, with a length of 10. 7712 * * `recordsTotal` - Full data set length 7713 * * `recordsDisplay` - Data set length once the current filtering criterion 7714 * are applied. 7715 */ 7716 _api_register( 'page.info()', function ( action ) { 7717 if ( this.context.length === 0 ) { 7718 return undefined; 7719 } 7720 7721 var 7722 settings = this.context[0], 7723 start = settings._iDisplayStart, 7724 len = settings.oFeatures.bPaginate ? settings._iDisplayLength : -1, 7725 visRecords = settings.fnRecordsDisplay(), 7726 all = len === -1; 7727 7728 return { 7729 "page": all ? 0 : Math.floor( start / len ), 7730 "pages": all ? 1 : Math.ceil( visRecords / len ), 7731 "start": start, 7732 "end": settings.fnDisplayEnd(), 7733 "length": len, 7734 "recordsTotal": settings.fnRecordsTotal(), 7735 "recordsDisplay": visRecords, 7736 "serverSide": _fnDataSource( settings ) === 'ssp' 7737 }; 7738 } ); 7739 7740 7741 /** 7742 * Get the current page length. 7743 * 7744 * @return {integer} Current page length. Note `-1` indicates that all records 7745 * are to be shown. 7746 *//** 7747 * Set the current page length. 7748 * 7749 * @param {integer} Page length to set. Use `-1` to show all records. 7750 * @returns {DataTables.Api} this 7751 */ 7752 _api_register( 'page.len()', function ( len ) { 7753 // Note that we can't call this function 'length()' because `length` 7754 // is a Javascript property of functions which defines how many arguments 7755 // the function expects. 7756 if ( len === undefined ) { 7757 return this.context.length !== 0 ? 7758 this.context[0]._iDisplayLength : 7759 undefined; 7760 } 7761 7762 // else, set the page length 7763 return this.iterator( 'table', function ( settings ) { 7764 _fnLengthChange( settings, len ); 7765 } ); 7766 } ); 7767 7768 7769 7770 var __reload = function ( settings, holdPosition, callback ) { 7771 // Use the draw event to trigger a callback 7772 if ( callback ) { 7773 var api = new _Api( settings ); 7774 7775 api.one( 'draw', function () { 7776 callback( api.ajax.json() ); 7777 } ); 7778 } 7779 7780 if ( _fnDataSource( settings ) == 'ssp' ) { 7781 _fnReDraw( settings, holdPosition ); 7782 } 7783 else { 7784 _fnProcessingDisplay( settings, true ); 7785 7786 // Cancel an existing request 7787 var xhr = settings.jqXHR; 7788 if ( xhr && xhr.readyState !== 4 ) { 7789 xhr.abort(); 7790 } 7791 7792 // Trigger xhr 7793 _fnBuildAjax( settings, [], function( json ) { 7794 _fnClearTable( settings ); 7795 7796 var data = _fnAjaxDataSrc( settings, json ); 7797 for ( var i=0, ien=data.length ; i<ien ; i++ ) { 7798 _fnAddData( settings, data[i] ); 7799 } 7800 7801 _fnReDraw( settings, holdPosition ); 7802 _fnProcessingDisplay( settings, false ); 7803 } ); 7804 } 7805 }; 7806 7807 7808 /** 7809 * Get the JSON response from the last Ajax request that DataTables made to the 7810 * server. Note that this returns the JSON from the first table in the current 7811 * context. 7812 * 7813 * @return {object} JSON received from the server. 7814 */ 7815 _api_register( 'ajax.json()', function () { 7816 var ctx = this.context; 7817 7818 if ( ctx.length > 0 ) { 7819 return ctx[0].json; 7820 } 7821 7822 // else return undefined; 7823 } ); 7824 7825 7826 /** 7827 * Get the data submitted in the last Ajax request 7828 */ 7829 _api_register( 'ajax.params()', function () { 7830 var ctx = this.context; 7831 7832 if ( ctx.length > 0 ) { 7833 return ctx[0].oAjaxData; 7834 } 7835 7836 // else return undefined; 7837 } ); 7838 7839 7840 /** 7841 * Reload tables from the Ajax data source. Note that this function will 7842 * automatically re-draw the table when the remote data has been loaded. 7843 * 7844 * @param {boolean} [reset=true] Reset (default) or hold the current paging 7845 * position. A full re-sort and re-filter is performed when this method is 7846 * called, which is why the pagination reset is the default action. 7847 * @returns {DataTables.Api} this 7848 */ 7849 _api_register( 'ajax.reload()', function ( callback, resetPaging ) { 7850 return this.iterator( 'table', function (settings) { 7851 __reload( settings, resetPaging===false, callback ); 7852 } ); 7853 } ); 7854 7855 7856 /** 7857 * Get the current Ajax URL. Note that this returns the URL from the first 7858 * table in the current context. 7859 * 7860 * @return {string} Current Ajax source URL 7861 *//** 7862 * Set the Ajax URL. Note that this will set the URL for all tables in the 7863 * current context. 7864 * 7865 * @param {string} url URL to set. 7866 * @returns {DataTables.Api} this 7867 */ 7868 _api_register( 'ajax.url()', function ( url ) { 7869 var ctx = this.context; 7870 7871 if ( url === undefined ) { 7872 // get 7873 if ( ctx.length === 0 ) { 7874 return undefined; 7875 } 7876 ctx = ctx[0]; 7877 7878 return ctx.ajax ? 7879 $.isPlainObject( ctx.ajax ) ? 7880 ctx.ajax.url : 7881 ctx.ajax : 7882 ctx.sAjaxSource; 7883 } 7884 7885 // set 7886 return this.iterator( 'table', function ( settings ) { 7887 if ( $.isPlainObject( settings.ajax ) ) { 7888 settings.ajax.url = url; 7889 } 7890 else { 7891 settings.ajax = url; 7892 } 7893 // No need to consider sAjaxSource here since DataTables gives priority 7894 // to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any 7895 // value of `sAjaxSource` redundant. 7896 } ); 7897 } ); 7898 7899 7900 /** 7901 * Load data from the newly set Ajax URL. Note that this method is only 7902 * available when `ajax.url()` is used to set a URL. Additionally, this method 7903 * has the same effect as calling `ajax.reload()` but is provided for 7904 * convenience when setting a new URL. Like `ajax.reload()` it will 7905 * automatically redraw the table once the remote data has been loaded. 7906 * 7907 * @returns {DataTables.Api} this 7908 */ 7909 _api_register( 'ajax.url().load()', function ( callback, resetPaging ) { 7910 // Same as a reload, but makes sense to present it for easy access after a 7911 // url change 7912 return this.iterator( 'table', function ( ctx ) { 7913 __reload( ctx, resetPaging===false, callback ); 7914 } ); 7915 } ); 7916 7917 7918 7919 7920 var _selector_run = function ( type, selector, selectFn, settings, opts ) 7921 { 7922 var 7923 out = [], res, 7924 a, i, ien, j, jen, 7925 selectorType = typeof selector; 7926 7927 // Can't just check for isArray here, as an API or jQuery instance might be 7928 // given with their array like look 7929 if ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) { 7930 selector = [ selector ]; 7931 } 7932 7933 for ( i=0, ien=selector.length ; i<ien ; i++ ) { 7934 // Only split on simple strings - complex expressions will be jQuery selectors 7935 a = selector[i] && selector[i].split && ! selector[i].match(/[\[\(:]/) ? 7936 selector[i].split(',') : 7937 [ selector[i] ]; 7938 7939 for ( j=0, jen=a.length ; j<jen ; j++ ) { 7940 res = selectFn( typeof a[j] === 'string' ? (a[j]).trim() : a[j] ); 7941 7942 if ( res && res.length ) { 7943 out = out.concat( res ); 7944 } 7945 } 7946 } 7947 7948 // selector extensions 7949 var ext = _ext.selector[ type ]; 7950 if ( ext.length ) { 7951 for ( i=0, ien=ext.length ; i<ien ; i++ ) { 7952 out = ext[i]( settings, opts, out ); 7953 } 7954 } 7955 7956 return _unique( out ); 7957 }; 7958 7959 7960 var _selector_opts = function ( opts ) 7961 { 7962 if ( ! opts ) { 7963 opts = {}; 7964 } 7965 7966 // Backwards compatibility for 1.9- which used the terminology filter rather 7967 // than search 7968 if ( opts.filter && opts.search === undefined ) { 7969 opts.search = opts.filter; 7970 } 7971 7972 return $.extend( { 7973 search: 'none', 7974 order: 'current', 7975 page: 'all' 7976 }, opts ); 7977 }; 7978 7979 7980 var _selector_first = function ( inst ) 7981 { 7982 // Reduce the API instance to the first item found 7983 for ( var i=0, ien=inst.length ; i<ien ; i++ ) { 7984 if ( inst[i].length > 0 ) { 7985 // Assign the first element to the first item in the instance 7986 // and truncate the instance and context 7987 inst[0] = inst[i]; 7988 inst[0].length = 1; 7989 inst.length = 1; 7990 inst.context = [ inst.context[i] ]; 7991 7992 return inst; 7993 } 7994 } 7995 7996 // Not found - return an empty instance 7997 inst.length = 0; 7998 return inst; 7999 }; 8000 8001 8002 var _selector_row_indexes = function ( settings, opts ) 8003 { 8004 var 8005 i, ien, tmp, a=[], 8006 displayFiltered = settings.aiDisplay, 8007 displayMaster = settings.aiDisplayMaster; 8008 8009 var 8010 search = opts.search, // none, applied, removed 8011 order = opts.order, // applied, current, index (original - compatibility with 1.9) 8012 page = opts.page; // all, current 8013 8014 if ( _fnDataSource( settings ) == 'ssp' ) { 8015 // In server-side processing mode, most options are irrelevant since 8016 // rows not shown don't exist and the index order is the applied order 8017 // Removed is a special case - for consistency just return an empty 8018 // array 8019 return search === 'removed' ? 8020 [] : 8021 _range( 0, displayMaster.length ); 8022 } 8023 else if ( page == 'current' ) { 8024 // Current page implies that order=current and filter=applied, since it is 8025 // fairly senseless otherwise, regardless of what order and search actually 8026 // are 8027 for ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) { 8028 a.push( displayFiltered[i] ); 8029 } 8030 } 8031 else if ( order == 'current' || order == 'applied' ) { 8032 if ( search == 'none') { 8033 a = displayMaster.slice(); 8034 } 8035 else if ( search == 'applied' ) { 8036 a = displayFiltered.slice(); 8037 } 8038 else if ( search == 'removed' ) { 8039 // O(n+m) solution by creating a hash map 8040 var displayFilteredMap = {}; 8041 8042 for ( var i=0, ien=displayFiltered.length ; i<ien ; i++ ) { 8043 displayFilteredMap[displayFiltered[i]] = null; 8044 } 8045 8046 a = $.map( displayMaster, function (el) { 8047 return ! displayFilteredMap.hasOwnProperty(el) ? 8048 el : 8049 null; 8050 } ); 8051 } 8052 } 8053 else if ( order == 'index' || order == 'original' ) { 8054 for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) { 8055 if ( search == 'none' ) { 8056 a.push( i ); 8057 } 8058 else { // applied | removed 8059 tmp = $.inArray( i, displayFiltered ); 8060 8061 if ((tmp === -1 && search == 'removed') || 8062 (tmp >= 0 && search == 'applied') ) 8063 { 8064 a.push( i ); 8065 } 8066 } 8067 } 8068 } 8069 8070 return a; 8071 }; 8072 8073 8074 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 8075 * Rows 8076 * 8077 * {} - no selector - use all available rows 8078 * {integer} - row aoData index 8079 * {node} - TR node 8080 * {string} - jQuery selector to apply to the TR elements 8081 * {array} - jQuery array of nodes, or simply an array of TR nodes 8082 * 8083 */ 8084 var __row_selector = function ( settings, selector, opts ) 8085 { 8086 var rows; 8087 var run = function ( sel ) { 8088 var selInt = _intVal( sel ); 8089 var i, ien; 8090 var aoData = settings.aoData; 8091 8092 // Short cut - selector is a number and no options provided (default is 8093 // all records, so no need to check if the index is in there, since it 8094 // must be - dev error if the index doesn't exist). 8095 if ( selInt !== null && ! opts ) { 8096 return [ selInt ]; 8097 } 8098 8099 if ( ! rows ) { 8100 rows = _selector_row_indexes( settings, opts ); 8101 } 8102 8103 if ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) { 8104 // Selector - integer 8105 return [ selInt ]; 8106 } 8107 else if ( sel === null || sel === undefined || sel === '' ) { 8108 // Selector - none 8109 return rows; 8110 } 8111 8112 // Selector - function 8113 if ( typeof sel === 'function' ) { 8114 return $.map( rows, function (idx) { 8115 var row = aoData[ idx ]; 8116 return sel( idx, row._aData, row.nTr ) ? idx : null; 8117 } ); 8118 } 8119 8120 // Selector - node 8121 if ( sel.nodeName ) { 8122 var rowIdx = sel._DT_RowIndex; // Property added by DT for fast lookup 8123 var cellIdx = sel._DT_CellIndex; 8124 8125 if ( rowIdx !== undefined ) { 8126 // Make sure that the row is actually still present in the table 8127 return aoData[ rowIdx ] && aoData[ rowIdx ].nTr === sel ? 8128 [ rowIdx ] : 8129 []; 8130 } 8131 else if ( cellIdx ) { 8132 return aoData[ cellIdx.row ] && aoData[ cellIdx.row ].nTr === sel.parentNode ? 8133 [ cellIdx.row ] : 8134 []; 8135 } 8136 else { 8137 var host = $(sel).closest('*[data-dt-row]'); 8138 return host.length ? 8139 [ host.data('dt-row') ] : 8140 []; 8141 } 8142 } 8143 8144 // ID selector. Want to always be able to select rows by id, regardless 8145 // of if the tr element has been created or not, so can't rely upon 8146 // jQuery here - hence a custom implementation. This does not match 8147 // Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything, 8148 // but to select it using a CSS selector engine (like Sizzle or 8149 // querySelect) it would need to need to be escaped for some characters. 8150 // DataTables simplifies this for row selectors since you can select 8151 // only a row. A # indicates an id any anything that follows is the id - 8152 // unescaped. 8153 if ( typeof sel === 'string' && sel.charAt(0) === '#' ) { 8154 // get row index from id 8155 var rowObj = settings.aIds[ sel.replace( /^#/, '' ) ]; 8156 if ( rowObj !== undefined ) { 8157 return [ rowObj.idx ]; 8158 } 8159 8160 // need to fall through to jQuery in case there is DOM id that 8161 // matches 8162 } 8163 8164 // Get nodes in the order from the `rows` array with null values removed 8165 var nodes = _removeEmpty( 8166 _pluck_order( settings.aoData, rows, 'nTr' ) 8167 ); 8168 8169 // Selector - jQuery selector string, array of nodes or jQuery object/ 8170 // As jQuery's .filter() allows jQuery objects to be passed in filter, 8171 // it also allows arrays, so this will cope with all three options 8172 return $(nodes) 8173 .filter( sel ) 8174 .map( function () { 8175 return this._DT_RowIndex; 8176 } ) 8177 .toArray(); 8178 }; 8179 8180 return _selector_run( 'row', selector, run, settings, opts ); 8181 }; 8182 8183 8184 _api_register( 'rows()', function ( selector, opts ) { 8185 // argument shifting 8186 if ( selector === undefined ) { 8187 selector = ''; 8188 } 8189 else if ( $.isPlainObject( selector ) ) { 8190 opts = selector; 8191 selector = ''; 8192 } 8193 8194 opts = _selector_opts( opts ); 8195 8196 var inst = this.iterator( 'table', function ( settings ) { 8197 return __row_selector( settings, selector, opts ); 8198 }, 1 ); 8199 8200 // Want argument shifting here and in __row_selector? 8201 inst.selector.rows = selector; 8202 inst.selector.opts = opts; 8203 8204 return inst; 8205 } ); 8206 8207 _api_register( 'rows().nodes()', function () { 8208 return this.iterator( 'row', function ( settings, row ) { 8209 return settings.aoData[ row ].nTr || undefined; 8210 }, 1 ); 8211 } ); 8212 8213 _api_register( 'rows().data()', function () { 8214 return this.iterator( true, 'rows', function ( settings, rows ) { 8215 return _pluck_order( settings.aoData, rows, '_aData' ); 8216 }, 1 ); 8217 } ); 8218 8219 _api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) { 8220 return this.iterator( 'row', function ( settings, row ) { 8221 var r = settings.aoData[ row ]; 8222 return type === 'search' ? r._aFilterData : r._aSortData; 8223 }, 1 ); 8224 } ); 8225 8226 _api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) { 8227 return this.iterator( 'row', function ( settings, row ) { 8228 _fnInvalidate( settings, row, src ); 8229 } ); 8230 } ); 8231 8232 _api_registerPlural( 'rows().indexes()', 'row().index()', function () { 8233 return this.iterator( 'row', function ( settings, row ) { 8234 return row; 8235 }, 1 ); 8236 } ); 8237 8238 _api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) { 8239 var a = []; 8240 var context = this.context; 8241 8242 // `iterator` will drop undefined values, but in this case we want them 8243 for ( var i=0, ien=context.length ; i<ien ; i++ ) { 8244 for ( var j=0, jen=this[i].length ; j<jen ; j++ ) { 8245 var id = context[i].rowIdFn( context[i].aoData[ this[i][j] ]._aData ); 8246 a.push( (hash === true ? '#' : '' )+ id ); 8247 } 8248 } 8249 8250 return new _Api( context, a ); 8251 } ); 8252 8253 _api_registerPlural( 'rows().remove()', 'row().remove()', function () { 8254 var that = this; 8255 8256 this.iterator( 'row', function ( settings, row, thatIdx ) { 8257 var data = settings.aoData; 8258 var rowData = data[ row ]; 8259 var i, ien, j, jen; 8260 var loopRow, loopCells; 8261 8262 data.splice( row, 1 ); 8263 8264 // Update the cached indexes 8265 for ( i=0, ien=data.length ; i<ien ; i++ ) { 8266 loopRow = data[i]; 8267 loopCells = loopRow.anCells; 8268 8269 // Rows 8270 if ( loopRow.nTr !== null ) { 8271 loopRow.nTr._DT_RowIndex = i; 8272 } 8273 8274 // Cells 8275 if ( loopCells !== null ) { 8276 for ( j=0, jen=loopCells.length ; j<jen ; j++ ) { 8277 loopCells[j]._DT_CellIndex.row = i; 8278 } 8279 } 8280 } 8281 8282 // Delete from the display arrays 8283 _fnDeleteIndex( settings.aiDisplayMaster, row ); 8284 _fnDeleteIndex( settings.aiDisplay, row ); 8285 _fnDeleteIndex( that[ thatIdx ], row, false ); // maintain local indexes 8286 8287 // For server-side processing tables - subtract the deleted row from the count 8288 if ( settings._iRecordsDisplay > 0 ) { 8289 settings._iRecordsDisplay--; 8290 } 8291 8292 // Check for an 'overflow' they case for displaying the table 8293 _fnLengthOverflow( settings ); 8294 8295 // Remove the row's ID reference if there is one 8296 var id = settings.rowIdFn( rowData._aData ); 8297 if ( id !== undefined ) { 8298 delete settings.aIds[ id ]; 8299 } 8300 } ); 8301 8302 this.iterator( 'table', function ( settings ) { 8303 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) { 8304 settings.aoData[i].idx = i; 8305 } 8306 } ); 8307 8308 return this; 8309 } ); 8310 8311 8312 _api_register( 'rows.add()', function ( rows ) { 8313 var newRows = this.iterator( 'table', function ( settings ) { 8314 var row, i, ien; 8315 var out = []; 8316 8317 for ( i=0, ien=rows.length ; i<ien ; i++ ) { 8318 row = rows[i]; 8319 8320 if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) { 8321 out.push( _fnAddTr( settings, row )[0] ); 8322 } 8323 else { 8324 out.push( _fnAddData( settings, row ) ); 8325 } 8326 } 8327 8328 return out; 8329 }, 1 ); 8330 8331 // Return an Api.rows() extended instance, so rows().nodes() etc can be used 8332 var modRows = this.rows( -1 ); 8333 modRows.pop(); 8334 $.merge( modRows, newRows ); 8335 8336 return modRows; 8337 } ); 8338 8339 8340 8341 8342 8343 /** 8344 * 8345 */ 8346 _api_register( 'row()', function ( selector, opts ) { 8347 return _selector_first( this.rows( selector, opts ) ); 8348 } ); 8349 8350 8351 _api_register( 'row().data()', function ( data ) { 8352 var ctx = this.context; 8353 8354 if ( data === undefined ) { 8355 // Get 8356 return ctx.length && this.length ? 8357 ctx[0].aoData[ this[0] ]._aData : 8358 undefined; 8359 } 8360 8361 // Set 8362 var row = ctx[0].aoData[ this[0] ]; 8363 row._aData = data; 8364 8365 // If the DOM has an id, and the data source is an array 8366 if ( Array.isArray( data ) && row.nTr && row.nTr.id ) { 8367 _fnSetObjectDataFn( ctx[0].rowId )( data, row.nTr.id ); 8368 } 8369 8370 // Automatically invalidate 8371 _fnInvalidate( ctx[0], this[0], 'data' ); 8372 8373 return this; 8374 } ); 8375 8376 8377 _api_register( 'row().node()', function () { 8378 var ctx = this.context; 8379 8380 return ctx.length && this.length ? 8381 ctx[0].aoData[ this[0] ].nTr || null : 8382 null; 8383 } ); 8384 8385 8386 _api_register( 'row.add()', function ( row ) { 8387 // Allow a jQuery object to be passed in - only a single row is added from 8388 // it though - the first element in the set 8389 if ( row instanceof $ && row.length ) { 8390 row = row[0]; 8391 } 8392 8393 var rows = this.iterator( 'table', function ( settings ) { 8394 if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) { 8395 return _fnAddTr( settings, row )[0]; 8396 } 8397 return _fnAddData( settings, row ); 8398 } ); 8399 8400 // Return an Api.rows() extended instance, with the newly added row selected 8401 return this.row( rows[0] ); 8402 } ); 8403 8404 8405 $(document).on('plugin-init.dt', function (e, context) { 8406 var api = new _Api( context ); 8407 var namespace = 'on-plugin-init'; 8408 var stateSaveParamsEvent = 'stateSaveParams.' + namespace; 8409 var destroyEvent = 'destroy. ' + namespace; 8410 8411 api.on( stateSaveParamsEvent, function ( e, settings, d ) { 8412 // This could be more compact with the API, but it is a lot faster as a simple 8413 // internal loop 8414 var idFn = settings.rowIdFn; 8415 var data = settings.aoData; 8416 var ids = []; 8417 8418 for (var i=0 ; i<data.length ; i++) { 8419 if (data[i]._detailsShow) { 8420 ids.push( '#' + idFn(data[i]._aData) ); 8421 } 8422 } 8423 8424 d.childRows = ids; 8425 }); 8426 8427 api.on( destroyEvent, function () { 8428 api.off(stateSaveParamsEvent + ' ' + destroyEvent); 8429 }); 8430 8431 var loaded = api.state.loaded(); 8432 8433 if ( loaded && loaded.childRows ) { 8434 api 8435 .rows( $.map(loaded.childRows, function (id){ 8436 return id.replace(/:/g, '\\:') 8437 }) ) 8438 .every( function () { 8439 _fnCallbackFire( context, null, 'requestChild', [ this ] ) 8440 }); 8441 } 8442 }); 8443 8444 var __details_add = function ( ctx, row, data, klass ) 8445 { 8446 // Convert to array of TR elements 8447 var rows = []; 8448 var addRow = function ( r, k ) { 8449 // Recursion to allow for arrays of jQuery objects 8450 if ( Array.isArray( r ) || r instanceof $ ) { 8451 for ( var i=0, ien=r.length ; i<ien ; i++ ) { 8452 addRow( r[i], k ); 8453 } 8454 return; 8455 } 8456 8457 // If we get a TR element, then just add it directly - up to the dev 8458 // to add the correct number of columns etc 8459 if ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) { 8460 rows.push( r ); 8461 } 8462 else { 8463 // Otherwise create a row with a wrapper 8464 var created = $('<tr><td></td></tr>').addClass( k ); 8465 $('td', created) 8466 .addClass( k ) 8467 .html( r ) 8468 [0].colSpan = _fnVisbleColumns( ctx ); 8469 8470 rows.push( created[0] ); 8471 } 8472 }; 8473 8474 addRow( data, klass ); 8475 8476 if ( row._details ) { 8477 row._details.detach(); 8478 } 8479 8480 row._details = $(rows); 8481 8482 // If the children were already shown, that state should be retained 8483 if ( row._detailsShow ) { 8484 row._details.insertAfter( row.nTr ); 8485 } 8486 }; 8487 8488 8489 // Make state saving of child row details async to allow them to be batch processed 8490 var __details_state = DataTable.util.throttle( 8491 function (ctx) { 8492 _fnSaveState( ctx[0] ) 8493 }, 8494 500 8495 ); 8496 8497 8498 var __details_remove = function ( api, idx ) 8499 { 8500 var ctx = api.context; 8501 8502 if ( ctx.length ) { 8503 var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ]; 8504 8505 if ( row && row._details ) { 8506 row._details.remove(); 8507 8508 row._detailsShow = undefined; 8509 row._details = undefined; 8510 $( row.nTr ).removeClass( 'dt-hasChild' ); 8511 __details_state( ctx ); 8512 } 8513 } 8514 }; 8515 8516 8517 var __details_display = function ( api, show ) { 8518 var ctx = api.context; 8519 8520 if ( ctx.length && api.length ) { 8521 var row = ctx[0].aoData[ api[0] ]; 8522 8523 if ( row._details ) { 8524 row._detailsShow = show; 8525 8526 if ( show ) { 8527 row._details.insertAfter( row.nTr ); 8528 $( row.nTr ).addClass( 'dt-hasChild' ); 8529 } 8530 else { 8531 row._details.detach(); 8532 $( row.nTr ).removeClass( 'dt-hasChild' ); 8533 } 8534 8535 _fnCallbackFire( ctx[0], null, 'childRow', [ show, api.row( api[0] ) ] ) 8536 8537 __details_events( ctx[0] ); 8538 __details_state( ctx ); 8539 } 8540 } 8541 }; 8542 8543 8544 var __details_events = function ( settings ) 8545 { 8546 var api = new _Api( settings ); 8547 var namespace = '.dt.DT_details'; 8548 var drawEvent = 'draw'+namespace; 8549 var colvisEvent = 'column-sizing'+namespace; 8550 var destroyEvent = 'destroy'+namespace; 8551 var data = settings.aoData; 8552 8553 api.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent ); 8554 8555 if ( _pluck( data, '_details' ).length > 0 ) { 8556 // On each draw, insert the required elements into the document 8557 api.on( drawEvent, function ( e, ctx ) { 8558 if ( settings !== ctx ) { 8559 return; 8560 } 8561 8562 api.rows( {page:'current'} ).eq(0).each( function (idx) { 8563 // Internal data grab 8564 var row = data[ idx ]; 8565 8566 if ( row._detailsShow ) { 8567 row._details.insertAfter( row.nTr ); 8568 } 8569 } ); 8570 } ); 8571 8572 // Column visibility change - update the colspan 8573 api.on( colvisEvent, function ( e, ctx, idx, vis ) { 8574 if ( settings !== ctx ) { 8575 return; 8576 } 8577 8578 // Update the colspan for the details rows (note, only if it already has 8579 // a colspan) 8580 var row, visible = _fnVisbleColumns( ctx ); 8581 8582 for ( var i=0, ien=data.length ; i<ien ; i++ ) { 8583 row = data[i]; 8584 8585 if ( row._details ) { 8586 row._details.
8586each(function () { 8587 var el = $(this).children('td'); 8588 8589 if (el.length == 1) { 8590 el.attr('colspan', visible); 8591 } 8592 }
vendor: 32,739 bytes, lines 8592-9799
8592); 8593 } 8594 } 8595 } ); 8596 8597 // Table destroyed - nuke any child rows 8598 api.on( destroyEvent, function ( e, ctx ) { 8599 if ( settings !== ctx ) { 8600 return; 8601 } 8602 8603 for ( var i=0, ien=data.length ; i<ien ; i++ ) { 8604 if ( data[i]._details ) { 8605 __details_remove( api, i ); 8606 } 8607 } 8608 } ); 8609 } 8610 }; 8611 8612 // Strings for the method names to help minification 8613 var _emp = ''; 8614 var _child_obj = _emp+'row().child'; 8615 var _child_mth = _child_obj+'()'; 8616 8617 // data can be: 8618 // tr 8619 // string 8620 // jQuery or array of any of the above 8621 _api_register( _child_mth, function ( data, klass ) { 8622 var ctx = this.context; 8623 8624 if ( data === undefined ) { 8625 // get 8626 return ctx.length && this.length ? 8627 ctx[0].aoData[ this[0] ]._details : 8628 undefined; 8629 } 8630 else if ( data === true ) { 8631 // show 8632 this.child.show(); 8633 } 8634 else if ( data === false ) { 8635 // remove 8636 __details_remove( this ); 8637 } 8638 else if ( ctx.length && this.length ) { 8639 // set 8640 __details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass ); 8641 } 8642 8643 return this; 8644 } ); 8645 8646 8647 _api_register( [ 8648 _child_obj+'.show()', 8649 _child_mth+'.show()' // only when `child()` was called with parameters (without 8650 ], function ( show ) { // it returns an object and this method is not executed) 8651 __details_display( this, true ); 8652 return this; 8653 } ); 8654 8655 8656 _api_register( [ 8657 _child_obj+'.hide()', 8658 _child_mth+'.hide()' // only when `child()` was called with parameters (without 8659 ], function () { // it returns an object and this method is not executed) 8660 __details_display( this, false ); 8661 return this; 8662 } ); 8663 8664 8665 _api_register( [ 8666 _child_obj+'.remove()', 8667 _child_mth+'.remove()' // only when `child()` was called with parameters (without 8668 ], function () { // it returns an object and this method is not executed) 8669 __details_remove( this ); 8670 return this; 8671 } ); 8672 8673 8674 _api_register( _child_obj+'.isShown()', function () { 8675 var ctx = this.context; 8676 8677 if ( ctx.length && this.length ) { 8678 // _detailsShown as false or undefined will fall through to return false 8679 return ctx[0].aoData[ this[0] ]._detailsShow || false; 8680 } 8681 return false; 8682 } ); 8683 8684 8685 8686 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 8687 * Columns 8688 * 8689 * {integer} - column index (>=0 count from left, <0 count from right) 8690 * "{integer}:visIdx" - visible column index (i.e. translate to column index) (>=0 count from left, <0 count from right) 8691 * "{integer}:visible" - alias for {integer}:visIdx (>=0 count from left, <0 count from right) 8692 * "{string}:name" - column name 8693 * "{string}" - jQuery selector on column header nodes 8694 * 8695 */ 8696 8697 // can be an array of these items, comma separated list, or an array of comma 8698 // separated lists 8699 8700 var __re_column_selector = /^([^:]+):(name|visIdx|visible)$/; 8701 8702 8703 // r1 and r2 are redundant - but it means that the parameters match for the 8704 // iterator callback in columns().data() 8705 var __columnData = function ( settings, column, r1, r2, rows ) { 8706 var a = []; 8707 for ( var row=0, ien=rows.length ; row<ien ; row++ ) { 8708 a.push( _fnGetCellData( settings, rows[row], column ) ); 8709 } 8710 return a; 8711 }; 8712 8713 8714 var __column_selector = function ( settings, selector, opts ) 8715 { 8716 var 8717 columns = settings.aoColumns, 8718 names = _pluck( columns, 'sName' ), 8719 nodes = _pluck( columns, 'nTh' ); 8720 8721 var run = function ( s ) { 8722 var selInt = _intVal( s ); 8723 8724 // Selector - all 8725 if ( s === '' ) { 8726 return _range( columns.length ); 8727 } 8728 8729 // Selector - index 8730 if ( selInt !== null ) { 8731 return [ selInt >= 0 ? 8732 selInt : // Count from left 8733 columns.length + selInt // Count from right (+ because its a negative value) 8734 ]; 8735 } 8736 8737 // Selector = function 8738 if ( typeof s === 'function' ) { 8739 var rows = _selector_row_indexes( settings, opts ); 8740 8741 return $.map( columns, function (col, idx) { 8742 return s( 8743 idx, 8744 __columnData( settings, idx, 0, 0, rows ), 8745 nodes[ idx ] 8746 ) ? idx : null; 8747 } ); 8748 } 8749 8750 // jQuery or string selector 8751 var match = typeof s === 'string' ? 8752 s.match( __re_column_selector ) : 8753 ''; 8754 8755 if ( match ) { 8756 switch( match[2] ) { 8757 case 'visIdx': 8758 case 'visible': 8759 var idx = parseInt( match[1], 10 ); 8760 // Visible index given, convert to column index 8761 if ( idx < 0 ) { 8762 // Counting from the right 8763 var visColumns = $.map( columns, function (col,i) { 8764 return col.bVisible ? i : null; 8765 } ); 8766 return [ visColumns[ visColumns.length + idx ] ]; 8767 } 8768 // Counting from the left 8769 return [ _fnVisibleToColumnIndex( settings, idx ) ]; 8770 8771 case 'name': 8772 // match by name. `names` is column index complete and in order 8773 return $.map( names, function (name, i) { 8774 return name === match[1] ? i : null; 8775 } ); 8776 8777 default: 8778 return []; 8779 } 8780 } 8781 8782 // Cell in the table body 8783 if ( s.nodeName && s._DT_CellIndex ) { 8784 return [ s._DT_CellIndex.column ]; 8785 } 8786 8787 // jQuery selector on the TH elements for the columns 8788 var jqResult = $( nodes ) 8789 .filter( s ) 8790 .map( function () { 8791 return $.inArray( this, nodes ); // `nodes` is column index complete and in order 8792 } ) 8793 .toArray(); 8794 8795 if ( jqResult.length || ! s.nodeName ) { 8796 return jqResult; 8797 } 8798 8799 // Otherwise a node which might have a `dt-column` data attribute, or be 8800 // a child or such an element 8801 var host = $(s).closest('*[data-dt-column]'); 8802 return host.length ? 8803 [ host.data('dt-column') ] : 8804 []; 8805 }; 8806 8807 return _selector_run( 'column', selector, run, settings, opts ); 8808 }; 8809 8810 8811 var __setColumnVis = function ( settings, column, vis ) { 8812 var 8813 cols = settings.aoColumns, 8814 col = cols[ column ], 8815 data = settings.aoData, 8816 row, cells, i, ien, tr; 8817 8818 // Get 8819 if ( vis === undefined ) { 8820 return col.bVisible; 8821 } 8822 8823 // Set 8824 // No change 8825 if ( col.bVisible === vis ) { 8826 return; 8827 } 8828 8829 if ( vis ) { 8830 // Insert column 8831 // Need to decide if we should use appendChild or insertBefore 8832 var insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 ); 8833 8834 for ( i=0, ien=data.length ; i<ien ; i++ ) { 8835 tr = data[i].nTr; 8836 cells = data[i].anCells; 8837 8838 if ( tr ) { 8839 // insertBefore can act like appendChild if 2nd arg is null 8840 tr.insertBefore( cells[ column ], cells[ insertBefore ] || null ); 8841 } 8842 } 8843 } 8844 else { 8845 // Remove column 8846 $( _pluck( settings.aoData, 'anCells', column ) ).detach(); 8847 } 8848 8849 // Common actions 8850 col.bVisible = vis; 8851 }; 8852 8853 8854 _api_register( 'columns()', function ( selector, opts ) { 8855 // argument shifting 8856 if ( selector === undefined ) { 8857 selector = ''; 8858 } 8859 else if ( $.isPlainObject( selector ) ) { 8860 opts = selector; 8861 selector = ''; 8862 } 8863 8864 opts = _selector_opts( opts ); 8865 8866 var inst = this.iterator( 'table', function ( settings ) { 8867 return __column_selector( settings, selector, opts ); 8868 }, 1 ); 8869 8870 // Want argument shifting here and in _row_selector? 8871 inst.selector.cols = selector; 8872 inst.selector.opts = opts; 8873 8874 return inst; 8875 } ); 8876 8877 _api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) { 8878 return this.iterator( 'column', function ( settings, column ) { 8879 return settings.aoColumns[column].nTh; 8880 }, 1 ); 8881 } ); 8882 8883 _api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) { 8884 return this.iterator( 'column', function ( settings, column ) { 8885 return settings.aoColumns[column].nTf; 8886 }, 1 ); 8887 } ); 8888 8889 _api_registerPlural( 'columns().data()', 'column().data()', function () { 8890 return this.iterator( 'column-rows', __columnData, 1 ); 8891 } ); 8892 8893 _api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () { 8894 return this.iterator( 'column', function ( settings, column ) { 8895 return settings.aoColumns[column].mData; 8896 }, 1 ); 8897 } ); 8898 8899 _api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) { 8900 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) { 8901 return _pluck_order( settings.aoData, rows, 8902 type === 'search' ? '_aFilterData' : '_aSortData', column 8903 ); 8904 }, 1 ); 8905 } ); 8906 8907 _api_registerPlural( 'columns().nodes()', 'column().nodes()', function () { 8908 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) { 8909 return _pluck_order( settings.aoData, rows, 'anCells', column ) ; 8910 }, 1 ); 8911 } ); 8912 8913 _api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) { 8914 var that = this; 8915 var ret = this.iterator( 'column', function ( settings, column ) { 8916 if ( vis === undefined ) { 8917 return settings.aoColumns[ column ].bVisible; 8918 } // else 8919 __setColumnVis( settings, column, vis ); 8920 } ); 8921 8922 // Group the column visibility changes 8923 if ( vis !== undefined ) { 8924 this.iterator( 'table', function ( settings ) { 8925 // Redraw the header after changes 8926 _fnDrawHead( settings, settings.aoHeader ); 8927 _fnDrawHead( settings, settings.aoFooter ); 8928 8929 // Update colspan for no records display. Child rows and extensions will use their own 8930 // listeners to do this - only need to update the empty table item here 8931 if ( ! settings.aiDisplay.length ) { 8932 $(settings.nTBody).find('td[colspan]').attr('colspan', _fnVisbleColumns(settings)); 8933 } 8934 8935 _fnSaveState( settings ); 8936 8937 // Second loop once the first is done for events 8938 that.iterator( 'column', function ( settings, column ) { 8939 _fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis, calc] ); 8940 } ); 8941 8942 if ( calc === undefined || calc ) { 8943 that.columns.adjust(); 8944 } 8945 }); 8946 } 8947 8948 return ret; 8949 } ); 8950 8951 _api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) { 8952 return this.iterator( 'column', function ( settings, column ) { 8953 return type === 'visible' ? 8954 _fnColumnIndexToVisible( settings, column ) : 8955 column; 8956 }, 1 ); 8957 } ); 8958 8959 _api_register( 'columns.adjust()', function () { 8960 return this.iterator( 'table', function ( settings ) { 8961 _fnAdjustColumnSizing( settings ); 8962 }, 1 ); 8963 } ); 8964 8965 _api_register( 'column.index()', function ( type, idx ) { 8966 if ( this.context.length !== 0 ) { 8967 var ctx = this.context[0]; 8968 8969 if ( type === 'fromVisible' || type === 'toData' ) { 8970 return _fnVisibleToColumnIndex( ctx, idx ); 8971 } 8972 else if ( type === 'fromData' || type === 'toVisible' ) { 8973 return _fnColumnIndexToVisible( ctx, idx ); 8974 } 8975 } 8976 } ); 8977 8978 _api_register( 'column()', function ( selector, opts ) { 8979 return _selector_first( this.columns( selector, opts ) ); 8980 } ); 8981 8982 var __cell_selector = function ( settings, selector, opts ) 8983 { 8984 var data = settings.aoData; 8985 var rows = _selector_row_indexes( settings, opts ); 8986 var cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) ); 8987 var allCells = $(_flatten( [], cells )); 8988 var row; 8989 var columns = settings.aoColumns.length; 8990 var a, i, ien, j, o, host; 8991 8992 var run = function ( s ) { 8993 var fnSelector = typeof s === 'function'; 8994 8995 if ( s === null || s === undefined || fnSelector ) { 8996 // All cells and function selectors 8997 a = []; 8998 8999 for ( i=0, ien=rows.length ; i<ien ; i++ ) { 9000 row = rows[i]; 9001 9002 for ( j=0 ; j<columns ; j++ ) { 9003 o = { 9004 row: row, 9005 column: j 9006 }; 9007 9008 if ( fnSelector ) { 9009 // Selector - function 9010 host = data[ row ]; 9011 9012 if ( s( o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null ) ) { 9013 a.push( o ); 9014 } 9015 } 9016 else { 9017 // Selector - all 9018 a.push( o ); 9019 } 9020 } 9021 } 9022 9023 return a; 9024 } 9025 9026 // Selector - index 9027 if ( $.isPlainObject( s ) ) { 9028 // Valid cell index and its in the array of selectable rows 9029 return s.column !== undefined && s.row !== undefined && $.inArray( s.row, rows ) !== -1 ? 9030 [s] : 9031 []; 9032 } 9033 9034 // Selector - jQuery filtered cells 9035 var jqResult = allCells 9036 .filter( s ) 9037 .map( function (i, el) { 9038 return { // use a new object, in case someone changes the values 9039 row: el._DT_CellIndex.row, 9040 column: el._DT_CellIndex.column 9041 }; 9042 } ) 9043 .toArray(); 9044 9045 if ( jqResult.length || ! s.nodeName ) { 9046 return jqResult; 9047 } 9048 9049 // Otherwise the selector is a node, and there is one last option - the 9050 // element might be a child of an element which has dt-row and dt-column 9051 // data attributes 9052 host = $(s).closest('*[data-dt-row]'); 9053 return host.length ? 9054 [ { 9055 row: host.data('dt-row'), 9056 column: host.data('dt-column') 9057 } ] : 9058 []; 9059 }; 9060 9061 return _selector_run( 'cell', selector, run, settings, opts ); 9062 }; 9063 9064 9065 9066 9067 _api_register( 'cells()', function ( rowSelector, columnSelector, opts ) { 9068 // Argument shifting 9069 if ( $.isPlainObject( rowSelector ) ) { 9070 // Indexes 9071 if ( rowSelector.row === undefined ) { 9072 // Selector options in first parameter 9073 opts = rowSelector; 9074 rowSelector = null; 9075 } 9076 else { 9077 // Cell index objects in first parameter 9078 opts = columnSelector; 9079 columnSelector = null; 9080 } 9081 } 9082 if ( $.isPlainObject( columnSelector ) ) { 9083 opts = columnSelector; 9084 columnSelector = null; 9085 } 9086 9087 // Cell selector 9088 if ( columnSelector === null || columnSelector === undefined ) { 9089 return this.iterator( 'table', function ( settings ) { 9090 return __cell_selector( settings, rowSelector, _selector_opts( opts ) ); 9091 } ); 9092 } 9093 9094 // The default built in options need to apply to row and columns 9095 var internalOpts = opts ? { 9096 page: opts.page, 9097 order: opts.order, 9098 search: opts.search 9099 } : {}; 9100 9101 // Row + column selector 9102 var columns = this.columns( columnSelector, internalOpts ); 9103 var rows = this.rows( rowSelector, internalOpts ); 9104 var i, ien, j, jen; 9105 9106 var cellsNoOpts = this.iterator( 'table', function ( settings, idx ) { 9107 var a = []; 9108 9109 for ( i=0, ien=rows[idx].length ; i<ien ; i++ ) { 9110 for ( j=0, jen=columns[idx].length ; j<jen ; j++ ) { 9111 a.push( { 9112 row: rows[idx][i], 9113 column: columns[idx][j] 9114 } ); 9115 } 9116 } 9117 9118 return a; 9119 }, 1 ); 9120 9121 // There is currently only one extension which uses a cell selector extension 9122 // It is a _major_ performance drag to run this if it isn't needed, so this is 9123 // an extension specific check at the moment 9124 var cells = opts && opts.selected ? 9125 this.cells( cellsNoOpts, opts ) : 9126 cellsNoOpts; 9127 9128 $.extend( cells.selector, { 9129 cols: columnSelector, 9130 rows: rowSelector, 9131 opts: opts 9132 } ); 9133 9134 return cells; 9135 } ); 9136 9137 9138 _api_registerPlural( 'cells().nodes()', 'cell().node()', function () { 9139 return this.iterator( 'cell', function ( settings, row, column ) { 9140 var data = settings.aoData[ row ]; 9141 9142 return data && data.anCells ? 9143 data.anCells[ column ] : 9144 undefined; 9145 }, 1 ); 9146 } ); 9147 9148 9149 _api_register( 'cells().data()', function () { 9150 return this.iterator( 'cell', function ( settings, row, column ) { 9151 return _fnGetCellData( settings, row, column ); 9152 }, 1 ); 9153 } ); 9154 9155 9156 _api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) { 9157 type = type === 'search' ? '_aFilterData' : '_aSortData'; 9158 9159 return this.iterator( 'cell', function ( settings, row, column ) { 9160 return settings.aoData[ row ][ type ][ column ]; 9161 }, 1 ); 9162 } ); 9163 9164 9165 _api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) { 9166 return this.iterator( 'cell', function ( settings, row, column ) { 9167 return _fnGetCellData( settings, row, column, type ); 9168 }, 1 ); 9169 } ); 9170 9171 9172 _api_registerPlural( 'cells().indexes()', 'cell().index()', function () { 9173 return this.iterator( 'cell', function ( settings, row, column ) { 9174 return { 9175 row: row, 9176 column: column, 9177 columnVisible: _fnColumnIndexToVisible( settings, column ) 9178 }; 9179 }, 1 ); 9180 } ); 9181 9182 9183 _api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) { 9184 return this.iterator( 'cell', function ( settings, row, column ) { 9185 _fnInvalidate( settings, row, src, column ); 9186 } ); 9187 } ); 9188 9189 9190 9191 _api_register( 'cell()', function ( rowSelector, columnSelector, opts ) { 9192 return _selector_first( this.cells( rowSelector, columnSelector, opts ) ); 9193 } ); 9194 9195 9196 _api_register( 'cell().data()', function ( data ) { 9197 var ctx = this.context; 9198 var cell = this[0]; 9199 9200 if ( data === undefined ) { 9201 // Get 9202 return ctx.length && cell.length ? 9203 _fnGetCellData( ctx[0], cell[0].row, cell[0].column ) : 9204 undefined; 9205 } 9206 9207 // Set 9208 _fnSetCellData( ctx[0], cell[0].row, cell[0].column, data ); 9209 _fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column ); 9210 9211 return this; 9212 } ); 9213 9214 9215 9216 /** 9217 * Get current ordering (sorting) that has been applied to the table. 9218 * 9219 * @returns {array} 2D array containing the sorting information for the first 9220 * table in the current context. Each element in the parent array represents 9221 * a column being sorted upon (i.e. multi-sorting with two columns would have 9222 * 2 inner arrays). The inner arrays may have 2 or 3 elements. The first is 9223 * the column index that the sorting condition applies to, the second is the 9224 * direction of the sort (`desc` or `asc`) and, optionally, the third is the 9225 * index of the sorting order from the `column.sorting` initialisation array. 9226 *//** 9227 * Set the ordering for the table. 9228 * 9229 * @param {integer} order Column index to sort upon. 9230 * @param {string} direction Direction of the sort to be applied (`asc` or `desc`) 9231 * @returns {DataTables.Api} this 9232 *//** 9233 * Set the ordering for the table. 9234 * 9235 * @param {array} order 1D array of sorting information to be applied. 9236 * @param {array} [...] Optional additional sorting conditions 9237 * @returns {DataTables.Api} this 9238 *//** 9239 * Set the ordering for the table. 9240 * 9241 * @param {array} order 2D array of sorting information to be applied. 9242 * @returns {DataTables.Api} this 9243 */ 9244 _api_register( 'order()', function ( order, dir ) { 9245 var ctx = this.context; 9246 9247 if ( order === undefined ) { 9248 // get 9249 return ctx.length !== 0 ? 9250 ctx[0].aaSorting : 9251 undefined; 9252 } 9253 9254 // set 9255 if ( typeof order === 'number' ) { 9256 // Simple column / direction passed in 9257 order = [ [ order, dir ] ]; 9258 } 9259 else if ( order.length && ! Array.isArray( order[0] ) ) { 9260 // Arguments passed in (list of 1D arrays) 9261 order = Array.prototype.slice.call( arguments ); 9262 } 9263 // otherwise a 2D array was passed in 9264 9265 return this.iterator( 'table', function ( settings ) { 9266 settings.aaSorting = order.slice(); 9267 } ); 9268 } ); 9269 9270 9271 /** 9272 * Attach a sort listener to an element for a given column 9273 * 9274 * @param {node|jQuery|string} node Identifier for the element(s) to attach the 9275 * listener to. This can take the form of a single DOM node, a jQuery 9276 * collection of nodes or a jQuery selector which will identify the node(s). 9277 * @param {integer} column the column that a click on this node will sort on 9278 * @param {function} [callback] callback function when sort is run 9279 * @returns {DataTables.Api} this 9280 */ 9281 _api_register( 'order.listener()', function ( node, column, callback ) { 9282 return this.iterator( 'table', function ( settings ) { 9283 _fnSortAttachListener( settings, node, column, callback ); 9284 } ); 9285 } ); 9286 9287 9288 _api_register( 'order.fixed()', function ( set ) { 9289 if ( ! set ) { 9290 var ctx = this.context; 9291 var fixed = ctx.length ? 9292 ctx[0].aaSortingFixed : 9293 undefined; 9294 9295 return Array.isArray( fixed ) ? 9296 { pre: fixed } : 9297 fixed; 9298 } 9299 9300 return this.iterator( 'table', function ( settings ) { 9301 settings.aaSortingFixed = $.extend( true, {}, set ); 9302 } ); 9303 } ); 9304 9305 9306 // Order by the selected column(s) 9307 _api_register( [ 9308 'columns().order()', 9309 'column().order()' 9310 ], function ( dir ) { 9311 var that = this; 9312 9313 return this.iterator( 'table', function ( settings, i ) { 9314 var sort = []; 9315 9316 $.each( that[i], function (j, col) { 9317 sort.push( [ col, dir ] ); 9318 } ); 9319 9320 settings.aaSorting = sort; 9321 } ); 9322 } ); 9323 9324 9325 9326 _api_register( 'search()', function ( input, regex, smart, caseInsen ) { 9327 var ctx = this.context; 9328 9329 if ( input === undefined ) { 9330 // get 9331 return ctx.length !== 0 ? 9332 ctx[0].oPreviousSearch.sSearch : 9333 undefined; 9334 } 9335 9336 // set 9337 return this.iterator( 'table', function ( settings ) { 9338 if ( ! settings.oFeatures.bFilter ) { 9339 return; 9340 } 9341 9342 _fnFilterComplete( settings, $.extend( {}, settings.oPreviousSearch, { 9343 "sSearch": input+"", 9344 "bRegex": regex === null ? false : regex, 9345 "bSmart": smart === null ? true : smart, 9346 "bCaseInsensitive": caseInsen === null ? true : caseInsen 9347 } ), 1 ); 9348 } ); 9349 } ); 9350 9351 9352 _api_registerPlural( 9353 'columns().search()', 9354 'column().search()', 9355 function ( input, regex, smart, caseInsen ) { 9356 return this.iterator( 'column', function ( settings, column ) { 9357 var preSearch = settings.aoPreSearchCols; 9358 9359 if ( input === undefined ) { 9360 // get 9361 return preSearch[ column ].sSearch; 9362 } 9363 9364 // set 9365 if ( ! settings.oFeatures.bFilter ) { 9366 return; 9367 } 9368 9369 $.extend( preSearch[ column ], { 9370 "sSearch": input+"", 9371 "bRegex": regex === null ? false : regex, 9372 "bSmart": smart === null ? true : smart, 9373 "bCaseInsensitive": caseInsen === null ? true : caseInsen 9374 } ); 9375 9376 _fnFilterComplete( settings, settings.oPreviousSearch, 1 ); 9377 } ); 9378 } 9379 ); 9380 9381 /* 9382 * State API methods 9383 */ 9384 9385 _api_register( 'state()', function () { 9386 return this.context.length ? 9387 this.context[0].oSavedState : 9388 null; 9389 } ); 9390 9391 9392 _api_register( 'state.clear()', function () { 9393 return this.iterator( 'table', function ( settings ) { 9394 // Save an empty object 9395 settings.fnStateSaveCallback.call( settings.oInstance, settings, {} ); 9396 } ); 9397 } ); 9398 9399 9400 _api_register( 'state.loaded()', function () { 9401 return this.context.length ? 9402 this.context[0].oLoadedState : 9403 null; 9404 } ); 9405 9406 9407 _api_register( 'state.save()', function () { 9408 return this.iterator( 'table', function ( settings ) { 9409 _fnSaveState( settings ); 9410 } ); 9411 } ); 9412 9413 9414 9415 /** 9416 * Set the jQuery or window object to be used by DataTables 9417 * 9418 * @param {*} module Library / container object 9419 * @param {string} [type] Library or container type `lib`, `win` or `datetime`. 9420 * If not provided, automatic detection is attempted. 9421 */ 9422 DataTable.use = function (module, type) { 9423 if (type === 'lib' || module.fn) { 9424 $ = module; 9425 } 9426 else if (type == 'win' || module.document) { 9427 window = module; 9428 document = module.document; 9429 } 9430 else if (type === 'datetime' || module.type === 'DateTime') { 9431 DataTable.DateTime = module; 9432 } 9433 } 9434 9435 /** 9436 * CommonJS factory function pass through. This will check if the arguments 9437 * given are a window object or a jQuery object. If so they are set 9438 * accordingly. 9439 * @param {*} root Window 9440 * @param {*} jq jQUery 9441 * @returns {boolean} Indicator 9442 */ 9443 DataTable.factory = function (root, jq) { 9444 var is = false; 9445 9446 // Test if the first parameter is a window object 9447 if (root && root.document) { 9448 window = root; 9449 document = root.document; 9450 } 9451 9452 // Test if the second parameter is a jQuery object 9453 if (jq && jq.fn && jq.fn.jquery) { 9454 $ = jq; 9455 is = true; 9456 } 9457 9458 return is; 9459 } 9460 9461 /** 9462 * Provide a common method for plug-ins to check the version of DataTables being 9463 * used, in order to ensure compatibility. 9464 * 9465 * @param {string} version Version string to check for, in the format "X.Y.Z". 9466 * Note that the formats "X" and "X.Y" are also acceptable. 9467 * @returns {boolean} true if this version of DataTables is greater or equal to 9468 * the required version, or false if this version of DataTales is not 9469 * suitable 9470 * @static 9471 * @dtopt API-Static 9472 * 9473 * @example 9474 * alert( $.fn.dataTable.versionCheck( '1.9.0' ) ); 9475 */ 9476 DataTable.versionCheck = DataTable.fnVersionCheck = function( version ) 9477 { 9478 var aThis = DataTable.version.split('.'); 9479 var aThat = version.split('.'); 9480 var iThis, iThat; 9481 9482 for ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) { 9483 iThis = parseInt( aThis[i], 10 ) || 0; 9484 iThat = parseInt( aThat[i], 10 ) || 0; 9485 9486 // Parts are the same, keep comparing 9487 if (iThis === iThat) { 9488 continue; 9489 } 9490 9491 // Parts are different, return immediately 9492 return iThis > iThat; 9493 } 9494 9495 return true; 9496 }; 9497 9498 9499 /** 9500 * Check if a `<table>` node is a DataTable table already or not. 9501 * 9502 * @param {node|jquery|string} table Table node, jQuery object or jQuery 9503 * selector for the table to test. Note that if more than more than one 9504 * table is passed on, only the first will be checked 9505 * @returns {boolean} true the table given is a DataTable, or false otherwise 9506 * @static 9507 * @dtopt API-Static 9508 * 9509 * @example 9510 * if ( ! $.fn.DataTable.isDataTable( '#example' ) ) { 9511 * $('#example').dataTable(); 9512 * } 9513 */ 9514 DataTable.isDataTable = DataTable.fnIsDataTable = function ( table ) 9515 { 9516 var t = $(table).get(0); 9517 var is = false; 9518 9519 if ( table instanceof DataTable.Api ) { 9520 return true; 9521 } 9522 9523 $.each( DataTable.settings, function (i, o) { 9524 var head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null; 9525 var foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null; 9526 9527 if ( o.nTable === t || head === t || foot === t ) { 9528 is = true; 9529 } 9530 } ); 9531 9532 return is; 9533 }; 9534 9535 9536 /** 9537 * Get all DataTable tables that have been initialised - optionally you can 9538 * select to get only currently visible tables. 9539 * 9540 * @param {boolean} [visible=false] Flag to indicate if you want all (default) 9541 * or visible tables only. 9542 * @returns {array} Array of `table` nodes (not DataTable instances) which are 9543 * DataTables 9544 * @static 9545 * @dtopt API-Static 9546 * 9547 * @example 9548 * $.each( $.fn.dataTable.tables(true), function () { 9549 * $(table).DataTable().columns.adjust(); 9550 * } ); 9551 */ 9552 DataTable.tables = DataTable.fnTables = function ( visible ) 9553 { 9554 var api = false; 9555 9556 if ( $.isPlainObject( visible ) ) { 9557 api = visible.api; 9558 visible = visible.visible; 9559 } 9560 9561 var a = $.map( DataTable.settings, function (o) { 9562 if ( !visible || (visible && $(o.nTable).is(':visible')) ) { 9563 return o.nTable; 9564 } 9565 } ); 9566 9567 return api ? 9568 new _Api( a ) : 9569 a; 9570 }; 9571 9572 9573 /** 9574 * Convert from camel case parameters to Hungarian notation. This is made public 9575 * for the extensions to provide the same ability as DataTables core to accept 9576 * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase 9577 * parameters. 9578 * 9579 * @param {object} src The model object which holds all parameters that can be 9580 * mapped. 9581 * @param {object} user The object to convert from camel case to Hungarian. 9582 * @param {boolean} force When set to `true`, properties which already have a 9583 * Hungarian value in the `user` object will be overwritten. Otherwise they 9584 * won't be. 9585 */ 9586 DataTable.camelToHungarian = _fnCamelToHungarian; 9587 9588 9589 9590 /** 9591 * 9592 */ 9593 _api_register( '$()', function ( selector, opts ) { 9594 var 9595 rows = this.rows( opts ).nodes(), // Get all rows 9596 jqRows = $(rows); 9597 9598 return $( [].concat( 9599 jqRows.filter( selector ).toArray(), 9600 jqRows.find( selector ).toArray() 9601 ) ); 9602 } ); 9603 9604 9605 // jQuery functions to operate on the tables 9606 $.each( [ 'on', 'one', 'off' ], function (i, key) { 9607 _api_register( key+'()', function ( /* event, handler */ ) { 9608 var args = Array.prototype.slice.call(arguments); 9609 9610 // Add the `dt` namespace automatically if it isn't already present 9611 args[0] = $.map( args[0].split( /\s/ ), function ( e ) { 9612 return ! e.match(/\.dt\b/) ? 9613 e+'.dt' : 9614 e; 9615 } ).join( ' ' ); 9616 9617 var inst = $( this.tables().nodes() ); 9618 inst[key].apply( inst, args ); 9619 return this; 9620 } ); 9621 } ); 9622 9623 9624 _api_register( 'clear()', function () { 9625 return this.iterator( 'table', function ( settings ) { 9626 _fnClearTable( settings ); 9627 } ); 9628 } ); 9629 9630 9631 _api_register( 'settings()', function () { 9632 return new _Api( this.context, this.context ); 9633 } ); 9634 9635 9636 _api_register( 'init()', function () { 9637 var ctx = this.context; 9638 return ctx.length ? ctx[0].oInit : null; 9639 } ); 9640 9641 9642 _api_register( 'data()', function () { 9643 return this.iterator( 'table', function ( settings ) { 9644 return _pluck( settings.aoData, '_aData' ); 9645 } ).flatten(); 9646 } ); 9647 9648 9649 _api_register( 'destroy()', function ( remove ) { 9650 remove = remove || false; 9651 9652 return this.iterator( 'table', function ( settings ) { 9653 var classes = settings.oClasses; 9654 var table = settings.nTable; 9655 var tbody = settings.nTBody; 9656 var thead = settings.nTHead; 9657 var tfoot = settings.nTFoot; 9658 var jqTable = $(table); 9659 var jqTbody = $(tbody); 9660 var jqWrapper = $(settings.nTableWrapper); 9661 var rows = $.map( settings.aoData, function (r) { return r.nTr; } ); 9662 var i, ien; 9663 9664 // Flag to note that the table is currently being destroyed - no action 9665 // should be taken 9666 settings.bDestroying = true; 9667 9668 // Fire off the destroy callbacks for plug-ins etc 9669 _fnCallbackFire( settings, "aoDestroyCallback", "destroy", [settings] ); 9670 9671 // If not being removed from the document, make all columns visible 9672 if ( ! remove ) { 9673 new _Api( settings ).columns().visible( true ); 9674 } 9675 9676 // Blitz all `DT` namespaced events (these are internal events, the 9677 // lowercase, `dt` events are user subscribed and they are responsible 9678 // for removing them 9679 jqWrapper.off('.DT').find(':not(tbody *)').off('.DT'); 9680 $(window).off('.DT-'+settings.sInstance); 9681 9682 // When scrolling we had to break the table up - restore it 9683 if ( table != thead.parentNode ) { 9684 jqTable.children('thead').detach(); 9685 jqTable.append( thead ); 9686 } 9687 9688 if ( tfoot && table != tfoot.parentNode ) { 9689 jqTable.children('tfoot').detach(); 9690 jqTable.append( tfoot ); 9691 } 9692 9693 settings.aaSorting = []; 9694 settings.aaSortingFixed = []; 9695 _fnSortingClasses( settings ); 9696 9697 $( rows ).removeClass( settings.asStripeClasses.join(' ') ); 9698 9699 $('th, td', thead).removeClass( classes.sSortable+' '+ 9700 classes.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone 9701 ); 9702 9703 // Add the TR elements back into the table in their original order 9704 jqTbody.children().detach(); 9705 jqTbody.append( rows ); 9706 9707 var orig = settings.nTableWrapper.parentNode; 9708 9709 // Remove the DataTables generated nodes, events and classes 9710 var removedMethod = remove ? 'remove' : 'detach'; 9711 jqTable[ removedMethod ](); 9712 jqWrapper[ removedMethod ](); 9713 9714 // If we need to reattach the table to the document 9715 if ( ! remove && orig ) { 9716 // insertBefore acts like appendChild if !arg[1] 9717 orig.insertBefore( table, settings.nTableReinsertBefore ); 9718 9719 // Restore the width of the original table - was read from the style property, 9720 // so we can restore directly to that 9721 jqTable 9722 .css( 'width', settings.sDestroyWidth ) 9723 .removeClass( classes.sTable ); 9724 9725 // If the were originally stripe classes - then we add them back here. 9726 // Note this is not fool proof (for example if not all rows had stripe 9727 // classes - but it's a good effort without getting carried away 9728 ien = settings.asDestroyStripes.length; 9729 9730 if ( ien ) { 9731 jqTbody.children().each( function (i) { 9732 $(this).addClass( settings.asDestroyStripes[i % ien] ); 9733 } ); 9734 } 9735 } 9736 9737 /* Remove the settings object from the settings array */ 9738 var idx = $.inArray( settings, DataTable.settings ); 9739 if ( idx !== -1 ) { 9740 DataTable.settings.splice( idx, 1 ); 9741 } 9742 } ); 9743 } ); 9744 9745 9746 // Add the `every()` method for rows, columns and cells in a compact form 9747 $.each( [ 'column', 'row', 'cell' ], function ( i, type ) { 9748 _api_register( type+'s().every()', function ( fn ) { 9749 var opts = this.selector.opts; 9750 var api = this; 9751 9752 return this.iterator( type, function ( settings, arg1, arg2, arg3, arg4 ) { 9753 // Rows and columns: 9754 // arg1 - index 9755 // arg2 - table counter 9756 // arg3 - loop counter 9757 // arg4 - undefined 9758 // Cells: 9759 // arg1 - row index 9760 // arg2 - column index 9761 // arg3 - table counter 9762 // arg4 - loop counter 9763 fn.call( 9764 api[ type ]( 9765 arg1, 9766 type==='cell' ? arg2 : opts, 9767 type==='cell' ? opts : undefined 9768 ), 9769 arg1, arg2, arg3, arg4 9770 ); 9771 } ); 9772 } ); 9773 } ); 9774 9775 9776 // i18n method for extensions to be able to use the language object from the 9777 // DataTable 9778 _api_register( 'i18n()', function ( token, def, plural ) { 9779 var ctx = this.context[0]; 9780 var resolved = _fnGetObjectDataFn( token )( ctx.oLanguage ); 9781 9782 if ( resolved === undefined ) { 9783 resolved = def; 9784 } 9785 9786 if ( plural !== undefined && $.isPlainObject( resolved ) ) { 9787 resolved = resolved[ plural ] !== undefined ? 9788 resolved[ plural ] : 9789 resolved._; 9790 } 9791 9792 return typeof resolved === 'string' 9793 ? resolved.replace( '%d', plural ) // nb: plural might be undefined, 9794 : resolved; 9795 } ); 9796 /** 9797 * Version string for plug-ins to check compatibility. Allowed format is 9798 * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used 9799 * only for non-release builds. See http
9799s://semver.org/ for more information. 9800 * @member 9801 * @type string 9802 * @default Version number 9803 */ 9804 DataTable.version = "1.13.11
vendor: 17,667 bytes, lines 9804-10380
9804"; 9805 9806 /** 9807 * Private data store, containing all of the settings objects that are 9808 * created for the tables on a given page. 9809 * 9810 * Note that the `DataTable.settings` object is aliased to 9811 * `jQuery.fn.dataTableExt` through which it may be accessed and 9812 * manipulated, or `jQuery.fn.dataTable.settings`. 9813 * @member 9814 * @type array 9815 * @default [] 9816 * @private 9817 */ 9818 DataTable.settings = []; 9819 9820 /** 9821 * Object models container, for the various models that DataTables has 9822 * available to it. These models define the objects that are used to hold 9823 * the active state and configuration of the table. 9824 * @namespace 9825 */ 9826 DataTable.models = {}; 9827 9828 9829 9830 /** 9831 * Template object for the way in which DataTables holds information about 9832 * search information for the global filter and individual column filters. 9833 * @namespace 9834 */ 9835 DataTable.models.oSearch = { 9836 /** 9837 * Flag to indicate if the filtering should be case insensitive or not 9838 * @type boolean 9839 * @default true 9840 */ 9841 "bCaseInsensitive": true, 9842 9843 /** 9844 * Applied search term 9845 * @type string 9846 * @default <i>Empty string</i> 9847 */ 9848 "sSearch": "", 9849 9850 /** 9851 * Flag to indicate if the search term should be interpreted as a 9852 * regular expression (true) or not (false) and therefore and special 9853 * regex characters escaped. 9854 * @type boolean 9855 * @default false 9856 */ 9857 "bRegex": false, 9858 9859 /** 9860 * Flag to indicate if DataTables is to use its smart filtering or not. 9861 * @type boolean 9862 * @default true 9863 */ 9864 "bSmart": true, 9865 9866 /** 9867 * Flag to indicate if DataTables should only trigger a search when 9868 * the return key is pressed. 9869 * @type boolean 9870 * @default false 9871 */ 9872 "return": false 9873 }; 9874 9875 9876 9877 9878 /** 9879 * Template object for the way in which DataTables holds information about 9880 * each individual row. This is the object format used for the settings 9881 * aoData array. 9882 * @namespace 9883 */ 9884 DataTable.models.oRow = { 9885 /** 9886 * TR element for the row 9887 * @type node 9888 * @default null 9889 */ 9890 "nTr": null, 9891 9892 /** 9893 * Array of TD elements for each row. This is null until the row has been 9894 * created. 9895 * @type array nodes 9896 * @default [] 9897 */ 9898 "anCells": null, 9899 9900 /** 9901 * Data object from the original data source for the row. This is either 9902 * an array if using the traditional form of DataTables, or an object if 9903 * using mData options. The exact type will depend on the passed in 9904 * data from the data source, or will be an array if using DOM a data 9905 * source. 9906 * @type array|object 9907 * @default [] 9908 */ 9909 "_aData": [], 9910 9911 /** 9912 * Sorting data cache - this array is ostensibly the same length as the 9913 * number of columns (although each index is generated only as it is 9914 * needed), and holds the data that is used for sorting each column in the 9915 * row. We do this cache generation at the start of the sort in order that 9916 * the formatting of the sort data need be done only once for each cell 9917 * per sort. This array should not be read from or written to by anything 9918 * other than the master sorting methods. 9919 * @type array 9920 * @default null 9921 * @private 9922 */ 9923 "_aSortData": null, 9924 9925 /** 9926 * Per cell filtering data cache. As per the sort data cache, used to 9927 * increase the performance of the filtering in DataTables 9928 * @type array 9929 * @default null 9930 * @private 9931 */ 9932 "_aFilterData": null, 9933 9934 /** 9935 * Filtering data cache. This is the same as the cell filtering cache, but 9936 * in this case a string rather than an array. This is easily computed with 9937 * a join on `_aFilterData`, but is provided as a cache so the join isn't 9938 * needed on every search (memory traded for performance) 9939 * @type array 9940 * @default null 9941 * @private 9942 */ 9943 "_sFilterRow": null, 9944 9945 /** 9946 * Cache of the class name that DataTables has applied to the row, so we 9947 * can quickly look at this variable rather than needing to do a DOM check 9948 * on className for the nTr property. 9949 * @type string 9950 * @default <i>Empty string</i> 9951 * @private 9952 */ 9953 "_sRowStripe": "", 9954 9955 /** 9956 * Denote if the original data source was from the DOM, or the data source 9957 * object. This is used for invalidating data, so DataTables can 9958 * automatically read data from the original source, unless uninstructed 9959 * otherwise. 9960 * @type string 9961 * @default null 9962 * @private 9963 */ 9964 "src": null, 9965 9966 /** 9967 * Index in the aoData array. This saves an indexOf lookup when we have the 9968 * object, but want to know the index 9969 * @type integer 9970 * @default -1 9971 * @private 9972 */ 9973 "idx": -1 9974 }; 9975 9976 9977 /** 9978 * Template object for the column information object in DataTables. This object 9979 * is held in the settings aoColumns array and contains all the information that 9980 * DataTables needs about each individual column. 9981 * 9982 * Note that this object is related to {@link DataTable.defaults.column} 9983 * but this one is the internal data store for DataTables's cache of columns. 9984 * It should NOT be manipulated outside of DataTables. Any configuration should 9985 * be done through the initialisation options. 9986 * @namespace 9987 */ 9988 DataTable.models.oColumn = { 9989 /** 9990 * Column index. This could be worked out on-the-fly with $.inArray, but it 9991 * is faster to just hold it as a variable 9992 * @type integer 9993 * @default null 9994 */ 9995 "idx": null, 9996 9997 /** 9998 * A list of the columns that sorting should occur on when this column 9999 * is sorted. That this property is an array allows multi-column sorting 10000 * to be defined for a column (for example first name / last name columns 10001 * would benefit from this). The values are integers pointing to the 10002 * columns to be sorted on (typically it will be a single integer pointing 10003 * at itself, but that doesn't need to be the case). 10004 * @type array 10005 */ 10006 "aDataSort": null, 10007 10008 /** 10009 * Define the sorting directions that are applied to the column, in sequence 10010 * as the column is repeatedly sorted upon - i.e. the first value is used 10011 * as the sorting direction when the column if first sorted (clicked on). 10012 * Sort it again (click again) and it will move on to the next index. 10013 * Repeat until loop. 10014 * @type array 10015 */ 10016 "asSorting": null, 10017 10018 /** 10019 * Flag to indicate if the column is searchable, and thus should be included 10020 * in the filtering or not. 10021 * @type boolean 10022 */ 10023 "bSearchable": null, 10024 10025 /** 10026 * Flag to indicate if the column is sortable or not. 10027 * @type boolean 10028 */ 10029 "bSortable": null, 10030 10031 /** 10032 * Flag to indicate if the column is currently visible in the table or not 10033 * @type boolean 10034 */ 10035 "bVisible": null, 10036 10037 /** 10038 * Store for manual type assignment using the `column.type` option. This 10039 * is held in store so we can manipulate the column's `sType` property. 10040 * @type string 10041 * @default null 10042 * @private 10043 */ 10044 "_sManualType": null, 10045 10046 /** 10047 * Flag to indicate if HTML5 data attributes should be used as the data 10048 * source for filtering or sorting. True is either are. 10049 * @type boolean 10050 * @default false 10051 * @private 10052 */ 10053 "_bAttrSrc": false, 10054 10055 /** 10056 * Developer definable function that is called whenever a cell is created (Ajax source, 10057 * etc) or processed for input (DOM source). This can be used as a compliment to mRender 10058 * allowing you to modify the DOM element (add background colour for example) when the 10059 * element is available. 10060 * @type function 10061 * @param {element} nTd The TD node that has been created 10062 * @param {*} sData The Data for the cell 10063 * @param {array|object} oData The data for the whole row 10064 * @param {int} iRow The row index for the aoData data store 10065 * @default null 10066 */ 10067 "fnCreatedCell": null, 10068 10069 /** 10070 * Function to get data from a cell in a column. You should <b>never</b> 10071 * access data directly through _aData internally in DataTables - always use 10072 * the method attached to this property. It allows mData to function as 10073 * required. This function is automatically assigned by the column 10074 * initialisation method 10075 * @type function 10076 * @param {array|object} oData The data array/object for the array 10077 * (i.e. aoData[]._aData) 10078 * @param {string} sSpecific The specific data type you want to get - 10079 * 'display', 'type' 'filter' 'sort' 10080 * @returns {*} The data for the cell from the given row's data 10081 * @default null 10082 */ 10083 "fnGetData": null, 10084 10085 /** 10086 * Function to set data for a cell in the column. You should <b>never</b> 10087 * set the data directly to _aData internally in DataTables - always use 10088 * this method. It allows mData to function as required. This function 10089 * is automatically assigned by the column initialisation method 10090 * @type function 10091 * @param {array|object} oData The data array/object for the array 10092 * (i.e. aoData[]._aData) 10093 * @param {*} sValue Value to set 10094 * @default null 10095 */ 10096 "fnSetData": null, 10097 10098 /** 10099 * Property to read the value for the cells in the column from the data 10100 * source array / object. If null, then the default content is used, if a 10101 * function is given then the return from the function is used. 10102 * @type function|int|string|null 10103 * @default null 10104 */ 10105 "mData": null, 10106 10107 /** 10108 * Partner property to mData which is used (only when defined) to get 10109 * the data - i.e. it is basically the same as mData, but without the 10110 * 'set' option, and also the data fed to it is the result from mData. 10111 * This is the rendering method to match the data method of mData. 10112 * @type function|int|string|null 10113 * @default null 10114 */ 10115 "mRender": null, 10116 10117 /** 10118 * Unique header TH/TD element for this column - this is what the sorting 10119 * listener is attached to (if sorting is enabled.) 10120 * @type node 10121 * @default null 10122 */ 10123 "nTh": null, 10124 10125 /** 10126 * Unique footer TH/TD element for this column (if there is one). Not used 10127 * in DataTables as such, but can be used for plug-ins to reference the 10128 * footer for each column. 10129 * @type node 10130 * @default null 10131 */ 10132 "nTf": null, 10133 10134 /** 10135 * The class to apply to all TD elements in the table's TBODY for the column 10136 * @type string 10137 * @default null 10138 */ 10139 "sClass": null, 10140 10141 /** 10142 * When DataTables calculates the column widths to assign to each column, 10143 * it finds the longest string in each column and then constructs a 10144 * temporary table and reads the widths from that. The problem with this 10145 * is that "mmm" is much wider then "iiii", but the latter is a longer 10146 * string - thus the calculation can go wrong (doing it properly and putting 10147 * it into an DOM object and measuring that is horribly(!) slow). Thus as 10148 * a "work around" we provide this option. It will append its value to the 10149 * text that is found to be the longest string for the column - i.e. padding. 10150 * @type string 10151 */ 10152 "sContentPadding": null, 10153 10154 /** 10155 * Allows a default value to be given for a column's data, and will be used 10156 * whenever a null data source is encountered (this can be because mData 10157 * is set to null, or because the data source itself is null). 10158 * @type string 10159 * @default null 10160 */ 10161 "sDefaultContent": null, 10162 10163 /** 10164 * Name for the column, allowing reference to the column by name as well as 10165 * by index (needs a lookup to work by name). 10166 * @type string 10167 */ 10168 "sName": null, 10169 10170 /** 10171 * Custom sorting data type - defines which of the available plug-ins in 10172 * afnSortData the custom sorting will use - if any is defined. 10173 * @type string 10174 * @default std 10175 */ 10176 "sSortDataType": 'std', 10177 10178 /** 10179 * Class to be applied to the header element when sorting on this column 10180 * @type string 10181 * @default null 10182 */ 10183 "sSortingClass": null, 10184 10185 /** 10186 * Class to be applied to the header element when sorting on this column - 10187 * when jQuery UI theming is used. 10188 * @type string 10189 * @default null 10190 */ 10191 "sSortingClassJUI": null, 10192 10193 /** 10194 * Title of the column - what is seen in the TH element (nTh). 10195 * @type string 10196 */ 10197 "sTitle": null, 10198 10199 /** 10200 * Column sorting and filtering type 10201 * @type string 10202 * @default null 10203 */ 10204 "sType": null, 10205 10206 /** 10207 * Width of the column 10208 * @type string 10209 * @default null 10210 */ 10211 "sWidth": null, 10212 10213 /** 10214 * Width of the column when it was first "encountered" 10215 * @type string 10216 * @default null 10217 */ 10218 "sWidthOrig": null 10219 }; 10220 10221 10222 /* 10223 * Developer note: The properties of the object below are given in Hungarian 10224 * notation, that was used as the interface for DataTables prior to v1.10, however 10225 * from v1.10 onwards the primary interface is camel case. In order to avoid 10226 * breaking backwards compatibility utterly with this change, the Hungarian 10227 * version is still, internally the primary interface, but is is not documented 10228 * - hence the @name tags in each doc comment. This allows a Javascript function 10229 * to create a map from Hungarian notation to camel case (going the other direction 10230 * would require each property to be listed, which would add around 3K to the size 10231 * of DataTables, while this method is about a 0.5K hit). 10232 * 10233 * Ultimately this does pave the way for Hungarian notation to be dropped 10234 * completely, but that is a massive amount of work and will break current 10235 * installs (therefore is on-hold until v2). 10236 */ 10237 10238 /** 10239 * Initialisation options that can be given to DataTables at initialisation 10240 * time. 10241 * @namespace 10242 */ 10243 DataTable.defaults = { 10244 /** 10245 * An array of data to use for the table, passed in at initialisation which 10246 * will be used in preference to any data which is already in the DOM. This is 10247 * particularly useful for constructing tables purely in Javascript, for 10248 * example with a custom Ajax call. 10249 * @type array 10250 * @default null 10251 * 10252 * @dtopt Option 10253 * @name DataTable.defaults.data 10254 * 10255 * @example 10256 * // Using a 2D array data source 10257 * $(document).ready( function () { 10258 * $('#example').dataTable( { 10259 * "data": [ 10260 * ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'], 10261 * ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'], 10262 * ], 10263 * "columns": [ 10264 * { "title": "Engine" }, 10265 * { "title": "Browser" }, 10266 * { "title": "Platform" }, 10267 * { "title": "Version" }, 10268 * { "title": "Grade" } 10269 * ] 10270 * } ); 10271 * } ); 10272 * 10273 * @example 10274 * // Using an array of objects as a data source (`data`) 10275 * $(document).ready( function () { 10276 * $('#example').dataTable( { 10277 * "data": [ 10278 * { 10279 * "engine": "Trident", 10280 * "browser": "Internet Explorer 4.0", 10281 * "platform": "Win 95+", 10282 * "version": 4, 10283 * "grade": "X" 10284 * }, 10285 * { 10286 * "engine": "Trident", 10287 * "browser": "Internet Explorer 5.0", 10288 * "platform": "Win 95+", 10289 * "version": 5, 10290 * "grade": "C" 10291 * } 10292 * ], 10293 * "columns": [ 10294 * { "title": "Engine", "data": "engine" }, 10295 * { "title": "Browser", "data": "browser" }, 10296 * { "title": "Platform", "data": "platform" }, 10297 * { "title": "Version", "data": "version" }, 10298 * { "title": "Grade", "data": "grade" } 10299 * ] 10300 * } ); 10301 * } ); 10302 */ 10303 "aaData": null, 10304 10305 10306 /** 10307 * If ordering is enabled, then DataTables will perform a first pass sort on 10308 * initialisation. You can define which column(s) the sort is performed 10309 * upon, and the sorting direction, with this variable. The `sorting` array 10310 * should contain an array for each column to be sorted initially containing 10311 * the column's index and a direction string ('asc' or 'desc'). 10312 * @type array 10313 * @default [[0,'asc']] 10314 * 10315 * @dtopt Option 10316 * @name DataTable.defaults.order 10317 * 10318 * @example 10319 * // Sort by 3rd column first, and then 4th column 10320 * $(document).ready( function() { 10321 * $('#example').dataTable( { 10322 * "order": [[2,'asc'], [3,'desc']] 10323 * } ); 10324 * } ); 10325 * 10326 * // No initial sorting 10327 * $(document).ready( function() { 10328 * $('#example').dataTable( { 10329 * "order": [] 10330 * } ); 10331 * } ); 10332 */ 10333 "aaSorting": [[0,'asc']], 10334 10335 10336 /** 10337 * This parameter is basically identical to the `sorting` parameter, but 10338 * cannot be overridden by user interaction with the table. What this means 10339 * is that you could have a column (visible or hidden) which the sorting 10340 * will always be forced on first - any sorting after that (from the user) 10341 * will then be performed as required. This can be useful for grouping rows 10342 * together. 10343 * @type array 10344 * @default null 10345 * 10346 * @dtopt Option 10347 * @name DataTable.defaults.orderFixed 10348 * 10349 * @example 10350 * $(document).ready( function() { 10351 * $('#example').dataTable( { 10352 * "orderFixed": [[0,'asc']] 10353 * } ); 10354 * } ) 10355 */ 10356 "aaSortingFixed": [], 10357 10358 10359 /** 10360 * DataTables can be instructed to load data to display in the table from a 10361 * Ajax source. This option defines how that Ajax call is made and where to. 10362 * 10363 * The `ajax` property has three different modes of operation, depending on 10364 * how it is defined. These are: 10365 * 10366 * * `string` - Set the URL from where the data should be loaded from. 10367 * * `object` - Define properties for `jQuery.ajax`. 10368 * * `function` - Custom data get function 10369 * 10370 * `string` 10371 * -------- 10372 * 10373 * As a string, the `ajax` property simply defines the URL from which 10374 * DataTables will load data. 10375 * 10376 * `object` 10377 * -------- 10378 * 10379 * As an object, the parameters in the object are passed to 10380 * [jQuery.ajax](http
10380s
vendor: 54,865 bytes, lines 10380-12088
10380://api.jquery.com/jQuery.ajax/) allowing fine control 10381 * of the Ajax request. DataTables has a number of default parameters which 10382 * you can override using this option. Please refer to the jQuery 10383 * documentation for a full description of the options available, although 10384 * the following parameters provide additional options in DataTables or 10385 * require special consideration: 10386 * 10387 * * `data` - As with jQuery, `data` can be provided as an object, but it 10388 * can also be used as a function to manipulate the data DataTables sends 10389 * to the server. The function takes a single parameter, an object of 10390 * parameters with the values that DataTables has readied for sending. An 10391 * object may be returned which will be merged into the DataTables 10392 * defaults, or you can add the items to the object that was passed in and 10393 * not return anything from the function. This supersedes `fnServerParams` 10394 * from DataTables 1.9-. 10395 * 10396 * * `dataSrc` - By default DataTables will look for the property `data` (or 10397 * `aaData` for compatibility with DataTables 1.9-) when obtaining data 10398 * from an Ajax source or for server-side processing - this parameter 10399 * allows that property to be changed. You can use Javascript dotted 10400 * object notation to get a data source for multiple levels of nesting, or 10401 * it my be used as a function. As a function it takes a single parameter, 10402 * the JSON returned from the server, which can be manipulated as 10403 * required, with the returned value being that used by DataTables as the 10404 * data source for the table. This supersedes `sAjaxDataProp` from 10405 * DataTables 1.9-. 10406 * 10407 * * `success` - Should not be overridden it is used internally in 10408 * DataTables. To manipulate / transform the data returned by the server 10409 * use `ajax.dataSrc`, or use `ajax` as a function (see below). 10410 * 10411 * `function` 10412 * ---------- 10413 * 10414 * As a function, making the Ajax call is left up to yourself allowing 10415 * complete control of the Ajax request. Indeed, if desired, a method other 10416 * than Ajax could be used to obtain the required data, such as Web storage 10417 * or an AIR database. 10418 * 10419 * The function is given four parameters and no return is required. The 10420 * parameters are: 10421 * 10422 * 1. _object_ - Data to send to the server 10423 * 2. _function_ - Callback function that must be executed when the required 10424 * data has been obtained. That data should be passed into the callback 10425 * as the only parameter 10426 * 3. _object_ - DataTables settings object for the table 10427 * 10428 * Note that this supersedes `fnServerData` from DataTables 1.9-. 10429 * 10430 * @type string|object|function 10431 * @default null 10432 * 10433 * @dtopt Option 10434 * @name DataTable.defaults.ajax 10435 * @since 1.10.0 10436 * 10437 * @example 10438 * // Get JSON data from a file via Ajax. 10439 * // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default). 10440 * $('#example').dataTable( { 10441 * "ajax": "data.json" 10442 * } ); 10443 * 10444 * @example 10445 * // Get JSON data from a file via Ajax, using `dataSrc` to change 10446 * // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`) 10447 * $('#example').dataTable( { 10448 * "ajax": { 10449 * "url": "data.json", 10450 * "dataSrc": "tableData" 10451 * } 10452 * } ); 10453 * 10454 * @example 10455 * // Get JSON data from a file via Ajax, using `dataSrc` to read data 10456 * // from a plain array rather than an array in an object 10457 * $('#example').dataTable( { 10458 * "ajax": { 10459 * "url": "data.json", 10460 * "dataSrc": "" 10461 * } 10462 * } ); 10463 * 10464 * @example 10465 * // Manipulate the data returned from the server - add a link to data 10466 * // (note this can, should, be done using `render` for the column - this 10467 * // is just a simple example of how the data can be manipulated). 10468 * $('#example').dataTable( { 10469 * "ajax": { 10470 * "url": "data.json", 10471 * "dataSrc": function ( json ) { 10472 * for ( var i=0, ien=json.length ; i<ien ; i++ ) { 10473 * json[i][0] = '<a href="/message/'+json[i][0]+'>View message</a>'; 10474 * } 10475 * return json; 10476 * } 10477 * } 10478 * } ); 10479 * 10480 * @example 10481 * // Add data to the request 10482 * $('#example').dataTable( { 10483 * "ajax": { 10484 * "url": "data.json", 10485 * "data": function ( d ) { 10486 * return { 10487 * "extra_search": $('#extra').val() 10488 * }; 10489 * } 10490 * } 10491 * } ); 10492 * 10493 * @example 10494 * // Send request as POST 10495 * $('#example').dataTable( { 10496 * "ajax": { 10497 * "url": "data.json", 10498 * "type": "POST" 10499 * } 10500 * } ); 10501 * 10502 * @example 10503 * // Get the data from localStorage (could interface with a form for 10504 * // adding, editing and removing rows). 10505 * $('#example').dataTable( { 10506 * "ajax": function (data, callback, settings) { 10507 * callback( 10508 * JSON.parse( localStorage.getItem('dataTablesData') ) 10509 * ); 10510 * } 10511 * } ); 10512 */ 10513 "ajax": null, 10514 10515 10516 /** 10517 * This parameter allows you to readily specify the entries in the length drop 10518 * down menu that DataTables shows when pagination is enabled. It can be 10519 * either a 1D array of options which will be used for both the displayed 10520 * option and the value, or a 2D array which will use the array in the first 10521 * position as the value, and the array in the second position as the 10522 * displayed options (useful for language strings such as 'All'). 10523 * 10524 * Note that the `pageLength` property will be automatically set to the 10525 * first value given in this array, unless `pageLength` is also provided. 10526 * @type array 10527 * @default [ 10, 25, 50, 100 ] 10528 * 10529 * @dtopt Option 10530 * @name DataTable.defaults.lengthMenu 10531 * 10532 * @example 10533 * $(document).ready( function() { 10534 * $('#example').dataTable( { 10535 * "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]] 10536 * } ); 10537 * } ); 10538 */ 10539 "aLengthMenu": [ 10, 25, 50, 100 ], 10540 10541 10542 /** 10543 * The `columns` option in the initialisation parameter allows you to define 10544 * details about the way individual columns behave. For a full list of 10545 * column options that can be set, please see 10546 * {@link DataTable.defaults.column}. Note that if you use `columns` to 10547 * define your columns, you must have an entry in the array for every single 10548 * column that you have in your table (these can be null if you don't which 10549 * to specify any options). 10550 * @member 10551 * 10552 * @name DataTable.defaults.column 10553 */ 10554 "aoColumns": null, 10555 10556 /** 10557 * Very similar to `columns`, `columnDefs` allows you to target a specific 10558 * column, multiple columns, or all columns, using the `targets` property of 10559 * each object in the array. This allows great flexibility when creating 10560 * tables, as the `columnDefs` arrays can be of any length, targeting the 10561 * columns you specifically want. `columnDefs` may use any of the column 10562 * options available: {@link DataTable.defaults.column}, but it _must_ 10563 * have `targets` defined in each object in the array. Values in the `targets` 10564 * array may be: 10565 * <ul> 10566 * <li>a string - class name will be matched on the TH for the column</li> 10567 * <li>0 or a positive integer - column index counting from the left</li> 10568 * <li>a negative integer - column index counting from the right</li> 10569 * <li>the string "_all" - all columns (i.e. assign a default)</li> 10570 * </ul> 10571 * @member 10572 * 10573 * @name DataTable.defaults.columnDefs 10574 */ 10575 "aoColumnDefs": null, 10576 10577 10578 /** 10579 * Basically the same as `search`, this parameter defines the individual column 10580 * filtering state at initialisation time. The array must be of the same size 10581 * as the number of columns, and each element be an object with the parameters 10582 * `search` and `escapeRegex` (the latter is optional). 'null' is also 10583 * accepted and the default will be used. 10584 * @type array 10585 * @default [] 10586 * 10587 * @dtopt Option 10588 * @name DataTable.defaults.searchCols 10589 * 10590 * @example 10591 * $(document).ready( function() { 10592 * $('#example').dataTable( { 10593 * "searchCols": [ 10594 * null, 10595 * { "search": "My filter" }, 10596 * null, 10597 * { "search": "^[0-9]", "escapeRegex": false } 10598 * ] 10599 * } ); 10600 * } ) 10601 */ 10602 "aoSearchCols": [], 10603 10604 10605 /** 10606 * An array of CSS classes that should be applied to displayed rows. This 10607 * array may be of any length, and DataTables will apply each class 10608 * sequentially, looping when required. 10609 * @type array 10610 * @default null <i>Will take the values determined by the `oClasses.stripe*` 10611 * options</i> 10612 * 10613 * @dtopt Option 10614 * @name DataTable.defaults.stripeClasses 10615 * 10616 * @example 10617 * $(document).ready( function() { 10618 * $('#example').dataTable( { 10619 * "stripeClasses": [ 'strip1', 'strip2', 'strip3' ] 10620 * } ); 10621 * } ) 10622 */ 10623 "asStripeClasses": null, 10624 10625 10626 /** 10627 * Enable or disable automatic column width calculation. This can be disabled 10628 * as an optimisation (it takes some time to calculate the widths) if the 10629 * tables widths are passed in using `columns`. 10630 * @type boolean 10631 * @default true 10632 * 10633 * @dtopt Features 10634 * @name DataTable.defaults.autoWidth 10635 * 10636 * @example 10637 * $(document).ready( function () { 10638 * $('#example').dataTable( { 10639 * "autoWidth": false 10640 * } ); 10641 * } ); 10642 */ 10643 "bAutoWidth": true, 10644 10645 10646 /** 10647 * Deferred rendering can provide DataTables with a huge speed boost when you 10648 * are using an Ajax or JS data source for the table. This option, when set to 10649 * true, will cause DataTables to defer the creation of the table elements for 10650 * each row until they are needed for a draw - saving a significant amount of 10651 * time. 10652 * @type boolean 10653 * @default false 10654 * 10655 * @dtopt Features 10656 * @name DataTable.defaults.deferRender 10657 * 10658 * @example 10659 * $(document).ready( function() { 10660 * $('#example').dataTable( { 10661 * "ajax": "sources/arrays.txt", 10662 * "deferRender": true 10663 * } ); 10664 * } ); 10665 */ 10666 "bDeferRender": false, 10667 10668 10669 /** 10670 * Replace a DataTable which matches the given selector and replace it with 10671 * one which has the properties of the new initialisation object passed. If no 10672 * table matches the selector, then the new DataTable will be constructed as 10673 * per normal. 10674 * @type boolean 10675 * @default false 10676 * 10677 * @dtopt Options 10678 * @name DataTable.defaults.destroy 10679 * 10680 * @example 10681 * $(document).ready( function() { 10682 * $('#example').dataTable( { 10683 * "srollY": "200px", 10684 * "paginate": false 10685 * } ); 10686 * 10687 * // Some time later.... 10688 * $('#example').dataTable( { 10689 * "filter": false, 10690 * "destroy": true 10691 * } ); 10692 * } ); 10693 */ 10694 "bDestroy": false, 10695 10696 10697 /** 10698 * Enable or disable filtering of data. Filtering in DataTables is "smart" in 10699 * that it allows the end user to input multiple words (space separated) and 10700 * will match a row containing those words, even if not in the order that was 10701 * specified (this allow matching across multiple columns). Note that if you 10702 * wish to use filtering in DataTables this must remain 'true' - to remove the 10703 * default filtering input box and retain filtering abilities, please use 10704 * {@link DataTable.defaults.dom}. 10705 * @type boolean 10706 * @default true 10707 * 10708 * @dtopt Features 10709 * @name DataTable.defaults.searching 10710 * 10711 * @example 10712 * $(document).ready( function () { 10713 * $('#example').dataTable( { 10714 * "searching": false 10715 * } ); 10716 * } ); 10717 */ 10718 "bFilter": true, 10719 10720 10721 /** 10722 * Enable or disable the table information display. This shows information 10723 * about the data that is currently visible on the page, including information 10724 * about filtered data if that action is being performed. 10725 * @type boolean 10726 * @default true 10727 * 10728 * @dtopt Features 10729 * @name DataTable.defaults.info 10730 * 10731 * @example 10732 * $(document).ready( function () { 10733 * $('#example').dataTable( { 10734 * "info": false 10735 * } ); 10736 * } ); 10737 */ 10738 "bInfo": true, 10739 10740 10741 /** 10742 * Allows the end user to select the size of a formatted page from a select 10743 * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`). 10744 * @type boolean 10745 * @default true 10746 * 10747 * @dtopt Features 10748 * @name DataTable.defaults.lengthChange 10749 * 10750 * @example 10751 * $(document).ready( function () { 10752 * $('#example').dataTable( { 10753 * "lengthChange": false 10754 * } ); 10755 * } ); 10756 */ 10757 "bLengthChange": true, 10758 10759 10760 /** 10761 * Enable or disable pagination. 10762 * @type boolean 10763 * @default true 10764 * 10765 * @dtopt Features 10766 * @name DataTable.defaults.paging 10767 * 10768 * @example 10769 * $(document).ready( function () { 10770 * $('#example').dataTable( { 10771 * "paging": false 10772 * } ); 10773 * } ); 10774 */ 10775 "bPaginate": true, 10776 10777 10778 /** 10779 * Enable or disable the display of a 'processing' indicator when the table is 10780 * being processed (e.g. a sort). This is particularly useful for tables with 10781 * large amounts of data where it can take a noticeable amount of time to sort 10782 * the entries. 10783 * @type boolean 10784 * @default false 10785 * 10786 * @dtopt Features 10787 * @name DataTable.defaults.processing 10788 * 10789 * @example 10790 * $(document).ready( function () { 10791 * $('#example').dataTable( { 10792 * "processing": true 10793 * } ); 10794 * } ); 10795 */ 10796 "bProcessing": false, 10797 10798 10799 /** 10800 * Retrieve the DataTables object for the given selector. Note that if the 10801 * table has already been initialised, this parameter will cause DataTables 10802 * to simply return the object that has already been set up - it will not take 10803 * account of any changes you might have made to the initialisation object 10804 * passed to DataTables (setting this parameter to true is an acknowledgement 10805 * that you understand this). `destroy` can be used to reinitialise a table if 10806 * you need. 10807 * @type boolean 10808 * @default false 10809 * 10810 * @dtopt Options 10811 * @name DataTable.defaults.retrieve 10812 * 10813 * @example 10814 * $(document).ready( function() { 10815 * initTable(); 10816 * tableActions(); 10817 * } ); 10818 * 10819 * function initTable () 10820 * { 10821 * return $('#example').dataTable( { 10822 * "scrollY": "200px", 10823 * "paginate": false, 10824 * "retrieve": true 10825 * } ); 10826 * } 10827 * 10828 * function tableActions () 10829 * { 10830 * var table = initTable(); 10831 * // perform API operations with oTable 10832 * } 10833 */ 10834 "bRetrieve": false, 10835 10836 10837 /** 10838 * When vertical (y) scrolling is enabled, DataTables will force the height of 10839 * the table's viewport to the given height at all times (useful for layout). 10840 * However, this can look odd when filtering data down to a small data set, 10841 * and the footer is left "floating" further down. This parameter (when 10842 * enabled) will cause DataTables to collapse the table's viewport down when 10843 * the result set will fit within the given Y height. 10844 * @type boolean 10845 * @default false 10846 * 10847 * @dtopt Options 10848 * @name DataTable.defaults.scrollCollapse 10849 * 10850 * @example 10851 * $(document).ready( function() { 10852 * $('#example').dataTable( { 10853 * "scrollY": "200", 10854 * "scrollCollapse": true 10855 * } ); 10856 * } ); 10857 */ 10858 "bScrollCollapse": false, 10859 10860 10861 /** 10862 * Configure DataTables to use server-side processing. Note that the 10863 * `ajax` parameter must also be given in order to give DataTables a 10864 * source to obtain the required data for each draw. 10865 * @type boolean 10866 * @default false 10867 * 10868 * @dtopt Features 10869 * @dtopt Server-side 10870 * @name DataTable.defaults.serverSide 10871 * 10872 * @example 10873 * $(document).ready( function () { 10874 * $('#example').dataTable( { 10875 * "serverSide": true, 10876 * "ajax": "xhr.php" 10877 * } ); 10878 * } ); 10879 */ 10880 "bServerSide": false, 10881 10882 10883 /** 10884 * Enable or disable sorting of columns. Sorting of individual columns can be 10885 * disabled by the `sortable` option for each column. 10886 * @type boolean 10887 * @default true 10888 * 10889 * @dtopt Features 10890 * @name DataTable.defaults.ordering 10891 * 10892 * @example 10893 * $(document).ready( function () { 10894 * $('#example').dataTable( { 10895 * "ordering": false 10896 * } ); 10897 * } ); 10898 */ 10899 "bSort": true, 10900 10901 10902 /** 10903 * Enable or display DataTables' ability to sort multiple columns at the 10904 * same time (activated by shift-click by the user). 10905 * @type boolean 10906 * @default true 10907 * 10908 * @dtopt Options 10909 * @name DataTable.defaults.orderMulti 10910 * 10911 * @example 10912 * // Disable multiple column sorting ability 10913 * $(document).ready( function () { 10914 * $('#example').dataTable( { 10915 * "orderMulti": false 10916 * } ); 10917 * } ); 10918 */ 10919 "bSortMulti": true, 10920 10921 10922 /** 10923 * Allows control over whether DataTables should use the top (true) unique 10924 * cell that is found for a single column, or the bottom (false - default). 10925 * This is useful when using complex headers. 10926 * @type boolean 10927 * @default false 10928 * 10929 * @dtopt Options 10930 * @name DataTable.defaults.orderCellsTop 10931 * 10932 * @example 10933 * $(document).ready( function() { 10934 * $('#example').dataTable( { 10935 * "orderCellsTop": true 10936 * } ); 10937 * } ); 10938 */ 10939 "bSortCellsTop": false, 10940 10941 10942 /** 10943 * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and 10944 * `sorting\_3` to the columns which are currently being sorted on. This is 10945 * presented as a feature switch as it can increase processing time (while 10946 * classes are removed and added) so for large data sets you might want to 10947 * turn this off. 10948 * @type boolean 10949 * @default true 10950 * 10951 * @dtopt Features 10952 * @name DataTable.defaults.orderClasses 10953 * 10954 * @example 10955 * $(document).ready( function () { 10956 * $('#example').dataTable( { 10957 * "orderClasses": false 10958 * } ); 10959 * } ); 10960 */ 10961 "bSortClasses": true, 10962 10963 10964 /** 10965 * Enable or disable state saving. When enabled HTML5 `localStorage` will be 10966 * used to save table display information such as pagination information, 10967 * display length, filtering and sorting. As such when the end user reloads 10968 * the page the display display will match what thy had previously set up. 10969 * 10970 * Due to the use of `localStorage` the default state saving is not supported 10971 * in IE6 or 7. If state saving is required in those browsers, use 10972 * `stateSaveCallback` to provide a storage solution such as cookies. 10973 * @type boolean 10974 * @default false 10975 * 10976 * @dtopt Features 10977 * @name DataTable.defaults.stateSave 10978 * 10979 * @example 10980 * $(document).ready( function () { 10981 * $('#example').dataTable( { 10982 * "stateSave": true 10983 * } ); 10984 * } ); 10985 */ 10986 "bStateSave": false, 10987 10988 10989 /** 10990 * This function is called when a TR element is created (and all TD child 10991 * elements have been inserted), or registered if using a DOM source, allowing 10992 * manipulation of the TR element (adding classes etc). 10993 * @type function 10994 * @param {node} row "TR" element for the current row 10995 * @param {array} data Raw data array for this row 10996 * @param {int} dataIndex The index of this row in the internal aoData array 10997 * 10998 * @dtopt Callbacks 10999 * @name DataTable.defaults.createdRow 11000 * 11001 * @example 11002 * $(document).ready( function() { 11003 * $('#example').dataTable( { 11004 * "createdRow": function( row, data, dataIndex ) { 11005 * // Bold the grade for all 'A' grade browsers 11006 * if ( data[4] == "A" ) 11007 * { 11008 * $('td:eq(4)', row).html( '<b>A</b>' ); 11009 * } 11010 * } 11011 * } ); 11012 * } ); 11013 */ 11014 "fnCreatedRow": null, 11015 11016 11017 /** 11018 * This function is called on every 'draw' event, and allows you to 11019 * dynamically modify any aspect you want about the created DOM. 11020 * @type function 11021 * @param {object} settings DataTables settings object 11022 * 11023 * @dtopt Callbacks 11024 * @name DataTable.defaults.drawCallback 11025 * 11026 * @example 11027 * $(document).ready( function() { 11028 * $('#example').dataTable( { 11029 * "drawCallback": function( settings ) { 11030 * alert( 'DataTables has redrawn the table' ); 11031 * } 11032 * } ); 11033 * } ); 11034 */ 11035 "fnDrawCallback": null, 11036 11037 11038 /** 11039 * Identical to fnHeaderCallback() but for the table footer this function 11040 * allows you to modify the table footer on every 'draw' event. 11041 * @type function 11042 * @param {node} foot "TR" element for the footer 11043 * @param {array} data Full table data (as derived from the original HTML) 11044 * @param {int} start Index for the current display starting point in the 11045 * display array 11046 * @param {int} end Index for the current display ending point in the 11047 * display array 11048 * @param {array int} display Index array to translate the visual position 11049 * to the full data array 11050 * 11051 * @dtopt Callbacks 11052 * @name DataTable.defaults.footerCallback 11053 * 11054 * @example 11055 * $(document).ready( function() { 11056 * $('#example').dataTable( { 11057 * "footerCallback": function( tfoot, data, start, end, display ) { 11058 * tfoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+start; 11059 * } 11060 * } ); 11061 * } ) 11062 */ 11063 "fnFooterCallback": null, 11064 11065 11066 /** 11067 * When rendering large numbers in the information element for the table 11068 * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers 11069 * to have a comma separator for the 'thousands' units (e.g. 1 million is 11070 * rendered as "1,000,000") to help readability for the end user. This 11071 * function will override the default method DataTables uses. 11072 * @type function 11073 * @member 11074 * @param {int} toFormat number to be formatted 11075 * @returns {string} formatted string for DataTables to show the number 11076 * 11077 * @dtopt Callbacks 11078 * @name DataTable.defaults.formatNumber 11079 * 11080 * @example 11081 * // Format a number using a single quote for the separator (note that 11082 * // this can also be done with the language.thousands option) 11083 * $(document).ready( function() { 11084 * $('#example').dataTable( { 11085 * "formatNumber": function ( toFormat ) { 11086 * return toFormat.toString().replace( 11087 * /\B(?=(\d{3})+(?!\d))/g, "'" 11088 * ); 11089 * }; 11090 * } ); 11091 * } ); 11092 */ 11093 "fnFormatNumber": function ( toFormat ) { 11094 return toFormat.toString().replace( 11095 /\B(?=(\d{3})+(?!\d))/g, 11096 this.oLanguage.sThousands 11097 ); 11098 }, 11099 11100 11101 /** 11102 * This function is called on every 'draw' event, and allows you to 11103 * dynamically modify the header row. This can be used to calculate and 11104 * display useful information about the table. 11105 * @type function 11106 * @param {node} head "TR" element for the header 11107 * @param {array} data Full table data (as derived from the original HTML) 11108 * @param {int} start Index for the current display starting point in the 11109 * display array 11110 * @param {int} end Index for the current display ending point in the 11111 * display array 11112 * @param {array int} display Index array to translate the visual position 11113 * to the full data array 11114 * 11115 * @dtopt Callbacks 11116 * @name DataTable.defaults.headerCallback 11117 * 11118 * @example 11119 * $(document).ready( function() { 11120 * $('#example').dataTable( { 11121 * "fheaderCallback": function( head, data, start, end, display ) { 11122 * head.getElementsByTagName('th')[0].innerHTML = "Displaying "+(end-start)+" records"; 11123 * } 11124 * } ); 11125 * } ) 11126 */ 11127 "fnHeaderCallback": null, 11128 11129 11130 /** 11131 * The information element can be used to convey information about the current 11132 * state of the table. Although the internationalisation options presented by 11133 * DataTables are quite capable of dealing with most customisations, there may 11134 * be times where you wish to customise the string further. This callback 11135 * allows you to do exactly that. 11136 * @type function 11137 * @param {object} oSettings DataTables settings object 11138 * @param {int} start Starting position in data for the draw 11139 * @param {int} end End position in data for the draw 11140 * @param {int} max Total number of rows in the table (regardless of 11141 * filtering) 11142 * @param {int} total Total number of rows in the data set, after filtering 11143 * @param {string} pre The string that DataTables has formatted using it's 11144 * own rules 11145 * @returns {string} The string to be displayed in the information element. 11146 * 11147 * @dtopt Callbacks 11148 * @name DataTable.defaults.infoCallback 11149 * 11150 * @example 11151 * $('#example').dataTable( { 11152 * "infoCallback": function( settings, start, end, max, total, pre ) { 11153 * return start +" to "+ end; 11154 * } 11155 * } ); 11156 */ 11157 "fnInfoCallback": null, 11158 11159 11160 /** 11161 * Called when the table has been initialised. Normally DataTables will 11162 * initialise sequentially and there will be no need for this function, 11163 * however, this does not hold true when using external language information 11164 * since that is obtained using an async XHR call. 11165 * @type function 11166 * @param {object} settings DataTables settings object 11167 * @param {object} json The JSON object request from the server - only 11168 * present if client-side Ajax sourced data is used 11169 * 11170 * @dtopt Callbacks 11171 * @name DataTable.defaults.initComplete 11172 * 11173 * @example 11174 * $(document).ready( function() { 11175 * $('#example').dataTable( { 11176 * "initComplete": function(settings, json) { 11177 * alert( 'DataTables has finished its initialisation.' ); 11178 * } 11179 * } ); 11180 * } ) 11181 */ 11182 "fnInitComplete": null, 11183 11184 11185 /** 11186 * Called at the very start of each table draw and can be used to cancel the 11187 * draw by returning false, any other return (including undefined) results in 11188 * the full draw occurring). 11189 * @type function 11190 * @param {object} settings DataTables settings object 11191 * @returns {boolean} False will cancel the draw, anything else (including no 11192 * return) will allow it to complete. 11193 * 11194 * @dtopt Callbacks 11195 * @name DataTable.defaults.preDrawCallback 11196 * 11197 * @example 11198 * $(document).ready( function() { 11199 * $('#example').dataTable( { 11200 * "preDrawCallback": function( settings ) { 11201 * if ( $('#test').val() == 1 ) { 11202 * return false; 11203 * } 11204 * } 11205 * } ); 11206 * } ); 11207 */ 11208 "fnPreDrawCallback": null, 11209 11210 11211 /** 11212 * This function allows you to 'post process' each row after it have been 11213 * generated for each table draw, but before it is rendered on screen. This 11214 * function might be used for setting the row class name etc. 11215 * @type function 11216 * @param {node} row "TR" element for the current row 11217 * @param {array} data Raw data array for this row 11218 * @param {int} displayIndex The display index for the current table draw 11219 * @param {int} displayIndexFull The index of the data in the full list of 11220 * rows (after filtering) 11221 * 11222 * @dtopt Callbacks 11223 * @name DataTable.defaults.rowCallback 11224 * 11225 * @example 11226 * $(document).ready( function() { 11227 * $('#example').dataTable( { 11228 * "rowCallback": function( row, data, displayIndex, displayIndexFull ) { 11229 * // Bold the grade for all 'A' grade browsers 11230 * if ( data[4] == "A" ) { 11231 * $('td:eq(4)', row).html( '<b>A</b>' ); 11232 * } 11233 * } 11234 * } ); 11235 * } ); 11236 */ 11237 "fnRowCallback": null, 11238 11239 11240 /** 11241 * __Deprecated__ The functionality provided by this parameter has now been 11242 * superseded by that provided through `ajax`, which should be used instead. 11243 * 11244 * This parameter allows you to override the default function which obtains 11245 * the data from the server so something more suitable for your application. 11246 * For example you could use POST data, or pull information from a Gears or 11247 * AIR database. 11248 * @type function 11249 * @member 11250 * @param {string} source HTTP source to obtain the data from (`ajax`) 11251 * @param {array} data A key/value pair object containing the data to send 11252 * to the server 11253 * @param {function} callback to be called on completion of the data get 11254 * process that will draw the data on the page. 11255 * @param {object} settings DataTables settings object 11256 * 11257 * @dtopt Callbacks 11258 * @dtopt Server-side 11259 * @name DataTable.defaults.serverData 11260 * 11261 * @deprecated 1.10. Please use `ajax` for this functionality now. 11262 */ 11263 "fnServerData": null, 11264 11265 11266 /** 11267 * __Deprecated__ The functionality provided by this parameter has now been 11268 * superseded by that provided through `ajax`, which should be used instead. 11269 * 11270 * It is often useful to send extra data to the server when making an Ajax 11271 * request - for example custom filtering information, and this callback 11272 * function makes it trivial to send extra information to the server. The 11273 * passed in parameter is the data set that has been constructed by 11274 * DataTables, and you can add to this or modify it as you require. 11275 * @type function 11276 * @param {array} data Data array (array of objects which are name/value 11277 * pairs) that has been constructed by DataTables and will be sent to the 11278 * server. In the case of Ajax sourced data with server-side processing 11279 * this will be an empty array, for server-side processing there will be a 11280 * significant number of parameters! 11281 * @returns {undefined} Ensure that you modify the data array passed in, 11282 * as this is passed by reference. 11283 * 11284 * @dtopt Callbacks 11285 * @dtopt Server-side 11286 * @name DataTable.defaults.serverParams 11287 * 11288 * @deprecated 1.10. Please use `ajax` for this functionality now. 11289 */ 11290 "fnServerParams": null, 11291 11292 11293 /** 11294 * Load the table state. With this function you can define from where, and how, the 11295 * state of a table is loaded. By default DataTables will load from `localStorage` 11296 * but you might wish to use a server-side database or cookies. 11297 * @type function 11298 * @member 11299 * @param {object} settings DataTables settings object 11300 * @param {object} callback Callback that can be executed when done. It 11301 * should be passed the loaded state object. 11302 * @return {object} The DataTables state object to be loaded 11303 * 11304 * @dtopt Callbacks 11305 * @name DataTable.defaults.stateLoadCallback 11306 * 11307 * @example 11308 * $(document).ready( function() { 11309 * $('#example').dataTable( { 11310 * "stateSave": true, 11311 * "stateLoadCallback": function (settings, callback) { 11312 * $.ajax( { 11313 * "url": "/state_load", 11314 * "dataType": "json", 11315 * "success": function (json) { 11316 * callback( json ); 11317 * } 11318 * } ); 11319 * } 11320 * } ); 11321 * } ); 11322 */ 11323 "fnStateLoadCallback": function ( settings ) { 11324 try { 11325 return JSON.parse( 11326 (settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem( 11327 'DataTables_'+settings.sInstance+'_'+location.pathname 11328 ) 11329 ); 11330 } catch (e) { 11331 return {}; 11332 } 11333 }, 11334 11335 11336 /** 11337 * Callback which allows modification of the saved state prior to loading that state. 11338 * This callback is called when the table is loading state from the stored data, but 11339 * prior to the settings object being modified by the saved state. Note that for 11340 * plug-in authors, you should use the `stateLoadParams` event to load parameters for 11341 * a plug-in. 11342 * @type function 11343 * @param {object} settings DataTables settings object 11344 * @param {object} data The state object that is to be loaded 11345 * 11346 * @dtopt Callbacks 11347 * @name DataTable.defaults.stateLoadParams 11348 * 11349 * @example 11350 * // Remove a saved filter, so filtering is never loaded 11351 * $(document).ready( function() { 11352 * $('#example').dataTable( { 11353 * "stateSave": true, 11354 * "stateLoadParams": function (settings, data) { 11355 * data.oSearch.sSearch = ""; 11356 * } 11357 * } ); 11358 * } ); 11359 * 11360 * @example 11361 * // Disallow state loading by returning false 11362 * $(document).ready( function() { 11363 * $('#example').dataTable( { 11364 * "stateSave": true, 11365 * "stateLoadParams": function (settings, data) { 11366 * return false; 11367 * } 11368 * } ); 11369 * } ); 11370 */ 11371 "fnStateLoadParams": null, 11372 11373 11374 /** 11375 * Callback that is called when the state has been loaded from the state saving method 11376 * and the DataTables settings object has been modified as a result of the loaded state. 11377 * @type function 11378 * @param {object} settings DataTables settings object 11379 * @param {object} data The state object that was loaded 11380 * 11381 * @dtopt Callbacks 11382 * @name DataTable.defaults.stateLoaded 11383 * 11384 * @example 11385 * // Show an alert with the filtering value that was saved 11386 * $(document).ready( function() { 11387 * $('#example').dataTable( { 11388 * "stateSave": true, 11389 * "stateLoaded": function (settings, data) { 11390 * alert( 'Saved filter was: '+data.oSearch.sSearch ); 11391 * } 11392 * } ); 11393 * } ); 11394 */ 11395 "fnStateLoaded": null, 11396 11397 11398 /** 11399 * Save the table state. This function allows you to define where and how the state 11400 * information for the table is stored By default DataTables will use `localStorage` 11401 * but you might wish to use a server-side database or cookies. 11402 * @type function 11403 * @member 11404 * @param {object} settings DataTables settings object 11405 * @param {object} data The state object to be saved 11406 * 11407 * @dtopt Callbacks 11408 * @name DataTable.defaults.stateSaveCallback 11409 * 11410 * @example 11411 * $(document).ready( function() { 11412 * $('#example').dataTable( { 11413 * "stateSave": true, 11414 * "stateSaveCallback": function (settings, data) { 11415 * // Send an Ajax request to the server with the state object 11416 * $.ajax( { 11417 * "url": "/state_save", 11418 * "data": data, 11419 * "dataType": "json", 11420 * "method": "POST" 11421 * "success": function () {} 11422 * } ); 11423 * } 11424 * } ); 11425 * } ); 11426 */ 11427 "fnStateSaveCallback": function ( settings, data ) { 11428 try { 11429 (settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem( 11430 'DataTables_'+settings.sInstance+'_'+location.pathname, 11431 JSON.stringify( data ) 11432 ); 11433 } catch (e) {} 11434 }, 11435 11436 11437 /** 11438 * Callback which allows modification of the state to be saved. Called when the table 11439 * has changed state a new state save is required. This method allows modification of 11440 * the state saving object prior to actually doing the save, including addition or 11441 * other state properties or modification. Note that for plug-in authors, you should 11442 * use the `stateSaveParams` event to save parameters for a plug-in. 11443 * @type function 11444 * @param {object} settings DataTables settings object 11445 * @param {object} data The state object to be saved 11446 * 11447 * @dtopt Callbacks 11448 * @name DataTable.defaults.stateSaveParams 11449 * 11450 * @example 11451 * // Remove a saved filter, so filtering is never saved 11452 * $(document).ready( function() { 11453 * $('#example').dataTable( { 11454 * "stateSave": true, 11455 * "stateSaveParams": function (settings, data) { 11456 * data.oSearch.sSearch = ""; 11457 * } 11458 * } ); 11459 * } ); 11460 */ 11461 "fnStateSaveParams": null, 11462 11463 11464 /** 11465 * Duration for which the saved state information is considered valid. After this period 11466 * has elapsed the state will be returned to the default. 11467 * Value is given in seconds. 11468 * @type int 11469 * @default 7200 <i>(2 hours)</i> 11470 * 11471 * @dtopt Options 11472 * @name DataTable.defaults.stateDuration 11473 * 11474 * @example 11475 * $(document).ready( function() { 11476 * $('#example').dataTable( { 11477 * "stateDuration": 60*60*24; // 1 day 11478 * } ); 11479 * } ) 11480 */ 11481 "iStateDuration": 7200, 11482 11483 11484 /** 11485 * When enabled DataTables will not make a request to the server for the first 11486 * page draw - rather it will use the data already on the page (no sorting etc 11487 * will be applied to it), thus saving on an XHR at load time. `deferLoading` 11488 * is used to indicate that deferred loading is required, but it is also used 11489 * to tell DataTables how many records there are in the full table (allowing 11490 * the information element and pagination to be displayed correctly). In the case 11491 * where a filtering is applied to the table on initial load, this can be 11492 * indicated by giving the parameter as an array, where the first element is 11493 * the number of records available after filtering and the second element is the 11494 * number of records without filtering (allowing the table information element 11495 * to be shown correctly). 11496 * @type int | array 11497 * @default null 11498 * 11499 * @dtopt Options 11500 * @name DataTable.defaults.deferLoading 11501 * 11502 * @example 11503 * // 57 records available in the table, no filtering applied 11504 * $(document).ready( function() { 11505 * $('#example').dataTable( { 11506 * "serverSide": true, 11507 * "ajax": "scripts/server_processing.php", 11508 * "deferLoading": 57 11509 * } ); 11510 * } ); 11511 * 11512 * @example 11513 * // 57 records after filtering, 100 without filtering (an initial filter applied) 11514 * $(document).ready( function() { 11515 * $('#example').dataTable( { 11516 * "serverSide": true, 11517 * "ajax": "scripts/server_processing.php", 11518 * "deferLoading": [ 57, 100 ], 11519 * "search": { 11520 * "search": "my_filter" 11521 * } 11522 * } ); 11523 * } ); 11524 */ 11525 "iDeferLoading": null, 11526 11527 11528 /** 11529 * Number of rows to display on a single page when using pagination. If 11530 * feature enabled (`lengthChange`) then the end user will be able to override 11531 * this to a custom setting using a pop-up menu. 11532 * @type int 11533 * @default 10 11534 * 11535 * @dtopt Options 11536 * @name DataTable.defaults.pageLength 11537 * 11538 * @example 11539 * $(document).ready( function() { 11540 * $('#example').dataTable( { 11541 * "pageLength": 50 11542 * } ); 11543 * } ) 11544 */ 11545 "iDisplayLength": 10, 11546 11547 11548 /** 11549 * Define the starting point for data display when using DataTables with 11550 * pagination. Note that this parameter is the number of records, rather than 11551 * the page number, so if you have 10 records per page and want to start on 11552 * the third page, it should be "20". 11553 * @type int 11554 * @default 0 11555 * 11556 * @dtopt Options 11557 * @name DataTable.defaults.displayStart 11558 * 11559 * @example 11560 * $(document).ready( function() { 11561 * $('#example').dataTable( { 11562 * "displayStart": 20 11563 * } ); 11564 * } ) 11565 */ 11566 "iDisplayStart": 0, 11567 11568 11569 /** 11570 * By default DataTables allows keyboard navigation of the table (sorting, paging, 11571 * and filtering) by adding a `tabindex` attribute to the required elements. This 11572 * allows you to tab through the controls and press the enter key to activate them. 11573 * The tabindex is default 0, meaning that the tab follows the flow of the document. 11574 * You can overrule this using this parameter if you wish. Use a value of -1 to 11575 * disable built-in keyboard navigation. 11576 * @type int 11577 * @default 0 11578 * 11579 * @dtopt Options 11580 * @name DataTable.defaults.tabIndex 11581 * 11582 * @example 11583 * $(document).ready( function() { 11584 * $('#example').dataTable( { 11585 * "tabIndex": 1 11586 * } ); 11587 * } ); 11588 */ 11589 "iTabIndex": 0, 11590 11591 11592 /** 11593 * Classes that DataTables assigns to the various components and features 11594 * that it adds to the HTML table. This allows classes to be configured 11595 * during initialisation in addition to through the static 11596 * {@link DataTable.ext.oStdClasses} object). 11597 * @namespace 11598 * @name DataTable.defaults.classes 11599 */ 11600 "oClasses": {}, 11601 11602 11603 /** 11604 * All strings that DataTables uses in the user interface that it creates 11605 * are defined in this object, allowing you to modified them individually or 11606 * completely replace them all as required. 11607 * @namespace 11608 * @name DataTable.defaults.language 11609 */ 11610 "oLanguage": { 11611 /** 11612 * Strings that are used for WAI-ARIA labels and controls only (these are not 11613 * actually visible on the page, but will be read by screenreaders, and thus 11614 * must be internationalised as well). 11615 * @namespace 11616 * @name DataTable.defaults.language.aria 11617 */ 11618 "oAria": { 11619 /** 11620 * ARIA label that is added to the table headers when the column may be 11621 * sorted ascending by activing the column (click or return when focused). 11622 * Note that the column header is prefixed to this string. 11623 * @type string 11624 * @default : activate to sort column ascending 11625 * 11626 * @dtopt Language 11627 * @name DataTable.defaults.language.aria.sortAscending 11628 * 11629 * @example 11630 * $(document).ready( function() { 11631 * $('#example').dataTable( { 11632 * "language": { 11633 * "aria": { 11634 * "sortAscending": " - click/return to sort ascending" 11635 * } 11636 * } 11637 * } ); 11638 * } ); 11639 */ 11640 "sSortAscending": ": activate to sort column ascending", 11641 11642 /** 11643 * ARIA label that is added to the table headers when the column may be 11644 * sorted descending by activing the column (click or return when focused). 11645 * Note that the column header is prefixed to this string. 11646 * @type string 11647 * @default : activate to sort column ascending 11648 * 11649 * @dtopt Language 11650 * @name DataTable.defaults.language.aria.sortDescending 11651 * 11652 * @example 11653 * $(document).ready( function() { 11654 * $('#example').dataTable( { 11655 * "language": { 11656 * "aria": { 11657 * "sortDescending": " - click/return to sort descending" 11658 * } 11659 * } 11660 * } ); 11661 * } ); 11662 */ 11663 "sSortDescending": ": activate to sort column descending" 11664 }, 11665 11666 /** 11667 * Pagination string used by DataTables for the built-in pagination 11668 * control types. 11669 * @namespace 11670 * @name DataTable.defaults.language.paginate 11671 */ 11672 "oPaginate": { 11673 /** 11674 * Text to use when using the 'full_numbers' type of pagination for the 11675 * button to take the user to the first page. 11676 * @type string 11677 * @default First 11678 * 11679 * @dtopt Language 11680 * @name DataTable.defaults.language.paginate.first 11681 * 11682 * @example 11683 * $(document).ready( function() { 11684 * $('#example').dataTable( { 11685 * "language": { 11686 * "paginate": { 11687 * "first": "First page" 11688 * } 11689 * } 11690 * } ); 11691 * } ); 11692 */ 11693 "sFirst": "First", 11694 11695 11696 /** 11697 * Text to use when using the 'full_numbers' type of pagination for the 11698 * button to take the user to the last page. 11699 * @type string 11700 * @default Last 11701 * 11702 * @dtopt Language 11703 * @name DataTable.defaults.language.paginate.last 11704 * 11705 * @example 11706 * $(document).ready( function() { 11707 * $('#example').dataTable( { 11708 * "language": { 11709 * "paginate": { 11710 * "last": "Last page" 11711 * } 11712 * } 11713 * } ); 11714 * } ); 11715 */ 11716 "sLast": "Last", 11717 11718 11719 /** 11720 * Text to use for the 'next' pagination button (to take the user to the 11721 * next page). 11722 * @type string 11723 * @default Next 11724 * 11725 * @dtopt Language 11726 * @name DataTable.defaults.language.paginate.next 11727 * 11728 * @example 11729 * $(document).ready( function() { 11730 * $('#example').dataTable( { 11731 * "language": { 11732 * "paginate": { 11733 * "next": "Next page" 11734 * } 11735 * } 11736 * } ); 11737 * } ); 11738 */ 11739 "sNext": "Next", 11740 11741 11742 /** 11743 * Text to use for the 'previous' pagination button (to take the user to 11744 * the previous page). 11745 * @type string 11746 * @default Previous 11747 * 11748 * @dtopt Language 11749 * @name DataTable.defaults.language.paginate.previous 11750 * 11751 * @example 11752 * $(document).ready( function() { 11753 * $('#example').dataTable( { 11754 * "language": { 11755 * "paginate": { 11756 * "previous": "Previous page" 11757 * } 11758 * } 11759 * } ); 11760 * } ); 11761 */ 11762 "sPrevious": "Previous" 11763 }, 11764 11765 /** 11766 * This string is shown in preference to `zeroRecords` when the table is 11767 * empty of data (regardless of filtering). Note that this is an optional 11768 * parameter - if it is not given, the value of `zeroRecords` will be used 11769 * instead (either the default or given value). 11770 * @type string 11771 * @default No data available in table 11772 * 11773 * @dtopt Language 11774 * @name DataTable.defaults.language.emptyTable 11775 * 11776 * @example 11777 * $(document).ready( function() { 11778 * $('#example').dataTable( { 11779 * "language": { 11780 * "emptyTable": "No data available in table" 11781 * } 11782 * } ); 11783 * } ); 11784 */ 11785 "sEmptyTable": "No data available in table", 11786 11787 11788 /** 11789 * This string gives information to the end user about the information 11790 * that is current on display on the page. The following tokens can be 11791 * used in the string and will be dynamically replaced as the table 11792 * display updates. This tokens can be placed anywhere in the string, or 11793 * removed as needed by the language requires: 11794 * 11795 * * `\_START\_` - Display index of the first record on the current page 11796 * * `\_END\_` - Display index of the last record on the current page 11797 * * `\_TOTAL\_` - Number of records in the table after filtering 11798 * * `\_MAX\_` - Number of records in the table without filtering 11799 * * `\_PAGE\_` - Current page number 11800 * * `\_PAGES\_` - Total number of pages of data in the table 11801 * 11802 * @type string 11803 * @default Showing _START_ to _END_ of _TOTAL_ entries 11804 * 11805 * @dtopt Language 11806 * @name DataTable.defaults.language.info 11807 * 11808 * @example 11809 * $(document).ready( function() { 11810 * $('#example').dataTable( { 11811 * "language": { 11812 * "info": "Showing page _PAGE_ of _PAGES_" 11813 * } 11814 * } ); 11815 * } ); 11816 */ 11817 "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries", 11818 11819 11820 /** 11821 * Display information string for when the table is empty. Typically the 11822 * format of this string should match `info`. 11823 * @type string 11824 * @default Showing 0 to 0 of 0 entries 11825 * 11826 * @dtopt Language 11827 * @name DataTable.defaults.language.infoEmpty 11828 * 11829 * @example 11830 * $(document).ready( function() { 11831 * $('#example').dataTable( { 11832 * "language": { 11833 * "infoEmpty": "No entries to show" 11834 * } 11835 * } ); 11836 * } ); 11837 */ 11838 "sInfoEmpty": "Showing 0 to 0 of 0 entries", 11839 11840 11841 /** 11842 * When a user filters the information in a table, this string is appended 11843 * to the information (`info`) to give an idea of how strong the filtering 11844 * is. The variable _MAX_ is dynamically updated. 11845 * @type string 11846 * @default (filtered from _MAX_ total entries) 11847 * 11848 * @dtopt Language 11849 * @name DataTable.defaults.language.infoFiltered 11850 * 11851 * @example 11852 * $(document).ready( function() { 11853 * $('#example').dataTable( { 11854 * "language": { 11855 * "infoFiltered": " - filtering from _MAX_ records" 11856 * } 11857 * } ); 11858 * } ); 11859 */ 11860 "sInfoFiltered": "(filtered from _MAX_ total entries)", 11861 11862 11863 /** 11864 * If can be useful to append extra information to the info string at times, 11865 * and this variable does exactly that. This information will be appended to 11866 * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are 11867 * being used) at all times. 11868 * @type string 11869 * @default <i>Empty string</i> 11870 * 11871 * @dtopt Language 11872 * @name DataTable.defaults.language.infoPostFix 11873 * 11874 * @example 11875 * $(document).ready( function() { 11876 * $('#example').dataTable( { 11877 * "language": { 11878 * "infoPostFix": "All records shown are derived from real information." 11879 * } 11880 * } ); 11881 * } ); 11882 */ 11883 "sInfoPostFix": "", 11884 11885 11886 /** 11887 * This decimal place operator is a little different from the other 11888 * language options since DataTables doesn't output floating point 11889 * numbers, so it won't ever use this for display of a number. Rather, 11890 * what this parameter does is modify the sort methods of the table so 11891 * that numbers which are in a format which has a character other than 11892 * a period (`.`) as a decimal place will be sorted numerically. 11893 * 11894 * Note that numbers with different decimal places cannot be shown in 11895 * the same table and still be sortable, the table must be consistent. 11896 * However, multiple different tables on the page can use different 11897 * decimal place characters. 11898 * @type string 11899 * @default 11900 * 11901 * @dtopt Language 11902 * @name DataTable.defaults.language.decimal 11903 * 11904 * @example 11905 * $(document).ready( function() { 11906 * $('#example').dataTable( { 11907 * "language": { 11908 * "decimal": "," 11909 * "thousands": "." 11910 * } 11911 * } ); 11912 * } ); 11913 */ 11914 "sDecimal": "", 11915 11916 11917 /** 11918 * DataTables has a build in number formatter (`formatNumber`) which is 11919 * used to format large numbers that are used in the table information. 11920 * By default a comma is used, but this can be trivially changed to any 11921 * character you wish with this parameter. 11922 * @type string 11923 * @default , 11924 * 11925 * @dtopt Language 11926 * @name DataTable.defaults.language.thousands 11927 * 11928 * @example 11929 * $(document).ready( function() { 11930 * $('#example').dataTable( { 11931 * "language": { 11932 * "thousands": "'" 11933 * } 11934 * } ); 11935 * } ); 11936 */ 11937 "sThousands": ",", 11938 11939 11940 /** 11941 * Detail the action that will be taken when the drop down menu for the 11942 * pagination length option is changed. The '_MENU_' variable is replaced 11943 * with a default select list of 10, 25, 50 and 100, and can be replaced 11944 * with a custom select box if required. 11945 * @type string 11946 * @default Show _MENU_ entries 11947 * 11948 * @dtopt Language 11949 * @name DataTable.defaults.language.lengthMenu 11950 * 11951 * @example 11952 * // Language change only 11953 * $(document).ready( function() { 11954 * $('#example').dataTable( { 11955 * "language": { 11956 * "lengthMenu": "Display _MENU_ records" 11957 * } 11958 * } ); 11959 * } ); 11960 * 11961 * @example 11962 * // Language and options change 11963 * $(document).ready( function() { 11964 * $('#example').dataTable( { 11965 * "language": { 11966 * "lengthMenu": 'Display <select>'+ 11967 * '<option value="10">10</option>'+ 11968 * '<option value="20">20</option>'+ 11969 * '<option value="30">30</option>'+ 11970 * '<option value="40">40</option>'+ 11971 * '<option value="50">50</option>'+ 11972 * '<option value="-1">All</option>'+ 11973 * '</select> records' 11974 * } 11975 * } ); 11976 * } ); 11977 */ 11978 "sLengthMenu": "Show _MENU_ entries", 11979 11980 11981 /** 11982 * When using Ajax sourced data and during the first draw when DataTables is 11983 * gathering the data, this message is shown in an empty row in the table to 11984 * indicate to the end user the the data is being loaded. Note that this 11985 * parameter is not used when loading data by server-side processing, just 11986 * Ajax sourced data with client-side processing. 11987 * @type string 11988 * @default Loading... 11989 * 11990 * @dtopt Language 11991 * @name DataTable.defaults.language.loadingRecords 11992 * 11993 * @example 11994 * $(document).ready( function() { 11995 * $('#example').dataTable( { 11996 * "language": { 11997 * "loadingRecords": "Please wait - loading..." 11998 * } 11999 * } ); 12000 * } ); 12001 */ 12002 "sLoadingRecords": "Loading...", 12003 12004 12005 /** 12006 * Text which is displayed when the table is processing a user action 12007 * (usually a sort command or similar). 12008 * @type string 12009 * 12010 * @dtopt Language 12011 * @name DataTable.defaults.language.processing 12012 * 12013 * @example 12014 * $(document).ready( function() { 12015 * $('#example').dataTable( { 12016 * "language": { 12017 * "processing": "DataTables is currently busy" 12018 * } 12019 * } ); 12020 * } ); 12021 */ 12022 "sProcessing": "", 12023 12024 12025 /** 12026 * Details the actions that will be taken when the user types into the 12027 * filtering input text box. The variable "_INPUT_", if used in the string, 12028 * is replaced with the HTML text box for the filtering input allowing 12029 * control over where it appears in the string. If "_INPUT_" is not given 12030 * then the input box is appended to the string automatically. 12031 * @type string 12032 * @default Search: 12033 * 12034 * @dtopt Language 12035 * @name DataTable.defaults.language.search 12036 * 12037 * @example 12038 * // Input text box will be appended at the end automatically 12039 * $(document).ready( function() { 12040 * $('#example').dataTable( { 12041 * "language": { 12042 * "search": "Filter records:" 12043 * } 12044 * } ); 12045 * } ); 12046 * 12047 * @example 12048 * // Specify where the filter should appear 12049 * $(document).ready( function() { 12050 * $('#example').dataTable( { 12051 * "language": { 12052 * "search": "Apply filter _INPUT_ to table" 12053 * } 12054 * } ); 12055 * } ); 12056 */ 12057 "sSearch": "Search:", 12058 12059 12060 /** 12061 * Assign a `placeholder` attribute to the search `input` element 12062 * @type string 12063 * @default 12064 * 12065 * @dtopt Language 12066 * @name DataTable.defaults.language.searchPlaceholder 12067 */ 12068 "sSearchPlaceholder": "", 12069 12070 12071 /** 12072 * All of the language information can be stored in a file on the 12073 * server-side, which DataTables will look up if this parameter is passed. 12074 * It must store the URL of the language file, which is in a JSON format, 12075 * and the object has the same properties as the oLanguage object in the 12076 * initialiser object (i.e. the above parameters). Please refer to one of 12077 * the example language files to see how this works in action. 12078 * @type string 12079 * @default <i>Empty string - i.e. disabled</i> 12080 * 12081 * @dtopt Language 12082 * @name DataTable.defaults.language.url 12083 * 12084 * @example 12085 * $(document).ready( function() { 12086 * $('#example').dataTable( { 12087 * "language": { 12088 * "url": "http
12088s
vendor: 83,377 bytes, lines 12088-14869
12088://www.sprymedia.co.uk/dataTables/lang.txt" 12089 * } 12090 * } ); 12091 * } ); 12092 */ 12093 "sUrl": "", 12094 12095 12096 /** 12097 * Text shown inside the table records when the is no information to be 12098 * displayed after filtering. `emptyTable` is shown when there is simply no 12099 * information in the table at all (regardless of filtering). 12100 * @type string 12101 * @default No matching records found 12102 * 12103 * @dtopt Language 12104 * @name DataTable.defaults.language.zeroRecords 12105 * 12106 * @example 12107 * $(document).ready( function() { 12108 * $('#example').dataTable( { 12109 * "language": { 12110 * "zeroRecords": "No records to display" 12111 * } 12112 * } ); 12113 * } ); 12114 */ 12115 "sZeroRecords": "No matching records found" 12116 }, 12117 12118 12119 /** 12120 * This parameter allows you to have define the global filtering state at 12121 * initialisation time. As an object the `search` parameter must be 12122 * defined, but all other parameters are optional. When `regex` is true, 12123 * the search string will be treated as a regular expression, when false 12124 * (default) it will be treated as a straight string. When `smart` 12125 * DataTables will use it's smart filtering methods (to word match at 12126 * any point in the data), when false this will not be done. 12127 * @namespace 12128 * @extends DataTable.models.oSearch 12129 * 12130 * @dtopt Options 12131 * @name DataTable.defaults.search 12132 * 12133 * @example 12134 * $(document).ready( function() { 12135 * $('#example').dataTable( { 12136 * "search": {"search": "Initial search"} 12137 * } ); 12138 * } ) 12139 */ 12140 "oSearch": $.extend( {}, DataTable.models.oSearch ), 12141 12142 12143 /** 12144 * __Deprecated__ The functionality provided by this parameter has now been 12145 * superseded by that provided through `ajax`, which should be used instead. 12146 * 12147 * By default DataTables will look for the property `data` (or `aaData` for 12148 * compatibility with DataTables 1.9-) when obtaining data from an Ajax 12149 * source or for server-side processing - this parameter allows that 12150 * property to be changed. You can use Javascript dotted object notation to 12151 * get a data source for multiple levels of nesting. 12152 * @type string 12153 * @default data 12154 * 12155 * @dtopt Options 12156 * @dtopt Server-side 12157 * @name DataTable.defaults.ajaxDataProp 12158 * 12159 * @deprecated 1.10. Please use `ajax` for this functionality now. 12160 */ 12161 "sAjaxDataProp": "data", 12162 12163 12164 /** 12165 * __Deprecated__ The functionality provided by this parameter has now been 12166 * superseded by that provided through `ajax`, which should be used instead. 12167 * 12168 * You can instruct DataTables to load data from an external 12169 * source using this parameter (use aData if you want to pass data in you 12170 * already have). Simply provide a url a JSON object can be obtained from. 12171 * @type string 12172 * @default null 12173 * 12174 * @dtopt Options 12175 * @dtopt Server-side 12176 * @name DataTable.defaults.ajaxSource 12177 * 12178 * @deprecated 1.10. Please use `ajax` for this functionality now. 12179 */ 12180 "sAjaxSource": null, 12181 12182 12183 /** 12184 * This initialisation variable allows you to specify exactly where in the 12185 * DOM you want DataTables to inject the various controls it adds to the page 12186 * (for example you might want the pagination controls at the top of the 12187 * table). DIV elements (with or without a custom class) can also be added to 12188 * aid styling. The follow syntax is used: 12189 * <ul> 12190 * <li>The following options are allowed: 12191 * <ul> 12192 * <li>'l' - Length changing</li> 12193 * <li>'f' - Filtering input</li> 12194 * <li>'t' - The table!</li> 12195 * <li>'i' - Information</li> 12196 * <li>'p' - Pagination</li> 12197 * <li>'r' - pRocessing</li> 12198 * </ul> 12199 * </li> 12200 * <li>The following constants are allowed: 12201 * <ul> 12202 * <li>'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li> 12203 * <li>'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li> 12204 * </ul> 12205 * </li> 12206 * <li>The following syntax is expected: 12207 * <ul> 12208 * <li>'<' and '>' - div elements</li> 12209 * <li>'<"class" and '>' - div with a class</li> 12210 * <li>'<"#id" and '>' - div with an ID</li> 12211 * </ul> 12212 * </li> 12213 * <li>Examples: 12214 * <ul> 12215 * <li>'<"wrapper"flipt>'</li> 12216 * <li>'<lf<t>ip>'</li> 12217 * </ul> 12218 * </li> 12219 * </ul> 12220 * @type string 12221 * @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b> 12222 * <"H"lfr>t<"F"ip> <i>(when `jQueryUI` is true)</i> 12223 * 12224 * @dtopt Options 12225 * @name DataTable.defaults.dom 12226 * 12227 * @example 12228 * $(document).ready( function() { 12229 * $('#example').dataTable( { 12230 * "dom": '<"top"i>rt<"bottom"flp><"clear">' 12231 * } ); 12232 * } ); 12233 */ 12234 "sDom": "lfrtip", 12235 12236 12237 /** 12238 * Search delay option. This will throttle full table searches that use the 12239 * DataTables provided search input element (it does not effect calls to 12240 * `dt-api search()`, providing a delay before the search is made. 12241 * @type integer 12242 * @default 0 12243 * 12244 * @dtopt Options 12245 * @name DataTable.defaults.searchDelay 12246 * 12247 * @example 12248 * $(document).ready( function() { 12249 * $('#example').dataTable( { 12250 * "searchDelay": 200 12251 * } ); 12252 * } ) 12253 */ 12254 "searchDelay": null, 12255 12256 12257 /** 12258 * DataTables features six different built-in options for the buttons to 12259 * display for pagination control: 12260 * 12261 * * `numbers` - Page number buttons only 12262 * * `simple` - 'Previous' and 'Next' buttons only 12263 * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers 12264 * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons 12265 * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus page numbers 12266 * * `first_last_numbers` - 'First' and 'Last' buttons, plus page numbers 12267 * 12268 * Further methods can be added using {@link DataTable.ext.oPagination}. 12269 * @type string 12270 * @default simple_numbers 12271 * 12272 * @dtopt Options 12273 * @name DataTable.defaults.pagingType 12274 * 12275 * @example 12276 * $(document).ready( function() { 12277 * $('#example').dataTable( { 12278 * "pagingType": "full_numbers" 12279 * } ); 12280 * } ) 12281 */ 12282 "sPaginationType": "simple_numbers", 12283 12284 12285 /** 12286 * Enable horizontal scrolling. When a table is too wide to fit into a 12287 * certain layout, or you have a large number of columns in the table, you 12288 * can enable x-scrolling to show the table in a viewport, which can be 12289 * scrolled. This property can be `true` which will allow the table to 12290 * scroll horizontally when needed, or any CSS unit, or a number (in which 12291 * case it will be treated as a pixel measurement). Setting as simply `true` 12292 * is recommended. 12293 * @type boolean|string 12294 * @default <i>blank string - i.e. disabled</i> 12295 * 12296 * @dtopt Features 12297 * @name DataTable.defaults.scrollX 12298 * 12299 * @example 12300 * $(document).ready( function() { 12301 * $('#example').dataTable( { 12302 * "scrollX": true, 12303 * "scrollCollapse": true 12304 * } ); 12305 * } ); 12306 */ 12307 "sScrollX": "", 12308 12309 12310 /** 12311 * This property can be used to force a DataTable to use more width than it 12312 * might otherwise do when x-scrolling is enabled. For example if you have a 12313 * table which requires to be well spaced, this parameter is useful for 12314 * "over-sizing" the table, and thus forcing scrolling. This property can by 12315 * any CSS unit, or a number (in which case it will be treated as a pixel 12316 * measurement). 12317 * @type string 12318 * @default <i>blank string - i.e. disabled</i> 12319 * 12320 * @dtopt Options 12321 * @name DataTable.defaults.scrollXInner 12322 * 12323 * @example 12324 * $(document).ready( function() { 12325 * $('#example').dataTable( { 12326 * "scrollX": "100%", 12327 * "scrollXInner": "110%" 12328 * } ); 12329 * } ); 12330 */ 12331 "sScrollXInner": "", 12332 12333 12334 /** 12335 * Enable vertical scrolling. Vertical scrolling will constrain the DataTable 12336 * to the given height, and enable scrolling for any data which overflows the 12337 * current viewport. This can be used as an alternative to paging to display 12338 * a lot of data in a small area (although paging and scrolling can both be 12339 * enabled at the same time). This property can be any CSS unit, or a number 12340 * (in which case it will be treated as a pixel measurement). 12341 * @type string 12342 * @default <i>blank string - i.e. disabled</i> 12343 * 12344 * @dtopt Features 12345 * @name DataTable.defaults.scrollY 12346 * 12347 * @example 12348 * $(document).ready( function() { 12349 * $('#example').dataTable( { 12350 * "scrollY": "200px", 12351 * "paginate": false 12352 * } ); 12353 * } ); 12354 */ 12355 "sScrollY": "", 12356 12357 12358 /** 12359 * __Deprecated__ The functionality provided by this parameter has now been 12360 * superseded by that provided through `ajax`, which should be used instead. 12361 * 12362 * Set the HTTP method that is used to make the Ajax call for server-side 12363 * processing or Ajax sourced data. 12364 * @type string 12365 * @default GET 12366 * 12367 * @dtopt Options 12368 * @dtopt Server-side 12369 * @name DataTable.defaults.serverMethod 12370 * 12371 * @deprecated 1.10. Please use `ajax` for this functionality now. 12372 */ 12373 "sServerMethod": "GET", 12374 12375 12376 /** 12377 * DataTables makes use of renderers when displaying HTML elements for 12378 * a table. These renderers can be added or modified by plug-ins to 12379 * generate suitable mark-up for a site. For example the Bootstrap 12380 * integration plug-in for DataTables uses a paging button renderer to 12381 * display pagination buttons in the mark-up required by Bootstrap. 12382 * 12383 * For further information about the renderers available see 12384 * DataTable.ext.renderer 12385 * @type string|object 12386 * @default null 12387 * 12388 * @name DataTable.defaults.renderer 12389 * 12390 */ 12391 "renderer": null, 12392 12393 12394 /** 12395 * Set the data property name that DataTables should use to get a row's id 12396 * to set as the `id` property in the node. 12397 * @type string 12398 * @default DT_RowId 12399 * 12400 * @name DataTable.defaults.rowId 12401 */ 12402 "rowId": "DT_RowId" 12403 }; 12404 12405 _fnHungarianMap( DataTable.defaults ); 12406 12407 12408 12409 /* 12410 * Developer note - See note in model.defaults.js about the use of Hungarian 12411 * notation and camel case. 12412 */ 12413 12414 /** 12415 * Column options that can be given to DataTables at initialisation time. 12416 * @namespace 12417 */ 12418 DataTable.defaults.column = { 12419 /** 12420 * Define which column(s) an order will occur on for this column. This 12421 * allows a column's ordering to take multiple columns into account when 12422 * doing a sort or use the data from a different column. For example first 12423 * name / last name columns make sense to do a multi-column sort over the 12424 * two columns. 12425 * @type array|int 12426 * @default null <i>Takes the value of the column index automatically</i> 12427 * 12428 * @name DataTable.defaults.column.orderData 12429 * @dtopt Columns 12430 * 12431 * @example 12432 * // Using `columnDefs` 12433 * $(document).ready( function() { 12434 * $('#example').dataTable( { 12435 * "columnDefs": [ 12436 * { "orderData": [ 0, 1 ], "targets": [ 0 ] }, 12437 * { "orderData": [ 1, 0 ], "targets": [ 1 ] }, 12438 * { "orderData": 2, "targets": [ 2 ] } 12439 * ] 12440 * } ); 12441 * } ); 12442 * 12443 * @example 12444 * // Using `columns` 12445 * $(document).ready( function() { 12446 * $('#example').dataTable( { 12447 * "columns": [ 12448 * { "orderData": [ 0, 1 ] }, 12449 * { "orderData": [ 1, 0 ] }, 12450 * { "orderData": 2 }, 12451 * null, 12452 * null 12453 * ] 12454 * } ); 12455 * } ); 12456 */ 12457 "aDataSort": null, 12458 "iDataSort": -1, 12459 12460 12461 /** 12462 * You can control the default ordering direction, and even alter the 12463 * behaviour of the sort handler (i.e. only allow ascending ordering etc) 12464 * using this parameter. 12465 * @type array 12466 * @default [ 'asc', 'desc' ] 12467 * 12468 * @name DataTable.defaults.column.orderSequence 12469 * @dtopt Columns 12470 * 12471 * @example 12472 * // Using `columnDefs` 12473 * $(document).ready( function() { 12474 * $('#example').dataTable( { 12475 * "columnDefs": [ 12476 * { "orderSequence": [ "asc" ], "targets": [ 1 ] }, 12477 * { "orderSequence": [ "desc", "asc", "asc" ], "targets": [ 2 ] }, 12478 * { "orderSequence": [ "desc" ], "targets": [ 3 ] } 12479 * ] 12480 * } ); 12481 * } ); 12482 * 12483 * @example 12484 * // Using `columns` 12485 * $(document).ready( function() { 12486 * $('#example').dataTable( { 12487 * "columns": [ 12488 * null, 12489 * { "orderSequence": [ "asc" ] }, 12490 * { "orderSequence": [ "desc", "asc", "asc" ] }, 12491 * { "orderSequence": [ "desc" ] }, 12492 * null 12493 * ] 12494 * } ); 12495 * } ); 12496 */ 12497 "asSorting": [ 'asc', 'desc' ], 12498 12499 12500 /** 12501 * Enable or disable filtering on the data in this column. 12502 * @type boolean 12503 * @default true 12504 * 12505 * @name DataTable.defaults.column.searchable 12506 * @dtopt Columns 12507 * 12508 * @example 12509 * // Using `columnDefs` 12510 * $(document).ready( function() { 12511 * $('#example').dataTable( { 12512 * "columnDefs": [ 12513 * { "searchable": false, "targets": [ 0 ] } 12514 * ] } ); 12515 * } ); 12516 * 12517 * @example 12518 * // Using `columns` 12519 * $(document).ready( function() { 12520 * $('#example').dataTable( { 12521 * "columns": [ 12522 * { "searchable": false }, 12523 * null, 12524 * null, 12525 * null, 12526 * null 12527 * ] } ); 12528 * } ); 12529 */ 12530 "bSearchable": true, 12531 12532 12533 /** 12534 * Enable or disable ordering on this column. 12535 * @type boolean 12536 * @default true 12537 * 12538 * @name DataTable.defaults.column.orderable 12539 * @dtopt Columns 12540 * 12541 * @example 12542 * // Using `columnDefs` 12543 * $(document).ready( function() { 12544 * $('#example').dataTable( { 12545 * "columnDefs": [ 12546 * { "orderable": false, "targets": [ 0 ] } 12547 * ] } ); 12548 * } ); 12549 * 12550 * @example 12551 * // Using `columns` 12552 * $(document).ready( function() { 12553 * $('#example').dataTable( { 12554 * "columns": [ 12555 * { "orderable": false }, 12556 * null, 12557 * null, 12558 * null, 12559 * null 12560 * ] } ); 12561 * } ); 12562 */ 12563 "bSortable": true, 12564 12565 12566 /** 12567 * Enable or disable the display of this column. 12568 * @type boolean 12569 * @default true 12570 * 12571 * @name DataTable.defaults.column.visible 12572 * @dtopt Columns 12573 * 12574 * @example 12575 * // Using `columnDefs` 12576 * $(document).ready( function() { 12577 * $('#example').dataTable( { 12578 * "columnDefs": [ 12579 * { "visible": false, "targets": [ 0 ] } 12580 * ] } ); 12581 * } ); 12582 * 12583 * @example 12584 * // Using `columns` 12585 * $(document).ready( function() { 12586 * $('#example').dataTable( { 12587 * "columns": [ 12588 * { "visible": false }, 12589 * null, 12590 * null, 12591 * null, 12592 * null 12593 * ] } ); 12594 * } ); 12595 */ 12596 "bVisible": true, 12597 12598 12599 /** 12600 * Developer definable function that is called whenever a cell is created (Ajax source, 12601 * etc) or processed for input (DOM source). This can be used as a compliment to mRender 12602 * allowing you to modify the DOM element (add background colour for example) when the 12603 * element is available. 12604 * @type function 12605 * @param {element} td The TD node that has been created 12606 * @param {*} cellData The Data for the cell 12607 * @param {array|object} rowData The data for the whole row 12608 * @param {int} row The row index for the aoData data store 12609 * @param {int} col The column index for aoColumns 12610 * 12611 * @name DataTable.defaults.column.createdCell 12612 * @dtopt Columns 12613 * 12614 * @example 12615 * $(document).ready( function() { 12616 * $('#example').dataTable( { 12617 * "columnDefs": [ { 12618 * "targets": [3], 12619 * "createdCell": function (td, cellData, rowData, row, col) { 12620 * if ( cellData == "1.7" ) { 12621 * $(td).css('color', 'blue') 12622 * } 12623 * } 12624 * } ] 12625 * }); 12626 * } ); 12627 */ 12628 "fnCreatedCell": null, 12629 12630 12631 /** 12632 * This parameter has been replaced by `data` in DataTables to ensure naming 12633 * consistency. `dataProp` can still be used, as there is backwards 12634 * compatibility in DataTables for this option, but it is strongly 12635 * recommended that you use `data` in preference to `dataProp`. 12636 * @name DataTable.defaults.column.dataProp 12637 */ 12638 12639 12640 /** 12641 * This property can be used to read data from any data source property, 12642 * including deeply nested objects / properties. `data` can be given in a 12643 * number of different ways which effect its behaviour: 12644 * 12645 * * `integer` - treated as an array index for the data source. This is the 12646 * default that DataTables uses (incrementally increased for each column). 12647 * * `string` - read an object property from the data source. There are 12648 * three 'special' options that can be used in the string to alter how 12649 * DataTables reads the data from the source object: 12650 * * `.` - Dotted Javascript notation. Just as you use a `.` in 12651 * Javascript to read from nested objects, so to can the options 12652 * specified in `data`. For example: `browser.version` or 12653 * `browser.name`. If your object parameter name contains a period, use 12654 * `\\` to escape it - i.e. `first\\.name`. 12655 * * `[]` - Array notation. DataTables can automatically combine data 12656 * from and array source, joining the data with the characters provided 12657 * between the two brackets. For example: `name[, ]` would provide a 12658 * comma-space separated list from the source array. If no characters 12659 * are provided between the brackets, the original array source is 12660 * returned. 12661 * * `()` - Function notation. Adding `()` to the end of a parameter will 12662 * execute a function of the name given. For example: `browser()` for a 12663 * simple function on the data source, `browser.version()` for a 12664 * function in a nested property or even `browser().version` to get an 12665 * object property if the function called returns an object. Note that 12666 * function notation is recommended for use in `render` rather than 12667 * `data` as it is much simpler to use as a renderer. 12668 * * `null` - use the original data source for the row rather than plucking 12669 * data directly from it. This action has effects on two other 12670 * initialisation options: 12671 * * `defaultContent` - When null is given as the `data` option and 12672 * `defaultContent` is specified for the column, the value defined by 12673 * `defaultContent` will be used for the cell. 12674 * * `render` - When null is used for the `data` option and the `render` 12675 * option is specified for the column, the whole data source for the 12676 * row is used for the renderer. 12677 * * `function` - the function given will be executed whenever DataTables 12678 * needs to set or get the data for a cell in the column. The function 12679 * takes three parameters: 12680 * * Parameters: 12681 * * `{array|object}` The data source for the row 12682 * * `{string}` The type call data requested - this will be 'set' when 12683 * setting data or 'filter', 'display', 'type', 'sort' or undefined 12684 * when gathering data. Note that when `undefined` is given for the 12685 * type DataTables expects to get the raw data for the object back< 12686 * * `{*}` Data to set when the second parameter is 'set'. 12687 * * Return: 12688 * * The return value from the function is not required when 'set' is 12689 * the type of call, but otherwise the return is what will be used 12690 * for the data requested. 12691 * 12692 * Note that `data` is a getter and setter option. If you just require 12693 * formatting of data for output, you will likely want to use `render` which 12694 * is simply a getter and thus simpler to use. 12695 * 12696 * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The 12697 * name change reflects the flexibility of this property and is consistent 12698 * with the naming of mRender. If 'mDataProp' is given, then it will still 12699 * be used by DataTables, as it automatically maps the old name to the new 12700 * if required. 12701 * 12702 * @type string|int|function|null 12703 * @default null <i>Use automatically calculated column index</i> 12704 * 12705 * @name DataTable.defaults.column.data 12706 * @dtopt Columns 12707 * 12708 * @example 12709 * // Read table data from objects 12710 * // JSON structure for each row: 12711 * // { 12712 * // "engine": {value}, 12713 * // "browser": {value}, 12714 * // "platform": {value}, 12715 * // "version": {value}, 12716 * // "grade": {value} 12717 * // } 12718 * $(document).ready( function() { 12719 * $('#example').dataTable( { 12720 * "ajaxSource": "sources/objects.txt", 12721 * "columns": [ 12722 * { "data": "engine" }, 12723 * { "data": "browser" }, 12724 * { "data": "platform" }, 12725 * { "data": "version" }, 12726 * { "data": "grade" } 12727 * ] 12728 * } ); 12729 * } ); 12730 * 12731 * @example 12732 * // Read information from deeply nested objects 12733 * // JSON structure for each row: 12734 * // { 12735 * // "engine": {value}, 12736 * // "browser": {value}, 12737 * // "platform": { 12738 * // "inner": {value} 12739 * // }, 12740 * // "details": [ 12741 * // {value}, {value} 12742 * // ] 12743 * // } 12744 * $(document).ready( function() { 12745 * $('#example').dataTable( { 12746 * "ajaxSource": "sources/deep.txt", 12747 * "columns": [ 12748 * { "data": "engine" }, 12749 * { "data": "browser" }, 12750 * { "data": "platform.inner" }, 12751 * { "data": "details.0" }, 12752 * { "data": "details.1" } 12753 * ] 12754 * } ); 12755 * } ); 12756 * 12757 * @example 12758 * // Using `data` as a function to provide different information for 12759 * // sorting, filtering and display. In this case, currency (price) 12760 * $(document).ready( function() { 12761 * $('#example').dataTable( { 12762 * "columnDefs": [ { 12763 * "targets": [ 0 ], 12764 * "data": function ( source, type, val ) { 12765 * if (type === 'set') { 12766 * source.price = val; 12767 * // Store the computed display and filter values for efficiency 12768 * source.price_display = val=="" ? "" : "$"+numberFormat(val); 12769 * source.price_filter = val=="" ? "" : "$"+numberFormat(val)+" "+val; 12770 * return; 12771 * } 12772 * else if (type === 'display') { 12773 * return source.price_display; 12774 * } 12775 * else if (type === 'filter') { 12776 * return source.price_filter; 12777 * } 12778 * // 'sort', 'type' and undefined all just use the integer 12779 * return source.price; 12780 * } 12781 * } ] 12782 * } ); 12783 * } ); 12784 * 12785 * @example 12786 * // Using default content 12787 * $(document).ready( function() { 12788 * $('#example').dataTable( { 12789 * "columnDefs": [ { 12790 * "targets": [ 0 ], 12791 * "data": null, 12792 * "defaultContent": "Click to edit" 12793 * } ] 12794 * } ); 12795 * } ); 12796 * 12797 * @example 12798 * // Using array notation - outputting a list from an array 12799 * $(document).ready( function() { 12800 * $('#example').dataTable( { 12801 * "columnDefs": [ { 12802 * "targets": [ 0 ], 12803 * "data": "name[, ]" 12804 * } ] 12805 * } ); 12806 * } ); 12807 * 12808 */ 12809 "mData": null, 12810 12811 12812 /** 12813 * This property is the rendering partner to `data` and it is suggested that 12814 * when you want to manipulate data for display (including filtering, 12815 * sorting etc) without altering the underlying data for the table, use this 12816 * property. `render` can be considered to be the the read only companion to 12817 * `data` which is read / write (then as such more complex). Like `data` 12818 * this option can be given in a number of different ways to effect its 12819 * behaviour: 12820 * 12821 * * `integer` - treated as an array index for the data source. This is the 12822 * default that DataTables uses (incrementally increased for each column). 12823 * * `string` - read an object property from the data source. There are 12824 * three 'special' options that can be used in the string to alter how 12825 * DataTables reads the data from the source object: 12826 * * `.` - Dotted Javascript notation. Just as you use a `.` in 12827 * Javascript to read from nested objects, so to can the options 12828 * specified in `data`. For example: `browser.version` or 12829 * `browser.name`. If your object parameter name contains a period, use 12830 * `\\` to escape it - i.e. `first\\.name`. 12831 * * `[]` - Array notation. DataTables can automatically combine data 12832 * from and array source, joining the data with the characters provided 12833 * between the two brackets. For example: `name[, ]` would provide a 12834 * comma-space separated list from the source array. If no characters 12835 * are provided between the brackets, the original array source is 12836 * returned. 12837 * * `()` - Function notation. Adding `()` to the end of a parameter will 12838 * execute a function of the name given. For example: `browser()` for a 12839 * simple function on the data source, `browser.version()` for a 12840 * function in a nested property or even `browser().version` to get an 12841 * object property if the function called returns an object. 12842 * * `object` - use different data for the different data types requested by 12843 * DataTables ('filter', 'display', 'type' or 'sort'). The property names 12844 * of the object is the data type the property refers to and the value can 12845 * defined using an integer, string or function using the same rules as 12846 * `render` normally does. Note that an `_` option _must_ be specified. 12847 * This is the default value to use if you haven't specified a value for 12848 * the data type requested by DataTables. 12849 * * `function` - the function given will be executed whenever DataTables 12850 * needs to set or get the data for a cell in the column. The function 12851 * takes three parameters: 12852 * * Parameters: 12853 * * {array|object} The data source for the row (based on `data`) 12854 * * {string} The type call data requested - this will be 'filter', 12855 * 'display', 'type' or 'sort'. 12856 * * {array|object} The full data source for the row (not based on 12857 * `data`) 12858 * * Return: 12859 * * The return value from the function is what will be used for the 12860 * data requested. 12861 * 12862 * @type string|int|function|object|null 12863 * @default null Use the data source value. 12864 * 12865 * @name DataTable.defaults.column.render 12866 * @dtopt Columns 12867 * 12868 * @example 12869 * // Create a comma separated list from an array of objects 12870 * $(document).ready( function() { 12871 * $('#example').dataTable( { 12872 * "ajaxSource": "sources/deep.txt", 12873 * "columns": [ 12874 * { "data": "engine" }, 12875 * { "data": "browser" }, 12876 * { 12877 * "data": "platform", 12878 * "render": "[, ].name" 12879 * } 12880 * ] 12881 * } ); 12882 * } ); 12883 * 12884 * @example 12885 * // Execute a function to obtain data 12886 * $(document).ready( function() { 12887 * $('#example').dataTable( { 12888 * "columnDefs": [ { 12889 * "targets": [ 0 ], 12890 * "data": null, // Use the full data source object for the renderer's source 12891 * "render": "browserName()" 12892 * } ] 12893 * } ); 12894 * } ); 12895 * 12896 * @example 12897 * // As an object, extracting different data for the different types 12898 * // This would be used with a data source such as: 12899 * // { "phone": 5552368, "phone_filter": "5552368 555-2368", "phone_display": "555-2368" } 12900 * // Here the `phone` integer is used for sorting and type detection, while `phone_filter` 12901 * // (which has both forms) is used for filtering for if a user inputs either format, while 12902 * // the formatted phone number is the one that is shown in the table. 12903 * $(document).ready( function() { 12904 * $('#example').dataTable( { 12905 * "columnDefs": [ { 12906 * "targets": [ 0 ], 12907 * "data": null, // Use the full data source object for the renderer's source 12908 * "render": { 12909 * "_": "phone", 12910 * "filter": "phone_filter", 12911 * "display": "phone_display" 12912 * } 12913 * } ] 12914 * } ); 12915 * } ); 12916 * 12917 * @example 12918 * // Use as a function to create a link from the data source 12919 * $(document).ready( function() { 12920 * $('#example').dataTable( { 12921 * "columnDefs": [ { 12922 * "targets": [ 0 ], 12923 * "data": "download_link", 12924 * "render": function ( data, type, full ) { 12925 * return '<a href="'+data+'">Download</a>'; 12926 * } 12927 * } ] 12928 * } ); 12929 * } ); 12930 */ 12931 "mRender": null, 12932 12933 12934 /** 12935 * Change the cell type created for the column - either TD cells or TH cells. This 12936 * can be useful as TH cells have semantic meaning in the table body, allowing them 12937 * to act as a header for a row (you may wish to add scope='row' to the TH elements). 12938 * @type string 12939 * @default td 12940 * 12941 * @name DataTable.defaults.column.cellType 12942 * @dtopt Columns 12943 * 12944 * @example 12945 * // Make the first column use TH cells 12946 * $(document).ready( function() { 12947 * $('#example').dataTable( { 12948 * "columnDefs": [ { 12949 * "targets": [ 0 ], 12950 * "cellType": "th" 12951 * } ] 12952 * } ); 12953 * } ); 12954 */ 12955 "sCellType": "td", 12956 12957 12958 /** 12959 * Class to give to each cell in this column. 12960 * @type string 12961 * @default <i>Empty string</i> 12962 * 12963 * @name DataTable.defaults.column.class 12964 * @dtopt Columns 12965 * 12966 * @example 12967 * // Using `columnDefs` 12968 * $(document).ready( function() { 12969 * $('#example').dataTable( { 12970 * "columnDefs": [ 12971 * { "class": "my_class", "targets": [ 0 ] } 12972 * ] 12973 * } ); 12974 * } ); 12975 * 12976 * @example 12977 * // Using `columns` 12978 * $(document).ready( function() { 12979 * $('#example').dataTable( { 12980 * "columns": [ 12981 * { "class": "my_class" }, 12982 * null, 12983 * null, 12984 * null, 12985 * null 12986 * ] 12987 * } ); 12988 * } ); 12989 */ 12990 "sClass": "", 12991 12992 /** 12993 * When DataTables calculates the column widths to assign to each column, 12994 * it finds the longest string in each column and then constructs a 12995 * temporary table and reads the widths from that. The problem with this 12996 * is that "mmm" is much wider then "iiii", but the latter is a longer 12997 * string - thus the calculation can go wrong (doing it properly and putting 12998 * it into an DOM object and measuring that is horribly(!) slow). Thus as 12999 * a "work around" we provide this option. It will append its value to the 13000 * text that is found to be the longest string for the column - i.e. padding. 13001 * Generally you shouldn't need this! 13002 * @type string 13003 * @default <i>Empty string<i> 13004 * 13005 * @name DataTable.defaults.column.contentPadding 13006 * @dtopt Columns 13007 * 13008 * @example 13009 * // Using `columns` 13010 * $(document).ready( function() { 13011 * $('#example').dataTable( { 13012 * "columns": [ 13013 * null, 13014 * null, 13015 * null, 13016 * { 13017 * "contentPadding": "mmm" 13018 * } 13019 * ] 13020 * } ); 13021 * } ); 13022 */ 13023 "sContentPadding": "", 13024 13025 13026 /** 13027 * Allows a default value to be given for a column's data, and will be used 13028 * whenever a null data source is encountered (this can be because `data` 13029 * is set to null, or because the data source itself is null). 13030 * @type string 13031 * @default null 13032 * 13033 * @name DataTable.defaults.column.defaultContent 13034 * @dtopt Columns 13035 * 13036 * @example 13037 * // Using `columnDefs` 13038 * $(document).ready( function() { 13039 * $('#example').dataTable( { 13040 * "columnDefs": [ 13041 * { 13042 * "data": null, 13043 * "defaultContent": "Edit", 13044 * "targets": [ -1 ] 13045 * } 13046 * ] 13047 * } ); 13048 * } ); 13049 * 13050 * @example 13051 * // Using `columns` 13052 * $(document).ready( function() { 13053 * $('#example').dataTable( { 13054 * "columns": [ 13055 * null, 13056 * null, 13057 * null, 13058 * { 13059 * "data": null, 13060 * "defaultContent": "Edit" 13061 * } 13062 * ] 13063 * } ); 13064 * } ); 13065 */ 13066 "sDefaultContent": null, 13067 13068 13069 /** 13070 * This parameter is only used in DataTables' server-side processing. It can 13071 * be exceptionally useful to know what columns are being displayed on the 13072 * client side, and to map these to database fields. When defined, the names 13073 * also allow DataTables to reorder information from the server if it comes 13074 * back in an unexpected order (i.e. if you switch your columns around on the 13075 * client-side, your server-side code does not also need updating). 13076 * @type string 13077 * @default <i>Empty string</i> 13078 * 13079 * @name DataTable.defaults.column.name 13080 * @dtopt Columns 13081 * 13082 * @example 13083 * // Using `columnDefs` 13084 * $(document).ready( function() { 13085 * $('#example').dataTable( { 13086 * "columnDefs": [ 13087 * { "name": "engine", "targets": [ 0 ] }, 13088 * { "name": "browser", "targets": [ 1 ] }, 13089 * { "name": "platform", "targets": [ 2 ] }, 13090 * { "name": "version", "targets": [ 3 ] }, 13091 * { "name": "grade", "targets": [ 4 ] } 13092 * ] 13093 * } ); 13094 * } ); 13095 * 13096 * @example 13097 * // Using `columns` 13098 * $(document).ready( function() { 13099 * $('#example').dataTable( { 13100 * "columns": [ 13101 * { "name": "engine" }, 13102 * { "name": "browser" }, 13103 * { "name": "platform" }, 13104 * { "name": "version" }, 13105 * { "name": "grade" } 13106 * ] 13107 * } ); 13108 * } ); 13109 */ 13110 "sName": "", 13111 13112 13113 /** 13114 * Defines a data source type for the ordering which can be used to read 13115 * real-time information from the table (updating the internally cached 13116 * version) prior to ordering. This allows ordering to occur on user 13117 * editable elements such as form inputs. 13118 * @type string 13119 * @default std 13120 * 13121 * @name DataTable.defaults.column.orderDataType 13122 * @dtopt Columns 13123 * 13124 * @example 13125 * // Using `columnDefs` 13126 * $(document).ready( function() { 13127 * $('#example').dataTable( { 13128 * "columnDefs": [ 13129 * { "orderDataType": "dom-text", "targets": [ 2, 3 ] }, 13130 * { "type": "numeric", "targets": [ 3 ] }, 13131 * { "orderDataType": "dom-select", "targets": [ 4 ] }, 13132 * { "orderDataType": "dom-checkbox", "targets": [ 5 ] } 13133 * ] 13134 * } ); 13135 * } ); 13136 * 13137 * @example 13138 * // Using `columns` 13139 * $(document).ready( function() { 13140 * $('#example').dataTable( { 13141 * "columns": [ 13142 * null, 13143 * null, 13144 * { "orderDataType": "dom-text" }, 13145 * { "orderDataType": "dom-text", "type": "numeric" }, 13146 * { "orderDataType": "dom-select" }, 13147 * { "orderDataType": "dom-checkbox" } 13148 * ] 13149 * } ); 13150 * } ); 13151 */ 13152 "sSortDataType": "std", 13153 13154 13155 /** 13156 * The title of this column. 13157 * @type string 13158 * @default null <i>Derived from the 'TH' value for this column in the 13159 * original HTML table.</i> 13160 * 13161 * @name DataTable.defaults.column.title 13162 * @dtopt Columns 13163 * 13164 * @example 13165 * // Using `columnDefs` 13166 * $(document).ready( function() { 13167 * $('#example').dataTable( { 13168 * "columnDefs": [ 13169 * { "title": "My column title", "targets": [ 0 ] } 13170 * ] 13171 * } ); 13172 * } ); 13173 * 13174 * @example 13175 * // Using `columns` 13176 * $(document).ready( function() { 13177 * $('#example').dataTable( { 13178 * "columns": [ 13179 * { "title": "My column title" }, 13180 * null, 13181 * null, 13182 * null, 13183 * null 13184 * ] 13185 * } ); 13186 * } ); 13187 */ 13188 "sTitle": null, 13189 13190 13191 /** 13192 * The type allows you to specify how the data for this column will be 13193 * ordered. Four types (string, numeric, date and html (which will strip 13194 * HTML tags before ordering)) are currently available. Note that only date 13195 * formats understood by Javascript's Date() object will be accepted as type 13196 * date. For example: "Mar 26, 2008 5:03 PM". May take the values: 'string', 13197 * 'numeric', 'date' or 'html' (by default). Further types can be adding 13198 * through plug-ins. 13199 * @type string 13200 * @default null <i>Auto-detected from raw data</i> 13201 * 13202 * @name DataTable.defaults.column.type 13203 * @dtopt Columns 13204 * 13205 * @example 13206 * // Using `columnDefs` 13207 * $(document).ready( function() { 13208 * $('#example').dataTable( { 13209 * "columnDefs": [ 13210 * { "type": "html", "targets": [ 0 ] } 13211 * ] 13212 * } ); 13213 * } ); 13214 * 13215 * @example 13216 * // Using `columns` 13217 * $(document).ready( function() { 13218 * $('#example').dataTable( { 13219 * "columns": [ 13220 * { "type": "html" }, 13221 * null, 13222 * null, 13223 * null, 13224 * null 13225 * ] 13226 * } ); 13227 * } ); 13228 */ 13229 "sType": null, 13230 13231 13232 /** 13233 * Defining the width of the column, this parameter may take any CSS value 13234 * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not 13235 * been given a specific width through this interface ensuring that the table 13236 * remains readable. 13237 * @type string 13238 * @default null <i>Automatic</i> 13239 * 13240 * @name DataTable.defaults.column.width 13241 * @dtopt Columns 13242 * 13243 * @example 13244 * // Using `columnDefs` 13245 * $(document).ready( function() { 13246 * $('#example').dataTable( { 13247 * "columnDefs": [ 13248 * { "width": "20%", "targets": [ 0 ] } 13249 * ] 13250 * } ); 13251 * } ); 13252 * 13253 * @example 13254 * // Using `columns` 13255 * $(document).ready( function() { 13256 * $('#example').dataTable( { 13257 * "columns": [ 13258 * { "width": "20%" }, 13259 * null, 13260 * null, 13261 * null, 13262 * null 13263 * ] 13264 * } ); 13265 * } ); 13266 */ 13267 "sWidth": null 13268 }; 13269 13270 _fnHungarianMap( DataTable.defaults.column ); 13271 13272 13273 13274 /** 13275 * DataTables settings object - this holds all the information needed for a 13276 * given table, including configuration, data and current application of the 13277 * table options. DataTables does not have a single instance for each DataTable 13278 * with the settings attached to that instance, but rather instances of the 13279 * DataTable "class" are created on-the-fly as needed (typically by a 13280 * $().dataTable() call) and the settings object is then applied to that 13281 * instance. 13282 * 13283 * Note that this object is related to {@link DataTable.defaults} but this 13284 * one is the internal data store for DataTables's cache of columns. It should 13285 * NOT be manipulated outside of DataTables. Any configuration should be done 13286 * through the initialisation options. 13287 * @namespace 13288 * @todo Really should attach the settings object to individual instances so we 13289 * don't need to create new instances on each $().dataTable() call (if the 13290 * table already exists). It would also save passing oSettings around and 13291 * into every single function. However, this is a very significant 13292 * architecture change for DataTables and will almost certainly break 13293 * backwards compatibility with older installations. This is something that 13294 * will be done in 2.0. 13295 */ 13296 DataTable.models.oSettings = { 13297 /** 13298 * Primary features of DataTables and their enablement state. 13299 * @namespace 13300 */ 13301 "oFeatures": { 13302 13303 /** 13304 * Flag to say if DataTables should automatically try to calculate the 13305 * optimum table and columns widths (true) or not (false). 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 "bAutoWidth": null, 13311 13312 /** 13313 * Delay the creation of TR and TD elements until they are actually 13314 * needed by a driven page draw. This can give a significant speed 13315 * increase for Ajax source and Javascript source data, but makes no 13316 * difference at all for DOM and server-side processing tables. 13317 * Note that this parameter will be set by the initialisation routine. To 13318 * set a default use {@link DataTable.defaults}. 13319 * @type boolean 13320 */ 13321 "bDeferRender": null, 13322 13323 /** 13324 * Enable filtering on the table or not. Note that if this is disabled 13325 * then there is no filtering at all on the table, including fnFilter. 13326 * To just remove the filtering input use sDom and remove the 'f' option. 13327 * Note that this parameter will be set by the initialisation routine. To 13328 * set a default use {@link DataTable.defaults}. 13329 * @type boolean 13330 */ 13331 "bFilter": null, 13332 13333 /** 13334 * Table information element (the 'Showing x of y records' div) enable 13335 * flag. 13336 * Note that this parameter will be set by the initialisation routine. To 13337 * set a default use {@link DataTable.defaults}. 13338 * @type boolean 13339 */ 13340 "bInfo": null, 13341 13342 /** 13343 * Present a user control allowing the end user to change the page size 13344 * when pagination is enabled. 13345 * Note that this parameter will be set by the initialisation routine. To 13346 * set a default use {@link DataTable.defaults}. 13347 * @type boolean 13348 */ 13349 "bLengthChange": null, 13350 13351 /** 13352 * Pagination enabled or not. Note that if this is disabled then length 13353 * changing must also be disabled. 13354 * Note that this parameter will be set by the initialisation routine. To 13355 * set a default use {@link DataTable.defaults}. 13356 * @type boolean 13357 */ 13358 "bPaginate": null, 13359 13360 /** 13361 * Processing indicator enable flag whenever DataTables is enacting a 13362 * user request - typically an Ajax request for server-side processing. 13363 * Note that this parameter will be set by the initialisation routine. To 13364 * set a default use {@link DataTable.defaults}. 13365 * @type boolean 13366 */ 13367 "bProcessing": null, 13368 13369 /** 13370 * Server-side processing enabled flag - when enabled DataTables will 13371 * get all data from the server for every draw - there is no filtering, 13372 * sorting or paging done on the client-side. 13373 * Note that this parameter will be set by the initialisation routine. To 13374 * set a default use {@link DataTable.defaults}. 13375 * @type boolean 13376 */ 13377 "bServerSide": null, 13378 13379 /** 13380 * Sorting enablement flag. 13381 * Note that this parameter will be set by the initialisation routine. To 13382 * set a default use {@link DataTable.defaults}. 13383 * @type boolean 13384 */ 13385 "bSort": null, 13386 13387 /** 13388 * Multi-column sorting 13389 * Note that this parameter will be set by the initialisation routine. To 13390 * set a default use {@link DataTable.defaults}. 13391 * @type boolean 13392 */ 13393 "bSortMulti": null, 13394 13395 /** 13396 * Apply a class to the columns which are being sorted to provide a 13397 * visual highlight or not. This can slow things down when enabled since 13398 * there is a lot of DOM interaction. 13399 * Note that this parameter will be set by the initialisation routine. To 13400 * set a default use {@link DataTable.defaults}. 13401 * @type boolean 13402 */ 13403 "bSortClasses": null, 13404 13405 /** 13406 * State saving enablement flag. 13407 * Note that this parameter will be set by the initialisation routine. To 13408 * set a default use {@link DataTable.defaults}. 13409 * @type boolean 13410 */ 13411 "bStateSave": null 13412 }, 13413 13414 13415 /** 13416 * Scrolling settings for a table. 13417 * @namespace 13418 */ 13419 "oScroll": { 13420 /** 13421 * When the table is shorter in height than sScrollY, collapse the 13422 * table container down to the height of the table (when true). 13423 * Note that this parameter will be set by the initialisation routine. To 13424 * set a default use {@link DataTable.defaults}. 13425 * @type boolean 13426 */ 13427 "bCollapse": null, 13428 13429 /** 13430 * Width of the scrollbar for the web-browser's platform. Calculated 13431 * during table initialisation. 13432 * @type int 13433 * @default 0 13434 */ 13435 "iBarWidth": 0, 13436 13437 /** 13438 * Viewport width for horizontal scrolling. Horizontal scrolling is 13439 * disabled if an empty string. 13440 * Note that this parameter will be set by the initialisation routine. To 13441 * set a default use {@link DataTable.defaults}. 13442 * @type string 13443 */ 13444 "sX": null, 13445 13446 /** 13447 * Width to expand the table to when using x-scrolling. Typically you 13448 * should not need to use this. 13449 * Note that this parameter will be set by the initialisation routine. To 13450 * set a default use {@link DataTable.defaults}. 13451 * @type string 13452 * @deprecated 13453 */ 13454 "sXInner": null, 13455 13456 /** 13457 * Viewport height for vertical scrolling. Vertical scrolling is disabled 13458 * if an empty string. 13459 * Note that this parameter will be set by the initialisation routine. To 13460 * set a default use {@link DataTable.defaults}. 13461 * @type string 13462 */ 13463 "sY": null 13464 }, 13465 13466 /** 13467 * Language information for the table. 13468 * @namespace 13469 * @extends DataTable.defaults.oLanguage 13470 */ 13471 "oLanguage": { 13472 /** 13473 * Information callback function. See 13474 * {@link DataTable.defaults.fnInfoCallback} 13475 * @type function 13476 * @default null 13477 */ 13478 "fnInfoCallback": null 13479 }, 13480 13481 /** 13482 * Browser support parameters 13483 * @namespace 13484 */ 13485 "oBrowser": { 13486 /** 13487 * Indicate if the browser incorrectly calculates width:100% inside a 13488 * scrolling element (IE6/7) 13489 * @type boolean 13490 * @default false 13491 */ 13492 "bScrollOversize": false, 13493 13494 /** 13495 * Determine if the vertical scrollbar is on the right or left of the 13496 * scrolling container - needed for rtl language layout, although not 13497 * all browsers move the scrollbar (Safari). 13498 * @type boolean 13499 * @default false 13500 */ 13501 "bScrollbarLeft": false, 13502 13503 /** 13504 * Flag for if `getBoundingClientRect` is fully supported or not 13505 * @type boolean 13506 * @default false 13507 */ 13508 "bBounding": false, 13509 13510 /** 13511 * Browser scrollbar width 13512 * @type integer 13513 * @default 0 13514 */ 13515 "barWidth": 0 13516 }, 13517 13518 13519 "ajax": null, 13520 13521 13522 /** 13523 * Array referencing the nodes which are used for the features. The 13524 * parameters of this object match what is allowed by sDom - i.e. 13525 * <ul> 13526 * <li>'l' - Length changing</li> 13527 * <li>'f' - Filtering input</li> 13528 * <li>'t' - The table!</li> 13529 * <li>'i' - Information</li> 13530 * <li>'p' - Pagination</li> 13531 * <li>'r' - pRocessing</li> 13532 * </ul> 13533 * @type array 13534 * @default [] 13535 */ 13536 "aanFeatures": [], 13537 13538 /** 13539 * Store data information - see {@link DataTable.models.oRow} for detailed 13540 * information. 13541 * @type array 13542 * @default [] 13543 */ 13544 "aoData": [], 13545 13546 /** 13547 * Array of indexes which are in the current display (after filtering etc) 13548 * @type array 13549 * @default [] 13550 */ 13551 "aiDisplay": [], 13552 13553 /** 13554 * Array of indexes for display - no filtering 13555 * @type array 13556 * @default [] 13557 */ 13558 "aiDisplayMaster": [], 13559 13560 /** 13561 * Map of row ids to data indexes 13562 * @type object 13563 * @default {} 13564 */ 13565 "aIds": {}, 13566 13567 /** 13568 * Store information about each column that is in use 13569 * @type array 13570 * @default [] 13571 */ 13572 "aoColumns": [], 13573 13574 /** 13575 * Store information about the table's header 13576 * @type array 13577 * @default [] 13578 */ 13579 "aoHeader": [], 13580 13581 /** 13582 * Store information about the table's footer 13583 * @type array 13584 * @default [] 13585 */ 13586 "aoFooter": [], 13587 13588 /** 13589 * Store the applied global search information in case we want to force a 13590 * research or compare the old search to a new one. 13591 * Note that this parameter will be set by the initialisation routine. To 13592 * set a default use {@link DataTable.defaults}. 13593 * @namespace 13594 * @extends DataTable.models.oSearch 13595 */ 13596 "oPreviousSearch": {}, 13597 13598 /** 13599 * Store the applied search for each column - see 13600 * {@link DataTable.models.oSearch} for the format that is used for the 13601 * filtering information for each column. 13602 * @type array 13603 * @default [] 13604 */ 13605 "aoPreSearchCols": [], 13606 13607 /** 13608 * Sorting that is applied to the table. Note that the inner arrays are 13609 * used in the following manner: 13610 * <ul> 13611 * <li>Index 0 - column number</li> 13612 * <li>Index 1 - current sorting direction</li> 13613 * </ul> 13614 * Note that this parameter will be set by the initialisation routine. To 13615 * set a default use {@link DataTable.defaults}. 13616 * @type array 13617 * @todo These inner arrays should really be objects 13618 */ 13619 "aaSorting": null, 13620 13621 /** 13622 * Sorting that is always applied to the table (i.e. prefixed in front of 13623 * aaSorting). 13624 * Note that this parameter will be set by the initialisation routine. To 13625 * set a default use {@link DataTable.defaults}. 13626 * @type array 13627 * @default [] 13628 */ 13629 "aaSortingFixed": [], 13630 13631 /** 13632 * Classes to use for the striping of a table. 13633 * Note that this parameter will be set by the initialisation routine. To 13634 * set a default use {@link DataTable.defaults}. 13635 * @type array 13636 * @default [] 13637 */ 13638 "asStripeClasses": null, 13639 13640 /** 13641 * If restoring a table - we should restore its striping classes as well 13642 * @type array 13643 * @default [] 13644 */ 13645 "asDestroyStripes": [], 13646 13647 /** 13648 * If restoring a table - we should restore its width 13649 * @type int 13650 * @default 0 13651 */ 13652 "sDestroyWidth": 0, 13653 13654 /** 13655 * Callback functions array for every time a row is inserted (i.e. on a draw). 13656 * @type array 13657 * @default [] 13658 */ 13659 "aoRowCallback": [], 13660 13661 /** 13662 * Callback functions for the header on each draw. 13663 * @type array 13664 * @default [] 13665 */ 13666 "aoHeaderCallback": [], 13667 13668 /** 13669 * Callback function for the footer on each draw. 13670 * @type array 13671 * @default [] 13672 */ 13673 "aoFooterCallback": [], 13674 13675 /** 13676 * Array of callback functions for draw callback functions 13677 * @type array 13678 * @default [] 13679 */ 13680 "aoDrawCallback": [], 13681 13682 /** 13683 * Array of callback functions for row created function 13684 * @type array 13685 * @default [] 13686 */ 13687 "aoRowCreatedCallback": [], 13688 13689 /** 13690 * Callback functions for just before the table is redrawn. A return of 13691 * false will be used to cancel the draw. 13692 * @type array 13693 * @default [] 13694 */ 13695 "aoPreDrawCallback": [], 13696 13697 /** 13698 * Callback functions for when the table has been initialised. 13699 * @type array 13700 * @default [] 13701 */ 13702 "aoInitComplete": [], 13703 13704 13705 /** 13706 * Callbacks for modifying the settings to be stored for state saving, prior to 13707 * saving state. 13708 * @type array 13709 * @default [] 13710 */ 13711 "aoStateSaveParams": [], 13712 13713 /** 13714 * Callbacks for modifying the settings that have been stored for state saving 13715 * prior to using the stored values to restore the state. 13716 * @type array 13717 * @default [] 13718 */ 13719 "aoStateLoadParams": [], 13720 13721 /** 13722 * Callbacks for operating on the settings object once the saved state has been 13723 * loaded 13724 * @type array 13725 * @default [] 13726 */ 13727 "aoStateLoaded": [], 13728 13729 /** 13730 * Cache the table ID for quick access 13731 * @type string 13732 * @default <i>Empty string</i> 13733 */ 13734 "sTableId": "", 13735 13736 /** 13737 * The TABLE node for the main table 13738 * @type node 13739 * @default null 13740 */ 13741 "nTable": null, 13742 13743 /** 13744 * Permanent ref to the thead element 13745 * @type node 13746 * @default null 13747 */ 13748 "nTHead": null, 13749 13750 /** 13751 * Permanent ref to the tfoot element - if it exists 13752 * @type node 13753 * @default null 13754 */ 13755 "nTFoot": null, 13756 13757 /** 13758 * Permanent ref to the tbody element 13759 * @type node 13760 * @default null 13761 */ 13762 "nTBody": null, 13763 13764 /** 13765 * Cache the wrapper node (contains all DataTables controlled elements) 13766 * @type node 13767 * @default null 13768 */ 13769 "nTableWrapper": null, 13770 13771 /** 13772 * Indicate if when using server-side processing the loading of data 13773 * should be deferred until the second draw. 13774 * Note that this parameter will be set by the initialisation routine. To 13775 * set a default use {@link DataTable.defaults}. 13776 * @type boolean 13777 * @default false 13778 */ 13779 "bDeferLoading": false, 13780 13781 /** 13782 * Indicate if all required information has been read in 13783 * @type boolean 13784 * @default false 13785 */ 13786 "bInitialised": false, 13787 13788 /** 13789 * Information about open rows. Each object in the array has the parameters 13790 * 'nTr' and 'nParent' 13791 * @type array 13792 * @default [] 13793 */ 13794 "aoOpenRows": [], 13795 13796 /** 13797 * Dictate the positioning of DataTables' control elements - see 13798 * {@link DataTable.model.oInit.sDom}. 13799 * Note that this parameter will be set by the initialisation routine. To 13800 * set a default use {@link DataTable.defaults}. 13801 * @type string 13802 * @default null 13803 */ 13804 "sDom": null, 13805 13806 /** 13807 * Search delay (in mS) 13808 * @type integer 13809 * @default null 13810 */ 13811 "searchDelay": null, 13812 13813 /** 13814 * Which type of pagination should be used. 13815 * Note that this parameter will be set by the initialisation routine. To 13816 * set a default use {@link DataTable.defaults}. 13817 * @type string 13818 * @default two_button 13819 */ 13820 "sPaginationType": "two_button", 13821 13822 /** 13823 * The state duration (for `stateSave`) in seconds. 13824 * Note that this parameter will be set by the initialisation routine. To 13825 * set a default use {@link DataTable.defaults}. 13826 * @type int 13827 * @default 0 13828 */ 13829 "iStateDuration": 0, 13830 13831 /** 13832 * Array of callback functions for state saving. Each array element is an 13833 * object with the following parameters: 13834 * <ul> 13835 * <li>function:fn - function to call. Takes two parameters, oSettings 13836 * and the JSON string to save that has been thus far created. Returns 13837 * a JSON string to be inserted into a json object 13838 * (i.e. '"param": [ 0, 1, 2]')</li> 13839 * <li>string:sName - name of callback</li> 13840 * </ul> 13841 * @type array 13842 * @default [] 13843 */ 13844 "aoStateSave": [], 13845 13846 /** 13847 * Array of callback functions for state loading. Each array element is an 13848 * object with the following parameters: 13849 * <ul> 13850 * <li>function:fn - function to call. Takes two parameters, oSettings 13851 * and the object stored. May return false to cancel state loading</li> 13852 * <li>string:sName - name of callback</li> 13853 * </ul> 13854 * @type array 13855 * @default [] 13856 */ 13857 "aoStateLoad": [], 13858 13859 /** 13860 * State that was saved. Useful for back reference 13861 * @type object 13862 * @default null 13863 */ 13864 "oSavedState": null, 13865 13866 /** 13867 * State that was loaded. Useful for back reference 13868 * @type object 13869 * @default null 13870 */ 13871 "oLoadedState": null, 13872 13873 /** 13874 * Source url for AJAX data for the table. 13875 * Note that this parameter will be set by the initialisation routine. To 13876 * set a default use {@link DataTable.defaults}. 13877 * @type string 13878 * @default null 13879 */ 13880 "sAjaxSource": null, 13881 13882 /** 13883 * Property from a given object from which to read the table data from. This 13884 * can be an empty string (when not server-side processing), in which case 13885 * it is assumed an an array is given directly. 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 "sAjaxDataProp": null, 13891 13892 /** 13893 * The last jQuery XHR object that was used for server-side data gathering. 13894 * This can be used for working with the XHR information in one of the 13895 * callbacks 13896 * @type object 13897 * @default null 13898 */ 13899 "jqXHR": null, 13900 13901 /** 13902 * JSON returned from the server in the last Ajax request 13903 * @type object 13904 * @default undefined 13905 */ 13906 "json": undefined, 13907 13908 /** 13909 * Data submitted as part of the last Ajax request 13910 * @type object 13911 * @default undefined 13912 */ 13913 "oAjaxData": undefined, 13914 13915 /** 13916 * Function to get the server-side data. 13917 * Note that this parameter will be set by the initialisation routine. To 13918 * set a default use {@link DataTable.defaults}. 13919 * @type function 13920 */ 13921 "fnServerData": null, 13922 13923 /** 13924 * Functions which are called prior to sending an Ajax request so extra 13925 * parameters can easily be sent to the server 13926 * @type array 13927 * @default [] 13928 */ 13929 "aoServerParams": [], 13930 13931 /** 13932 * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if 13933 * required). 13934 * Note that this parameter will be set by the initialisation routine. To 13935 * set a default use {@link DataTable.defaults}. 13936 * @type string 13937 */ 13938 "sServerMethod": null, 13939 13940 /** 13941 * Format numbers for display. 13942 * Note that this parameter will be set by the initialisation routine. To 13943 * set a default use {@link DataTable.defaults}. 13944 * @type function 13945 */ 13946 "fnFormatNumber": null, 13947 13948 /** 13949 * List of options that can be used for the user selectable length menu. 13950 * Note that this parameter will be set by the initialisation routine. To 13951 * set a default use {@link DataTable.defaults}. 13952 * @type array 13953 * @default [] 13954 */ 13955 "aLengthMenu": null, 13956 13957 /** 13958 * Counter for the draws that the table does. Also used as a tracker for 13959 * server-side processing 13960 * @type int 13961 * @default 0 13962 */ 13963 "iDraw": 0, 13964 13965 /** 13966 * Indicate if a redraw is being done - useful for Ajax 13967 * @type boolean 13968 * @default false 13969 */ 13970 "bDrawing": false, 13971 13972 /** 13973 * Draw index (iDraw) of the last error when parsing the returned data 13974 * @type int 13975 * @default -1 13976 */ 13977 "iDrawError": -1, 13978 13979 /** 13980 * Paging display length 13981 * @type int 13982 * @default 10 13983 */ 13984 "_iDisplayLength": 10, 13985 13986 /** 13987 * Paging start point - aiDisplay index 13988 * @type int 13989 * @default 0 13990 */ 13991 "_iDisplayStart": 0, 13992 13993 /** 13994 * Server-side processing - number of records in the result set 13995 * (i.e. before filtering), Use fnRecordsTotal rather than 13996 * this property to get the value of the number of records, regardless of 13997 * the server-side processing setting. 13998 * @type int 13999 * @default 0 14000 * @private 14001 */ 14002 "_iRecordsTotal": 0, 14003 14004 /** 14005 * Server-side processing - number of records in the current display set 14006 * (i.e. after filtering). Use fnRecordsDisplay rather than 14007 * this property to get the value of the number of records, regardless of 14008 * the server-side processing setting. 14009 * @type boolean 14010 * @default 0 14011 * @private 14012 */ 14013 "_iRecordsDisplay": 0, 14014 14015 /** 14016 * The classes to use for the table 14017 * @type object 14018 * @default {} 14019 */ 14020 "oClasses": {}, 14021 14022 /** 14023 * Flag attached to the settings object so you can check in the draw 14024 * callback if filtering has been done in the draw. Deprecated in favour of 14025 * events. 14026 * @type boolean 14027 * @default false 14028 * @deprecated 14029 */ 14030 "bFiltered": false, 14031 14032 /** 14033 * Flag attached to the settings object so you can check in the draw 14034 * callback if sorting has been done in the draw. Deprecated in favour of 14035 * events. 14036 * @type boolean 14037 * @default false 14038 * @deprecated 14039 */ 14040 "bSorted": false, 14041 14042 /** 14043 * Indicate that if multiple rows are in the header and there is more than 14044 * one unique cell per column, if the top one (true) or bottom one (false) 14045 * should be used for sorting / title by DataTables. 14046 * Note that this parameter will be set by the initialisation routine. To 14047 * set a default use {@link DataTable.defaults}. 14048 * @type boolean 14049 */ 14050 "bSortCellsTop": null, 14051 14052 /** 14053 * Initialisation object that is used for the table 14054 * @type object 14055 * @default null 14056 */ 14057 "oInit": null, 14058 14059 /** 14060 * Destroy callback functions - for plug-ins to attach themselves to the 14061 * destroy so they can clean up markup and events. 14062 * @type array 14063 * @default [] 14064 */ 14065 "aoDestroyCallback": [], 14066 14067 14068 /** 14069 * Get the number of records in the current record set, before filtering 14070 * @type function 14071 */ 14072 "fnRecordsTotal": function () 14073 { 14074 return _fnDataSource( this ) == 'ssp' ? 14075 this._iRecordsTotal * 1 : 14076 this.aiDisplayMaster.length; 14077 }, 14078 14079 /** 14080 * Get the number of records in the current record set, after filtering 14081 * @type function 14082 */ 14083 "fnRecordsDisplay": function () 14084 { 14085 return _fnDataSource( this ) == 'ssp' ? 14086 this._iRecordsDisplay * 1 : 14087 this.aiDisplay.length; 14088 }, 14089 14090 /** 14091 * Get the display end point - aiDisplay index 14092 * @type function 14093 */ 14094 "fnDisplayEnd": function () 14095 { 14096 var 14097 len = this._iDisplayLength, 14098 start = this._iDisplayStart, 14099 calc = start + len, 14100 records = this.aiDisplay.length, 14101 features = this.oFeatures, 14102 paginate = features.bPaginate; 14103 14104 if ( features.bServerSide ) { 14105 return paginate === false || len === -1 ? 14106 start + records : 14107 Math.min( start+len, this._iRecordsDisplay ); 14108 } 14109 else { 14110 return ! paginate || calc>records || len===-1 ? 14111 records : 14112 calc; 14113 } 14114 }, 14115 14116 /** 14117 * The DataTables object for this table 14118 * @type object 14119 * @default null 14120 */ 14121 "oInstance": null, 14122 14123 /** 14124 * Unique identifier for each instance of the DataTables object. If there 14125 * is an ID on the table node, then it takes that value, otherwise an 14126 * incrementing internal counter is used. 14127 * @type string 14128 * @default null 14129 */ 14130 "sInstance": null, 14131 14132 /** 14133 * tabindex attribute value that is added to DataTables control elements, allowing 14134 * keyboard navigation of the table and its controls. 14135 */ 14136 "iTabIndex": 0, 14137 14138 /** 14139 * DIV container for the footer scrolling table if scrolling 14140 */ 14141 "nScrollHead": null, 14142 14143 /** 14144 * DIV container for the footer scrolling table if scrolling 14145 */ 14146 "nScrollFoot": null, 14147 14148 /** 14149 * Last applied sort 14150 * @type array 14151 * @default [] 14152 */ 14153 "aLastSort": [], 14154 14155 /** 14156 * Stored plug-in instances 14157 * @type object 14158 * @default {} 14159 */ 14160 "oPlugins": {}, 14161 14162 /** 14163 * Function used to get a row's id from the row's data 14164 * @type function 14165 * @default null 14166 */ 14167 "rowIdFn": null, 14168 14169 /** 14170 * Data location where to store a row's id 14171 * @type string 14172 * @default null 14173 */ 14174 "rowId": null 14175 }; 14176 14177 /** 14178 * Extension object for DataTables that is used to provide all extension 14179 * options. 14180 * 14181 * Note that the `DataTable.ext` object is available through 14182 * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is 14183 * also aliased to `jQuery.fn.dataTableExt` for historic reasons. 14184 * @namespace 14185 * @extends DataTable.models.ext 14186 */ 14187 14188 14189 /** 14190 * DataTables extensions 14191 * 14192 * This namespace acts as a collection area for plug-ins that can be used to 14193 * extend DataTables capabilities. Indeed many of the build in methods 14194 * use this method to provide their own capabilities (sorting methods for 14195 * example). 14196 * 14197 * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy 14198 * reasons 14199 * 14200 * @namespace 14201 */ 14202 DataTable.ext = _ext = { 14203 /** 14204 * Buttons. For use with the Buttons extension for DataTables. This is 14205 * defined here so other extensions can define buttons regardless of load 14206 * order. It is _not_ used by DataTables core. 14207 * 14208 * @type object 14209 * @default {} 14210 */ 14211 buttons: {}, 14212 14213 14214 /** 14215 * Element class names 14216 * 14217 * @type object 14218 * @default {} 14219 */ 14220 classes: {}, 14221 14222 14223 /** 14224 * DataTables build type (expanded by the download builder) 14225 * 14226 * @type string 14227 */ 14228 builder: "-source-", 14229 14230 14231 /** 14232 * Error reporting. 14233 * 14234 * How should DataTables report an error. Can take the value 'alert', 14235 * 'throw', 'none' or a function. 14236 * 14237 * @type string|function 14238 * @default alert 14239 */ 14240 errMode: "alert", 14241 14242 14243 /** 14244 * Feature plug-ins. 14245 * 14246 * This is an array of objects which describe the feature plug-ins that are 14247 * available to DataTables. These feature plug-ins are then available for 14248 * use through the `dom` initialisation option. 14249 * 14250 * Each feature plug-in is described by an object which must have the 14251 * following properties: 14252 * 14253 * * `fnInit` - function that is used to initialise the plug-in, 14254 * * `cFeature` - a character so the feature can be enabled by the `dom` 14255 * instillation option. This is case sensitive. 14256 * 14257 * The `fnInit` function has the following input parameters: 14258 * 14259 * 1. `{object}` DataTables settings object: see 14260 * {@link DataTable.models.oSettings} 14261 * 14262 * And the following return is expected: 14263 * 14264 * * {node|null} The element which contains your feature. Note that the 14265 * return may also be void if your plug-in does not require to inject any 14266 * DOM elements into DataTables control (`dom`) - for example this might 14267 * be useful when developing a plug-in which allows table control via 14268 * keyboard entry 14269 * 14270 * @type array 14271 * 14272 * @example 14273 * $.fn.dataTable.ext.features.push( { 14274 * "fnInit": function( oSettings ) { 14275 * return new TableTools( { "oDTSettings": oSettings } ); 14276 * }, 14277 * "cFeature": "T" 14278 * } ); 14279 */ 14280 feature: [], 14281 14282 14283 /** 14284 * Row searching. 14285 * 14286 * This method of searching is complimentary to the default type based 14287 * searching, and a lot more comprehensive as it allows you complete control 14288 * over the searching logic. Each element in this array is a function 14289 * (parameters described below) that is called for every row in the table, 14290 * and your logic decides if it should be included in the searching data set 14291 * or not. 14292 * 14293 * Searching functions have the following input parameters: 14294 * 14295 * 1. `{object}` DataTables settings object: see 14296 * {@link DataTable.models.oSettings} 14297 * 2. `{array|object}` Data for the row to be processed (same as the 14298 * original format that was passed in as the data source, or an array 14299 * from a DOM data source 14300 * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which 14301 * can be useful to retrieve the `TR` element if you need DOM interaction. 14302 * 14303 * And the following return is expected: 14304 * 14305 * * {boolean} Include the row in the searched result set (true) or not 14306 * (false) 14307 * 14308 * Note that as with the main search ability in DataTables, technically this 14309 * is "filtering", since it is subtractive. However, for consistency in 14310 * naming we call it searching here. 14311 * 14312 * @type array 14313 * @default [] 14314 * 14315 * @example 14316 * // The following example shows custom search being applied to the 14317 * // fourth column (i.e. the data[3] index) based on two input values 14318 * // from the end-user, matching the data in a certain range. 14319 * $.fn.dataTable.ext.search.push( 14320 * function( settings, data, dataIndex ) { 14321 * var min = document.getElementById('min').value * 1; 14322 * var max = document.getElementById('max').value * 1; 14323 * var version = data[3] == "-" ? 0 : data[3]*1; 14324 * 14325 * if ( min == "" && max == "" ) { 14326 * return true; 14327 * } 14328 * else if ( min == "" && version < max ) { 14329 * return true; 14330 * } 14331 * else if ( min < version && "" == max ) { 14332 * return true; 14333 * } 14334 * else if ( min < version && version < max ) { 14335 * return true; 14336 * } 14337 * return false; 14338 * } 14339 * ); 14340 */ 14341 search: [], 14342 14343 14344 /** 14345 * Selector extensions 14346 * 14347 * The `selector` option can be used to extend the options available for the 14348 * selector modifier options (`selector-modifier` object data type) that 14349 * each of the three built in selector types offer (row, column and cell + 14350 * their plural counterparts). For example the Select extension uses this 14351 * mechanism to provide an option to select only rows, columns and cells 14352 * that have been marked as selected by the end user (`{selected: true}`), 14353 * which can be used in conjunction with the existing built in selector 14354 * options. 14355 * 14356 * Each property is an array to which functions can be pushed. The functions 14357 * take three attributes: 14358 * 14359 * * Settings object for the host table 14360 * * Options object (`selector-modifier` object type) 14361 * * Array of selected item indexes 14362 * 14363 * The return is an array of the resulting item indexes after the custom 14364 * selector has been applied. 14365 * 14366 * @type object 14367 */ 14368 selector: { 14369 cell: [], 14370 column: [], 14371 row: [] 14372 }, 14373 14374 14375 /** 14376 * Internal functions, exposed for used in plug-ins. 14377 * 14378 * Please note that you should not need to use the internal methods for 14379 * anything other than a plug-in (and even then, try to avoid if possible). 14380 * The internal function may change between releases. 14381 * 14382 * @type object 14383 * @default {} 14384 */ 14385 internal: {}, 14386 14387 14388 /** 14389 * Legacy configuration options. Enable and disable legacy options that 14390 * are available in DataTables. 14391 * 14392 * @type object 14393 */ 14394 legacy: { 14395 /** 14396 * Enable / disable DataTables 1.9 compatible server-side processing 14397 * requests 14398 * 14399 * @type boolean 14400 * @default null 14401 */ 14402 ajax: null 14403 }, 14404 14405 14406 /** 14407 * Pagination plug-in methods. 14408 * 14409 * Each entry in this object is a function and defines which buttons should 14410 * be shown by the pagination rendering method that is used for the table: 14411 * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the 14412 * buttons are displayed in the document, while the functions here tell it 14413 * what buttons to display. This is done by returning an array of button 14414 * descriptions (what each button will do). 14415 * 14416 * Pagination types (the four built in options and any additional plug-in 14417 * options defined here) can be used through the `paginationType` 14418 * initialisation parameter. 14419 * 14420 * The functions defined take two parameters: 14421 * 14422 * 1. `{int} page` The current page index 14423 * 2. `{int} pages` The number of pages in the table 14424 * 14425 * Each function is expected to return an array where each element of the 14426 * array can be one of: 14427 * 14428 * * `first` - Jump to first page when activated 14429 * * `last` - Jump to last page when activated 14430 * * `previous` - Show previous page when activated 14431 * * `next` - Show next page when activated 14432 * * `{int}` - Show page of the index given 14433 * * `{array}` - A nested array containing the above elements to add a 14434 * containing 'DIV' element (might be useful for styling). 14435 * 14436 * Note that DataTables v1.9- used this object slightly differently whereby 14437 * an object with two functions would be defined for each plug-in. That 14438 * ability is still supported by DataTables 1.10+ to provide backwards 14439 * compatibility, but this option of use is now decremented and no longer 14440 * documented in DataTables 1.10+. 14441 * 14442 * @type object 14443 * @default {} 14444 * 14445 * @example 14446 * // Show previous, next and current page buttons only 14447 * $.fn.dataTableExt.oPagination.current = function ( page, pages ) { 14448 * return [ 'previous', page, 'next' ]; 14449 * }; 14450 */ 14451 pager: {}, 14452 14453 14454 renderer: { 14455 pageButton: {}, 14456 header: {} 14457 }, 14458 14459 14460 /** 14461 * Ordering plug-ins - custom data source 14462 * 14463 * The extension options for ordering of data available here is complimentary 14464 * to the default type based ordering that DataTables typically uses. It 14465 * allows much greater control over the the data that is being used to 14466 * order a column, but is necessarily therefore more complex. 14467 * 14468 * This type of ordering is useful if you want to do ordering based on data 14469 * live from the DOM (for example the contents of an 'input' element) rather 14470 * than just the static string that DataTables knows of. 14471 * 14472 * The way these plug-ins work is that you create an array of the values you 14473 * wish to be ordering for the column in question and then return that 14474 * array. The data in the array much be in the index order of the rows in 14475 * the table (not the currently ordering order!). Which order data gathering 14476 * function is run here depends on the `dt-init columns.orderDataType` 14477 * parameter that is used for the column (if any). 14478 * 14479 * The functions defined take two parameters: 14480 * 14481 * 1. `{object}` DataTables settings object: see 14482 * {@link DataTable.models.oSettings} 14483 * 2. `{int}` Target column index 14484 * 14485 * Each function is expected to return an array: 14486 * 14487 * * `{array}` Data for the column to be ordering upon 14488 * 14489 * @type array 14490 * 14491 * @example 14492 * // Ordering using `input` node values 14493 * $.fn.dataTable.ext.order['dom-text'] = function ( settings, col ) 14494 * { 14495 * return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) { 14496 * return $('input', td).val(); 14497 * } ); 14498 * } 14499 */ 14500 order: {}, 14501 14502 14503 /** 14504 * Type based plug-ins. 14505 * 14506 * Each column in DataTables has a type assigned to it, either by automatic 14507 * detection or by direct assignment using the `type` option for the column. 14508 * The type of a column will effect how it is ordering and search (plug-ins 14509 * can also make use of the column type if required). 14510 * 14511 * @namespace 14512 */ 14513 type: { 14514 /** 14515 * Type detection functions. 14516 * 14517 * The functions defined in this object are used to automatically detect 14518 * a column's type, making initialisation of DataTables super easy, even 14519 * when complex data is in the table. 14520 * 14521 * The functions defined take two parameters: 14522 * 14523 * 1. `{*}` Data from the column cell to be analysed 14524 * 2. `{settings}` DataTables settings object. This can be used to 14525 * perform context specific type detection - for example detection 14526 * based on language settings such as using a comma for a decimal 14527 * place. Generally speaking the options from the settings will not 14528 * be required 14529 * 14530 * Each function is expected to return: 14531 * 14532 * * `{string|null}` Data type detected, or null if unknown (and thus 14533 * pass it on to the other type detection functions. 14534 * 14535 * @type array 14536 * 14537 * @example 14538 * // Currency type detection plug-in: 14539 * $.fn.dataTable.ext.type.detect.push( 14540 * function ( data, settings ) { 14541 * // Check the numeric part 14542 * if ( ! data.substring(1).match(/[0-9]/) ) { 14543 * return null; 14544 * } 14545 * 14546 * // Check prefixed by currency 14547 * if ( data.charAt(0) == '$' || data.charAt(0) == '£' ) { 14548 * return 'currency'; 14549 * } 14550 * return null; 14551 * } 14552 * ); 14553 */ 14554 detect: [], 14555 14556 14557 /** 14558 * Type based search formatting. 14559 * 14560 * The type based searching functions can be used to pre-format the 14561 * data to be search on. For example, it can be used to strip HTML 14562 * tags or to de-format telephone numbers for numeric only searching. 14563 * 14564 * Note that is a search is not defined for a column of a given type, 14565 * no search formatting will be performed. 14566 * 14567 * Pre-processing of searching data plug-ins - When you assign the sType 14568 * for a column (or have it automatically detected for you by DataTables 14569 * or a type detection plug-in), you will typically be using this for 14570 * custom sorting, but it can also be used to provide custom searching 14571 * by allowing you to pre-processing the data and returning the data in 14572 * the format that should be searched upon. This is done by adding 14573 * functions this object with a parameter name which matches the sType 14574 * for that target column. This is the corollary of <i>afnSortData</i> 14575 * for searching data. 14576 * 14577 * The functions defined take a single parameter: 14578 * 14579 * 1. `{*}` Data from the column cell to be prepared for searching 14580 * 14581 * Each function is expected to return: 14582 * 14583 * * `{string|null}` Formatted string that will be used for the searching. 14584 * 14585 * @type object 14586 * @default {} 14587 * 14588 * @example 14589 * $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) { 14590 * return d.replace(/\n/g," ").replace( /<.*?>/g, "" ); 14591 * } 14592 */ 14593 search: {}, 14594 14595 14596 /** 14597 * Type based ordering. 14598 * 14599 * The column type tells DataTables what ordering to apply to the table 14600 * when a column is sorted upon. The order for each type that is defined, 14601 * is defined by the functions available in this object. 14602 * 14603 * Each ordering option can be described by three properties added to 14604 * this object: 14605 * 14606 * * `{type}-pre` - Pre-formatting function 14607 * * `{type}-asc` - Ascending order function 14608 * * `{type}-desc` - Descending order function 14609 * 14610 * All three can be used together, only `{type}-pre` or only 14611 * `{type}-asc` and `{type}-desc` together. It is generally recommended 14612 * that only `{type}-pre` is used, as this provides the optimal 14613 * implementation in terms of speed, although the others are provided 14614 * for compatibility with existing Javascript sort functions. 14615 * 14616 * `{type}-pre`: Functions defined take a single parameter: 14617 * 14618 * 1. `{*}` Data from the column cell to be prepared for ordering 14619 * 14620 * And return: 14621 * 14622 * * `{*}` Data to be sorted upon 14623 * 14624 * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort 14625 * functions, taking two parameters: 14626 * 14627 * 1. `{*}` Data to compare to the second parameter 14628 * 2. `{*}` Data to compare to the first parameter 14629 * 14630 * And returning: 14631 * 14632 * * `{*}` Ordering match: <0 if first parameter should be sorted lower 14633 * than the second parameter, ===0 if the two parameters are equal and 14634 * >0 if the first parameter should be sorted height than the second 14635 * parameter. 14636 * 14637 * @type object 14638 * @default {} 14639 * 14640 * @example 14641 * // Numeric ordering of formatted numbers with a pre-formatter 14642 * $.extend( $.fn.dataTable.ext.type.order, { 14643 * "string-pre": function(x) { 14644 * a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" ); 14645 * return parseFloat( a ); 14646 * } 14647 * } ); 14648 * 14649 * @example 14650 * // Case-sensitive string ordering, with no pre-formatting method 14651 * $.extend( $.fn.dataTable.ext.order, { 14652 * "string-case-asc": function(x,y) { 14653 * return ((x < y) ? -1 : ((x > y) ? 1 : 0)); 14654 * }, 14655 * "string-case-desc": function(x,y) { 14656 * return ((x < y) ? 1 : ((x > y) ? -1 : 0)); 14657 * } 14658 * } ); 14659 */ 14660 order: {} 14661 }, 14662 14663 /** 14664 * Unique DataTables instance counter 14665 * 14666 * @type int 14667 * @private 14668 */ 14669 _unique: 0, 14670 14671 14672 // 14673 // Depreciated 14674 // The following properties are retained for backwards compatibility only. 14675 // The should not be used in new projects and will be removed in a future 14676 // version 14677 // 14678 14679 /** 14680 * Version check function. 14681 * @type function 14682 * @depreciated Since 1.10 14683 */ 14684 fnVersionCheck: DataTable.fnVersionCheck, 14685 14686 14687 /** 14688 * Index for what 'this' index API functions should use 14689 * @type int 14690 * @deprecated Since v1.10 14691 */ 14692 iApiIndex: 0, 14693 14694 14695 /** 14696 * jQuery UI class container 14697 * @type object 14698 * @deprecated Since v1.10 14699 */ 14700 oJUIClasses: {}, 14701 14702 14703 /** 14704 * Software version 14705 * @type string 14706 * @deprecated Since v1.10 14707 */ 14708 sVersion: DataTable.version 14709 }; 14710 14711 14712 // 14713 // Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts 14714 // 14715 $.extend( _ext, { 14716 afnFiltering: _ext.search, 14717 aTypes: _ext.type.detect, 14718 ofnSearch: _ext.type.search, 14719 oSort: _ext.type.order, 14720 afnSortData: _ext.order, 14721 aoFeatures: _ext.feature, 14722 oApi: _ext.internal, 14723 oStdClasses: _ext.classes, 14724 oPagination: _ext.pager 14725 } ); 14726 14727 14728 $.extend( DataTable.ext.classes, { 14729 "sTable": "dataTable", 14730 "sNoFooter": "no-footer", 14731 14732 /* Paging buttons */ 14733 "sPageButton": "paginate_button", 14734 "sPageButtonActive": "current", 14735 "sPageButtonDisabled": "disabled", 14736 14737 /* Striping classes */ 14738 "sStripeOdd": "odd", 14739 "sStripeEven": "even", 14740 14741 /* Empty row */ 14742 "sRowEmpty": "dataTables_empty", 14743 14744 /* Features */ 14745 "sWrapper": "dataTables_wrapper", 14746 "sFilter": "dataTables_filter", 14747 "sInfo": "dataTables_info", 14748 "sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */ 14749 "sLength": "dataTables_length", 14750 "sProcessing": "dataTables_processing", 14751 14752 /* Sorting */ 14753 "sSortAsc": "sorting_asc", 14754 "sSortDesc": "sorting_desc", 14755 "sSortable": "sorting", /* Sortable in both directions */ 14756 "sSortableAsc": "sorting_desc_disabled", 14757 "sSortableDesc": "sorting_asc_disabled", 14758 "sSortableNone": "sorting_disabled", 14759 "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */ 14760 14761 /* Filtering */ 14762 "sFilterInput": "", 14763 14764 /* Page length */ 14765 "sLengthSelect": "", 14766 14767 /* Scrolling */ 14768 "sScrollWrapper": "dataTables_scroll", 14769 "sScrollHead": "dataTables_scrollHead", 14770 "sScrollHeadInner": "dataTables_scrollHeadInner", 14771 "sScrollBody": "dataTables_scrollBody", 14772 "sScrollFoot": "dataTables_scrollFoot", 14773 "sScrollFootInner": "dataTables_scrollFootInner", 14774 14775 /* Misc */ 14776 "sHeaderTH": "", 14777 "sFooterTH": "", 14778 14779 // Deprecated 14780 "sSortJUIAsc": "", 14781 "sSortJUIDesc": "", 14782 "sSortJUI": "", 14783 "sSortJUIAscAllowed": "", 14784 "sSortJUIDescAllowed": "", 14785 "sSortJUIWrapper": "", 14786 "sSortIcon": "", 14787 "sJUIHeader": "", 14788 "sJUIFooter": "" 14789 } ); 14790 14791 14792 var extPagination = DataTable.ext.pager; 14793 14794 function _numbers ( page, pages ) { 14795 var 14796 numbers = [], 14797 buttons = extPagination.numbers_length, 14798 half = Math.floor( buttons / 2 ), 14799 i = 1; 14800 14801 if ( pages <= buttons ) { 14802 numbers = _range( 0, pages ); 14803 } 14804 else if ( page <= half ) { 14805 numbers = _range( 0, buttons-2 ); 14806 numbers.push( 'ellipsis' ); 14807 numbers.push( pages-1 ); 14808 } 14809 else if ( page >= pages - 1 - half ) { 14810 numbers = _range( pages-(buttons-2), pages ); 14811 numbers.splice( 0, 0, 'ellipsis' ); // no unshift in ie6 14812 numbers.splice( 0, 0, 0 ); 14813 } 14814 else { 14815 numbers = _range( page-half+2, page+half-1 ); 14816 numbers.push( 'ellipsis' ); 14817 numbers.push( pages-1 ); 14818 numbers.splice( 0, 0, 'ellipsis' ); 14819 numbers.splice( 0, 0, 0 ); 14820 } 14821 14822 numbers.DT_el = 'span'; 14823 return numbers; 14824 } 14825 14826 14827 $.extend( extPagination, { 14828 simple: function ( page, pages ) { 14829 return [ 'previous', 'next' ]; 14830 }, 14831 14832 full: function ( page, pages ) { 14833 return [ 'first', 'previous', 'next', 'last' ]; 14834 }, 14835 14836 numbers: function ( page, pages ) { 14837 return [ _numbers(page, pages) ]; 14838 }, 14839 14840 simple_numbers: function ( page, pages ) { 14841 return [ 'previous', _numbers(page, pages), 'next' ]; 14842 }, 14843 14844 full_numbers: function ( page, pages ) { 14845 return [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ]; 14846 }, 14847 14848 first_last_numbers: function (page, pages) { 14849 return ['first', _numbers(page, pages), 'last']; 14850 }, 14851 14852 // For testing and plug-ins to use 14853 _numbers: _numbers, 14854 14855 // Number of number buttons (including ellipsis) to show. _Must be odd!_ 14856 numbers_length: 7 14857 } ); 14858 14859 14860 $.extend( true, DataTable.ext.renderer, { 14861 pageButton: { 14862 _: function ( settings, host, idx, buttons, page, pages ) { 14863 var classes = settings.oClasses; 14864 var lang = settings.oLanguage.oPaginate; 14865 var aria = settings.oLanguage.oAria.paginate || {}; 14866 var btnDisplay, btnClass; 14867 14868 var attach = function( container, buttons ) { 14869 var i, ien, node, button
vendor: 7,650 bytes, lines 14869-15165
14869; 14870 var disabledClass = classes.sPageButtonDisabled; 14871 var clickHandler = function ( e ) { 14872 _fnPageChange( settings, e.data.action, true ); 14873 }; 14874 14875 for ( i=0, ien=buttons.length ; i<ien ; i++ ) { 14876 button = buttons[i]; 14877 14878 if ( Array.isArray( button ) ) { 14879 var inner = $( '<'+(button.DT_el || 'div')+'/>' ) 14880 .appendTo( container ); 14881 attach( inner, button ); 14882 } 14883 else { 14884 var disabled = false; 14885 14886 btnDisplay = null; 14887 btnClass = button; 14888 14889 switch ( button ) { 14890 case 'ellipsis': 14891 container.append('<span class="ellipsis">…</span>'); 14892 break; 14893 14894 case 'first': 14895 btnDisplay = lang.sFirst; 14896 14897 if ( page === 0 ) { 14898 disabled = true; 14899 } 14900 break; 14901 14902 case 'previous': 14903 btnDisplay = lang.sPrevious; 14904 14905 if ( page === 0 ) { 14906 disabled = true; 14907 } 14908 break; 14909 14910 case 'next': 14911 btnDisplay = lang.sNext; 14912 14913 if ( pages === 0 || page === pages-1 ) { 14914 disabled = true; 14915 } 14916 break; 14917 14918 case 'last': 14919 btnDisplay = lang.sLast; 14920 14921 if ( pages === 0 || page === pages-1 ) { 14922 disabled = true; 14923 } 14924 break; 14925 14926 default: 14927 btnDisplay = settings.fnFormatNumber( button + 1 ); 14928 btnClass = page === button ? 14929 classes.sPageButtonActive : ''; 14930 break; 14931 } 14932 14933 if ( btnDisplay !== null ) { 14934 var tag = settings.oInit.pagingTag || 'a'; 14935 14936 if (disabled) { 14937 btnClass += ' ' + disabledClass; 14938 } 14939 14940 node = $('<'+tag+'>', { 14941 'class': classes.sPageButton+' '+btnClass, 14942 'aria-controls': settings.sTableId, 14943 'aria-disabled': disabled ? 'true' : null, 14944 'aria-label': aria[ button ], 14945 'role': 'link', 14946 'aria-current': btnClass === classes.sPageButtonActive ? 'page' : null, 14947 'data-dt-idx': button, 14948 'tabindex': disabled ? -1 : settings.iTabIndex, 14949 'id': idx === 0 && typeof button === 'string' ? 14950 settings.sTableId +'_'+ button : 14951 null 14952 } ) 14953 .html( btnDisplay ) 14954 .appendTo( container ); 14955 14956 _fnBindAction( 14957 node, {action: button}, clickHandler 14958 ); 14959 } 14960 } 14961 } 14962 }; 14963 14964 // IE9 throws an 'unknown error' if document.activeElement is used 14965 // inside an iframe or frame. Try / catch the error. Not good for 14966 // accessibility, but neither are frames. 14967 var activeEl; 14968 14969 try { 14970 // Because this approach is destroying and recreating the paging 14971 // elements, focus is lost on the select button which is bad for 14972 // accessibility. So we want to restore focus once the draw has 14973 // completed 14974 activeEl = $(host).find(document.activeElement).data('dt-idx'); 14975 } 14976 catch (e) {} 14977 14978 attach( $(host).empty(), buttons ); 14979 14980 if ( activeEl !== undefined ) { 14981 $(host).find( '[data-dt-idx='+activeEl+']' ).trigger('focus'); 14982 } 14983 } 14984 } 14985 } ); 14986 14987 14988 14989 // Built in type detection. See model.ext.aTypes for information about 14990 // what is required from this methods. 14991 $.extend( DataTable.ext.type.detect, [ 14992 // Plain numbers - first since V8 detects some plain numbers as dates 14993 // e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...). 14994 function ( d, settings ) 14995 { 14996 var decimal = settings.oLanguage.sDecimal; 14997 return _isNumber( d, decimal ) ? 'num'+decimal : null; 14998 }, 14999 15000 // Dates (only those recognised by the browser's Date.parse) 15001 function ( d, settings ) 15002 { 15003 // V8 tries _very_ hard to make a string passed into `Date.parse()` 15004 // valid, so we need to use a regex to restrict date formats. Use a 15005 // plug-in for anything other than ISO8601 style strings 15006 if ( d && !(d instanceof Date) && ! _re_date.test(d) ) { 15007 return null; 15008 } 15009 var parsed = Date.parse(d); 15010 return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null; 15011 }, 15012 15013 // Formatted numbers 15014 function ( d, settings ) 15015 { 15016 var decimal = settings.oLanguage.sDecimal; 15017 return _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null; 15018 }, 15019 15020 // HTML numeric 15021 function ( d, settings ) 15022 { 15023 var decimal = settings.oLanguage.sDecimal; 15024 return _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null; 15025 }, 15026 15027 // HTML numeric, formatted 15028 function ( d, settings ) 15029 { 15030 var decimal = settings.oLanguage.sDecimal; 15031 return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null; 15032 }, 15033 15034 // HTML (this is strict checking - there must be html) 15035 function ( d, settings ) 15036 { 15037 return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ? 15038 'html' : null; 15039 } 15040 ] ); 15041 15042 15043 15044 // Filter formatting functions. See model.ext.ofnSearch for information about 15045 // what is required from these methods. 15046 // 15047 // Note that additional search methods are added for the html numbers and 15048 // html formatted numbers by `_addNumericSort()` when we know what the decimal 15049 // place is 15050 15051 15052 $.extend( DataTable.ext.type.search, { 15053 html: function ( data ) { 15054 return _empty(data) ? 15055 data : 15056 typeof data === 'string' ? 15057 data 15058 .replace( _re_new_lines, " " ) 15059 .replace( _re_html, "" ) : 15060 ''; 15061 }, 15062 15063 string: function ( data ) { 15064 return _empty(data) ? 15065 data : 15066 typeof data === 'string' ? 15067 data.replace( _re_new_lines, " " ) : 15068 data; 15069 } 15070 } ); 15071 15072 15073 15074 var __numericReplace = function ( d, decimalPlace, re1, re2 ) { 15075 if ( d !== 0 && (!d || d === '-') ) { 15076 return -Infinity; 15077 } 15078 15079 var type = typeof d; 15080 15081 if (type === 'number' || type === 'bigint') { 15082 return d; 15083 } 15084 15085 // If a decimal place other than `.` is used, it needs to be given to the 15086 // function so we can detect it and replace with a `.` which is the only 15087 // decimal place Javascript recognises - it is not locale aware. 15088 if ( decimalPlace ) { 15089 d = _numToDecimal( d, decimalPlace ); 15090 } 15091 15092 if ( d.replace ) { 15093 if ( re1 ) { 15094 d = d.replace( re1, '' ); 15095 } 15096 15097 if ( re2 ) { 15098 d = d.replace( re2, '' ); 15099 } 15100 } 15101 15102 return d * 1; 15103 }; 15104 15105 15106 // Add the numeric 'deformatting' functions for sorting and search. This is done 15107 // in a function to provide an easy ability for the language options to add 15108 // additional methods if a non-period decimal place is used. 15109 function _addNumericSort ( decimalPlace ) { 15110 $.each( 15111 { 15112 // Plain numbers 15113 "num": function ( d ) { 15114 return __numericReplace( d, decimalPlace ); 15115 }, 15116 15117 // Formatted numbers 15118 "num-fmt": function ( d ) { 15119 return __numericReplace( d, decimalPlace, _re_formatted_numeric ); 15120 }, 15121 15122 // HTML numeric 15123 "html-num": function ( d ) { 15124 return __numericReplace( d, decimalPlace, _re_html ); 15125 }, 15126 15127 // HTML numeric, formatted 15128 "html-num-fmt": function ( d ) { 15129 return __numericReplace( d, decimalPlace, _re_html, _re_formatted_numeric ); 15130 } 15131 }, 15132 function ( key, fn ) { 15133 // Add the ordering method 15134 _ext.type.order[ key+decimalPlace+'-pre' ] = fn; 15135 15136 // For HTML types add a search formatter that will strip the HTML 15137 if ( key.match(/^html\-/) ) { 15138 _ext.type.search[ key+decimalPlace ] = _ext.type.search.html; 15139 } 15140 } 15141 ); 15142 } 15143 15144 15145 // Default sort methods 15146 $.extend( _ext.type.order, { 15147 // Dates 15148 "date-pre": function ( d ) { 15149 var ts = Date.parse( d ); 15150 return isNaN(ts) ? -Infinity : ts; 15151 }, 15152 15153 // html 15154 "html-pre": function ( a ) { 15155 return _empty(a) ? 15156 '' : 15157 a.replace ? 15158 a.replace( /<.*?>/g, "" ).toLowerCase() : 15159 a+''; 15160 }, 15161 15162 // string 15163 "string-pre": function ( a ) { 15164 // This is a little complex, but faster than always calling toString, 15165 // https
vendor: 15,860 bytes, lines 15165-15733
15165://jsperf.com/tostring-v-check 15166 return _empty(a) ? 15167 '' : 15168 typeof a === 'string' ? 15169 a.toLowerCase() : 15170 ! a.toString ? 15171 '' : 15172 a.toString(); 15173 }, 15174 15175 // string-asc and -desc are retained only for compatibility with the old 15176 // sort methods 15177 "string-asc": function ( x, y ) { 15178 return ((x < y) ? -1 : ((x > y) ? 1 : 0)); 15179 }, 15180 15181 "string-desc": function ( x, y ) { 15182 return ((x < y) ? 1 : ((x > y) ? -1 : 0)); 15183 } 15184 } ); 15185 15186 15187 // Numeric sorting types - order doesn't matter here 15188 _addNumericSort( '' ); 15189 15190 15191 $.extend( true, DataTable.ext.renderer, { 15192 header: { 15193 _: function ( settings, cell, column, classes ) { 15194 // No additional mark-up required 15195 // Attach a sort listener to update on sort - note that using the 15196 // `DT` namespace will allow the event to be removed automatically 15197 // on destroy, while the `dt` namespaced event is the one we are 15198 // listening for 15199 $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) { 15200 if ( settings !== ctx ) { // need to check this this is the host 15201 return; // table, not a nested one 15202 } 15203 15204 var colIdx = column.idx; 15205 15206 cell 15207 .removeClass( 15208 classes.sSortAsc +' '+ 15209 classes.sSortDesc 15210 ) 15211 .addClass( columns[ colIdx ] == 'asc' ? 15212 classes.sSortAsc : columns[ colIdx ] == 'desc' ? 15213 classes.sSortDesc : 15214 column.sSortingClass 15215 ); 15216 } ); 15217 }, 15218 15219 jqueryui: function ( settings, cell, column, classes ) { 15220 $('<div/>') 15221 .addClass( classes.sSortJUIWrapper ) 15222 .append( cell.contents() ) 15223 .append( $('<span/>') 15224 .addClass( classes.sSortIcon+' '+column.sSortingClassJUI ) 15225 ) 15226 .appendTo( cell ); 15227 15228 // Attach a sort listener to update on sort 15229 $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) { 15230 if ( settings !== ctx ) { 15231 return; 15232 } 15233 15234 var colIdx = column.idx; 15235 15236 cell 15237 .removeClass( classes.sSortAsc +" "+classes.sSortDesc ) 15238 .addClass( columns[ colIdx ] == 'asc' ? 15239 classes.sSortAsc : columns[ colIdx ] == 'desc' ? 15240 classes.sSortDesc : 15241 column.sSortingClass 15242 ); 15243 15244 cell 15245 .find( 'span.'+classes.sSortIcon ) 15246 .removeClass( 15247 classes.sSortJUIAsc +" "+ 15248 classes.sSortJUIDesc +" "+ 15249 classes.sSortJUI +" "+ 15250 classes.sSortJUIAscAllowed +" "+ 15251 classes.sSortJUIDescAllowed 15252 ) 15253 .addClass( columns[ colIdx ] == 'asc' ? 15254 classes.sSortJUIAsc : columns[ colIdx ] == 'desc' ? 15255 classes.sSortJUIDesc : 15256 column.sSortingClassJUI 15257 ); 15258 } ); 15259 } 15260 } 15261 } ); 15262 15263 /* 15264 * Public helper functions. These aren't used internally by DataTables, or 15265 * called by any of the options passed into DataTables, but they can be used 15266 * externally by developers working with DataTables. They are helper functions 15267 * to make working with DataTables a little bit easier. 15268 */ 15269 15270 var __htmlEscapeEntities = function ( d ) { 15271 if (Array.isArray(d)) { 15272 d = d.join(','); 15273 } 15274 15275 return typeof d === 'string' ? 15276 d 15277 .replace(/&/g, '&') 15278 .replace(/</g, '<') 15279 .replace(/>/g, '>') 15280 .replace(/"/g, '"') : 15281 d; 15282 }; 15283 15284 // Common logic for moment, luxon or a date action 15285 function __mld( dt, momentFn, luxonFn, dateFn, arg1 ) { 15286 if (window.moment) { 15287 return dt[momentFn]( arg1 ); 15288 } 15289 else if (window.luxon) { 15290 return dt[luxonFn]( arg1 ); 15291 } 15292 15293 return dateFn ? dt[dateFn]( arg1 ) : dt; 15294 } 15295 15296 15297 var __mlWarning = false; 15298 function __mldObj (d, format, locale) { 15299 var dt; 15300 15301 if (window.moment) { 15302 dt = window.moment.utc( d, format, locale, true ); 15303 15304 if (! dt.isValid()) { 15305 return null; 15306 } 15307 } 15308 else if (window.luxon) { 15309 dt = format && typeof d === 'string' 15310 ? window.luxon.DateTime.fromFormat( d, format ) 15311 : window.luxon.DateTime.fromISO( d ); 15312 15313 if (! dt.isValid) { 15314 return null; 15315 } 15316 15317 dt.setLocale(locale); 15318 } 15319 else if (! format) { 15320 // No format given, must be ISO 15321 dt = new Date(d); 15322 } 15323 else { 15324 if (! __mlWarning) { 15325 alert('DataTables warning: Formatted date without Moment.js or Luxon - https://datatables.net/tn/17'); 15326 } 15327 15328 __mlWarning = true; 15329 } 15330 15331 return dt; 15332 } 15333 15334 // Wrapper for date, datetime and time which all operate the same way with the exception of 15335 // the output string for auto locale support 15336 function __mlHelper (localeString) { 15337 return function ( from, to, locale, def ) { 15338 // Luxon and Moment support 15339 // Argument shifting 15340 if ( arguments.length === 0 ) { 15341 locale = 'en'; 15342 to = null; // means toLocaleString 15343 from = null; // means iso8601 15344 } 15345 else if ( arguments.length === 1 ) { 15346 locale = 'en'; 15347 to = from; 15348 from = null; 15349 } 15350 else if ( arguments.length === 2 ) { 15351 locale = to; 15352 to = from; 15353 from = null; 15354 } 15355 15356 var typeName = 'datetime-' + to; 15357 15358 // Add type detection and sorting specific to this date format - we need to be able to identify 15359 // date type columns as such, rather than as numbers in extensions. Hence the need for this. 15360 if (! DataTable.ext.type.order[typeName]) { 15361 // The renderer will give the value to type detect as the type! 15362 DataTable.ext.type.detect.unshift(function (d) { 15363 return d === typeName ? typeName : false; 15364 }); 15365 15366 // The renderer gives us Moment, Luxon or Date obects for the sorting, all of which have a 15367 // `valueOf` which gives milliseconds epoch 15368 DataTable.ext.type.order[typeName + '-asc'] = function (a, b) { 15369 var x = a.valueOf(); 15370 var y = b.valueOf(); 15371 15372 return x === y 15373 ? 0 15374 : x < y 15375 ? -1 15376 : 1; 15377 } 15378 15379 DataTable.ext.type.order[typeName + '-desc'] = function (a, b) { 15380 var x = a.valueOf(); 15381 var y = b.valueOf(); 15382 15383 return x === y 15384 ? 0 15385 : x > y 15386 ? -1 15387 : 1; 15388 } 15389 } 15390 15391 return function ( d, type ) { 15392 // Allow for a default value 15393 if (d === null || d === undefined) { 15394 if (def === '--now') { 15395 // We treat everything as UTC further down, so no changes are 15396 // made, as such need to get the local date / time as if it were 15397 // UTC 15398 var local = new Date(); 15399 d = new Date( Date.UTC( 15400 local.getFullYear(), local.getMonth(), local.getDate(), 15401 local.getHours(), local.getMinutes(), local.getSeconds() 15402 ) ); 15403 } 15404 else { 15405 d = ''; 15406 } 15407 } 15408 15409 if (type === 'type') { 15410 // Typing uses the type name for fast matching 15411 return typeName; 15412 } 15413 15414 if (d === '') { 15415 return type !== 'sort' 15416 ? '' 15417 : __mldObj('0000-01-01 00:00:00', null, locale); 15418 } 15419 15420 // Shortcut. If `from` and `to` are the same, we are using the renderer to 15421 // format for ordering, not display - its already in the display format. 15422 if ( to !== null && from === to && type !== 'sort' && type !== 'type' && ! (d instanceof Date) ) { 15423 return d; 15424 } 15425 15426 var dt = __mldObj(d, from, locale); 15427 15428 if (dt === null) { 15429 return d; 15430 } 15431 15432 if (type === 'sort') { 15433 return dt; 15434 } 15435 15436 var formatted = to === null 15437 ? __mld(dt, 'toDate', 'toJSDate', '')[localeString]() 15438 : __mld(dt, 'format', 'toFormat', 'toISOString', to); 15439 15440 // XSS protection 15441 return type === 'display' ? 15442 __htmlEscapeEntities( formatted ) : 15443 formatted; 15444 }; 15445 } 15446 } 15447 15448 // Based on locale, determine standard number formatting 15449 // Fallback for legacy browsers is US English 15450 var __thousands = ','; 15451 var __decimal = '.'; 15452 15453 if (window.Intl !== undefined) { 15454 try { 15455 var num = new Intl.NumberFormat().formatToParts(100000.1); 15456 15457 for (var i=0 ; i<num.length ; i++) { 15458 if (num[i].type === 'group') { 15459 __thousands = num[i].value; 15460 } 15461 else if (num[i].type === 'decimal') { 15462 __decimal = num[i].value; 15463 } 15464 } 15465 } 15466 catch (e) { 15467 // noop 15468 } 15469 } 15470 15471 // Formatted date time detection - use by declaring the formats you are going to use 15472 DataTable.datetime = function ( format, locale ) { 15473 var typeName = 'datetime-detect-' + format; 15474 15475 if (! locale) { 15476 locale = 'en'; 15477 } 15478 15479 if (! DataTable.ext.type.order[typeName]) { 15480 DataTable.ext.type.detect.unshift(function (d) { 15481 var dt = __mldObj(d, format, locale); 15482 return d === '' || dt ? typeName : false; 15483 }); 15484 15485 DataTable.ext.type.order[typeName + '-pre'] = function (d) { 15486 return __mldObj(d, format, locale) || 0; 15487 } 15488 } 15489 } 15490 15491 /** 15492 * Helpers for `columns.render`. 15493 * 15494 * The options defined here can be used with the `columns.render` initialisation 15495 * option to provide a display renderer. The following functions are defined: 15496 * 15497 * * `number` - Will format numeric data (defined by `columns.data`) for 15498 * display, retaining the original unformatted data for sorting and filtering. 15499 * It takes 5 parameters: 15500 * * `string` - Thousands grouping separator 15501 * * `string` - Decimal point indicator 15502 * * `integer` - Number of decimal points to show 15503 * * `string` (optional) - Prefix. 15504 * * `string` (optional) - Postfix (/suffix). 15505 * * `text` - Escape HTML to help prevent XSS attacks. It has no optional 15506 * parameters. 15507 * 15508 * @example 15509 * // Column definition using the number renderer 15510 * { 15511 * data: "salary", 15512 * render: $.fn.dataTable.render.number( '\'', '.', 0, '$' ) 15513 * } 15514 * 15515 * @namespace 15516 */ 15517 DataTable.render = { 15518 date: __mlHelper('toLocaleDateString'), 15519 datetime: __mlHelper('toLocaleString'), 15520 time: __mlHelper('toLocaleTimeString'), 15521 number: function ( thousands, decimal, precision, prefix, postfix ) { 15522 // Auto locale detection 15523 if (thousands === null || thousands === undefined) { 15524 thousands = __thousands; 15525 } 15526 15527 if (decimal === null || decimal === undefined) { 15528 decimal = __decimal; 15529 } 15530 15531 return { 15532 display: function ( d ) { 15533 if ( typeof d !== 'number' && typeof d !== 'string' ) { 15534 return d; 15535 } 15536 15537 if (d === '' || d === null) { 15538 return d; 15539 } 15540 15541 var negative = d < 0 ? '-' : ''; 15542 var flo = parseFloat( d ); 15543 15544 // If NaN then there isn't much formatting that we can do - just 15545 // return immediately, escaping any HTML (this was supposed to 15546 // be a number after all) 15547 if ( isNaN( flo ) ) { 15548 return __htmlEscapeEntities( d ); 15549 } 15550 15551 flo = flo.toFixed( precision ); 15552 d = Math.abs( flo ); 15553 15554 var intPart = parseInt( d, 10 ); 15555 var floatPart = precision ? 15556 decimal+(d - intPart).toFixed( precision ).substring( 2 ): 15557 ''; 15558 15559 // If zero, then can't have a negative prefix 15560 if (intPart === 0 && parseFloat(floatPart) === 0) { 15561 negative = ''; 15562 } 15563 15564 return negative + (prefix||'') + 15565 intPart.toString().replace( 15566 /\B(?=(\d{3})+(?!\d))/g, thousands 15567 ) + 15568 floatPart + 15569 (postfix||''); 15570 } 15571 }; 15572 }, 15573 15574 text: function () { 15575 return { 15576 display: __htmlEscapeEntities, 15577 filter: __htmlEscapeEntities 15578 }; 15579 } 15580 }; 15581 15582 15583 /* 15584 * This is really a good bit rubbish this method of exposing the internal methods 15585 * publicly... - To be fixed in 2.0 using methods on the prototype 15586 */ 15587 15588 15589 /** 15590 * Create a wrapper function for exporting an internal functions to an external API. 15591 * @param {string} fn API function name 15592 * @returns {function} wrapped function 15593 * @memberof DataTable#internal 15594 */ 15595 function _fnExternApiFunc (fn) 15596 { 15597 return function() { 15598 var args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat( 15599 Array.prototype.slice.call(arguments) 15600 ); 15601 return DataTable.ext.internal[fn].apply( this, args ); 15602 }; 15603 } 15604 15605 15606 /** 15607 * Reference to internal functions for use by plug-in developers. Note that 15608 * these methods are references to internal functions and are considered to be 15609 * private. If you use these methods, be aware that they are liable to change 15610 * between versions. 15611 * @namespace 15612 */ 15613 $.extend( DataTable.ext.internal, { 15614 _fnExternApiFunc: _fnExternApiFunc, 15615 _fnBuildAjax: _fnBuildAjax, 15616 _fnAjaxUpdate: _fnAjaxUpdate, 15617 _fnAjaxParameters: _fnAjaxParameters, 15618 _fnAjaxUpdateDraw: _fnAjaxUpdateDraw, 15619 _fnAjaxDataSrc: _fnAjaxDataSrc, 15620 _fnAddColumn: _fnAddColumn, 15621 _fnColumnOptions: _fnColumnOptions, 15622 _fnAdjustColumnSizing: _fnAdjustColumnSizing, 15623 _fnVisibleToColumnIndex: _fnVisibleToColumnIndex, 15624 _fnColumnIndexToVisible: _fnColumnIndexToVisible, 15625 _fnVisbleColumns: _fnVisbleColumns, 15626 _fnGetColumns: _fnGetColumns, 15627 _fnColumnTypes: _fnColumnTypes, 15628 _fnApplyColumnDefs: _fnApplyColumnDefs, 15629 _fnHungarianMap: _fnHungarianMap, 15630 _fnCamelToHungarian: _fnCamelToHungarian, 15631 _fnLanguageCompat: _fnLanguageCompat, 15632 _fnBrowserDetect: _fnBrowserDetect, 15633 _fnAddData: _fnAddData, 15634 _fnAddTr: _fnAddTr, 15635 _fnNodeToDataIndex: _fnNodeToDataIndex, 15636 _fnNodeToColumnIndex: _fnNodeToColumnIndex, 15637 _fnGetCellData: _fnGetCellData, 15638 _fnSetCellData: _fnSetCellData, 15639 _fnSplitObjNotation: _fnSplitObjNotation, 15640 _fnGetObjectDataFn: _fnGetObjectDataFn, 15641 _fnSetObjectDataFn: _fnSetObjectDataFn, 15642 _fnGetDataMaster: _fnGetDataMaster, 15643 _fnClearTable: _fnClearTable, 15644 _fnDeleteIndex: _fnDeleteIndex, 15645 _fnInvalidate: _fnInvalidate, 15646 _fnGetRowElements: _fnGetRowElements, 15647 _fnCreateTr: _fnCreateTr, 15648 _fnBuildHead: _fnBuildHead, 15649 _fnDrawHead: _fnDrawHead, 15650 _fnDraw: _fnDraw, 15651 _fnReDraw: _fnReDraw, 15652 _fnAddOptionsHtml: _fnAddOptionsHtml, 15653 _fnDetectHeader: _fnDetectHeader, 15654 _fnGetUniqueThs: _fnGetUniqueThs, 15655 _fnFeatureHtmlFilter: _fnFeatureHtmlFilter, 15656 _fnFilterComplete: _fnFilterComplete, 15657 _fnFilterCustom: _fnFilterCustom, 15658 _fnFilterColumn: _fnFilterColumn, 15659 _fnFilter: _fnFilter, 15660 _fnFilterCreateSearch: _fnFilterCreateSearch, 15661 _fnEscapeRegex: _fnEscapeRegex, 15662 _fnFilterData: _fnFilterData, 15663 _fnFeatureHtmlInfo: _fnFeatureHtmlInfo, 15664 _fnUpdateInfo: _fnUpdateInfo, 15665 _fnInfoMacros: _fnInfoMacros, 15666 _fnInitialise: _fnInitialise, 15667 _fnInitComplete: _fnInitComplete, 15668 _fnLengthChange: _fnLengthChange, 15669 _fnFeatureHtmlLength: _fnFeatureHtmlLength, 15670 _fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate, 15671 _fnPageChange: _fnPageChange, 15672 _fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing, 15673 _fnProcessingDisplay: _fnProcessingDisplay, 15674 _fnFeatureHtmlTable: _fnFeatureHtmlTable, 15675 _fnScrollDraw: _fnScrollDraw, 15676 _fnApplyToChildren: _fnApplyToChildren, 15677 _fnCalculateColumnWidths: _fnCalculateColumnWidths, 15678 _fnThrottle: _fnThrottle, 15679 _fnConvertToWidth: _fnConvertToWidth, 15680 _fnGetWidestNode: _fnGetWidestNode, 15681 _fnGetMaxLenString: _fnGetMaxLenString, 15682 _fnStringToCss: _fnStringToCss, 15683 _fnSortFlatten: _fnSortFlatten, 15684 _fnSort: _fnSort, 15685 _fnSortAria: _fnSortAria, 15686 _fnSortListener: _fnSortListener, 15687 _fnSortAttachListener: _fnSortAttachListener, 15688 _fnSortingClasses: _fnSortingClasses, 15689 _fnSortData: _fnSortData, 15690 _fnSaveState: _fnSaveState, 15691 _fnLoadState: _fnLoadState, 15692 _fnImplementState: _fnImplementState, 15693 _fnSettingsFromNode: _fnSettingsFromNode, 15694 _fnLog: _fnLog, 15695 _fnMap: _fnMap, 15696 _fnBindAction: _fnBindAction, 15697 _fnCallbackReg: _fnCallbackReg, 15698 _fnCallbackFire: _fnCallbackFire, 15699 _fnLengthOverflow: _fnLengthOverflow, 15700 _fnRenderer: _fnRenderer, 15701 _fnDataSource: _fnDataSource, 15702 _fnRowAttributes: _fnRowAttributes, 15703 _fnExtend: _fnExtend, 15704 _fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant 15705 // in 1.10, so this dead-end function is 15706 // added to prevent errors 15707 } ); 15708 15709 15710 // jQuery access 15711 $.fn.dataTable = DataTable; 15712 15713 // Provide access to the host jQuery object (circular reference) 15714 DataTable.$ = $; 15715 15716 // Legacy aliases 15717 $.fn.dataTableSettings = DataTable.settings; 15718 $.fn.dataTableExt = DataTable.ext; 15719 15720 // With a capital `D` we return a DataTables API instance rather than a 15721 // jQuery object 15722 $.fn.DataTable = function ( opts ) { 15723 return $(this).dataTable( opts ).api(); 15724 }; 15725 15726 // All properties that are available to $.fn.dataTable should also be 15727 // available on $.fn.DataTable 15728 $.each( DataTable, function ( prop, val ) { 15729 $.fn.DataTable[ prop ] = val; 15730 } ); 15731 15732 return DataTable; 15733}));
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.