vendor: 5,670 bytes, lines 1-116
1/*! DataTables 1.12.1 2 * ©2008-2022 SpryMedia Ltd - datatables.net/license 3 */ 4 5/** 6 * @summary DataTables 7 * @description Paginate, search and order HTML tables 8 * @version 1.12.1 9 * @author SpryMedia Ltd 10 * @contact www.datatables.net 11 * @copyright SpryMedia Ltd. 12 * 13 * This source file is free software, available under the following license: 14 * MIT license - http://datatables.net/license 15 * 16 * This source file is distributed in the hope that it will be useful, but 17 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 18 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. 19 * 20 * For details please refer to: http://www.datatables.net 21 */ 22 23/*jslint evil: true, undef: true, browser: true */ 24/*globals $,require,jQuery,define,_selector_run,_selector_opts,_selector_first,_selector_row_indexes,_ext,_Api,_api_register,_api_registerPlural,_re_new_lines,_re_html,_re_formatted_numeric,_re_escape_regex,_empty,_intVal,_numToDecimal,_isNumber,_isHtml,_htmlNumeric,_pluck,_pluck_order,_range,_stripHtml,_unique,_fnBuildAjax,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnAjaxDataSrc,_fnAddColumn,_fnColumnOptions,_fnAdjustColumnSizing,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnVisbleColumns,_fnGetColumns,_fnColumnTypes,_fnApplyColumnDefs,_fnHungarianMap,_fnCamelToHungarian,_fnLanguageCompat,_fnBrowserDetect,_fnAddData,_fnAddTr,_fnNodeToDataIndex,_fnNodeToColumnIndex,_fnGetCellData,_fnSetCellData,_fnSplitObjNotation,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnGetDataMaster,_fnClearTable,_fnDeleteIndex,_fnInvalidate,_fnGetRowElements,_fnCreateTr,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAddOptionsHtml,_fnDetectHeader,_fnGetUniqueThs,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnFilterCreateSearch,_fnEscapeRegex,_fnFilterData,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnInfoMacros,_fnInitialise,_fnInitComplete,_fnLengthChange,_fnFeatureHtmlLength,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnFeatureHtmlTable,_fnScrollDraw,_fnApplyToChildren,_fnCalculateColumnWidths,_fnThrottle,_fnConvertToWidth,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/ 25 26(function( factory ) { 27 "use strict"; 28 29 if ( typeof define === 'function' && define.amd ) { 30 // AMD 31 define( ['jquery'], function ( $ ) { 32 return factory( $, window, document ); 33 } ); 34 } 35 else if ( typeof exports === 'object' ) { 36 // CommonJS 37 module.exports = function (root, $) { 38 if ( ! root ) { 39 // CommonJS environments without a window global must pass a 40 // root. This will give an error otherwise 41 root = window; 42 } 43 44 if ( ! $ ) { 45 $ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window 46 require('jquery') : 47 require('jquery')( root ); 48 } 49 50 return factory( $, root, root.document ); 51 }; 52 } 53 else { 54 // Browser 55 window.DataTable = factory( jQuery, window, document ); 56 } 57} 58(function( $, window, document, undefined ) { 59 "use strict"; 60 61 62 var DataTable = function ( selector, options ) 63 { 64 // When creating with `new`, create a new DataTable, returning the API instance 65 if (this instanceof DataTable) { 66 return $(selector).DataTable(options); 67 } 68 else { 69 // Argument switching 70 options = selector; 71 } 72 73 /** 74 * Perform a jQuery selector action on the table's TR elements (from the tbody) and 75 * return the resulting jQuery object. 76 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on 77 * @param {object} [oOpts] Optional parameters for modifying the rows to be included 78 * @param {string} [oOpts.filter=none] Select TR elements that meet the current filter 79 * criterion ("applied") or all TR elements (i.e. no filter). 80 * @param {string} [oOpts.order=current] Order of the TR elements in the processed array. 81 * Can be either 'current', whereby the current sorting of the table is used, or 82 * 'original' whereby the original order the data was read into the table is used. 83 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page 84 * ("current") or not ("all"). If 'current' is given, then order is assumed to be 85 * 'current' and filter is 'applied', regardless of what they might be given as. 86 * @returns {object} jQuery object, filtered by the given selector. 87 * @dtopt API 88 * @deprecated Since v1.10 89 * 90 * @example 91 * $(document).ready(function() { 92 * var oTable = $('#example').dataTable(); 93 * 94 * // Highlight every second row 95 * oTable.$('tr:odd').css('backgroundColor', 'blue'); 96 * } ); 97 * 98 * @example 99 * $(document).ready(function() { 100 * var oTable = $('#example').dataTable(); 101 * 102 * // Filter to rows with 'Webkit' in them, add a background colour and then 103 * // remove the filter, thus highlighting the 'Webkit' rows only. 104 * oTable.fnFilter('Webkit'); 105 * oTable.$('tr', {"search": "applied"}).css('backgroundColor', 'blue'); 106 * oTable.fnFilter(''); 107 * } ); 108 */ 109 this.$ = function ( sSelector, oOpts ) 110 { 111 return this.api(true).$( sSelector, oOpts ); 112 }; 113 114 115 /** 116 * Almost identical to $ in operation, but in this case returns the data for the matched
117 * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes 118 * rather than any descendants, so the data can be obtained for the row/cell. If matching 119 * rows are found, the data returned is the original data array/object that was used to 120 * create the row (or a generated array if from a DOM source). 121 * 122 * This method is often useful in-combination with $ where both functions are given the 123 * same parameters and the array indexes will match identically. 124 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on 125 * @param {object} [oOpts] Optional parameters for modifying the rows to be included 126 * @param {string} [oOpts.filter=none] Select elements that meet the current filter 127 * criterion ("applied") or all elements (i.e. no filter). 128 * @param {string} [oOpts.order=current] Order of the data in the processed array. 129 * Can be either 'current', whereby the current sorting of the table is used, or 130 * 'original' whereby the original order the data was read into the table is used. 131 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page 132 * ("current") or not ("all"). If 'current' is given, then order is assumed to be 133 * 'current' and filter is 'applied', regardless of what they might be given as. 134 * @returns {array} Data for the matched elements. If any elements, as a result of the 135 * selector, were not TR, TD or TH elements in the DataTable, they will have a null 136 * entry in the array. 137 * @dtopt API 138 * @deprecated Since v1.10 139 * 140 * @example 141 * $(document).ready(function() { 142 * var oTable = $('#example').dataTable(); 143 * 144 * // Get the data from the first row in the table 145 * var data = oTable._('tr:first'); 146 * 147 * // Do something useful with the data 148 * alert( "First cell is: "+data[0] ); 149 * } ); 150 * 151 * @example 152 * $(document).ready(function() { 153 * var oTable = $('#example').dataTable(); 154 * 155 * // Filter to 'Webkit' and get all data for 156 * oTable.fnFilter('Webkit'); 157 * var data = oTable._('tr', {"search": "applied"}); 158 * 159 * // Do something with the data 160 * alert( data.length+" rows matched the search" ); 161 * } ); 162 */ 163 this._ = function ( sSelector, oOpts ) 164 { 165 return this.api(true).rows( sSelector, oOpts ).data(); 166 }; 167 168 169 /** 170 * Create a DataTables Api instance, with the currently selected tables for 171 * the Api's context. 172 * @param {boolean} [traditional=false] Set the API instance's context to be 173 * only the table referred to by the `DataTable.ext.iApiIndex` option, as was 174 * used in the API presented by DataTables 1.9- (i.e. the traditional mode), 175 * or if all tables captured in the jQuery object should be used. 176 * @return {DataTables.Api} 177 */ 178 this.api = function ( traditional ) 179 { 180 return traditional ? 181 new _Api( 182 _fnSettingsFromNode( this[ _ext.iApiIndex ] ) 183 ) : 184 new _Api( this ); 185 }; 186 187 188 /** 189 * Add a single new row or multiple rows of data to the table. Please note 190 * that this is suitable for client-side processing only - if you are using 191 * server-side processing (i.e. "bServerSide": true), then to add data, you 192 * must add it to the data source, i.e. the server-side, through an Ajax call. 193 * @param {array|object} data The data to be added to the table. This can be: 194 * <ul> 195 * <li>1D array of data - add a single row with the data provided</li> 196 * <li>2D array of arrays - add multiple rows in a single call</li> 197 * <li>object - data object when using <i>mData</i></li> 198 * <li>array of objects - multiple data objects when using <i>mData</i></li> 199 * </ul> 200 * @param {bool} [redraw=true] redraw the table or not 201 * @returns {array} An array of integers, representing the list of indexes in 202 * <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to 203 * the table. 204 * @dtopt API 205 * @deprecated Since v1.10 206 * 207 * @example 208 * // Global var for counter 209 * var giCount = 2; 210 * 211 * $(document).ready(function() { 212 * $('#example').dataTable(); 213 * } ); 214 * 215 * function fnClickAddRow() { 216 * $('#example').dataTable().fnAddData( [ 217 * giCount+".1", 218 * giCount+".2", 219 * giCount+".3", 220 * giCount+".4" ] 221 * ); 222 * 223 * giCount++; 224 * } 225 */ 226 this.fnAddData = function( data, redraw ) 227 { 228 var api = this.api( true ); 229 230 /* Check if we want to add multiple rows or not */ 231 var rows = Array.isArray(data) && ( Array.isArray(data[0]) || $.isPlainObject(data[0]) ) ? 232 api.rows.add( data ) : 233 api.row.add( data ); 234 235 if ( redraw === undefined || redraw ) { 236 api.draw(); 237 } 238 239 return rows.flatten().toArray(); 240 }; 241 242 243 /** 244 * This function will make DataTables recalculate the column sizes, based on the data 245 * contained in the table and the sizes applied to the columns (in the DOM, CSS or 246 * through the sWidth parameter). This can be useful when the width of the table's
vendor: 200,033 bytes, lines 247-6961
247 * parent element changes (for example a window resize). 248 * @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to 249 * @dtopt API 250 * @deprecated Since v1.10 251 * 252 * @example 253 * $(document).ready(function() { 254 * var oTable = $('#example').dataTable( { 255 * "sScrollY": "200px", 256 * "bPaginate": false 257 * } ); 258 * 259 * $(window).on('resize', function () { 260 * oTable.fnAdjustColumnSizing(); 261 * } ); 262 * } ); 263 */ 264 this.fnAdjustColumnSizing = function ( bRedraw ) 265 { 266 var api = this.api( true ).columns.adjust(); 267 var settings = api.settings()[0]; 268 var scroll = settings.oScroll; 269 270 if ( bRedraw === undefined || bRedraw ) { 271 api.draw( false ); 272 } 273 else if ( scroll.sX !== "" || scroll.sY !== "" ) { 274 /* If not redrawing, but scrolling, we want to apply the new column sizes anyway */ 275 _fnScrollDraw( settings ); 276 } 277 }; 278 279 280 /** 281 * Quickly and simply clear a table 282 * @param {bool} [bRedraw=true] redraw the table or not 283 * @dtopt API 284 * @deprecated Since v1.10 285 * 286 * @example 287 * $(document).ready(function() { 288 * var oTable = $('#example').dataTable(); 289 * 290 * // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...) 291 * oTable.fnClearTable(); 292 * } ); 293 */ 294 this.fnClearTable = function( bRedraw ) 295 { 296 var api = this.api( true ).clear(); 297 298 if ( bRedraw === undefined || bRedraw ) { 299 api.draw(); 300 } 301 }; 302 303 304 /** 305 * The exact opposite of 'opening' a row, this function will close any rows which 306 * are currently 'open'. 307 * @param {node} nTr the table row to 'close' 308 * @returns {int} 0 on success, or 1 if failed (can't find the row) 309 * @dtopt API 310 * @deprecated Since v1.10 311 * 312 * @example 313 * $(document).ready(function() { 314 * var oTable; 315 * 316 * // 'open' an information row when a row is clicked on 317 * $('#example tbody tr').click( function () { 318 * if ( oTable.fnIsOpen(this) ) { 319 * oTable.fnClose( this ); 320 * } else { 321 * oTable.fnOpen( this, "Temporary row opened", "info_row" ); 322 * } 323 * } ); 324 * 325 * oTable = $('#example').dataTable(); 326 * } ); 327 */ 328 this.fnClose = function( nTr ) 329 { 330 this.api( true ).row( nTr ).child.hide(); 331 }; 332 333 334 /** 335 * Remove a row for the table 336 * @param {mixed} target The index of the row from aoData to be deleted, or 337 * the TR element you want to delete 338 * @param {function|null} [callBack] Callback function 339 * @param {bool} [redraw=true] Redraw the table or not 340 * @returns {array} The row that was deleted 341 * @dtopt API 342 * @deprecated Since v1.10 343 * 344 * @example 345 * $(document).ready(function() { 346 * var oTable = $('#example').dataTable(); 347 * 348 * // Immediately remove the first row 349 * oTable.fnDeleteRow( 0 ); 350 * } ); 351 */ 352 this.fnDeleteRow = function( target, callback, redraw ) 353 { 354 var api = this.api( true ); 355 var rows = api.rows( target ); 356 var settings = rows.settings()[0]; 357 var data = settings.aoData[ rows[0][0] ]; 358 359 rows.remove(); 360 361 if ( callback ) { 362 callback.call( this, settings, data ); 363 } 364 365 if ( redraw === undefined || redraw ) { 366 api.draw(); 367 } 368 369 return data; 370 }; 371 372 373 /** 374 * Restore the table to it's original state in the DOM by removing all of DataTables 375 * enhancements, alterations to the DOM structure of the table and event listeners. 376 * @param {boolean} [remove=false] Completely remove the table from the DOM 377 * @dtopt API 378 * @deprecated Since v1.10 379 * 380 * @example 381 * $(document).ready(function() { 382 * // This example is fairly pointless in reality, but shows how fnDestroy can be used 383 * var oTable = $('#example').dataTable(); 384 * oTable.fnDestroy(); 385 * } ); 386 */ 387 this.fnDestroy = function ( remove ) 388 { 389 this.api( true ).destroy( remove ); 390 }; 391 392 393 /** 394 * Redraw the table 395 * @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw. 396 * @dtopt API 397 * @deprecated Since v1.10 398 * 399 * @example 400 * $(document).ready(function() { 401 * var oTable = $('#example').dataTable(); 402 * 403 * // Re-draw the table - you wouldn't want to do it here, but it's an example :-) 404 * oTable.fnDraw(); 405 * } ); 406 */ 407 this.fnDraw = function( complete ) 408 { 409 // Note that this isn't an exact match to the old call to _fnDraw - it takes 410 // into account the new data, but can hold position. 411 this.api( true ).draw( complete ); 412 }; 413 414 415 /** 416 * Filter the input based on data 417 * @param {string} sInput String to filter the table on 418 * @param {int|null} [iColumn] Column to limit filtering to 419 * @param {bool} [bRegex=false] Treat as regular expression or not 420 * @param {bool} [bSmart=true] Perform smart filtering or not 421 * @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es) 422 * @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false) 423 * @dtopt API 424 * @deprecated Since v1.10 425 * 426 * @example 427 * $(document).ready(function() { 428 * var oTable = $('#example').dataTable(); 429 * 430 * // Sometime later - filter... 431 * oTable.fnFilter( 'test string' ); 432 * } ); 433 */ 434 this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive ) 435 { 436 var api = this.api( true ); 437 438 if ( iColumn === null || iColumn === undefined ) { 439 api.search( sInput, bRegex, bSmart, bCaseInsensitive ); 440 } 441 else { 442 api.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive ); 443 } 444 445 api.draw(); 446 }; 447 448 449 /** 450 * Get the data for the whole table, an individual row or an individual cell based on the 451 * provided parameters. 452 * @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as 453 * a TR node then the data source for the whole row will be returned. If given as a 454 * TD/TH cell node then iCol will be automatically calculated and the data for the 455 * cell returned. If given as an integer, then this is treated as the aoData internal 456 * data index for the row (see fnGetPosition) and the data for that row used. 457 * @param {int} [col] Optional column index that you want the data of. 458 * @returns {array|object|string} If mRow is undefined, then the data for all rows is 459 * returned. If mRow is defined, just data for that row, and is iCol is 460 * defined, only data for the designated cell is returned. 461 * @dtopt API 462 * @deprecated Since v1.10 463 * 464 * @example 465 * // Row data 466 * $(document).ready(function() { 467 * oTable = $('#example').dataTable(); 468 * 469 * oTable.$('tr').click( function () { 470 * var data = oTable.fnGetData( this ); 471 * // ... do something with the array / object of data for the row 472 * } ); 473 * } ); 474 * 475 * @example 476 * // Individual cell data 477 * $(document).ready(function() { 478 * oTable = $('#example').dataTable(); 479 * 480 * oTable.$('td').click( function () { 481 * var sData = oTable.fnGetData( this ); 482 * alert( 'The cell clicked on had the value of '+sData ); 483 * } ); 484 * } ); 485 */ 486 this.fnGetData = function( src, col ) 487 { 488 var api = this.api( true ); 489 490 if ( src !== undefined ) { 491 var type = src.nodeName ? src.nodeName.toLowerCase() : ''; 492 493 return col !== undefined || type == 'td' || type == 'th' ? 494 api.cell( src, col ).data() : 495 api.row( src ).data() || null; 496 } 497 498 return api.data().toArray(); 499 }; 500 501 502 /** 503 * Get an array of the TR nodes that are used in the table's body. Note that you will 504 * typically want to use the '$' API method in preference to this as it is more 505 * flexible. 506 * @param {int} [iRow] Optional row index for the TR element you want 507 * @returns {array|node} If iRow is undefined, returns an array of all TR elements 508 * in the table's body, or iRow is defined, just the TR element requested. 509 * @dtopt API 510 * @deprecated Since v1.10 511 * 512 * @example 513 * $(document).ready(function() { 514 * var oTable = $('#example').dataTable(); 515 * 516 * // Get the nodes from the table 517 * var nNodes = oTable.fnGetNodes( ); 518 * } ); 519 */ 520 this.fnGetNodes = function( iRow ) 521 { 522 var api = this.api( true ); 523 524 return iRow !== undefined ? 525 api.row( iRow ).node() : 526 api.rows().nodes().flatten().toArray(); 527 }; 528 529 530 /** 531 * Get the array indexes of a particular cell from it's DOM element 532 * and column index including hidden columns 533 * @param {node} node this can either be a TR, TD or TH in the table's body 534 * @returns {int} If nNode is given as a TR, then a single index is returned, or 535 * if given as a cell, an array of [row index, column index (visible), 536 * column index (all)] is given. 537 * @dtopt API 538 * @deprecated Since v1.10 539 * 540 * @example 541 * $(document).ready(function() { 542 * $('#example tbody td').click( function () { 543 * // Get the position of the current data from the node 544 * var aPos = oTable.fnGetPosition( this ); 545 * 546 * // Get the data array for this row 547 * var aData = oTable.fnGetData( aPos[0] ); 548 * 549 * // Update the data array and return the value 550 * aData[ aPos[1] ] = 'clicked'; 551 * this.innerHTML = 'clicked'; 552 * } ); 553 * 554 * // Init DataTables 555 * oTable = $('#example').dataTable(); 556 * } ); 557 */ 558 this.fnGetPosition = function( node ) 559 { 560 var api = this.api( true ); 561 var nodeName = node.nodeName.toUpperCase(); 562 563 if ( nodeName == 'TR' ) { 564 return api.row( node ).index(); 565 } 566 else if ( nodeName == 'TD' || nodeName == 'TH' ) { 567 var cell = api.cell( node ).index(); 568 569 return [ 570 cell.row, 571 cell.columnVisible, 572 cell.column 573 ]; 574 } 575 return null; 576 }; 577 578 579 /** 580 * Check to see if a row is 'open' or not. 581 * @param {node} nTr the table row to check 582 * @returns {boolean} true if the row is currently open, false otherwise 583 * @dtopt API 584 * @deprecated Since v1.10 585 * 586 * @example 587 * $(document).ready(function() { 588 * var oTable; 589 * 590 * // 'open' an information row when a row is clicked on 591 * $('#example tbody tr').click( function () { 592 * if ( oTable.fnIsOpen(this) ) { 593 * oTable.fnClose( this ); 594 * } else { 595 * oTable.fnOpen( this, "Temporary row opened", "info_row" ); 596 * } 597 * } ); 598 * 599 * oTable = $('#example').dataTable(); 600 * } ); 601 */ 602 this.fnIsOpen = function( nTr ) 603 { 604 return this.api( true ).row( nTr ).child.isShown(); 605 }; 606 607 608 /** 609 * This function will place a new row directly after a row which is currently 610 * on display on the page, with the HTML contents that is passed into the 611 * function. This can be used, for example, to ask for confirmation that a 612 * particular record should be deleted. 613 * @param {node} nTr The table row to 'open' 614 * @param {string|node|jQuery} mHtml The HTML to put into the row 615 * @param {string} sClass Class to give the new TD cell 616 * @returns {node} The row opened. Note that if the table row passed in as the 617 * first parameter, is not found in the table, this method will silently 618 * return. 619 * @dtopt API 620 * @deprecated Since v1.10 621 * 622 * @example 623 * $(document).ready(function() { 624 * var oTable; 625 * 626 * // 'open' an information row when a row is clicked on 627 * $('#example tbody tr').click( function () { 628 * if ( oTable.fnIsOpen(this) ) { 629 * oTable.fnClose( this ); 630 * } else { 631 * oTable.fnOpen( this, "Temporary row opened", "info_row" ); 632 * } 633 * } ); 634 * 635 * oTable = $('#example').dataTable(); 636 * } ); 637 */ 638 this.fnOpen = function( nTr, mHtml, sClass ) 639 { 640 return this.api( true ) 641 .row( nTr ) 642 .child( mHtml, sClass ) 643 .show() 644 .child()[0]; 645 }; 646 647 648 /** 649 * Change the pagination - provides the internal logic for pagination in a simple API 650 * function. With this function you can have a DataTables table go to the next, 651 * previous, first or last pages. 652 * @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last" 653 * or page number to jump to (integer), note that page 0 is the first page. 654 * @param {bool} [bRedraw=true] Redraw the table or not 655 * @dtopt API 656 * @deprecated Since v1.10 657 * 658 * @example 659 * $(document).ready(function() { 660 * var oTable = $('#example').dataTable(); 661 * oTable.fnPageChange( 'next' ); 662 * } ); 663 */ 664 this.fnPageChange = function ( mAction, bRedraw ) 665 { 666 var api = this.api( true ).page( mAction ); 667 668 if ( bRedraw === undefined || bRedraw ) { 669 api.draw(false); 670 } 671 }; 672 673 674 /** 675 * Show a particular column 676 * @param {int} iCol The column whose display should be changed 677 * @param {bool} bShow Show (true) or hide (false) the column 678 * @param {bool} [bRedraw=true] Redraw the table or not 679 * @dtopt API 680 * @deprecated Since v1.10 681 * 682 * @example 683 * $(document).ready(function() { 684 * var oTable = $('#example').dataTable(); 685 * 686 * // Hide the second column after initialisation 687 * oTable.fnSetColumnVis( 1, false ); 688 * } ); 689 */ 690 this.fnSetColumnVis = function ( iCol, bShow, bRedraw ) 691 { 692 var api = this.api( true ).column( iCol ).visible( bShow ); 693 694 if ( bRedraw === undefined || bRedraw ) { 695 api.columns.adjust().draw(); 696 } 697 }; 698 699 700 /** 701 * Get the settings for a particular table for external manipulation 702 * @returns {object} DataTables settings object. See 703 * {@link DataTable.models.oSettings} 704 * @dtopt API 705 * @deprecated Since v1.10 706 * 707 * @example 708 * $(document).ready(function() { 709 * var oTable = $('#example').dataTable(); 710 * var oSettings = oTable.fnSettings(); 711 * 712 * // Show an example parameter from the settings 713 * alert( oSettings._iDisplayStart ); 714 * } ); 715 */ 716 this.fnSettings = function() 717 { 718 return _fnSettingsFromNode( this[_ext.iApiIndex] ); 719 }; 720 721 722 /** 723 * Sort the table by a particular column 724 * @param {int} iCol the data index to sort on. Note that this will not match the 725 * 'display index' if you have hidden data entries 726 * @dtopt API 727 * @deprecated Since v1.10 728 * 729 * @example 730 * $(document).ready(function() { 731 * var oTable = $('#example').dataTable(); 732 * 733 * // Sort immediately with columns 0 and 1 734 * oTable.fnSort( [ [0,'asc'], [1,'asc'] ] ); 735 * } ); 736 */ 737 this.fnSort = function( aaSort ) 738 { 739 this.api( true ).order( aaSort ).draw(); 740 }; 741 742 743 /** 744 * Attach a sort listener to an element for a given column 745 * @param {node} nNode the element to attach the sort listener to 746 * @param {int} iColumn the column that a click on this node will sort on 747 * @param {function} [fnCallback] callback function when sort is run 748 * @dtopt API 749 * @deprecated Since v1.10 750 * 751 * @example 752 * $(document).ready(function() { 753 * var oTable = $('#example').dataTable(); 754 * 755 * // Sort on column 1, when 'sorter' is clicked on 756 * oTable.fnSortListener( document.getElementById('sorter'), 1 ); 757 * } ); 758 */ 759 this.fnSortListener = function( nNode, iColumn, fnCallback ) 760 { 761 this.api( true ).order.listener( nNode, iColumn, fnCallback ); 762 }; 763 764 765 /** 766 * Update a table cell or row - this method will accept either a single value to 767 * update the cell with, an array of values with one element for each column or 768 * an object in the same format as the original data source. The function is 769 * self-referencing in order to make the multi column updates easier. 770 * @param {object|array|string} mData Data to update the cell/row with 771 * @param {node|int} mRow TR element you want to update or the aoData index 772 * @param {int} [iColumn] The column to update, give as null or undefined to 773 * update a whole row. 774 * @param {bool} [bRedraw=true] Redraw the table or not 775 * @param {bool} [bAction=true] Perform pre-draw actions or not 776 * @returns {int} 0 on success, 1 on error 777 * @dtopt API 778 * @deprecated Since v1.10 779 * 780 * @example 781 * $(document).ready(function() { 782 * var oTable = $('#example').dataTable(); 783 * oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell 784 * oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row 785 * } ); 786 */ 787 this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction ) 788 { 789 var api = this.api( true ); 790 791 if ( iColumn === undefined || iColumn === null ) { 792 api.row( mRow ).data( mData ); 793 } 794 else { 795 api.cell( mRow, iColumn ).data( mData ); 796 } 797 798 if ( bAction === undefined || bAction ) { 799 api.columns.adjust(); 800 } 801 802 if ( bRedraw === undefined || bRedraw ) { 803 api.draw(); 804 } 805 return 0; 806 }; 807 808 809 /** 810 * Provide a common method for plug-ins to check the version of DataTables being used, in order 811 * to ensure compatibility. 812 * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the 813 * formats "X" and "X.Y" are also acceptable. 814 * @returns {boolean} true if this version of DataTables is greater or equal to the required 815 * version, or false if this version of DataTales is not suitable 816 * @method 817 * @dtopt API 818 * @deprecated Since v1.10 819 * 820 * @example 821 * $(document).ready(function() { 822 * var oTable = $('#example').dataTable(); 823 * alert( oTable.fnVersionCheck( '1.9.0' ) ); 824 * } ); 825 */ 826 this.fnVersionCheck = _ext.fnVersionCheck; 827 828 829 var _that = this; 830 var emptyInit = options === undefined; 831 var len = this.length; 832 833 if ( emptyInit ) { 834 options = {}; 835 } 836 837 this.oApi = this.internal = _ext.internal; 838 839 // Extend with old style plug-in API methods 840 for ( var fn in DataTable.ext.internal ) { 841 if ( fn ) { 842 this[fn] = _fnExternApiFunc(fn); 843 } 844 } 845 846 this.each(function() { 847 // For each initialisation we want to give it a clean initialisation 848 // object that can be bashed around 849 var o = {}; 850 var oInit = len > 1 ? // optimisation for single table case 851 _fnExtend( o, options, true ) : 852 options; 853 854 /*global oInit,_that,emptyInit*/ 855 var i=0, iLen, j, jLen, k, kLen; 856 var sId = this.getAttribute( 'id' ); 857 var bInitHandedOff = false; 858 var defaults = DataTable.defaults; 859 var $this = $(this); 860 861 862 /* Sanity check */ 863 if ( this.nodeName.toLowerCase() != 'table' ) 864 { 865 _fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 ); 866 return; 867 } 868 869 /* Backwards compatibility for the defaults */ 870 _fnCompatOpts( defaults ); 871 _fnCompatCols( defaults.column ); 872 873 /* Convert the camel-case defaults to Hungarian */ 874 _fnCamelToHungarian( defaults, defaults, true ); 875 _fnCamelToHungarian( defaults.column, defaults.column, true ); 876 877 /* Setting up the initialisation object */ 878 _fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ), true ); 879 880 881 882 /* Check to see if we are re-initialising a table */ 883 var allSettings = DataTable.settings; 884 for ( i=0, iLen=allSettings.length ; i<iLen ; i++ ) 885 { 886 var s = allSettings[i]; 887 888 /* Base check on table node */ 889 if ( 890 s.nTable == this || 891 (s.nTHead && s.nTHead.parentNode == this) || 892 (s.nTFoot && s.nTFoot.parentNode == this) 893 ) { 894 var bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve; 895 var bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy; 896 897 if ( emptyInit || bRetrieve ) 898 { 899 return s.oInstance; 900 } 901 else if ( bDestroy ) 902 { 903 s.oInstance.fnDestroy(); 904 break; 905 } 906 else 907 { 908 _fnLog( s, 0, 'Cannot reinitialise DataTable', 3 ); 909 return; 910 } 911 } 912 913 /* If the element we are initialising has the same ID as a table which was previously 914 * initialised, but the table nodes don't match (from before) then we destroy the old 915 * instance by simply deleting it. This is under the assumption that the table has been 916 * destroyed by other methods. Anyone using non-id selectors will need to do this manually 917 */ 918 if ( s.sTableId == this.id ) 919 { 920 allSettings.splice( i, 1 ); 921 break; 922 } 923 } 924 925 /* Ensure the table has an ID - required for accessibility */ 926 if ( sId === null || sId === "" ) 927 { 928 sId = "DataTables_Table_"+(DataTable.ext._unique++); 929 this.id = sId; 930 } 931 932 /* Create the settings object for this table and set some of the default parameters */ 933 var oSettings = $.extend( true, {}, DataTable.models.oSettings, { 934 "sDestroyWidth": $this[0].style.width, 935 "sInstance": sId, 936 "sTableId": sId 937 } ); 938 oSettings.nTable = this; 939 oSettings.oApi = _that.internal; 940 oSettings.oInit = oInit; 941 942 allSettings.push( oSettings ); 943 944 // Need to add the instance after the instance after the settings object has been added 945 // to the settings array, so we can self reference the table instance if more than one 946 oSettings.oInstance = (_that.length===1) ? _that : $this.dataTable(); 947 948 // Backwards compatibility, before we apply all the defaults 949 _fnCompatOpts( oInit ); 950 _fnLanguageCompat( oInit.oLanguage ); 951 952 // If the length menu is given, but the init display length is not, use the length menu 953 if ( oInit.aLengthMenu && ! oInit.iDisplayLength ) 954 { 955 oInit.iDisplayLength = Array.isArray( oInit.aLengthMenu[0] ) ? 956 oInit.aLengthMenu[0][0] : oInit.aLengthMenu[0]; 957 } 958 959 // Apply the defaults and init options to make a single init object will all 960 // options defined from defaults and instance options. 961 oInit = _fnExtend( $.extend( true, {}, defaults ), oInit ); 962 963 964 // Map the initialisation options onto the settings object 965 _fnMap( oSettings.oFeatures, oInit, [ 966 "bPaginate", 967 "bLengthChange", 968 "bFilter", 969 "bSort", 970 "bSortMulti", 971 "bInfo", 972 "bProcessing", 973 "bAutoWidth", 974 "bSortClasses", 975 "bServerSide", 976 "bDeferRender" 977 ] ); 978 _fnMap( oSettings, oInit, [ 979 "asStripeClasses", 980 "ajax", 981 "fnServerData", 982 "fnFormatNumber", 983 "sServerMethod", 984 "aaSorting", 985 "aaSortingFixed", 986 "aLengthMenu", 987 "sPaginationType", 988 "sAjaxSource", 989 "sAjaxDataProp", 990 "iStateDuration", 991 "sDom", 992 "bSortCellsTop", 993 "iTabIndex", 994 "fnStateLoadCallback", 995 "fnStateSaveCallback", 996 "renderer", 997 "searchDelay", 998 "rowId", 999 [ "iCookieDuration", "iStateDuration" ], // backwards compat 1000 [ "oSearch", "oPreviousSearch" ], 1001 [ "aoSearchCols", "aoPreSearchCols" ], 1002 [ "iDisplayLength", "_iDisplayLength" ] 1003 ] ); 1004 _fnMap( oSettings.oScroll, oInit, [ 1005 [ "sScrollX", "sX" ], 1006 [ "sScrollXInner", "sXInner" ], 1007 [ "sScrollY", "sY" ], 1008 [ "bScrollCollapse", "bCollapse" ] 1009 ] ); 1010 _fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" ); 1011 1012 /* Callback functions which are array driven */ 1013 _fnCallbackReg( oSettings, 'aoDrawCallback', oInit.fnDrawCallback, 'user' ); 1014 _fnCallbackReg( oSettings, 'aoServerParams', oInit.fnServerParams, 'user' ); 1015 _fnCallbackReg( oSettings, 'aoStateSaveParams', oInit.fnStateSaveParams, 'user' ); 1016 _fnCallbackReg( oSettings, 'aoStateLoadParams', oInit.fnStateLoadParams, 'user' ); 1017 _fnCallbackReg( oSettings, 'aoStateLoaded', oInit.fnStateLoaded, 'user' ); 1018 _fnCallbackReg( oSettings, 'aoRowCallback', oInit.fnRowCallback, 'user' ); 1019 _fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow, 'user' ); 1020 _fnCallbackReg( oSettings, 'aoHeaderCallback', oInit.fnHeaderCallback, 'user' ); 1021 _fnCallbackReg( oSettings, 'aoFooterCallback', oInit.fnFooterCallback, 'user' ); 1022 _fnCallbackReg( oSettings, 'aoInitComplete', oInit.fnInitComplete, 'user' ); 1023 _fnCallbackReg( oSettings, 'aoPreDrawCallback', oInit.fnPreDrawCallback, 'user' ); 1024 1025 oSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId ); 1026 1027 /* Browser support detection */ 1028 _fnBrowserDetect( oSettings ); 1029 1030 var oClasses = oSettings.oClasses; 1031 1032 $.extend( oClasses, DataTable.ext.classes, oInit.oClasses ); 1033 $this.addClass( oClasses.sTable ); 1034 1035 1036 if ( oSettings.iInitDisplayStart === undefined ) 1037 { 1038 /* Display start point, taking into account the save saving */ 1039 oSettings.iInitDisplayStart = oInit.iDisplayStart; 1040 oSettings._iDisplayStart = oInit.iDisplayStart; 1041 } 1042 1043 if ( oInit.iDeferLoading !== null ) 1044 { 1045 oSettings.bDeferLoading = true; 1046 var tmp = Array.isArray( oInit.iDeferLoading ); 1047 oSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading; 1048 oSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading; 1049 } 1050 1051 /* Language definitions */ 1052 var oLanguage = oSettings.oLanguage; 1053 $.extend( true, oLanguage, oInit.oLanguage ); 1054 1055 if ( oLanguage.sUrl ) 1056 { 1057 /* Get the language definitions from a file - because this Ajax call makes the language 1058 * get async to the remainder of this function we use bInitHandedOff to indicate that 1059 * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor 1060 */ 1061 $.ajax( { 1062 dataType: 'json', 1063 url: oLanguage.sUrl, 1064 success: function ( json ) { 1065 _fnCamelToHungarian( defaults.oLanguage, json ); 1066 _fnLanguageCompat( json ); 1067 $.extend( true, oLanguage, json, oSettings.oInit.oLanguage ); 1068 1069 _fnCallbackFire( oSettings, null, 'i18n', [oSettings]); 1070 _fnInitialise( oSettings ); 1071 }, 1072 error: function () { 1073 // Error occurred loading language file, continue on as best we can 1074 _fnInitialise( oSettings ); 1075 } 1076 } ); 1077 bInitHandedOff = true; 1078 } 1079 else { 1080 _fnCallbackFire( oSettings, null, 'i18n', [oSettings]); 1081 } 1082 1083 /* 1084 * Stripes 1085 */ 1086 if ( oInit.asStripeClasses === null ) 1087 { 1088 oSettings.asStripeClasses =[ 1089 oClasses.sStripeOdd, 1090 oClasses.sStripeEven 1091 ]; 1092 } 1093 1094 /* Remove row stripe classes if they are already on the table row */ 1095 var stripeClasses = oSettings.asStripeClasses; 1096 var rowOne = $this.children('tbody').find('tr').eq(0); 1097 if ( $.inArray( true, $.map( stripeClasses, function(el, i) { 1098 return rowOne.hasClass(el); 1099 } ) ) !== -1 ) { 1100 $('tbody tr', this).removeClass( stripeClasses.join(' ') ); 1101 oSettings.asDestroyStripes = stripeClasses.slice(); 1102 } 1103 1104 /* 1105 * Columns 1106 * See if we should load columns automatically or use defined ones 1107 */ 1108 var anThs = []; 1109 var aoColumnsInit; 1110 var nThead = this.getElementsByTagName('thead'); 1111 if ( nThead.length !== 0 ) 1112 { 1113 _fnDetectHeader( oSettings.aoHeader, nThead[0] ); 1114 anThs = _fnGetUniqueThs( oSettings ); 1115 } 1116 1117 /* If not given a column array, generate one with nulls */ 1118 if ( oInit.aoColumns === null ) 1119 { 1120 aoColumnsInit = []; 1121 for ( i=0, iLen=anThs.length ; i<iLen ; i++ ) 1122 { 1123 aoColumnsInit.push( null ); 1124 } 1125 } 1126 else 1127 { 1128 aoColumnsInit = oInit.aoColumns; 1129 } 1130 1131 /* Add the columns */ 1132 for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ ) 1133 { 1134 _fnAddColumn( oSettings, anThs ? anThs[i] : null ); 1135 } 1136 1137 /* Apply the column definitions */ 1138 _fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) { 1139 _fnColumnOptions( oSettings, iCol, oDef ); 1140 } ); 1141 1142 /* HTML5 attribute detection - build an mData object automatically if the 1143 * attributes are found 1144 */ 1145 if ( rowOne.length ) { 1146 var a = function ( cell, name ) { 1147 return cell.getAttribute( 'data-'+name ) !== null ? name : null; 1148 }; 1149 1150 $( rowOne[0] ).children('th, td').each( function (i, cell) { 1151 var col = oSettings.aoColumns[i]; 1152 1153 if ( col.mData === i ) { 1154 var sort = a( cell, 'sort' ) || a( cell, 'order' ); 1155 var filter = a( cell, 'filter' ) || a( cell, 'search' ); 1156 1157 if ( sort !== null || filter !== null ) { 1158 col.mData = { 1159 _: i+'.display', 1160 sort: sort !== null ? i+'.@data-'+sort : undefined, 1161 type: sort !== null ? i+'.@data-'+sort : undefined, 1162 filter: filter !== null ? i+'.@data-'+filter : undefined 1163 }; 1164 1165 _fnColumnOptions( oSettings, i ); 1166 } 1167 } 1168 } ); 1169 } 1170 1171 var features = oSettings.oFeatures; 1172 var loadedInit = function () { 1173 /* 1174 * Sorting 1175 * @todo For modularisation (1.11) this needs to do into a sort start up handler 1176 */ 1177 1178 // If aaSorting is not defined, then we use the first indicator in asSorting 1179 // in case that has been altered, so the default sort reflects that option 1180 if ( oInit.aaSorting === undefined ) { 1181 var sorting = oSettings.aaSorting; 1182 for ( i=0, iLen=sorting.length ; i<iLen ; i++ ) { 1183 sorting[i][1] = oSettings.aoColumns[ i ].asSorting[0]; 1184 } 1185 } 1186 1187 /* Do a first pass on the sorting classes (allows any size changes to be taken into 1188 * account, and also will apply sorting disabled classes if disabled 1189 */ 1190 _fnSortingClasses( oSettings ); 1191 1192 if ( features.bSort ) { 1193 _fnCallbackReg( oSettings, 'aoDrawCallback', function () { 1194 if ( oSettings.bSorted ) { 1195 var aSort = _fnSortFlatten( oSettings ); 1196 var sortedColumns = {}; 1197 1198 $.each( aSort, function (i, val) { 1199 sortedColumns[ val.src ] = val.dir; 1200 } ); 1201 1202 _fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] ); 1203 _fnSortAria( oSettings ); 1204 } 1205 } ); 1206 } 1207 1208 _fnCallbackReg( oSettings, 'aoDrawCallback', function () { 1209 if ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) { 1210 _fnSortingClasses( oSettings ); 1211 } 1212 }, 'sc' ); 1213 1214 1215 /* 1216 * Final init 1217 * Cache the header, body and footer as required, creating them if needed 1218 */ 1219 1220 // Work around for Webkit bug 83867 - store the caption-side before removing from doc 1221 var captions = $this.children('caption').each( function () { 1222 this._captionSide = $(this).css('caption-side'); 1223 } ); 1224 1225 var thead = $this.children('thead'); 1226 if ( thead.length === 0 ) { 1227 thead = $('<thead/>').appendTo($this); 1228 } 1229 oSettings.nTHead = thead[0]; 1230 1231 var tbody = $this.children('tbody'); 1232 if ( tbody.length === 0 ) { 1233 tbody = $('<tbody/>').insertAfter(thead); 1234 } 1235 oSettings.nTBody = tbody[0]; 1236 1237 var tfoot = $this.children('tfoot'); 1238 if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") ) { 1239 // If we are a scrolling table, and no footer has been given, then we need to create 1240 // a tfoot element for the caption element to be appended to 1241 tfoot = $('<tfoot/>').appendTo($this); 1242 } 1243 1244 if ( tfoot.length === 0 || tfoot.children().length === 0 ) { 1245 $this.addClass( oClasses.sNoFooter ); 1246 } 1247 else if ( tfoot.length > 0 ) { 1248 oSettings.nTFoot = tfoot[0]; 1249 _fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot ); 1250 } 1251 1252 /* Check if there is data passing into the constructor */ 1253 if ( oInit.aaData ) { 1254 for ( i=0 ; i<oInit.aaData.length ; i++ ) { 1255 _fnAddData( oSettings, oInit.aaData[ i ] ); 1256 } 1257 } 1258 else if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' ) { 1259 /* Grab the data from the page - only do this when deferred loading or no Ajax 1260 * source since there is no point in reading the DOM data if we are then going 1261 * to replace it with Ajax data 1262 */ 1263 _fnAddTr( oSettings, $(oSettings.nTBody).children('tr') ); 1264 } 1265 1266 /* Copy the data index array */ 1267 oSettings.aiDisplay = oSettings.aiDisplayMaster.slice(); 1268 1269 /* Initialisation complete - table can be drawn */ 1270 oSettings.bInitialised = true; 1271 1272 /* Check if we need to initialise the table (it might not have been handed off to the 1273 * language processor) 1274 */ 1275 if ( bInitHandedOff === false ) { 1276 _fnInitialise( oSettings ); 1277 } 1278 }; 1279 1280 /* Must be done after everything which can be overridden by the state saving! */ 1281 _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' ); 1282 1283 if ( oInit.bStateSave ) 1284 { 1285 features.bStateSave = true; 1286 _fnLoadState( oSettings, oInit, loadedInit ); 1287 } 1288 else { 1289 loadedInit(); 1290 } 1291 1292 } ); 1293 _that = null; 1294 return this; 1295 }; 1296 1297 1298 /* 1299 * It is useful to have variables which are scoped locally so only the 1300 * DataTables functions can access them and they don't leak into global space. 1301 * At the same time these functions are often useful over multiple files in the 1302 * core and API, so we list, or at least document, all variables which are used 1303 * by DataTables as private variables here. This also ensures that there is no 1304 * clashing of variable names and that they can easily referenced for reuse. 1305 */ 1306 1307 1308 // Defined else where 1309 // _selector_run 1310 // _selector_opts 1311 // _selector_first 1312 // _selector_row_indexes 1313 1314 var _ext; // DataTable.ext 1315 var _Api; // DataTable.Api 1316 var _api_register; // DataTable.Api.register 1317 var _api_registerPlural; // DataTable.Api.registerPlural 1318 1319 var _re_dic = {}; 1320 var _re_new_lines = /[\r\n\u2028]/g; 1321 var _re_html = /<.*?>/g; 1322 1323 // This is not strict ISO8601 - Date.parse() is quite lax, although 1324 // implementations differ between browsers. 1325 var _re_date = /^\d{2,4}[\.\/\-]\d{1,2}[\.\/\-]\d{1,2}([T ]{1}\d{1,2}[:\.]\d{2}([\.:]\d{2})?)?$/; 1326 1327 // Escape regular expression special characters 1328 var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' ); 1329 1330 // http://en.wikipedia.org/wiki/Foreign_exchange_market 1331 // - \u20BD - Russian ruble. 1332 // - \u20a9 - South Korean Won 1333 // - \u20BA - Turkish Lira 1334 // - \u20B9 - Indian Rupee 1335 // - R - Brazil (R$) and South Africa 1336 // - fr - Swiss Franc 1337 // - kr - Swedish krona, Norwegian krone and Danish krone 1338 // - \u2009 is thin space and \u202F is narrow no-break space, both used in many 1339 // - É - Bitcoin 1340 // - Î - Ethereum 1341 // standards as thousands separators. 1342 var _re_formatted_numeric = /['\u00A0,$£â¬Â¥%\u2009\u202F\u20BD\u20a9\u20BArfkÉÎ]/gi; 1343 1344 1345 var _empty = function ( d ) { 1346 return !d || d === true || d === '-' ? true : false; 1347 }; 1348 1349 1350 var _intVal = function ( s ) { 1351 var integer = parseInt( s, 10 ); 1352 return !isNaN(integer) && isFinite(s) ? integer : null; 1353 }; 1354 1355 // Convert from a formatted number with characters other than `.` as the 1356 // decimal place, to a Javascript number 1357 var _numToDecimal = function ( num, decimalPoint ) { 1358 // Cache created regular expressions for speed as this function is called often 1359 if ( ! _re_dic[ decimalPoint ] ) { 1360 _re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' ); 1361 } 1362 return typeof num === 'string' && decimalPoint !== '.' ? 1363 num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) : 1364 num; 1365 }; 1366 1367 1368 var _isNumber = function ( d, decimalPoint, formatted ) { 1369 var strType = typeof d === 'string'; 1370 1371 // If empty return immediately so there must be a number if it is a 1372 // formatted string (this stops the string "k", or "kr", etc being detected 1373 // as a formatted number for currency 1374 if ( _empty( d ) ) { 1375 return true; 1376 } 1377 1378 if ( decimalPoint && strType ) { 1379 d = _numToDecimal( d, decimalPoint ); 1380 } 1381 1382 if ( formatted && strType ) { 1383 d = d.replace( _re_formatted_numeric, '' ); 1384 } 1385 1386 return !isNaN( parseFloat(d) ) && isFinite( d ); 1387 }; 1388 1389 1390 // A string without HTML in it can be considered to be HTML still 1391 var _isHtml = function ( d ) { 1392 return _empty( d ) || typeof d === 'string'; 1393 }; 1394 1395 1396 var _htmlNumeric = function ( d, decimalPoint, formatted ) { 1397 if ( _empty( d ) ) { 1398 return true; 1399 } 1400 1401 var html = _isHtml( d ); 1402 return ! html ? 1403 null : 1404 _isNumber( _stripHtml( d ), decimalPoint, formatted ) ? 1405 true : 1406 null; 1407 }; 1408 1409 1410 var _pluck = function ( a, prop, prop2 ) { 1411 var out = []; 1412 var i=0, ien=a.length; 1413 1414 // Could have the test in the loop for slightly smaller code, but speed 1415 // is essential here 1416 if ( prop2 !== undefined ) { 1417 for ( ; i<ien ; i++ ) { 1418 if ( a[i] && a[i][ prop ] ) { 1419 out.push( a[i][ prop ][ prop2 ] ); 1420 } 1421 } 1422 } 1423 else { 1424 for ( ; i<ien ; i++ ) { 1425 if ( a[i] ) { 1426 out.push( a[i][ prop ] ); 1427 } 1428 } 1429 } 1430 1431 return out; 1432 }; 1433 1434 1435 // Basically the same as _pluck, but rather than looping over `a` we use `order` 1436 // as the indexes to pick from `a` 1437 var _pluck_order = function ( a, order, prop, prop2 ) 1438 { 1439 var out = []; 1440 var i=0, ien=order.length; 1441 1442 // Could have the test in the loop for slightly smaller code, but speed 1443 // is essential here 1444 if ( prop2 !== undefined ) { 1445 for ( ; i<ien ; i++ ) { 1446 if ( a[ order[i] ][ prop ] ) { 1447 out.push( a[ order[i] ][ prop ][ prop2 ] ); 1448 } 1449 } 1450 } 1451 else { 1452 for ( ; i<ien ; i++ ) { 1453 out.push( a[ order[i] ][ prop ] ); 1454 } 1455 } 1456 1457 return out; 1458 }; 1459 1460 1461 var _range = function ( len, start ) 1462 { 1463 var out = []; 1464 var end; 1465 1466 if ( start === undefined ) { 1467 start = 0; 1468 end = len; 1469 } 1470 else { 1471 end = start; 1472 start = len; 1473 } 1474 1475 for ( var i=start ; i<end ; i++ ) { 1476 out.push( i ); 1477 } 1478 1479 return out; 1480 }; 1481 1482 1483 var _removeEmpty = function ( a ) 1484 { 1485 var out = []; 1486 1487 for ( var i=0, ien=a.length ; i<ien ; i++ ) { 1488 if ( a[i] ) { // careful - will remove all falsy values! 1489 out.push( a[i] ); 1490 } 1491 } 1492 1493 return out; 1494 }; 1495 1496 1497 var _stripHtml = function ( d ) { 1498 return d.replace( _re_html, '' ); 1499 }; 1500 1501 1502 /** 1503 * Determine if all values in the array are unique. This means we can short 1504 * cut the _unique method at the cost of a single loop. A sorted array is used 1505 * to easily check the values. 1506 * 1507 * @param {array} src Source array 1508 * @return {boolean} true if all unique, false otherwise 1509 * @ignore 1510 */ 1511 var _areAllUnique = function ( src ) { 1512 if ( src.length < 2 ) { 1513 return true; 1514 } 1515 1516 var sorted = src.slice().sort(); 1517 var last = sorted[0]; 1518 1519 for ( var i=1, ien=sorted.length ; i<ien ; i++ ) { 1520 if ( sorted[i] === last ) { 1521 return false; 1522 } 1523 1524 last = sorted[i]; 1525 } 1526 1527 return true; 1528 }; 1529 1530 1531 /** 1532 * Find the unique elements in a source array. 1533 * 1534 * @param {array} src Source array 1535 * @return {array} Array of unique items 1536 * @ignore 1537 */ 1538 var _unique = function ( src ) 1539 { 1540 if ( _areAllUnique( src ) ) { 1541 return src.slice(); 1542 } 1543 1544 // A faster unique method is to use object keys to identify used values, 1545 // but this doesn't work with arrays or objects, which we must also 1546 // consider. See jsperf.com/compare-array-unique-versions/4 for more 1547 // information. 1548 var 1549 out = [], 1550 val, 1551 i, ien=src.length, 1552 j, k=0; 1553 1554 again: for ( i=0 ; i<ien ; i++ ) { 1555 val = src[i]; 1556 1557 for ( j=0 ; j<k ; j++ ) { 1558 if ( out[j] === val ) { 1559 continue again; 1560 } 1561 } 1562 1563 out.push( val ); 1564 k++; 1565 } 1566 1567 return out; 1568 }; 1569 1570 // Surprisingly this is faster than [].concat.apply 1571 // https://jsperf.com/flatten-an-array-loop-vs-reduce/2 1572 var _flatten = function (out, val) { 1573 if (Array.isArray(val)) { 1574 for (var i=0 ; i<val.length ; i++) { 1575 _flatten(out, val[i]); 1576 } 1577 } 1578 else { 1579 out.push(val); 1580 } 1581 1582 return out; 1583 } 1584 1585 var _includes = function (search, start) { 1586 if (start === undefined) { 1587 start = 0; 1588 } 1589 1590 return this.indexOf(search, start) !== -1; 1591 }; 1592 1593 // Array.isArray polyfill. 1594 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray 1595 if (! Array.isArray) { 1596 Array.isArray = function(arg) { 1597 return Object.prototype.toString.call(arg) === '[object Array]'; 1598 }; 1599 } 1600 1601 if (! Array.prototype.includes) { 1602 Array.prototype.includes = _includes; 1603 } 1604 1605 // .trim() polyfill 1606 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/trim 1607 if (!String.prototype.trim) { 1608 String.prototype.trim = function () { 1609 return this.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ''); 1610 }; 1611 } 1612 1613 if (! String.prototype.includes) { 1614 String.prototype.includes = _includes; 1615 } 1616 1617 /** 1618 * DataTables utility methods 1619 * 1620 * This namespace provides helper methods that DataTables uses internally to 1621 * create a DataTable, but which are not exclusively used only for DataTables. 1622 * These methods can be used by extension authors to save the duplication of 1623 * code. 1624 * 1625 * @namespace 1626 */ 1627 DataTable.util = { 1628 /** 1629 * Throttle the calls to a function. Arguments and context are maintained 1630 * for the throttled function. 1631 * 1632 * @param {function} fn Function to be called 1633 * @param {integer} freq Call frequency in mS 1634 * @return {function} Wrapped function 1635 */ 1636 throttle: function ( fn, freq ) { 1637 var 1638 frequency = freq !== undefined ? freq : 200, 1639 last, 1640 timer; 1641 1642 return function () { 1643 var 1644 that = this, 1645 now = +new Date(), 1646 args = arguments; 1647 1648 if ( last && now < last + frequency ) { 1649 clearTimeout( timer ); 1650 1651 timer = setTimeout( function () { 1652 last = undefined; 1653 fn.apply( that, args ); 1654 }, frequency ); 1655 } 1656 else { 1657 last = now; 1658 fn.apply( that, args ); 1659 } 1660 }; 1661 }, 1662 1663 1664 /** 1665 * Escape a string such that it can be used in a regular expression 1666 * 1667 * @param {string} val string to escape 1668 * @returns {string} escaped string 1669 */ 1670 escapeRegex: function ( val ) { 1671 return val.replace( _re_escape_regex, '\\$1' ); 1672 }, 1673 1674 /** 1675 * Create a function that will write to a nested object or array 1676 * @param {*} source JSON notation string 1677 * @returns Write function 1678 */ 1679 set: function ( source ) { 1680 if ( $.isPlainObject( source ) ) { 1681 /* Unlike get, only the underscore (global) option is used for for 1682 * setting data since we don't know the type here. This is why an object 1683 * option is not documented for `mData` (which is read/write), but it is 1684 * for `mRender` which is read only. 1685 */ 1686 return DataTable.util.set( source._ ); 1687 } 1688 else if ( source === null ) { 1689 // Nothing to do when the data source is null 1690 return function () {}; 1691 } 1692 else if ( typeof source === 'function' ) { 1693 return function (data, val, meta) { 1694 source( data, 'set', val, meta ); 1695 }; 1696 } 1697 else if ( typeof source === 'string' && (source.indexOf('.') !== -1 || 1698 source.indexOf('[') !== -1 || source.indexOf('(') !== -1) ) 1699 { 1700 // Like the get, we need to get data from a nested object 1701 var setData = function (data, val, src) { 1702 var a = _fnSplitObjNotation( src ), b; 1703 var aLast = a[a.length-1]; 1704 var arrayNotation, funcNotation, o, innerSrc; 1705 1706 for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ ) { 1707 // Protect against prototype pollution 1708 if (a[i] === '__proto__' || a[i] === 'constructor') { 1709 throw new Error('Cannot set prototype values'); 1710 } 1711 1712 // Check if we are dealing with an array notation request 1713 arrayNotation = a[i].match(__reArray); 1714 funcNotation = a[i].match(__reFn); 1715 1716 if ( arrayNotation ) { 1717 a[i] = a[i].replace(__reArray, ''); 1718 data[ a[i] ] = []; 1719 1720 // Get the remainder of the nested object to set so we can recurse 1721 b = a.slice(); 1722 b.splice( 0, i+1 ); 1723 innerSrc = b.join('.'); 1724 1725 // Traverse each entry in the array setting the properties requested 1726 if ( Array.isArray( val ) ) { 1727 for ( var j=0, jLen=val.length ; j<jLen ; j++ ) { 1728 o = {}; 1729 setData( o, val[j], innerSrc ); 1730 data[ a[i] ].push( o ); 1731 } 1732 } 1733 else { 1734 // We've been asked to save data to an array, but it 1735 // isn't array data to be saved. Best that can be done 1736 // is to just save the value. 1737 data[ a[i] ] = val; 1738 } 1739 1740 // The inner call to setData has already traversed through the remainder 1741 // of the source and has set the data, thus we can exit here 1742 return; 1743 } 1744 else if ( funcNotation ) { 1745 // Function call 1746 a[i] = a[i].replace(__reFn, ''); 1747 data = data[ a[i] ]( val ); 1748 } 1749 1750 // If the nested object doesn't currently exist - since we are 1751 // trying to set the value - create it 1752 if ( data[ a[i] ] === null || data[ a[i] ] === undefined ) { 1753 data[ a[i] ] = {}; 1754 } 1755 data = data[ a[i] ]; 1756 } 1757 1758 // Last item in the input - i.e, the actual set 1759 if ( aLast.match(__reFn ) ) { 1760 // Function call 1761 data = data[ aLast.replace(__reFn, '') ]( val ); 1762 } 1763 else { 1764 // If array notation is used, we just want to strip it and use the property name 1765 // and assign the value. If it isn't used, then we get the result we want anyway 1766 data[ aLast.replace(__reArray, '') ] = val; 1767 } 1768 }; 1769 1770 return function (data, val) { // meta is also passed in, but not used 1771 return setData( data, val, source ); 1772 }; 1773 } 1774 else { 1775 // Array or flat object mapping 1776 return function (data, val) { // meta is also passed in, but not used 1777 data[source] = val; 1778 }; 1779 } 1780 }, 1781 1782 /** 1783 * Create a function that will read nested objects from arrays, based on JSON notation 1784 * @param {*} source JSON notation string 1785 * @returns Value read 1786 */ 1787 get: function ( source ) { 1788 if ( $.isPlainObject( source ) ) { 1789 // Build an object of get functions, and wrap them in a single call 1790 var o = {}; 1791 $.each( source, function (key, val) { 1792 if ( val ) { 1793 o[key] = DataTable.util.get( val ); 1794 } 1795 } ); 1796 1797 return function (data, type, row, meta) { 1798 var t = o[type] || o._; 1799 return t !== undefined ? 1800 t(data, type, row, meta) : 1801 data; 1802 }; 1803 } 1804 else if ( source === null ) { 1805 // Give an empty string for rendering / sorting etc 1806 return function (data) { // type, row and meta also passed, but not used 1807 return data; 1808 }; 1809 } 1810 else if ( typeof source === 'function' ) { 1811 return function (data, type, row, meta) { 1812 return source( data, type, row, meta ); 1813 }; 1814 } 1815 else if ( typeof source === 'string' && (source.indexOf('.') !== -1 || 1816 source.indexOf('[') !== -1 || source.indexOf('(') !== -1) ) 1817 { 1818 /* If there is a . in the source string then the data source is in a 1819 * nested object so we loop over the data for each level to get the next 1820 * level down. On each loop we test for undefined, and if found immediately 1821 * return. This allows entire objects to be missing and sDefaultContent to 1822 * be used if defined, rather than throwing an error 1823 */ 1824 var fetchData = function (data, type, src) { 1825 var arrayNotation, funcNotation, out, innerSrc; 1826 1827 if ( src !== "" ) { 1828 var a = _fnSplitObjNotation( src ); 1829 1830 for ( var i=0, iLen=a.length ; i<iLen ; i++ ) { 1831 // Check if we are dealing with special notation 1832 arrayNotation = a[i].match(__reArray); 1833 funcNotation = a[i].match(__reFn); 1834 1835 if ( arrayNotation ) { 1836 // Array notation 1837 a[i] = a[i].replace(__reArray, ''); 1838 1839 // Condition allows simply [] to be passed in 1840 if ( a[i] !== "" ) { 1841 data = data[ a[i] ]; 1842 } 1843 out = []; 1844 1845 // Get the remainder of the nested object to get 1846 a.splice( 0, i+1 ); 1847 innerSrc = a.join('.'); 1848 1849 // Traverse each entry in the array getting the properties requested 1850 if ( Array.isArray( data ) ) { 1851 for ( var j=0, jLen=data.length ; j<jLen ; j++ ) { 1852 out.push( fetchData( data[j], type, innerSrc ) ); 1853 } 1854 } 1855 1856 // If a string is given in between the array notation indicators, that 1857 // is used to join the strings together, otherwise an array is returned 1858 var join = arrayNotation[0].substring(1, arrayNotation[0].length-1); 1859 data = (join==="") ? out : out.join(join); 1860 1861 // The inner call to fetchData has already traversed through the remainder 1862 // of the source requested, so we exit from the loop 1863 break; 1864 } 1865 else if ( funcNotation ) { 1866 // Function call 1867 a[i] = a[i].replace(__reFn, ''); 1868 data = data[ a[i] ](); 1869 continue; 1870 } 1871 1872 if ( data === null || data[ a[i] ] === undefined ) { 1873 return undefined; 1874 } 1875 1876 data = data[ a[i] ]; 1877 } 1878 } 1879 1880 return data; 1881 }; 1882 1883 return function (data, type) { // row and meta also passed, but not used 1884 return fetchData( data, type, source ); 1885 }; 1886 } 1887 else { 1888 // Array or flat object mapping 1889 return function (data, type) { // row and meta also passed, but not used 1890 return data[source]; 1891 }; 1892 } 1893 } 1894 }; 1895 1896 1897 1898 /** 1899 * Create a mapping object that allows camel case parameters to be looked up 1900 * for their Hungarian counterparts. The mapping is stored in a private 1901 * parameter called `_hungarianMap` which can be accessed on the source object. 1902 * @param {object} o 1903 * @memberof DataTable#oApi 1904 */ 1905 function _fnHungarianMap ( o ) 1906 { 1907 var 1908 hungarian = 'a aa ai ao as b fn i m o s ', 1909 match, 1910 newKey, 1911 map = {}; 1912 1913 $.each( o, function (key, val) { 1914 match = key.match(/^([^A-Z]+?)([A-Z])/); 1915 1916 if ( match && hungarian.indexOf(match[1]+' ') !== -1 ) 1917 { 1918 newKey = key.replace( match[0], match[2].toLowerCase() ); 1919 map[ newKey ] = key; 1920 1921 if ( match[1] === 'o' ) 1922 { 1923 _fnHungarianMap( o[key] ); 1924 } 1925 } 1926 } ); 1927 1928 o._hungarianMap = map; 1929 } 1930 1931 1932 /** 1933 * Convert from camel case parameters to Hungarian, based on a Hungarian map 1934 * created by _fnHungarianMap. 1935 * @param {object} src The model object which holds all parameters that can be 1936 * mapped. 1937 * @param {object} user The object to convert from camel case to Hungarian. 1938 * @param {boolean} force When set to `true`, properties which already have a 1939 * Hungarian value in the `user` object will be overwritten. Otherwise they 1940 * won't be. 1941 * @memberof DataTable#oApi 1942 */ 1943 function _fnCamelToHungarian ( src, user, force ) 1944 { 1945 if ( ! src._hungarianMap ) { 1946 _fnHungarianMap( src ); 1947 } 1948 1949 var hungarianKey; 1950 1951 $.each( user, function (key, val) { 1952 hungarianKey = src._hungarianMap[ key ]; 1953 1954 if ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) ) 1955 { 1956 // For objects, we need to buzz down into the object to copy parameters 1957 if ( hungarianKey.charAt(0) === 'o' ) 1958 { 1959 // Copy the camelCase options over to the hungarian 1960 if ( ! user[ hungarianKey ] ) { 1961 user[ hungarianKey ] = {}; 1962 } 1963 $.extend( true, user[hungarianKey], user[key] ); 1964 1965 _fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force ); 1966 } 1967 else { 1968 user[hungarianKey] = user[ key ]; 1969 } 1970 } 1971 } ); 1972 } 1973 1974 1975 /** 1976 * Language compatibility - when certain options are given, and others aren't, we 1977 * need to duplicate the values over, in order to provide backwards compatibility 1978 * with older language files. 1979 * @param {object} oSettings dataTables settings object 1980 * @memberof DataTable#oApi 1981 */ 1982 function _fnLanguageCompat( lang ) 1983 { 1984 // Note the use of the Hungarian notation for the parameters in this method as 1985 // this is called after the mapping of camelCase to Hungarian 1986 var defaults = DataTable.defaults.oLanguage; 1987 1988 // Default mapping 1989 var defaultDecimal = defaults.sDecimal; 1990 if ( defaultDecimal ) { 1991 _addNumericSort( defaultDecimal ); 1992 } 1993 1994 if ( lang ) { 1995 var zeroRecords = lang.sZeroRecords; 1996 1997 // Backwards compatibility - if there is no sEmptyTable given, then use the same as 1998 // sZeroRecords - assuming that is given. 1999 if ( ! lang.sEmptyTable && zeroRecords && 2000 defaults.sEmptyTable === "No data available in table" ) 2001 { 2002 _fnMap( lang, lang, 'sZeroRecords', 'sEmptyTable' ); 2003 } 2004 2005 // Likewise with loading records 2006 if ( ! lang.sLoadingRecords && zeroRecords && 2007 defaults.sLoadingRecords === "Loading..." ) 2008 { 2009 _fnMap( lang, lang, 'sZeroRecords', 'sLoadingRecords' ); 2010 } 2011 2012 // Old parameter name of the thousands separator mapped onto the new 2013 if ( lang.sInfoThousands ) { 2014 lang.sThousands = lang.sInfoThousands; 2015 } 2016 2017 var decimal = lang.sDecimal; 2018 if ( decimal && defaultDecimal !== decimal ) { 2019 _addNumericSort( decimal ); 2020 } 2021 } 2022 } 2023 2024 2025 /** 2026 * Map one parameter onto another 2027 * @param {object} o Object to map 2028 * @param {*} knew The new parameter name 2029 * @param {*} old The old parameter name 2030 */ 2031 var _fnCompatMap = function ( o, knew, old ) { 2032 if ( o[ knew ] !== undefined ) { 2033 o[ old ] = o[ knew ]; 2034 } 2035 }; 2036 2037 2038 /** 2039 * Provide backwards compatibility for the main DT options. Note that the new 2040 * options are mapped onto the old parameters, so this is an external interface 2041 * change only. 2042 * @param {object} init Object to map 2043 */ 2044 function _fnCompatOpts ( init ) 2045 { 2046 _fnCompatMap( init, 'ordering', 'bSort' ); 2047 _fnCompatMap( init, 'orderMulti', 'bSortMulti' ); 2048 _fnCompatMap( init, 'orderClasses', 'bSortClasses' ); 2049 _fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' ); 2050 _fnCompatMap( init, 'order', 'aaSorting' ); 2051 _fnCompatMap( init, 'orderFixed', 'aaSortingFixed' ); 2052 _fnCompatMap( init, 'paging', 'bPaginate' ); 2053 _fnCompatMap( init, 'pagingType', 'sPaginationType' ); 2054 _fnCompatMap( init, 'pageLength', 'iDisplayLength' ); 2055 _fnCompatMap( init, 'searching', 'bFilter' ); 2056 2057 // Boolean initialisation of x-scrolling 2058 if ( typeof init.sScrollX === 'boolean' ) { 2059 init.sScrollX = init.sScrollX ? '100%' : ''; 2060 } 2061 if ( typeof init.scrollX === 'boolean' ) { 2062 init.scrollX = init.scrollX ? '100%' : ''; 2063 } 2064 2065 // Column search objects are in an array, so it needs to be converted 2066 // element by element 2067 var searchCols = init.aoSearchCols; 2068 2069 if ( searchCols ) { 2070 for ( var i=0, ien=searchCols.length ; i<ien ; i++ ) { 2071 if ( searchCols[i] ) { 2072 _fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] ); 2073 } 2074 } 2075 } 2076 } 2077 2078 2079 /** 2080 * Provide backwards compatibility for column options. Note that the new options 2081 * are mapped onto the old parameters, so this is an external interface change 2082 * only. 2083 * @param {object} init Object to map 2084 */ 2085 function _fnCompatCols ( init ) 2086 { 2087 _fnCompatMap( init, 'orderable', 'bSortable' ); 2088 _fnCompatMap( init, 'orderData', 'aDataSort' ); 2089 _fnCompatMap( init, 'orderSequence', 'asSorting' ); 2090 _fnCompatMap( init, 'orderDataType', 'sortDataType' ); 2091 2092 // orderData can be given as an integer 2093 var dataSort = init.aDataSort; 2094 if ( typeof dataSort === 'number' && ! Array.isArray( dataSort ) ) { 2095 init.aDataSort = [ dataSort ]; 2096 } 2097 } 2098 2099 2100 /** 2101 * Browser feature detection for capabilities, quirks 2102 * @param {object} settings dataTables settings object 2103 * @memberof DataTable#oApi 2104 */ 2105 function _fnBrowserDetect( settings ) 2106 { 2107 // We don't need to do this every time DataTables is constructed, the values 2108 // calculated are specific to the browser and OS configuration which we 2109 // don't expect to change between initialisations 2110 if ( ! DataTable.__browser ) { 2111 var browser = {}; 2112 DataTable.__browser = browser; 2113 2114 // Scrolling feature / quirks detection 2115 var n = $('<div/>') 2116 .css( { 2117 position: 'fixed', 2118 top: 0, 2119 left: $(window).scrollLeft()*-1, // allow for scrolling 2120 height: 1, 2121 width: 1, 2122 overflow: 'hidden' 2123 } ) 2124 .append( 2125 $('<div/>') 2126 .css( { 2127 position: 'absolute', 2128 top: 1, 2129 left: 1, 2130 width: 100, 2131 overflow: 'scroll' 2132 } ) 2133 .append( 2134 $('<div/>') 2135 .css( { 2136 width: '100%', 2137 height: 10 2138 } ) 2139 ) 2140 ) 2141 .appendTo( 'body' ); 2142 2143 var outer = n.children(); 2144 var inner = outer.children(); 2145 2146 // Numbers below, in order, are: 2147 // inner.offsetWidth, inner.clientWidth, outer.offsetWidth, outer.clientWidth 2148 // 2149 // IE6 XP: 100 100 100 83 2150 // IE7 Vista: 100 100 100 83 2151 // IE 8+ Windows: 83 83 100 83 2152 // Evergreen Windows: 83 83 100 83 2153 // Evergreen Mac with scrollbars: 85 85 100 85 2154 // Evergreen Mac without scrollbars: 100 100 100 100 2155 2156 // Get scrollbar width 2157 browser.barWidth = outer[0].offsetWidth - outer[0].clientWidth; 2158 2159 // IE6/7 will oversize a width 100% element inside a scrolling element, to 2160 // include the width of the scrollbar, while other browsers ensure the inner 2161 // element is contained without forcing scrolling 2162 browser.bScrollOversize = inner[0].offsetWidth === 100 && outer[0].clientWidth !== 100; 2163 2164 // In rtl text layout, some browsers (most, but not all) will place the 2165 // scrollbar on the left, rather than the right. 2166 browser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1; 2167 2168 // IE8- don't provide height and width for getBoundingClientRect 2169 browser.bBounding = n[0].getBoundingClientRect().width ? true : false; 2170 2171 n.remove(); 2172 } 2173 2174 $.extend( settings.oBrowser, DataTable.__browser ); 2175 settings.oScroll.iBarWidth = DataTable.__browser.barWidth; 2176 } 2177 2178 2179 /** 2180 * Array.prototype reduce[Right] method, used for browsers which don't support 2181 * JS 1.6. Done this way to reduce code size, since we iterate either way 2182 * @param {object} settings dataTables settings object 2183 * @memberof DataTable#oApi 2184 */ 2185 function _fnReduce ( that, fn, init, start, end, inc ) 2186 { 2187 var 2188 i = start, 2189 value, 2190 isSet = false; 2191 2192 if ( init !== undefined ) { 2193 value = init; 2194 isSet = true; 2195 } 2196 2197 while ( i !== end ) { 2198 if ( ! that.hasOwnProperty(i) ) { 2199 continue; 2200 } 2201 2202 value = isSet ? 2203 fn( value, that[i], i, that ) : 2204 that[i]; 2205 2206 isSet = true; 2207 i += inc; 2208 } 2209 2210 return value; 2211 } 2212 2213 /** 2214 * Add a column to the list used for the table with default values 2215 * @param {object} oSettings dataTables settings object 2216 * @param {node} nTh The th element for this column 2217 * @memberof DataTable#oApi 2218 */ 2219 function _fnAddColumn( oSettings, nTh ) 2220 { 2221 // Add column to aoColumns array 2222 var oDefaults = DataTable.defaults.column; 2223 var iCol = oSettings.aoColumns.length; 2224 var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, { 2225 "nTh": nTh ? nTh : document.createElement('th'), 2226 "sTitle": oDefaults.sTitle ? oDefaults.sTitle : nTh ? nTh.innerHTML : '', 2227 "aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol], 2228 "mData": oDefaults.mData ? oDefaults.mData : iCol, 2229 idx: iCol 2230 } ); 2231 oSettings.aoColumns.push( oCol ); 2232 2233 // Add search object for column specific search. Note that the `searchCols[ iCol ]` 2234 // passed into extend can be undefined. This allows the user to give a default 2235 // with only some of the parameters defined, and also not give a default 2236 var searchCols = oSettings.aoPreSearchCols; 2237 searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] ); 2238 2239 // Use the default column options function to initialise classes etc 2240 _fnColumnOptions( oSettings, iCol, $(nTh).data() ); 2241 } 2242 2243 2244 /** 2245 * Apply options for a column 2246 * @param {object} oSettings dataTables settings object 2247 * @param {int} iCol column index to consider 2248 * @param {object} oOptions object with sType, bVisible and bSearchable etc 2249 * @memberof DataTable#oApi 2250 */ 2251 function _fnColumnOptions( oSettings, iCol, oOptions ) 2252 { 2253 var oCol = oSettings.aoColumns[ iCol ]; 2254 var oClasses = oSettings.oClasses; 2255 var th = $(oCol.nTh); 2256 2257 // Try to get width information from the DOM. We can't get it from CSS 2258 // as we'd need to parse the CSS stylesheet. `width` option can override 2259 if ( ! oCol.sWidthOrig ) { 2260 // Width attribute 2261 oCol.sWidthOrig = th.attr('width') || null; 2262 2263 // Style attribute 2264 var t = (th.attr('style') || '').match(/width:\s*(\d+[pxem%]+)/); 2265 if ( t ) { 2266 oCol.sWidthOrig = t[1]; 2267 } 2268 } 2269 2270 /* User specified column options */ 2271 if ( oOptions !== undefined && oOptions !== null ) 2272 { 2273 // Backwards compatibility 2274 _fnCompatCols( oOptions ); 2275 2276 // Map camel case parameters to their Hungarian counterparts 2277 _fnCamelToHungarian( DataTable.defaults.column, oOptions, true ); 2278 2279 /* Backwards compatibility for mDataProp */ 2280 if ( oOptions.mDataProp !== undefined && !oOptions.mData ) 2281 { 2282 oOptions.mData = oOptions.mDataProp; 2283 } 2284 2285 if ( oOptions.sType ) 2286 { 2287 oCol._sManualType = oOptions.sType; 2288 } 2289 2290 // `class` is a reserved word in Javascript, so we need to provide 2291 // the ability to use a valid name for the camel case input 2292 if ( oOptions.className && ! oOptions.sClass ) 2293 { 2294 oOptions.sClass = oOptions.className; 2295 } 2296 if ( oOptions.sClass ) { 2297 th.addClass( oOptions.sClass ); 2298 } 2299 2300 var origClass = oCol.sClass; 2301 2302 $.extend( oCol, oOptions ); 2303 _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" ); 2304 2305 // Merge class from previously defined classes with this one, rather than just 2306 // overwriting it in the extend above 2307 if (origClass !== oCol.sClass) { 2308 oCol.sClass = origClass + ' ' + oCol.sClass; 2309 } 2310 2311 /* iDataSort to be applied (backwards compatibility), but aDataSort will take 2312 * priority if defined 2313 */ 2314 if ( oOptions.iDataSort !== undefined ) 2315 { 2316 oCol.aDataSort = [ oOptions.iDataSort ]; 2317 } 2318 _fnMap( oCol, oOptions, "aDataSort" ); 2319 } 2320 2321 /* Cache the data get and set functions for speed */ 2322 var mDataSrc = oCol.mData; 2323 var mData = _fnGetObjectDataFn( mDataSrc ); 2324 var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null; 2325 2326 var attrTest = function( src ) { 2327 return typeof src === 'string' && src.indexOf('@') !== -1; 2328 }; 2329 oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && ( 2330 attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter) 2331 ); 2332 oCol._setter = null; 2333 2334 oCol.fnGetData = function (rowData, type, meta) { 2335 var innerData = mData( rowData, type, undefined, meta ); 2336 2337 return mRender && type ? 2338 mRender( innerData, type, rowData, meta ) : 2339 innerData; 2340 }; 2341 oCol.fnSetData = function ( rowData, val, meta ) { 2342 return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta ); 2343 }; 2344 2345 // Indicate if DataTables should read DOM data as an object or array 2346 // Used in _fnGetRowElements 2347 if ( typeof mDataSrc !== 'number' ) { 2348 oSettings._rowReadObject = true; 2349 } 2350 2351 /* Feature sorting overrides column specific when off */ 2352 if ( !oSettings.oFeatures.bSort ) 2353 { 2354 oCol.bSortable = false; 2355 th.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called 2356 } 2357 2358 /* Check that the class assignment is correct for sorting */ 2359 var bAsc = $.inArray('asc', oCol.asSorting) !== -1; 2360 var bDesc = $.inArray('desc', oCol.asSorting) !== -1; 2361 if ( !oCol.bSortable || (!bAsc && !bDesc) ) 2362 { 2363 oCol.sSortingClass = oClasses.sSortableNone; 2364 oCol.sSortingClassJUI = ""; 2365 } 2366 else if ( bAsc && !bDesc ) 2367 { 2368 oCol.sSortingClass = oClasses.sSortableAsc; 2369 oCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed; 2370 } 2371 else if ( !bAsc && bDesc ) 2372 { 2373 oCol.sSortingClass = oClasses.sSortableDesc; 2374 oCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed; 2375 } 2376 else 2377 { 2378 oCol.sSortingClass = oClasses.sSortable; 2379 oCol.sSortingClassJUI = oClasses.sSortJUI; 2380 } 2381 } 2382 2383 2384 /** 2385 * Adjust the table column widths for new data. Note: you would probably want to 2386 * do a redraw after calling this function! 2387 * @param {object} settings dataTables settings object 2388 * @memberof DataTable#oApi 2389 */ 2390 function _fnAdjustColumnSizing ( settings ) 2391 { 2392 /* Not interested in doing column width calculation if auto-width is disabled */ 2393 if ( settings.oFeatures.bAutoWidth !== false ) 2394 { 2395 var columns = settings.aoColumns; 2396 2397 _fnCalculateColumnWidths( settings ); 2398 for ( var i=0 , iLen=columns.length ; i<iLen ; i++ ) 2399 { 2400 columns[i].nTh.style.width = columns[i].sWidth; 2401 } 2402 } 2403 2404 var scroll = settings.oScroll; 2405 if ( scroll.sY !== '' || scroll.sX !== '') 2406 { 2407 _fnScrollDraw( settings ); 2408 } 2409 2410 _fnCallbackFire( settings, null, 'column-sizing', [settings] ); 2411 } 2412 2413 2414 /** 2415 * Convert the index of a visible column to the index in the data array (take account 2416 * of hidden columns) 2417 * @param {object} oSettings dataTables settings object 2418 * @param {int} iMatch Visible column index to lookup 2419 * @returns {int} i the data index 2420 * @memberof DataTable#oApi 2421 */ 2422 function _fnVisibleToColumnIndex( oSettings, iMatch ) 2423 { 2424 var aiVis = _fnGetColumns( oSettings, 'bVisible' ); 2425 2426 return typeof aiVis[iMatch] === 'number' ? 2427 aiVis[iMatch] : 2428 null; 2429 } 2430 2431 2432 /** 2433 * Convert the index of an index in the data array and convert it to the visible 2434 * column index (take account of hidden columns) 2435 * @param {int} iMatch Column index to lookup 2436 * @param {object} oSettings dataTables settings object 2437 * @returns {int} i the data index 2438 * @memberof DataTable#oApi 2439 */ 2440 function _fnColumnIndexToVisible( oSettings, iMatch ) 2441 { 2442 var aiVis = _fnGetColumns( oSettings, 'bVisible' ); 2443 var iPos = $.inArray( iMatch, aiVis ); 2444 2445 return iPos !== -1 ? iPos : null; 2446 } 2447 2448 2449 /** 2450 * Get the number of visible columns 2451 * @param {object} oSettings dataTables settings object 2452 * @returns {int} i the number of visible columns 2453 * @memberof DataTable#oApi 2454 */ 2455 function _fnVisbleColumns( oSettings ) 2456 { 2457 var vis = 0; 2458 2459 // No reduce in IE8, use a loop for now 2460 $.each( oSettings.aoColumns, function ( i, col ) { 2461 if ( col.bVisible && $(col.nTh).css('display') !== 'none' ) { 2462 vis++; 2463 } 2464 } ); 2465 2466 return vis; 2467 } 2468 2469 2470 /** 2471 * Get an array of column indexes that match a given property 2472 * @param {object} oSettings dataTables settings object 2473 * @param {string} sParam Parameter in aoColumns to look for - typically 2474 * bVisible or bSearchable 2475 * @returns {array} Array of indexes with matched properties 2476 * @memberof DataTable#oApi 2477 */ 2478 function _fnGetColumns( oSettings, sParam ) 2479 { 2480 var a = []; 2481 2482 $.map( oSettings.aoColumns, function(val, i) { 2483 if ( val[sParam] ) { 2484 a.push( i ); 2485 } 2486 } ); 2487 2488 return a; 2489 } 2490 2491 2492 /** 2493 * Calculate the 'type' of a column 2494 * @param {object} settings dataTables settings object 2495 * @memberof DataTable#oApi 2496 */ 2497 function _fnColumnTypes ( settings ) 2498 { 2499 var columns = settings.aoColumns; 2500 var data = settings.aoData; 2501 var types = DataTable.ext.type.detect; 2502 var i, ien, j, jen, k, ken; 2503 var col, cell, detectedType, cache; 2504 2505 // For each column, spin over the 2506 for ( i=0, ien=columns.length ; i<ien ; i++ ) { 2507 col = columns[i]; 2508 cache = []; 2509 2510 if ( ! col.sType && col._sManualType ) { 2511 col.sType = col._sManualType; 2512 } 2513 else if ( ! col.sType ) { 2514 for ( j=0, jen=types.length ; j<jen ; j++ ) { 2515 for ( k=0, ken=data.length ; k<ken ; k++ ) { 2516 // Use a cache array so we only need to get the type data 2517 // from the formatter once (when using multiple detectors) 2518 if ( cache[k] === undefined ) { 2519 cache[k] = _fnGetCellData( settings, k, i, 'type' ); 2520 } 2521 2522 detectedType = types[j]( cache[k], settings ); 2523 2524 // If null, then this type can't apply to this column, so 2525 // rather than testing all cells, break out. There is an 2526 // exception for the last type which is `html`. We need to 2527 // scan all rows since it is possible to mix string and HTML 2528 // types 2529 if ( ! detectedType && j !== types.length-1 ) { 2530 break; 2531 } 2532 2533 // Only a single match is needed for html type since it is 2534 // bottom of the pile and very similar to string - but it 2535 // must not be empty 2536 if ( detectedType === 'html' && ! _empty(cache[k]) ) { 2537 break; 2538 } 2539 } 2540 2541 // Type is valid for all data points in the column - use this 2542 // type 2543 if ( detectedType ) { 2544 col.sType = detectedType; 2545 break; 2546 } 2547 } 2548 2549 // Fall back - if no type was detected, always use string 2550 if ( ! col.sType ) { 2551 col.sType = 'string'; 2552 } 2553 } 2554 } 2555 } 2556 2557 2558 /** 2559 * Take the column definitions and static columns arrays and calculate how 2560 * they relate to column indexes. The callback function will then apply the 2561 * definition found for a column to a suitable configuration object. 2562 * @param {object} oSettings dataTables settings object 2563 * @param {array} aoColDefs The aoColumnDefs array that is to be applied 2564 * @param {array} aoCols The aoColumns array that defines columns individually 2565 * @param {function} fn Callback function - takes two parameters, the calculated 2566 * column index and the definition for that column. 2567 * @memberof DataTable#oApi 2568 */ 2569 function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn ) 2570 { 2571 var i, iLen, j, jLen, k, kLen, def; 2572 var columns = oSettings.aoColumns; 2573 2574 // Column definitions with aTargets 2575 if ( aoColDefs ) 2576 { 2577 /* Loop over the definitions array - loop in reverse so first instance has priority */ 2578 for ( i=aoColDefs.length-1 ; i>=0 ; i-- ) 2579 { 2580 def = aoColDefs[i]; 2581 2582 /* Each definition can target multiple columns, as it is an array */ 2583 var aTargets = def.target !== undefined 2584 ? def.target 2585 : def.targets !== undefined 2586 ? def.targets 2587 : def.aTargets; 2588 2589 if ( ! Array.isArray( aTargets ) ) 2590 { 2591 aTargets = [ aTargets ]; 2592 } 2593 2594 for ( j=0, jLen=aTargets.length ; j<jLen ; j++ ) 2595 { 2596 if ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 ) 2597 { 2598 /* Add columns that we don't yet know about */ 2599 while( columns.length <= aTargets[j] ) 2600 { 2601 _fnAddColumn( oSettings ); 2602 } 2603 2604 /* Integer, basic index */ 2605 fn( aTargets[j], def ); 2606 } 2607 else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 ) 2608 { 2609 /* Negative integer, right to left column counting */ 2610 fn( columns.length+aTargets[j], def ); 2611 } 2612 else if ( typeof aTargets[j] === 'string' ) 2613 { 2614 /* Class name matching on TH element */ 2615 for ( k=0, kLen=columns.length ; k<kLen ; k++ ) 2616 { 2617 if ( aTargets[j] == "_all" || 2618 $(columns[k].nTh).hasClass( aTargets[j] ) ) 2619 { 2620 fn( k, def ); 2621 } 2622 } 2623 } 2624 } 2625 } 2626 } 2627 2628 // Statically defined columns array 2629 if ( aoCols ) 2630 { 2631 for ( i=0, iLen=aoCols.length ; i<iLen ; i++ ) 2632 { 2633 fn( i, aoCols[i] ); 2634 } 2635 } 2636 } 2637 2638 /** 2639 * Add a data array to the table, creating DOM node etc. This is the parallel to 2640 * _fnGatherData, but for adding rows from a Javascript source, rather than a 2641 * DOM source. 2642 * @param {object} oSettings dataTables settings object 2643 * @param {array} aData data array to be added 2644 * @param {node} [nTr] TR element to add to the table - optional. If not given, 2645 * DataTables will create a row automatically 2646 * @param {array} [anTds] Array of TD|TH elements for the row - must be given 2647 * if nTr is. 2648 * @returns {int} >=0 if successful (index of new aoData entry), -1 if failed 2649 * @memberof DataTable#oApi 2650 */ 2651 function _fnAddData ( oSettings, aDataIn, nTr, anTds ) 2652 { 2653 /* Create the object for storing information about this new row */ 2654 var iRow = oSettings.aoData.length; 2655 var oData = $.extend( true, {}, DataTable.models.oRow, { 2656 src: nTr ? 'dom' : 'data', 2657 idx: iRow 2658 } ); 2659 2660 oData._aData = aDataIn; 2661 oSettings.aoData.push( oData ); 2662 2663 /* Create the cells */ 2664 var nTd, sThisType; 2665 var columns = oSettings.aoColumns; 2666 2667 // Invalidate the column types as the new data needs to be revalidated 2668 for ( var i=0, iLen=columns.length ; i<iLen ; i++ ) 2669 { 2670 columns[i].sType = null; 2671 } 2672 2673 /* Add to the display array */ 2674 oSettings.aiDisplayMaster.push( iRow ); 2675 2676 var id = oSettings.rowIdFn( aDataIn ); 2677 if ( id !== undefined ) { 2678 oSettings.aIds[ id ] = oData; 2679 } 2680 2681 /* Create the DOM information, or register it if already present */ 2682 if ( nTr || ! oSettings.oFeatures.bDeferRender ) 2683 { 2684 _fnCreateTr( oSettings, iRow, nTr, anTds ); 2685 } 2686 2687 return iRow; 2688 } 2689 2690 2691 /** 2692 * Add one or more TR elements to the table. Generally we'd expect to 2693 * use this for reading data from a DOM sourced table, but it could be 2694 * used for an TR element. Note that if a TR is given, it is used (i.e. 2695 * it is not cloned). 2696 * @param {object} settings dataTables settings object 2697 * @param {array|node|jQuery} trs The TR element(s) to add to the table 2698 * @returns {array} Array of indexes for the added rows 2699 * @memberof DataTable#oApi 2700 */ 2701 function _fnAddTr( settings, trs ) 2702 { 2703 var row; 2704 2705 // Allow an individual node to be passed in 2706 if ( ! (trs instanceof $) ) { 2707 trs = $(trs); 2708 } 2709 2710 return trs.map( function (i, el) { 2711 row = _fnGetRowElements( settings, el ); 2712 return _fnAddData( settings, row.data, el, row.cells ); 2713 } ); 2714 } 2715 2716 2717 /** 2718 * Take a TR element and convert it to an index in aoData 2719 * @param {object} oSettings dataTables settings object 2720 * @param {node} n the TR element to find 2721 * @returns {int} index if the node is found, null if not 2722 * @memberof DataTable#oApi 2723 */ 2724 function _fnNodeToDataIndex( oSettings, n ) 2725 { 2726 return (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null; 2727 } 2728 2729 2730 /** 2731 * Take a TD element and convert it into a column data index (not the visible index) 2732 * @param {object} oSettings dataTables settings object 2733 * @param {int} iRow The row number the TD/TH can be found in 2734 * @param {node} n The TD/TH element to find 2735 * @returns {int} index if the node is found, -1 if not 2736 * @memberof DataTable#oApi 2737 */ 2738 function _fnNodeToColumnIndex( oSettings, iRow, n ) 2739 { 2740 return $.inArray( n, oSettings.aoData[ iRow ].anCells ); 2741 } 2742 2743 2744 /** 2745 * Get the data for a given cell from the internal cache, taking into account data mapping 2746 * @param {object} settings dataTables settings object 2747 * @param {int} rowIdx aoData row id 2748 * @param {int} colIdx Column index 2749 * @param {string} type data get type ('display', 'type' 'filter|search' 'sort|order') 2750 * @returns {*} Cell data 2751 * @memberof DataTable#oApi 2752 */ 2753 function _fnGetCellData( settings, rowIdx, colIdx, type ) 2754 { 2755 if (type === 'search') { 2756 type = 'filter'; 2757 } 2758 else if (type === 'order') { 2759 type = 'sort'; 2760 } 2761 2762 var draw = settings.iDraw; 2763 var col = settings.aoColumns[colIdx]; 2764 var rowData = settings.aoData[rowIdx]._aData; 2765 var defaultContent = col.sDefaultContent; 2766 var cellData = col.fnGetData( rowData, type, { 2767 settings: settings, 2768 row: rowIdx, 2769 col: colIdx 2770 } ); 2771 2772 if ( cellData === undefined ) { 2773 if ( settings.iDrawError != draw && defaultContent === null ) { 2774 _fnLog( settings, 0, "Requested unknown parameter "+ 2775 (typeof col.mData=='function' ? '{function}' : "'"+col.mData+"'")+ 2776 " for row "+rowIdx+", column "+colIdx, 4 ); 2777 settings.iDrawError = draw; 2778 } 2779 return defaultContent; 2780 } 2781 2782 // When the data source is null and a specific data type is requested (i.e. 2783 // not the original data), we can use default column data 2784 if ( (cellData === rowData || cellData === null) && defaultContent !== null && type !== undefined ) { 2785 cellData = defaultContent; 2786 } 2787 else if ( typeof cellData === 'function' ) { 2788 // If the data source is a function, then we run it and use the return, 2789 // executing in the scope of the data object (for instances) 2790 return cellData.call( rowData ); 2791 } 2792 2793 if ( cellData === null && type === 'display' ) { 2794 return ''; 2795 } 2796 2797 if ( type === 'filter' ) { 2798 var fomatters = DataTable.ext.type.search; 2799 2800 if ( fomatters[ col.sType ] ) { 2801 cellData = fomatters[ col.sType ]( cellData ); 2802 } 2803 } 2804 2805 return cellData; 2806 } 2807 2808 2809 /** 2810 * Set the value for a specific cell, into the internal data cache 2811 * @param {object} settings dataTables settings object 2812 * @param {int} rowIdx aoData row id 2813 * @param {int} colIdx Column index 2814 * @param {*} val Value to set 2815 * @memberof DataTable#oApi 2816 */ 2817 function _fnSetCellData( settings, rowIdx, colIdx, val ) 2818 { 2819 var col = settings.aoColumns[colIdx]; 2820 var rowData = settings.aoData[rowIdx]._aData; 2821 2822 col.fnSetData( rowData, val, { 2823 settings: settings, 2824 row: rowIdx, 2825 col: colIdx 2826 } ); 2827 } 2828 2829 2830 // Private variable that is used to match action syntax in the data property object 2831 var __reArray = /\[.*?\]$/; 2832 var __reFn = /\(\)$/; 2833 2834 /** 2835 * Split string on periods, taking into account escaped periods 2836 * @param {string} str String to split 2837 * @return {array} Split string 2838 */ 2839 function _fnSplitObjNotation( str ) 2840 { 2841 return $.map( str.match(/(\\.|[^\.])+/g) || [''], function ( s ) { 2842 return s.replace(/\\\./g, '.'); 2843 } ); 2844 } 2845 2846 2847 /** 2848 * Return a function that can be used to get data from a source object, taking 2849 * into account the ability to use nested objects as a source 2850 * @param {string|int|function} mSource The data source for the object 2851 * @returns {function} Data get function 2852 * @memberof DataTable#oApi 2853 */ 2854 var _fnGetObjectDataFn = DataTable.util.get; 2855 2856 2857 /** 2858 * Return a function that can be used to set data from a source object, taking 2859 * into account the ability to use nested objects as a source 2860 * @param {string|int|function} mSource The data source for the object 2861 * @returns {function} Data set function 2862 * @memberof DataTable#oApi 2863 */ 2864 var _fnSetObjectDataFn = DataTable.util.set; 2865 2866 2867 /** 2868 * Return an array with the full table data 2869 * @param {object} oSettings dataTables settings object 2870 * @returns array {array} aData Master data array 2871 * @memberof DataTable#oApi 2872 */ 2873 function _fnGetDataMaster ( settings ) 2874 { 2875 return _pluck( settings.aoData, '_aData' ); 2876 } 2877 2878 2879 /** 2880 * Nuke the table 2881 * @param {object} oSettings dataTables settings object 2882 * @memberof DataTable#oApi 2883 */ 2884 function _fnClearTable( settings ) 2885 { 2886 settings.aoData.length = 0; 2887 settings.aiDisplayMaster.length = 0; 2888 settings.aiDisplay.length = 0; 2889 settings.aIds = {}; 2890 } 2891 2892 2893 /** 2894 * Take an array of integers (index array) and remove a target integer (value - not 2895 * the key!) 2896 * @param {array} a Index array to target 2897 * @param {int} iTarget value to find 2898 * @memberof DataTable#oApi 2899 */ 2900 function _fnDeleteIndex( a, iTarget, splice ) 2901 { 2902 var iTargetIndex = -1; 2903 2904 for ( var i=0, iLen=a.length ; i<iLen ; i++ ) 2905 { 2906 if ( a[i] == iTarget ) 2907 { 2908 iTargetIndex = i; 2909 } 2910 else if ( a[i] > iTarget ) 2911 { 2912 a[i]--; 2913 } 2914 } 2915 2916 if ( iTargetIndex != -1 && splice === undefined ) 2917 { 2918 a.splice( iTargetIndex, 1 ); 2919 } 2920 } 2921 2922 2923 /** 2924 * Mark cached data as invalid such that a re-read of the data will occur when 2925 * the cached data is next requested. Also update from the data source object. 2926 * 2927 * @param {object} settings DataTables settings object 2928 * @param {int} rowIdx Row index to invalidate 2929 * @param {string} [src] Source to invalidate from: undefined, 'auto', 'dom' 2930 * or 'data' 2931 * @param {int} [colIdx] Column index to invalidate. If undefined the whole 2932 * row will be invalidated 2933 * @memberof DataTable#oApi 2934 * 2935 * @todo For the modularisation of v1.11 this will need to become a callback, so 2936 * the sort and filter methods can subscribe to it. That will required 2937 * initialisation options for sorting, which is why it is not already baked in 2938 */ 2939 function _fnInvalidate( settings, rowIdx, src, colIdx ) 2940 { 2941 var row = settings.aoData[ rowIdx ]; 2942 var i, ien; 2943 var cellWrite = function ( cell, col ) { 2944 // This is very frustrating, but in IE if you just write directly 2945 // to innerHTML, and elements that are overwritten are GC'ed, 2946 // even if there is a reference to them elsewhere 2947 while ( cell.childNodes.length ) { 2948 cell.removeChild( cell.firstChild ); 2949 } 2950 2951 cell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' ); 2952 }; 2953 2954 // Are we reading last data from DOM or the data object? 2955 if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) { 2956 // Read the data from the DOM 2957 row._aData = _fnGetRowElements( 2958 settings, row, colIdx, colIdx === undefined ? undefined : row._aData 2959 ) 2960 .data; 2961 } 2962 else { 2963 // Reading from data object, update the DOM 2964 var cells = row.anCells; 2965 2966 if ( cells ) { 2967 if ( colIdx !== undefined ) { 2968 cellWrite( cells[colIdx], colIdx ); 2969 } 2970 else { 2971 for ( i=0, ien=cells.length ; i<ien ; i++ ) { 2972 cellWrite( cells[i], i ); 2973 } 2974 } 2975 } 2976 } 2977 2978 // For both row and cell invalidation, the cached data for sorting and 2979 // filtering is nulled out 2980 row._aSortData = null; 2981 row._aFilterData = null; 2982 2983 // Invalidate the type for a specific column (if given) or all columns since 2984 // the data might have changed 2985 var cols = settings.aoColumns; 2986 if ( colIdx !== undefined ) { 2987 cols[ colIdx ].sType = null; 2988 } 2989 else { 2990 for ( i=0, ien=cols.length ; i<ien ; i++ ) { 2991 cols[i].sType = null; 2992 } 2993 2994 // Update DataTables special `DT_*` attributes for the row 2995 _fnRowAttributes( settings, row ); 2996 } 2997 } 2998 2999 3000 /** 3001 * Build a data source object from an HTML row, reading the contents of the 3002 * cells that are in the row. 3003 * 3004 * @param {object} settings DataTables settings object 3005 * @param {node|object} TR element from which to read data or existing row 3006 * object from which to re-read the data from the cells 3007 * @param {int} [colIdx] Optional column index 3008 * @param {array|object} [d] Data source object. If `colIdx` is given then this 3009 * parameter should also be given and will be used to write the data into. 3010 * Only the column in question will be written 3011 * @returns {object} Object with two parameters: `data` the data read, in 3012 * document order, and `cells` and array of nodes (they can be useful to the 3013 * caller, so rather than needing a second traversal to get them, just return 3014 * them from here). 3015 * @memberof DataTable#oApi 3016 */ 3017 function _fnGetRowElements( settings, row, colIdx, d ) 3018 { 3019 var 3020 tds = [], 3021 td = row.firstChild, 3022 name, col, o, i=0, contents, 3023 columns = settings.aoColumns, 3024 objectRead = settings._rowReadObject; 3025 3026 // Allow the data object to be passed in, or construct 3027 d = d !== undefined ? 3028 d : 3029 objectRead ? 3030 {} : 3031 []; 3032 3033 var attr = function ( str, td ) { 3034 if ( typeof str === 'string' ) { 3035 var idx = str.indexOf('@'); 3036 3037 if ( idx !== -1 ) { 3038 var attr = str.substring( idx+1 ); 3039 var setter = _fnSetObjectDataFn( str ); 3040 setter( d, td.getAttribute( attr ) ); 3041 } 3042 } 3043 }; 3044 3045 // Read data from a cell and store into the data object 3046 var cellProcess = function ( cell ) { 3047 if ( colIdx === undefined || colIdx === i ) { 3048 col = columns[i]; 3049 contents = (cell.innerHTML).trim(); 3050 3051 if ( col && col._bAttrSrc ) { 3052 var setter = _fnSetObjectDataFn( col.mData._ ); 3053 setter( d, contents ); 3054 3055 attr( col.mData.sort, cell ); 3056 attr( col.mData.type, cell ); 3057 attr( col.mData.filter, cell ); 3058 } 3059 else { 3060 // Depending on the `data` option for the columns the data can 3061 // be read to either an object or an array. 3062 if ( objectRead ) { 3063 if ( ! col._setter ) { 3064 // Cache the setter function 3065 col._setter = _fnSetObjectDataFn( col.mData ); 3066 } 3067 col._setter( d, contents ); 3068 } 3069 else { 3070 d[i] = contents; 3071 } 3072 } 3073 } 3074 3075 i++; 3076 }; 3077 3078 if ( td ) { 3079 // `tr` element was passed in 3080 while ( td ) { 3081 name = td.nodeName.toUpperCase(); 3082 3083 if ( name == "TD" || name == "TH" ) { 3084 cellProcess( td ); 3085 tds.push( td ); 3086 } 3087 3088 td = td.nextSibling; 3089 } 3090 } 3091 else { 3092 // Existing row object passed in 3093 tds = row.anCells; 3094 3095 for ( var j=0, jen=tds.length ; j<jen ; j++ ) { 3096 cellProcess( tds[j] ); 3097 } 3098 } 3099 3100 // Read the ID from the DOM if present 3101 var rowNode = row.firstChild ? row : row.nTr; 3102 3103 if ( rowNode ) { 3104 var id = rowNode.getAttribute( 'id' ); 3105 3106 if ( id ) { 3107 _fnSetObjectDataFn( settings.rowId )( d, id ); 3108 } 3109 } 3110 3111 return { 3112 data: d, 3113 cells: tds 3114 }; 3115 } 3116 /** 3117 * Create a new TR element (and it's TD children) for a row 3118 * @param {object} oSettings dataTables settings object 3119 * @param {int} iRow Row to consider 3120 * @param {node} [nTrIn] TR element to add to the table - optional. If not given, 3121 * DataTables will create a row automatically 3122 * @param {array} [anTds] Array of TD|TH elements for the row - must be given 3123 * if nTr is. 3124 * @memberof DataTable#oApi 3125 */ 3126 function _fnCreateTr ( oSettings, iRow, nTrIn, anTds ) 3127 { 3128 var 3129 row = oSettings.aoData[iRow], 3130 rowData = row._aData, 3131 cells = [], 3132 nTr, nTd, oCol, 3133 i, iLen, create; 3134 3135 if ( row.nTr === null ) 3136 { 3137 nTr = nTrIn || document.createElement('tr'); 3138 3139 row.nTr = nTr; 3140 row.anCells = cells; 3141 3142 /* Use a private property on the node to allow reserve mapping from the node 3143 * to the aoData array for fast look up 3144 */ 3145 nTr._DT_RowIndex = iRow; 3146 3147 /* Special parameters can be given by the data source to be used on the row */ 3148 _fnRowAttributes( oSettings, row ); 3149 3150 /* Process each column */ 3151 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ ) 3152 { 3153 oCol = oSettings.aoColumns[i]; 3154 create = nTrIn ? false : true; 3155 3156 nTd = create ? document.createElement( oCol.sCellType ) : anTds[i]; 3157 nTd._DT_CellIndex = { 3158 row: iRow, 3159 column: i 3160 }; 3161 3162 cells.push( nTd ); 3163 3164 // Need to create the HTML if new, or if a rendering function is defined 3165 if ( create || ((oCol.mRender || oCol.mData !== i) && 3166 (!$.isPlainObject(oCol.mData) || oCol.mData._ !== i+'.display') 3167 )) { 3168 nTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' ); 3169 } 3170 3171 /* Add user defined class */ 3172 if ( oCol.sClass ) 3173 { 3174 nTd.className += ' '+oCol.sClass; 3175 } 3176 3177 // Visibility - add or remove as required 3178 if ( oCol.bVisible && ! nTrIn ) 3179 { 3180 nTr.appendChild( nTd ); 3181 } 3182 else if ( ! oCol.bVisible && nTrIn ) 3183 { 3184 nTd.parentNode.removeChild( nTd ); 3185 } 3186 3187 if ( oCol.fnCreatedCell ) 3188 { 3189 oCol.fnCreatedCell.call( oSettings.oInstance, 3190 nTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i 3191 ); 3192 } 3193 } 3194 3195 _fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [nTr, rowData, iRow, cells] ); 3196 } 3197 } 3198 3199 3200 /** 3201 * Add attributes to a row based on the special `DT_*` parameters in a data 3202 * source object. 3203 * @param {object} settings DataTables settings object 3204 * @param {object} DataTables row object for the row to be modified 3205 * @memberof DataTable#oApi 3206 */ 3207 function _fnRowAttributes( settings, row ) 3208 { 3209 var tr = row.nTr; 3210 var data = row._aData; 3211 3212 if ( tr ) { 3213 var id = settings.rowIdFn( data ); 3214 3215 if ( id ) { 3216 tr.id = id; 3217 } 3218 3219 if ( data.DT_RowClass ) { 3220 // Remove any classes added by DT_RowClass before 3221 var a = data.DT_RowClass.split(' '); 3222 row.__rowc = row.__rowc ? 3223 _unique( row.__rowc.concat( a ) ) : 3224 a; 3225 3226 $(tr) 3227 .removeClass( row.__rowc.join(' ') ) 3228 .addClass( data.DT_RowClass ); 3229 } 3230 3231 if ( data.DT_RowAttr ) { 3232 $(tr).attr( data.DT_RowAttr ); 3233 } 3234 3235 if ( data.DT_RowData ) { 3236 $(tr).data( data.DT_RowData ); 3237 } 3238 } 3239 } 3240 3241 3242 /** 3243 * Create the HTML header for the table 3244 * @param {object} oSettings dataTables settings object 3245 * @memberof DataTable#oApi 3246 */ 3247 function _fnBuildHead( oSettings ) 3248 { 3249 var i, ien, cell, row, column; 3250 var thead = oSettings.nTHead; 3251 var tfoot = oSettings.nTFoot; 3252 var createHeader = $('th, td', thead).length === 0; 3253 var classes = oSettings.oClasses; 3254 var columns = oSettings.aoColumns; 3255 3256 if ( createHeader ) { 3257 row = $('<tr/>').appendTo( thead ); 3258 } 3259 3260 for ( i=0, ien=columns.length ; i<ien ; i++ ) { 3261 column = columns[i]; 3262 cell = $( column.nTh ).addClass( column.sClass ); 3263 3264 if ( createHeader ) { 3265 cell.appendTo( row ); 3266 } 3267 3268 // 1.11 move into sorting 3269 if ( oSettings.oFeatures.bSort ) { 3270 cell.addClass( column.sSortingClass ); 3271 3272 if ( column.bSortable !== false ) { 3273 cell 3274 .attr( 'tabindex', oSettings.iTabIndex ) 3275 .attr( 'aria-controls', oSettings.sTableId ); 3276 3277 _fnSortAttachListener( oSettings, column.nTh, i ); 3278 } 3279 } 3280 3281 if ( column.sTitle != cell[0].innerHTML ) { 3282 cell.html( column.sTitle ); 3283 } 3284 3285 _fnRenderer( oSettings, 'header' )( 3286 oSettings, cell, column, classes 3287 ); 3288 } 3289 3290 if ( createHeader ) { 3291 _fnDetectHeader( oSettings.aoHeader, thead ); 3292 } 3293 3294 /* Deal with the footer - add classes if required */ 3295 $(thead).children('tr').children('th, td').addClass( classes.sHeaderTH ); 3296 $(tfoot).children('tr').children('th, td').addClass( classes.sFooterTH ); 3297 3298 // Cache the footer cells. Note that we only take the cells from the first 3299 // row in the footer. If there is more than one row the user wants to 3300 // interact with, they need to use the table().foot() method. Note also this 3301 // allows cells to be used for multiple columns using colspan 3302 if ( tfoot !== null ) { 3303 var cells = oSettings.aoFooter[0]; 3304 3305 for ( i=0, ien=cells.length ; i<ien ; i++ ) { 3306 column = columns[i]; 3307 column.nTf = cells[i].cell; 3308 3309 if ( column.sClass ) { 3310 $(column.nTf).addClass( column.sClass ); 3311 } 3312 } 3313 } 3314 } 3315 3316 3317 /** 3318 * Draw the header (or footer) element based on the column visibility states. The 3319 * methodology here is to use the layout array from _fnDetectHeader, modified for 3320 * the instantaneous column visibility, to construct the new layout. The grid is 3321 * traversed over cell at a time in a rows x columns grid fashion, although each 3322 * cell insert can cover multiple elements in the grid - which is tracks using the 3323 * aApplied array. Cell inserts in the grid will only occur where there isn't 3324 * already a cell in that position. 3325 * @param {object} oSettings dataTables settings object 3326 * @param array {objects} aoSource Layout array from _fnDetectHeader 3327 * @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc, 3328 * @memberof DataTable#oApi 3329 */ 3330 function _fnDrawHead( oSettings, aoSource, bIncludeHidden ) 3331 { 3332 var i, iLen, j, jLen, k, kLen, n, nLocalTr; 3333 var aoLocal = []; 3334 var aApplied = []; 3335 var iColumns = oSettings.aoColumns.length; 3336 var iRowspan, iColspan; 3337 3338 if ( ! aoSource ) 3339 { 3340 return; 3341 } 3342 3343 if ( bIncludeHidden === undefined ) 3344 { 3345 bIncludeHidden = false; 3346 } 3347 3348 /* Make a copy of the master layout array, but without the visible columns in it */ 3349 for ( i=0, iLen=aoSource.length ; i<iLen ; i++ ) 3350 { 3351 aoLocal[i] = aoSource[i].slice(); 3352 aoLocal[i].nTr = aoSource[i].nTr; 3353 3354 /* Remove any columns which are currently hidden */ 3355 for ( j=iColumns-1 ; j>=0 ; j-- ) 3356 { 3357 if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden ) 3358 { 3359 aoLocal[i].splice( j, 1 ); 3360 } 3361 } 3362 3363 /* Prep the applied array - it needs an element for each row */ 3364 aApplied.push( [] ); 3365 } 3366 3367 for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ ) 3368 { 3369 nLocalTr = aoLocal[i].nTr; 3370 3371 /* All cells are going to be replaced, so empty out the row */ 3372 if ( nLocalTr ) 3373 { 3374 while( (n = nLocalTr.firstChild) ) 3375 { 3376 nLocalTr.removeChild( n ); 3377 } 3378 } 3379 3380 for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ ) 3381 { 3382 iRowspan = 1; 3383 iColspan = 1; 3384 3385 /* Check to see if there is already a cell (row/colspan) covering our target 3386 * insert point. If there is, then there is nothing to do. 3387 */ 3388 if ( aApplied[i][j] === undefined ) 3389 { 3390 nLocalTr.appendChild( aoLocal[i][j].cell ); 3391 aApplied[i][j] = 1; 3392 3393 /* Expand the cell to cover as many rows as needed */ 3394 while ( aoLocal[i+iRowspan] !== undefined && 3395 aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell ) 3396 { 3397 aApplied[i+iRowspan][j] = 1; 3398 iRowspan++; 3399 } 3400 3401 /* Expand the cell to cover as many columns as needed */ 3402 while ( aoLocal[i][j+iColspan] !== undefined && 3403 aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell ) 3404 { 3405 /* Must update the applied array over the rows for the columns */ 3406 for ( k=0 ; k<iRowspan ; k++ ) 3407 { 3408 aApplied[i+k][j+iColspan] = 1; 3409 } 3410 iColspan++; 3411 } 3412 3413 /* Do the actual expansion in the DOM */ 3414 $(aoLocal[i][j].cell) 3415 .attr('rowspan', iRowspan) 3416 .attr('colspan', iColspan); 3417 } 3418 } 3419 } 3420 } 3421 3422 3423 /** 3424 * Insert the required TR nodes into the table for display 3425 * @param {object} oSettings dataTables settings object 3426 * @param ajaxComplete true after ajax call to complete rendering 3427 * @memberof DataTable#oApi 3428 */ 3429 function _fnDraw( oSettings, ajaxComplete ) 3430 { 3431 // Allow for state saving and a custom start position 3432 _fnStart( oSettings ); 3433 3434 /* Provide a pre-callback function which can be used to cancel the draw is false is returned */ 3435 var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] ); 3436 if ( $.inArray( false, aPreDraw ) !== -1 ) 3437 { 3438 _fnProcessingDisplay( oSettings, false ); 3439 return; 3440 } 3441 3442 var anRows = []; 3443 var iRowCount = 0; 3444 var asStripeClasses = oSettings.asStripeClasses; 3445 var iStripes = asStripeClasses.length; 3446 var oLang = oSettings.oLanguage; 3447 var bServerSide = _fnDataSource( oSettings ) == 'ssp'; 3448 var aiDisplay = oSettings.aiDisplay; 3449 var iDisplayStart = oSettings._iDisplayStart; 3450 var iDisplayEnd = oSettings.fnDisplayEnd(); 3451 3452 oSettings.bDrawing = true; 3453 3454 /* Server-side processing draw intercept */ 3455 if ( oSettings.bDeferLoading ) 3456 { 3457 oSettings.bDeferLoading = false; 3458 oSettings.iDraw++; 3459 _fnProcessingDisplay( oSettings, false ); 3460 } 3461 else if ( !bServerSide ) 3462 { 3463 oSettings.iDraw++; 3464 } 3465 else if ( !oSettings.bDestroying && !ajaxComplete) 3466 { 3467 _fnAjaxUpdate( oSettings ); 3468 return; 3469 } 3470 3471 if ( aiDisplay.length !== 0 ) 3472 { 3473 var iStart = bServerSide ? 0 : iDisplayStart; 3474 var iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd; 3475 3476 for ( var j=iStart ; j<iEnd ; j++ ) 3477 { 3478 var iDataIndex = aiDisplay[j]; 3479 var aoData = oSettings.aoData[ iDataIndex ]; 3480 if ( aoData.nTr === null ) 3481 { 3482 _fnCreateTr( oSettings, iDataIndex ); 3483 } 3484 3485 var nRow = aoData.nTr; 3486 3487 /* Remove the old striping classes and then add the new one */ 3488 if ( iStripes !== 0 ) 3489 { 3490 var sStripe = asStripeClasses[ iRowCount % iStripes ]; 3491 if ( aoData._sRowStripe != sStripe ) 3492 { 3493 $(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe ); 3494 aoData._sRowStripe = sStripe; 3495 } 3496 } 3497 3498 // Row callback functions - might want to manipulate the row 3499 // iRowCount and j are not currently documented. Are they at all 3500 // useful? 3501 _fnCallbackFire( oSettings, 'aoRowCallback', null, 3502 [nRow, aoData._aData, iRowCount, j, iDataIndex] ); 3503 3504 anRows.push( nRow ); 3505 iRowCount++; 3506 } 3507 } 3508 else 3509 { 3510 /* Table is empty - create a row with an empty message in it */ 3511 var sZero = oLang.sZeroRecords; 3512 if ( oSettings.iDraw == 1 && _fnDataSource( oSettings ) == 'ajax' ) 3513 { 3514 sZero = oLang.sLoadingRecords; 3515 } 3516 else if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 ) 3517 { 3518 sZero = oLang.sEmptyTable; 3519 } 3520 3521 anRows[ 0 ] = $( '<tr/>', { 'class': iStripes ? asStripeClasses[0] : '' } ) 3522 .append( $('<td />', { 3523 'valign': 'top', 3524 'colSpan': _fnVisbleColumns( oSettings ), 3525 'class': oSettings.oClasses.sRowEmpty 3526 } ).html( sZero ) )[0]; 3527 } 3528 3529 /* Header and footer callbacks */ 3530 _fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0], 3531 _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] ); 3532 3533 _fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0], 3534 _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] ); 3535 3536 var body = $(oSettings.nTBody); 3537 3538 body.children().detach(); 3539 body.append( $(anRows) ); 3540 3541 /* Call all required callback functions for the end of a draw */ 3542 _fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] ); 3543 3544 /* Draw is complete, sorting and filtering must be as well */ 3545 oSettings.bSorted = false; 3546 oSettings.bFiltered = false; 3547 oSettings.bDrawing = false; 3548 } 3549 3550 3551 /** 3552 * Redraw the table - taking account of the various features which are enabled 3553 * @param {object} oSettings dataTables settings object 3554 * @param {boolean} [holdPosition] Keep the current paging position. By default 3555 * the paging is reset to the first page 3556 * @memberof DataTable#oApi 3557 */ 3558 function _fnReDraw( settings, holdPosition ) 3559 { 3560 var 3561 features = settings.oFeatures, 3562 sort = features.bSort, 3563 filter = features.bFilter; 3564 3565 if ( sort ) { 3566 _fnSort( settings ); 3567 } 3568 3569 if ( filter ) { 3570 _fnFilterComplete( settings, settings.oPreviousSearch ); 3571 } 3572 else { 3573 // No filtering, so we want to just use the display master 3574 settings.aiDisplay = settings.aiDisplayMaster.slice(); 3575 } 3576 3577 if ( holdPosition !== true ) { 3578 settings._iDisplayStart = 0; 3579 } 3580 3581 // Let any modules know about the draw hold position state (used by 3582 // scrolling internally) 3583 settings._drawHold = holdPosition; 3584 3585 _fnDraw( settings ); 3586 3587 settings._drawHold = false; 3588 } 3589 3590 3591 /** 3592 * Add the options to the page HTML for the table 3593 * @param {object} oSettings dataTables settings object 3594 * @memberof DataTable#oApi 3595 */ 3596 function _fnAddOptionsHtml ( oSettings ) 3597 { 3598 var classes = oSettings.oClasses; 3599 var table = $(oSettings.nTable); 3600 var holding = $('<div/>').insertBefore( table ); // Holding element for speed 3601 var features = oSettings.oFeatures; 3602 3603 // All DataTables are wrapped in a div 3604 var insert = $('<div/>', { 3605 id: oSettings.sTableId+'_wrapper', 3606 'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter) 3607 } ); 3608 3609 oSettings.nHolding = holding[0]; 3610 oSettings.nTableWrapper = insert[0]; 3611 oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling; 3612 3613 /* Loop over the user set positioning and place the elements as needed */ 3614 var aDom = oSettings.sDom.split(''); 3615 var featureNode, cOption, nNewNode, cNext, sAttr, j; 3616 for ( var i=0 ; i<aDom.length ; i++ ) 3617 { 3618 featureNode = null; 3619 cOption = aDom[i]; 3620 3621 if ( cOption == '<' ) 3622 { 3623 /* New container div */ 3624 nNewNode = $('<div/>')[0]; 3625 3626 /* Check to see if we should append an id and/or a class name to the container */ 3627 cNext = aDom[i+1]; 3628 if ( cNext == "'" || cNext == '"' ) 3629 { 3630 sAttr = ""; 3631 j = 2; 3632 while ( aDom[i+j] != cNext ) 3633 { 3634 sAttr += aDom[i+j]; 3635 j++; 3636 } 3637 3638 /* Replace jQuery UI constants @todo depreciated */ 3639 if ( sAttr == "H" ) 3640 { 3641 sAttr = classes.sJUIHeader; 3642 } 3643 else if ( sAttr == "F" ) 3644 { 3645 sAttr = classes.sJUIFooter; 3646 } 3647 3648 /* The attribute can be in the format of "#id.class", "#id" or "class" This logic 3649 * breaks the string into parts and applies them as needed 3650 */ 3651 if ( sAttr.indexOf('.') != -1 ) 3652 { 3653 var aSplit = sAttr.split('.'); 3654 nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1); 3655 nNewNode.className = aSplit[1]; 3656 } 3657 else if ( sAttr.charAt(0) == "#" ) 3658 { 3659 nNewNode.id = sAttr.substr(1, sAttr.length-1); 3660 } 3661 else 3662 { 3663 nNewNode.className = sAttr; 3664 } 3665 3666 i += j; /* Move along the position array */ 3667 } 3668 3669 insert.append( nNewNode ); 3670 insert = $(nNewNode); 3671 } 3672 else if ( cOption == '>' ) 3673 { 3674 /* End container div */ 3675 insert = insert.parent(); 3676 } 3677 // @todo Move options into their own plugins? 3678 else if ( cOption == 'l' && features.bPaginate && features.bLengthChange ) 3679 { 3680 /* Length */ 3681 featureNode = _fnFeatureHtmlLength( oSettings ); 3682 } 3683 else if ( cOption == 'f' && features.bFilter ) 3684 { 3685 /* Filter */ 3686 featureNode = _fnFeatureHtmlFilter( oSettings ); 3687 } 3688 else if ( cOption == 'r' && features.bProcessing ) 3689 { 3690 /* pRocessing */ 3691 featureNode = _fnFeatureHtmlProcessing( oSettings ); 3692 } 3693 else if ( cOption == 't' ) 3694 { 3695 /* Table */ 3696 featureNode = _fnFeatureHtmlTable( oSettings ); 3697 } 3698 else if ( cOption == 'i' && features.bInfo ) 3699 { 3700 /* Info */ 3701 featureNode = _fnFeatureHtmlInfo( oSettings ); 3702 } 3703 else if ( cOption == 'p' && features.bPaginate ) 3704 { 3705 /* Pagination */ 3706 featureNode = _fnFeatureHtmlPaginate( oSettings ); 3707 } 3708 else if ( DataTable.ext.feature.length !== 0 ) 3709 { 3710 /* Plug-in features */ 3711 var aoFeatures = DataTable.ext.feature; 3712 for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ ) 3713 { 3714 if ( cOption == aoFeatures[k].cFeature ) 3715 { 3716 featureNode = aoFeatures[k].fnInit( oSettings ); 3717 break; 3718 } 3719 } 3720 } 3721 3722 /* Add to the 2D features array */ 3723 if ( featureNode ) 3724 { 3725 var aanFeatures = oSettings.aanFeatures; 3726 3727 if ( ! aanFeatures[cOption] ) 3728 { 3729 aanFeatures[cOption] = []; 3730 } 3731 3732 aanFeatures[cOption].push( featureNode ); 3733 insert.append( featureNode ); 3734 } 3735 } 3736 3737 /* Built our DOM structure - replace the holding div with what we want */ 3738 holding.replaceWith( insert ); 3739 oSettings.nHolding = null; 3740 } 3741 3742 3743 /** 3744 * Use the DOM source to create up an array of header cells. The idea here is to 3745 * create a layout grid (array) of rows x columns, which contains a reference 3746 * to the cell that that point in the grid (regardless of col/rowspan), such that 3747 * any column / row could be removed and the new grid constructed 3748 * @param array {object} aLayout Array to store the calculated layout in 3749 * @param {node} nThead The header/footer element for the table 3750 * @memberof DataTable#oApi 3751 */ 3752 function _fnDetectHeader ( aLayout, nThead ) 3753 { 3754 var nTrs = $(nThead).children('tr'); 3755 var nTr, nCell; 3756 var i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan; 3757 var bUnique; 3758 var fnShiftCol = function ( a, i, j ) { 3759 var k = a[i]; 3760 while ( k[j] ) { 3761 j++; 3762 } 3763 return j; 3764 }; 3765 3766 aLayout.splice( 0, aLayout.length ); 3767 3768 /* We know how many rows there are in the layout - so prep it */ 3769 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ ) 3770 { 3771 aLayout.push( [] ); 3772 } 3773 3774 /* Calculate a layout array */ 3775 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ ) 3776 { 3777 nTr = nTrs[i]; 3778 iColumn = 0; 3779 3780 /* For every cell in the row... */ 3781 nCell = nTr.firstChild; 3782 while ( nCell ) { 3783 if ( nCell.nodeName.toUpperCase() == "TD" || 3784 nCell.nodeName.toUpperCase() == "TH" ) 3785 { 3786 /* Get the col and rowspan attributes from the DOM and sanitise them */ 3787 iColspan = nCell.getAttribute('colspan') * 1; 3788 iRowspan = nCell.getAttribute('rowspan') * 1; 3789 iColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan; 3790 iRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan; 3791 3792 /* There might be colspan cells already in this row, so shift our target 3793 * accordingly 3794 */ 3795 iColShifted = fnShiftCol( aLayout, i, iColumn ); 3796 3797 /* Cache calculation for unique columns */ 3798 bUnique = iColspan === 1 ? true : false; 3799 3800 /* If there is col / rowspan, copy the information into the layout grid */ 3801 for ( l=0 ; l<iColspan ; l++ ) 3802 { 3803 for ( k=0 ; k<iRowspan ; k++ ) 3804 { 3805 aLayout[i+k][iColShifted+l] = { 3806 "cell": nCell, 3807 "unique": bUnique 3808 }; 3809 aLayout[i+k].nTr = nTr; 3810 } 3811 } 3812 } 3813 nCell = nCell.nextSibling; 3814 } 3815 } 3816 } 3817 3818 3819 /** 3820 * Get an array of unique th elements, one for each column 3821 * @param {object} oSettings dataTables settings object 3822 * @param {node} nHeader automatically detect the layout from this node - optional 3823 * @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional 3824 * @returns array {node} aReturn list of unique th's 3825 * @memberof DataTable#oApi 3826 */ 3827 function _fnGetUniqueThs ( oSettings, nHeader, aLayout ) 3828 { 3829 var aReturn = []; 3830 if ( !aLayout ) 3831 { 3832 aLayout = oSettings.aoHeader; 3833 if ( nHeader ) 3834 { 3835 aLayout = []; 3836 _fnDetectHeader( aLayout, nHeader ); 3837 } 3838 } 3839 3840 for ( var i=0, iLen=aLayout.length ; i<iLen ; i++ ) 3841 { 3842 for ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ ) 3843 { 3844 if ( aLayout[i][j].unique && 3845 (!aReturn[j] || !oSettings.bSortCellsTop) ) 3846 { 3847 aReturn[j] = aLayout[i][j].cell; 3848 } 3849 } 3850 } 3851 3852 return aReturn; 3853 } 3854 3855 /** 3856 * Set the start position for draw 3857 * @param {object} oSettings dataTables settings object 3858 */ 3859 function _fnStart( oSettings ) 3860 { 3861 var bServerSide = _fnDataSource( oSettings ) == 'ssp'; 3862 var iInitDisplayStart = oSettings.iInitDisplayStart; 3863 3864 // Check and see if we have an initial draw position from state saving 3865 if ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 ) 3866 { 3867 oSettings._iDisplayStart = bServerSide ? 3868 iInitDisplayStart : 3869 iInitDisplayStart >= oSettings.fnRecordsDisplay() ? 3870 0 : 3871 iInitDisplayStart; 3872 3873 oSettings.iInitDisplayStart = -1; 3874 } 3875 } 3876 3877 /** 3878 * Create an Ajax call based on the table's settings, taking into account that 3879 * parameters can have multiple forms, and backwards compatibility. 3880 * 3881 * @param {object} oSettings dataTables settings object 3882 * @param {array} data Data to send to the server, required by 3883 * DataTables - may be augmented by developer callbacks 3884 * @param {function} fn Callback function to run when data is obtained 3885 */ 3886 function _fnBuildAjax( oSettings, data, fn ) 3887 { 3888 // Compatibility with 1.9-, allow fnServerData and event to manipulate 3889 _fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] ); 3890 3891 // Convert to object based for 1.10+ if using the old array scheme which can 3892 // come from server-side processing or serverParams 3893 if ( data && Array.isArray(data) ) { 3894 var tmp = {}; 3895 var rbracket = /(.*?)\[\]$/; 3896 3897 $.each( data, function (key, val) { 3898 var match = val.name.match(rbracket); 3899 3900 if ( match ) { 3901 // Support for arrays 3902 var name = match[0]; 3903 3904 if ( ! tmp[ name ] ) { 3905 tmp[ name ] = []; 3906 } 3907 tmp[ name ].push( val.value ); 3908 } 3909 else { 3910 tmp[val.name] = val.value; 3911 } 3912 } ); 3913 data = tmp; 3914 } 3915 3916 var ajaxData; 3917 var ajax = oSettings.ajax; 3918 var instance = oSettings.oInstance; 3919 var callback = function ( json ) { 3920 var status = oSettings.jqXHR 3921 ? oSettings.jqXHR.status 3922 : null; 3923 3924 if ( json === null || (typeof status === 'number' && status == 204 ) ) { 3925 json = {}; 3926 _fnAjaxDataSrc( oSettings, json, [] ); 3927 } 3928 3929 var error = json.error || json.sError; 3930 if ( error ) { 3931 _fnLog( oSettings, 0, error ); 3932 } 3933 3934 oSettings.json = json; 3935 3936 _fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR] ); 3937 fn( json ); 3938 }; 3939 3940 if ( $.isPlainObject( ajax ) && ajax.data ) 3941 { 3942 ajaxData = ajax.data; 3943 3944 var newData = typeof ajaxData === 'function' ? 3945 ajaxData( data, oSettings ) : // fn can manipulate data or return 3946 ajaxData; // an object object or array to merge 3947 3948 // If the function returned something, use that alone 3949 data = typeof ajaxData === 'function' && newData ? 3950 newData : 3951 $.extend( true, data, newData ); 3952 3953 // Remove the data property as we've resolved it already and don't want 3954 // jQuery to do it again (it is restored at the end of the function) 3955 delete ajax.data; 3956 } 3957 3958 var baseAjax = { 3959 "data": data, 3960 "success": callback, 3961 "dataType": "json", 3962 "cache": false, 3963 "type": oSettings.sServerMethod, 3964 "error": function (xhr, error, thrown) { 3965 var ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR] ); 3966 3967 if ( $.inArray( true, ret ) === -1 ) { 3968 if ( error == "parsererror" ) { 3969 _fnLog( oSettings, 0, 'Invalid JSON response', 1 ); 3970 } 3971 else if ( xhr.readyState === 4 ) { 3972 _fnLog( oSettings, 0, 'Ajax error', 7 ); 3973 } 3974 } 3975 3976 _fnProcessingDisplay( oSettings, false ); 3977 } 3978 }; 3979 3980 // Store the data submitted for the API 3981 oSettings.oAjaxData = data; 3982 3983 // Allow plug-ins and external processes to modify the data 3984 _fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data] ); 3985 3986 if ( oSettings.fnServerData ) 3987 { 3988 // DataTables 1.9- compatibility 3989 oSettings.fnServerData.call( instance, 3990 oSettings.sAjaxSource, 3991 $.map( data, function (val, key) { // Need to convert back to 1.9 trad format 3992 return { name: key, value: val }; 3993 } ), 3994 callback, 3995 oSettings 3996 ); 3997 } 3998 else if ( oSettings.sAjaxSource || typeof ajax === 'string' ) 3999 { 4000 // DataTables 1.9- compatibility 4001 oSettings.jqXHR = $.ajax( $.extend( baseAjax, { 4002 url: ajax || oSettings.sAjaxSource 4003 } ) ); 4004 } 4005 else if ( typeof ajax === 'function' ) 4006 { 4007 // Is a function - let the caller define what needs to be done 4008 oSettings.jqXHR = ajax.call( instance, data, callback, oSettings ); 4009 } 4010 else 4011 { 4012 // Object to extend the base settings 4013 oSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) ); 4014 4015 // Restore for next time around 4016 ajax.data = ajaxData; 4017 } 4018 } 4019 4020 4021 /** 4022 * Update the table using an Ajax call 4023 * @param {object} settings dataTables settings object 4024 * @returns {boolean} Block the table drawing or not 4025 * @memberof DataTable#oApi 4026 */ 4027 function _fnAjaxUpdate( settings ) 4028 { 4029 settings.iDraw++; 4030 _fnProcessingDisplay( settings, true ); 4031 4032 _fnBuildAjax( 4033 settings, 4034 _fnAjaxParameters( settings ), 4035 function(json) { 4036 _fnAjaxUpdateDraw( settings, json ); 4037 } 4038 ); 4039 } 4040 4041 4042 /** 4043 * Build up the parameters in an object needed for a server-side processing 4044 * request. Note that this is basically done twice, is different ways - a modern 4045 * method which is used by default in DataTables 1.10 which uses objects and 4046 * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if 4047 * the sAjaxSource option is used in the initialisation, or the legacyAjax 4048 * option is set. 4049 * @param {object} oSettings dataTables settings object 4050 * @returns {bool} block the table drawing or not 4051 * @memberof DataTable#oApi 4052 */ 4053 function _fnAjaxParameters( settings ) 4054 { 4055 var 4056 columns = settings.aoColumns, 4057 columnCount = columns.length, 4058 features = settings.oFeatures, 4059 preSearch = settings.oPreviousSearch, 4060 preColSearch = settings.aoPreSearchCols, 4061 i, data = [], dataProp, column, columnSearch, 4062 sort = _fnSortFlatten( settings ), 4063 displayStart = settings._iDisplayStart, 4064 displayLength = features.bPaginate !== false ? 4065 settings._iDisplayLength : 4066 -1; 4067 4068 var param = function ( name, value ) { 4069 data.push( { 'name': name, 'value': value } ); 4070 }; 4071 4072 // DataTables 1.9- compatible method 4073 param( 'sEcho', settings.iDraw ); 4074 param( 'iColumns', columnCount ); 4075 param( 'sColumns', _pluck( columns, 'sName' ).join(',') ); 4076 param( 'iDisplayStart', displayStart ); 4077 param( 'iDisplayLength', displayLength ); 4078 4079 // DataTables 1.10+ method 4080 var d = { 4081 draw: settings.iDraw, 4082 columns: [], 4083 order: [], 4084 start: displayStart, 4085 length: displayLength, 4086 search: { 4087 value: preSearch.sSearch, 4088 regex: preSearch.bRegex 4089 } 4090 }; 4091 4092 for ( i=0 ; i<columnCount ; i++ ) { 4093 column = columns[i]; 4094 columnSearch = preColSearch[i]; 4095 dataProp = typeof column.mData=="function" ? 'function' : column.mData ; 4096 4097 d.columns.push( { 4098 data: dataProp, 4099 name: column.sName, 4100 searchable: column.bSearchable, 4101 orderable: column.bSortable, 4102 search: { 4103 value: columnSearch.sSearch, 4104 regex: columnSearch.bRegex 4105 } 4106 } ); 4107 4108 param( "mDataProp_"+i, dataProp ); 4109 4110 if ( features.bFilter ) { 4111 param( 'sSearch_'+i, columnSearch.sSearch ); 4112 param( 'bRegex_'+i, columnSearch.bRegex ); 4113 param( 'bSearchable_'+i, column.bSearchable ); 4114 } 4115 4116 if ( features.bSort ) { 4117 param( 'bSortable_'+i, column.bSortable ); 4118 } 4119 } 4120 4121 if ( features.bFilter ) { 4122 param( 'sSearch', preSearch.sSearch ); 4123 param( 'bRegex', preSearch.bRegex ); 4124 } 4125 4126 if ( features.bSort ) { 4127 $.each( sort, function ( i, val ) { 4128 d.order.push( { column: val.col, dir: val.dir } ); 4129 4130 param( 'iSortCol_'+i, val.col ); 4131 param( 'sSortDir_'+i, val.dir ); 4132 } ); 4133 4134 param( 'iSortingCols', sort.length ); 4135 } 4136 4137 // If the legacy.ajax parameter is null, then we automatically decide which 4138 // form to use, based on sAjaxSource 4139 var legacy = DataTable.ext.legacy.ajax; 4140 if ( legacy === null ) { 4141 return settings.sAjaxSource ? data : d; 4142 } 4143 4144 // Otherwise, if legacy has been specified then we use that to decide on the 4145 // form 4146 return legacy ? data : d; 4147 } 4148 4149 4150 /** 4151 * Data the data from the server (nuking the old) and redraw the table 4152 * @param {object} oSettings dataTables settings object 4153 * @param {object} json json data return from the server. 4154 * @param {string} json.sEcho Tracking flag for DataTables to match requests 4155 * @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering 4156 * @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering 4157 * @param {array} json.aaData The data to display on this page 4158 * @param {string} [json.sColumns] Column ordering (sName, comma separated) 4159 * @memberof DataTable#oApi 4160 */ 4161 function _fnAjaxUpdateDraw ( settings, json ) 4162 { 4163 // v1.10 uses camelCase variables, while 1.9 uses Hungarian notation. 4164 // Support both 4165 var compat = function ( old, modern ) { 4166 return json[old] !== undefined ? json[old] : json[modern]; 4167 }; 4168 4169 var data = _fnAjaxDataSrc( settings, json ); 4170 var draw = compat( 'sEcho', 'draw' ); 4171 var recordsTotal = compat( 'iTotalRecords', 'recordsTotal' ); 4172 var recordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' ); 4173 4174 if ( draw !== undefined ) { 4175 // Protect against out of sequence returns 4176 if ( draw*1 < settings.iDraw ) { 4177 return; 4178 } 4179 settings.iDraw = draw * 1; 4180 } 4181 4182 // No data in returned object, so rather than an array, we show an empty table 4183 if ( ! data ) { 4184 data = []; 4185 } 4186 4187 _fnClearTable( settings ); 4188 settings._iRecordsTotal = parseInt(recordsTotal, 10); 4189 settings._iRecordsDisplay = parseInt(recordsFiltered, 10); 4190 4191 for ( var i=0, ien=data.length ; i<ien ; i++ ) { 4192 _fnAddData( settings, data[i] ); 4193 } 4194 settings.aiDisplay = settings.aiDisplayMaster.slice(); 4195 4196 _fnDraw( settings, true ); 4197 4198 if ( ! settings._bInitComplete ) { 4199 _fnInitComplete( settings, json ); 4200 } 4201 4202 _fnProcessingDisplay( settings, false ); 4203 } 4204 4205 4206 /** 4207 * Get the data from the JSON data source to use for drawing a table. Using 4208 * `_fnGetObjectDataFn` allows the data to be sourced from a property of the 4209 * source object, or from a processing function. 4210 * @param {object} oSettings dataTables settings object 4211 * @param {object} json Data source object / array from the server 4212 * @return {array} Array of data to use 4213 */ 4214 function _fnAjaxDataSrc ( oSettings, json, write ) 4215 { 4216 var dataSrc = $.isPlainObject( oSettings.ajax ) && oSettings.ajax.dataSrc !== undefined ? 4217 oSettings.ajax.dataSrc : 4218 oSettings.sAjaxDataProp; // Compatibility with 1.9-. 4219 4220 if ( ! write ) { 4221 if ( dataSrc === 'data' ) { 4222 // If the default, then we still want to support the old style, and safely ignore 4223 // it if possible 4224 return json.aaData || json[dataSrc]; 4225 } 4226 4227 return dataSrc !== "" ? 4228 _fnGetObjectDataFn( dataSrc )( json ) : 4229 json; 4230 } 4231 4232 // set 4233 _fnSetObjectDataFn( dataSrc )( json, write ); 4234 } 4235 4236 /** 4237 * Generate the node required for filtering text 4238 * @returns {node} Filter control element 4239 * @param {object} oSettings dataTables settings object 4240 * @memberof DataTable#oApi 4241 */ 4242 function _fnFeatureHtmlFilter ( settings ) 4243 { 4244 var classes = settings.oClasses; 4245 var tableId = settings.sTableId; 4246 var language = settings.oLanguage; 4247 var previousSearch = settings.oPreviousSearch; 4248 var features = settings.aanFeatures; 4249 var input = '<input type="search" class="'+classes.sFilterInput+'"/>'; 4250 4251 var str = language.sSearch; 4252 str = str.match(/_INPUT_/) ? 4253 str.replace('_INPUT_', input) : 4254 str+input; 4255 4256 var filter = $('<div/>', { 4257 'id': ! features.f ? tableId+'_filter' : null, 4258 'class': classes.sFilter 4259 } ) 4260 .append( $('<label/>' ).append( str ) ); 4261 4262 var searchFn = function(event) { 4263 /* Update all other filter input elements for the new display */ 4264 var n = features.f; 4265 var val = !this.value ? "" : this.value; // mental IE8 fix :-( 4266 if(previousSearch.return && event.key !== "Enter") { 4267 return; 4268 } 4269 /* Now do the filter */ 4270 if ( val != previousSearch.sSearch ) { 4271 _fnFilterComplete( settings, { 4272 "sSearch": val, 4273 "bRegex": previousSearch.bRegex, 4274 "bSmart": previousSearch.bSmart , 4275 "bCaseInsensitive": previousSearch.bCaseInsensitive, 4276 "return": previousSearch.return 4277 } ); 4278 4279 // Need to redraw, without resorting 4280 settings._iDisplayStart = 0; 4281 _fnDraw( settings ); 4282 } 4283 }; 4284 4285 var searchDelay = settings.searchDelay !== null ? 4286 settings.searchDelay : 4287 _fnDataSource( settings ) === 'ssp' ? 4288 400 : 4289 0; 4290 4291 var jqFilter = $('input', filter) 4292 .val( previousSearch.sSearch ) 4293 .attr( 'placeholder', language.sSearchPlaceholder ) 4294 .on( 4295 'keyup.DT search.DT input.DT paste.DT cut.DT', 4296 searchDelay ? 4297 _fnThrottle( searchFn, searchDelay ) : 4298 searchFn 4299 ) 4300 .on( 'mouseup', function(e) { 4301 // Edge fix! Edge 17 does not trigger anything other than mouse events when clicking 4302 // on the clear icon (Edge bug 17584515). This is safe in other browsers as `searchFn` 4303 // checks the value to see if it has changed. In other browsers it won't have. 4304 setTimeout( function () { 4305 searchFn.call(jqFilter[0], e); 4306 }, 10); 4307 } ) 4308 .on( 'keypress.DT', function(e) { 4309 /* Prevent form submission */ 4310 if ( e.keyCode == 13 ) { 4311 return false; 4312 } 4313 } ) 4314 .attr('aria-controls', tableId); 4315 4316 // Update the input elements whenever the table is filtered 4317 $(settings.nTable).on( 'search.dt.DT', function ( ev, s ) { 4318 if ( settings === s ) { 4319 // IE9 throws an 'unknown error' if document.activeElement is used 4320 // inside an iframe or frame... 4321 try { 4322 if ( jqFilter[0] !== document.activeElement ) { 4323 jqFilter.val( previousSearch.sSearch ); 4324 } 4325 } 4326 catch ( e ) {} 4327 } 4328 } ); 4329 4330 return filter[0]; 4331 } 4332 4333 4334 /** 4335 * Filter the table using both the global filter and column based filtering 4336 * @param {object} oSettings dataTables settings object 4337 * @param {object} oSearch search information 4338 * @param {int} [iForce] force a research of the master array (1) or not (undefined or 0) 4339 * @memberof DataTable#oApi 4340 */ 4341 function _fnFilterComplete ( oSettings, oInput, iForce ) 4342 { 4343 var oPrevSearch = oSettings.oPreviousSearch; 4344 var aoPrevSearch = oSettings.aoPreSearchCols; 4345 var fnSaveFilter = function ( oFilter ) { 4346 /* Save the filtering values */ 4347 oPrevSearch.sSearch = oFilter.sSearch; 4348 oPrevSearch.bRegex = oFilter.bRegex; 4349 oPrevSearch.bSmart = oFilter.bSmart; 4350 oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive; 4351 oPrevSearch.return = oFilter.return; 4352 }; 4353 var fnRegex = function ( o ) { 4354 // Backwards compatibility with the bEscapeRegex option 4355 return o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex; 4356 }; 4357 4358 // Resolve any column types that are unknown due to addition or invalidation 4359 // @todo As per sort - can this be moved into an event handler? 4360 _fnColumnTypes( oSettings ); 4361 4362 /* In server-side processing all filtering is done by the server, so no point hanging around here */ 4363 if ( _fnDataSource( oSettings ) != 'ssp' ) 4364 { 4365 /* Global filter */ 4366 _fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive, oInput.return ); 4367 fnSaveFilter( oInput ); 4368 4369 /* Now do the individual column filter */ 4370 for ( var i=0 ; i<aoPrevSearch.length ; i++ ) 4371 { 4372 _fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, fnRegex(aoPrevSearch[i]), 4373 aoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive ); 4374 } 4375 4376 /* Custom filtering */ 4377 _fnFilterCustom( oSettings ); 4378 } 4379 else 4380 { 4381 fnSaveFilter( oInput ); 4382 } 4383 4384 /* Tell the draw function we have been filtering */ 4385 oSettings.bFiltered = true; 4386 _fnCallbackFire( oSettings, null, 'search', [oSettings] ); 4387 } 4388 4389 4390 /** 4391 * Apply custom filtering functions 4392 * @param {object} oSettings dataTables settings object 4393 * @memberof DataTable#oApi 4394 */ 4395 function _fnFilterCustom( settings ) 4396 { 4397 var filters = DataTable.ext.search; 4398 var displayRows = settings.aiDisplay; 4399 var row, rowIdx; 4400 4401 for ( var i=0, ien=filters.length ; i<ien ; i++ ) { 4402 var rows = []; 4403 4404 // Loop over each row and see if it should be included 4405 for ( var j=0, jen=displayRows.length ; j<jen ; j++ ) { 4406 rowIdx = displayRows[ j ]; 4407 row = settings.aoData[ rowIdx ]; 4408 4409 if ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) { 4410 rows.push( rowIdx ); 4411 } 4412 } 4413 4414 // So the array reference doesn't break set the results into the 4415 // existing array 4416 displayRows.length = 0; 4417 $.merge( displayRows, rows ); 4418 } 4419 } 4420 4421 4422 /** 4423 * Filter the table on a per-column basis 4424 * @param {object} oSettings dataTables settings object 4425 * @param {string} sInput string to filter on 4426 * @param {int} iColumn column to filter 4427 * @param {bool} bRegex treat search string as a regular expression or not 4428 * @param {bool} bSmart use smart filtering or not 4429 * @param {bool} bCaseInsensitive Do case insensitive matching or not 4430 * @memberof DataTable#oApi 4431 */ 4432 function _fnFilterColumn ( settings, searchStr, colIdx, regex, smart, caseInsensitive ) 4433 { 4434 if ( searchStr === '' ) { 4435 return; 4436 } 4437 4438 var data; 4439 var out = []; 4440 var display = settings.aiDisplay; 4441 var rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive ); 4442 4443 for ( var i=0 ; i<display.length ; i++ ) { 4444 data = settings.aoData[ display[i] ]._aFilterData[ colIdx ]; 4445 4446 if ( rpSearch.test( data ) ) { 4447 out.push( display[i] ); 4448 } 4449 } 4450 4451 settings.aiDisplay = out; 4452 } 4453 4454 4455 /** 4456 * Filter the data table based on user input and draw the table 4457 * @param {object} settings dataTables settings object 4458 * @param {string} input string to filter on 4459 * @param {int} force optional - force a research of the master array (1) or not (undefined or 0) 4460 * @param {bool} regex treat as a regular expression or not 4461 * @param {bool} smart perform smart filtering or not 4462 * @param {bool} caseInsensitive Do case insensitive matching or not 4463 * @memberof DataTable#oApi 4464 */ 4465 function _fnFilter( settings, input, force, regex, smart, caseInsensitive ) 4466 { 4467 var rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive ); 4468 var prevSearch = settings.oPreviousSearch.sSearch; 4469 var displayMaster = settings.aiDisplayMaster; 4470 var display, invalidated, i; 4471 var filtered = []; 4472 4473 // Need to take account of custom filtering functions - always filter 4474 if ( DataTable.ext.search.length !== 0 ) { 4475 force = true; 4476 } 4477 4478 // Check if any of the rows were invalidated 4479 invalidated = _fnFilterData( settings ); 4480 4481 // If the input is blank - we just want the full data set 4482 if ( input.length <= 0 ) { 4483 settings.aiDisplay = displayMaster.slice(); 4484 } 4485 else { 4486 // New search - start from the master array 4487 if ( invalidated || 4488 force || 4489 regex || 4490 prevSearch.length > input.length || 4491 input.indexOf(prevSearch) !== 0 || 4492 settings.bSorted // On resort, the display master needs to be 4493 // re-filtered since indexes will have changed 4494 ) { 4495 settings.aiDisplay = displayMaster.slice(); 4496 } 4497 4498 // Search the display array 4499 display = settings.aiDisplay; 4500 4501 for ( i=0 ; i<display.length ; i++ ) { 4502 if ( rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) { 4503 filtered.push( display[i] ); 4504 } 4505 } 4506 4507 settings.aiDisplay = filtered; 4508 } 4509 } 4510 4511 4512 /** 4513 * Build a regular expression object suitable for searching a table 4514 * @param {string} sSearch string to search for 4515 * @param {bool} bRegex treat as a regular expression or not 4516 * @param {bool} bSmart perform smart filtering or not 4517 * @param {bool} bCaseInsensitive Do case insensitive matching or not 4518 * @returns {RegExp} constructed object 4519 * @memberof DataTable#oApi 4520 */ 4521 function _fnFilterCreateSearch( search, regex, smart, caseInsensitive ) 4522 { 4523 search = regex ? 4524 search : 4525 _fnEscapeRegex( search ); 4526 4527 if ( smart ) { 4528 /* For smart filtering we want to allow the search to work regardless of 4529 * word order. We also want double quoted text to be preserved, so word 4530 * order is important - a la google. So this is what we want to 4531 * generate: 4532 * 4533 * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$ 4534 */ 4535 var a = $.map( search.match( /"[^"]+"|[^ ]+/g ) || [''], function ( word ) { 4536 if ( word.charAt(0) === '"' ) { 4537 var m = word.match( /^"(.*)"$/ ); 4538 word = m ? m[1] : word; 4539 } 4540 4541 return word.replace('"', ''); 4542 } ); 4543 4544 search = '^(?=.*?'+a.join( ')(?=.*?' )+').*$'; 4545 } 4546 4547 return new RegExp( search, caseInsensitive ? 'i' : '' ); 4548 } 4549 4550 4551 /** 4552 * Escape a string such that it can be used in a regular expression 4553 * @param {string} sVal string to escape 4554 * @returns {string} escaped string 4555 * @memberof DataTable#oApi 4556 */ 4557 var _fnEscapeRegex = DataTable.util.escapeRegex; 4558 4559 var __filter_div = $('<div>')[0]; 4560 var __filter_div_textContent = __filter_div.textContent !== undefined; 4561 4562 // Update the filtering data for each row if needed (by invalidation or first run) 4563 function _fnFilterData ( settings ) 4564 { 4565 var columns = settings.aoColumns; 4566 var column; 4567 var i, j, ien, jen, filterData, cellData, row; 4568 var wasInvalidated = false; 4569 4570 for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) { 4571 row = settings.aoData[i]; 4572 4573 if ( ! row._aFilterData ) { 4574 filterData = []; 4575 4576 for ( j=0, jen=columns.length ; j<jen ; j++ ) { 4577 column = columns[j]; 4578 4579 if ( column.bSearchable ) { 4580 cellData = _fnGetCellData( settings, i, j, 'filter' ); 4581 4582 // Search in DataTables 1.10 is string based. In 1.11 this 4583 // should be altered to also allow strict type checking. 4584 if ( cellData === null ) { 4585 cellData = ''; 4586 } 4587 4588 if ( typeof cellData !== 'string' && cellData.toString ) { 4589 cellData = cellData.toString(); 4590 } 4591 } 4592 else { 4593 cellData = ''; 4594 } 4595 4596 // If it looks like there is an HTML entity in the string, 4597 // attempt to decode it so sorting works as expected. Note that 4598 // we could use a single line of jQuery to do this, but the DOM 4599 // method used here is much faster http://jsperf.com/html-decode 4600 if ( cellData.indexOf && cellData.indexOf('&') !== -1 ) { 4601 __filter_div.innerHTML = cellData; 4602 cellData = __filter_div_textContent ? 4603 __filter_div.textContent : 4604 __filter_div.innerText; 4605 } 4606 4607 if ( cellData.replace ) { 4608 cellData = cellData.replace(/[\r\n\u2028]/g, ''); 4609 } 4610 4611 filterData.push( cellData ); 4612 } 4613 4614 row._aFilterData = filterData; 4615 row._sFilterRow = filterData.join(' '); 4616 wasInvalidated = true; 4617 } 4618 } 4619 4620 return wasInvalidated; 4621 } 4622 4623 4624 /** 4625 * Convert from the internal Hungarian notation to camelCase for external 4626 * interaction 4627 * @param {object} obj Object to convert 4628 * @returns {object} Inverted object 4629 * @memberof DataTable#oApi 4630 */ 4631 function _fnSearchToCamel ( obj ) 4632 { 4633 return { 4634 search: obj.sSearch, 4635 smart: obj.bSmart, 4636 regex: obj.bRegex, 4637 caseInsensitive: obj.bCaseInsensitive 4638 }; 4639 } 4640 4641 4642 4643 /** 4644 * Convert from camelCase notation to the internal Hungarian. We could use the 4645 * Hungarian convert function here, but this is cleaner 4646 * @param {object} obj Object to convert 4647 * @returns {object} Inverted object 4648 * @memberof DataTable#oApi 4649 */ 4650 function _fnSearchToHung ( obj ) 4651 { 4652 return { 4653 sSearch: obj.search, 4654 bSmart: obj.smart, 4655 bRegex: obj.regex, 4656 bCaseInsensitive: obj.caseInsensitive 4657 }; 4658 } 4659 4660 /** 4661 * Generate the node required for the info display 4662 * @param {object} oSettings dataTables settings object 4663 * @returns {node} Information element 4664 * @memberof DataTable#oApi 4665 */ 4666 function _fnFeatureHtmlInfo ( settings ) 4667 { 4668 var 4669 tid = settings.sTableId, 4670 nodes = settings.aanFeatures.i, 4671 n = $('<div/>', { 4672 'class': settings.oClasses.sInfo, 4673 'id': ! nodes ? tid+'_info' : null 4674 } ); 4675 4676 if ( ! nodes ) { 4677 // Update display on each draw 4678 settings.aoDrawCallback.push( { 4679 "fn": _fnUpdateInfo, 4680 "sName": "information" 4681 } ); 4682 4683 n 4684 .attr( 'role', 'status' ) 4685 .attr( 'aria-live', 'polite' ); 4686 4687 // Table is described by our info div 4688 $(settings.nTable).attr( 'aria-describedby', tid+'_info' ); 4689 } 4690 4691 return n[0]; 4692 } 4693 4694 4695 /** 4696 * Update the information elements in the display 4697 * @param {object} settings dataTables settings object 4698 * @memberof DataTable#oApi 4699 */ 4700 function _fnUpdateInfo ( settings ) 4701 { 4702 /* Show information about the table */ 4703 var nodes = settings.aanFeatures.i; 4704 if ( nodes.length === 0 ) { 4705 return; 4706 } 4707 4708 var 4709 lang = settings.oLanguage, 4710 start = settings._iDisplayStart+1, 4711 end = settings.fnDisplayEnd(), 4712 max = settings.fnRecordsTotal(), 4713 total = settings.fnRecordsDisplay(), 4714 out = total ? 4715 lang.sInfo : 4716 lang.sInfoEmpty; 4717 4718 if ( total !== max ) { 4719 /* Record set after filtering */ 4720 out += ' ' + lang.sInfoFiltered; 4721 } 4722 4723 // Convert the macros 4724 out += lang.sInfoPostFix; 4725 out = _fnInfoMacros( settings, out ); 4726 4727 var callback = lang.fnInfoCallback; 4728 if ( callback !== null ) { 4729 out = callback.call( settings.oInstance, 4730 settings, start, end, max, total, out 4731 ); 4732 } 4733 4734 $(nodes).html( out ); 4735 } 4736 4737 4738 function _fnInfoMacros ( settings, str ) 4739 { 4740 // When infinite scrolling, we are always starting at 1. _iDisplayStart is used only 4741 // internally 4742 var 4743 formatter = settings.fnFormatNumber, 4744 start = settings._iDisplayStart+1, 4745 len = settings._iDisplayLength, 4746 vis = settings.fnRecordsDisplay(), 4747 all = len === -1; 4748 4749 return str. 4750 replace(/_START_/g, formatter.call( settings, start ) ). 4751 replace(/_END_/g, formatter.call( settings, settings.fnDisplayEnd() ) ). 4752 replace(/_MAX_/g, formatter.call( settings, settings.fnRecordsTotal() ) ). 4753 replace(/_TOTAL_/g, formatter.call( settings, vis ) ). 4754 replace(/_PAGE_/g, formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ). 4755 replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) ); 4756 } 4757 4758 4759 4760 /** 4761 * Draw the table for the first time, adding all required features 4762 * @param {object} settings dataTables settings object 4763 * @memberof DataTable#oApi 4764 */ 4765 function _fnInitialise ( settings ) 4766 { 4767 var i, iLen, iAjaxStart=settings.iInitDisplayStart; 4768 var columns = settings.aoColumns, column; 4769 var features = settings.oFeatures; 4770 var deferLoading = settings.bDeferLoading; // value modified by the draw 4771 4772 /* Ensure that the table data is fully initialised */ 4773 if ( ! settings.bInitialised ) { 4774 setTimeout( function(){ _fnInitialise( settings ); }, 200 ); 4775 return; 4776 } 4777 4778 /* Show the display HTML options */ 4779 _fnAddOptionsHtml( settings ); 4780 4781 /* Build and draw the header / footer for the table */ 4782 _fnBuildHead( settings ); 4783 _fnDrawHead( settings, settings.aoHeader ); 4784 _fnDrawHead( settings, settings.aoFooter ); 4785 4786 /* Okay to show that something is going on now */ 4787 _fnProcessingDisplay( settings, true ); 4788 4789 /* Calculate sizes for columns */ 4790 if ( features.bAutoWidth ) { 4791 _fnCalculateColumnWidths( settings ); 4792 } 4793 4794 for ( i=0, iLen=columns.length ; i<iLen ; i++ ) { 4795 column = columns[i]; 4796 4797 if ( column.sWidth ) { 4798 column.nTh.style.width = _fnStringToCss( column.sWidth ); 4799 } 4800 } 4801 4802 _fnCallbackFire( settings, null, 'preInit', [settings] ); 4803 4804 // If there is default sorting required - let's do it. The sort function 4805 // will do the drawing for us. Otherwise we draw the table regardless of the 4806 // Ajax source - this allows the table to look initialised for Ajax sourcing 4807 // data (show 'loading' message possibly) 4808 _fnReDraw( settings ); 4809 4810 // Server-side processing init complete is done by _fnAjaxUpdateDraw 4811 var dataSrc = _fnDataSource( settings ); 4812 if ( dataSrc != 'ssp' || deferLoading ) { 4813 // if there is an ajax source load the data 4814 if ( dataSrc == 'ajax' ) { 4815 _fnBuildAjax( settings, [], function(json) { 4816 var aData = _fnAjaxDataSrc( settings, json ); 4817 4818 // Got the data - add it to the table 4819 for ( i=0 ; i<aData.length ; i++ ) { 4820 _fnAddData( settings, aData[i] ); 4821 } 4822 4823 // Reset the init display for cookie saving. We've already done 4824 // a filter, and therefore cleared it before. So we need to make 4825 // it appear 'fresh' 4826 settings.iInitDisplayStart = iAjaxStart; 4827 4828 _fnReDraw( settings ); 4829 4830 _fnProcessingDisplay( settings, false ); 4831 _fnInitComplete( settings, json ); 4832 }, settings ); 4833 } 4834 else { 4835 _fnProcessingDisplay( settings, false ); 4836 _fnInitComplete( settings ); 4837 } 4838 } 4839 } 4840 4841 4842 /** 4843 * Draw the table for the first time, adding all required features 4844 * @param {object} oSettings dataTables settings object 4845 * @param {object} [json] JSON from the server that completed the table, if using Ajax source 4846 * with client-side processing (optional) 4847 * @memberof DataTable#oApi 4848 */ 4849 function _fnInitComplete ( settings, json ) 4850 { 4851 settings._bInitComplete = true; 4852 4853 // When data was added after the initialisation (data or Ajax) we need to 4854 // calculate the column sizing 4855 if ( json || settings.oInit.aaData ) { 4856 _fnAdjustColumnSizing( settings ); 4857 } 4858 4859 _fnCallbackFire( settings, null, 'plugin-init', [settings, json] ); 4860 _fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] ); 4861 } 4862 4863 4864 function _fnLengthChange ( settings, val ) 4865 { 4866 var len = parseInt( val, 10 ); 4867 settings._iDisplayLength = len; 4868 4869 _fnLengthOverflow( settings ); 4870 4871 // Fire length change event 4872 _fnCallbackFire( settings, null, 'length', [settings, len] ); 4873 } 4874 4875 4876 /** 4877 * Generate the node required for user display length changing 4878 * @param {object} settings dataTables settings object 4879 * @returns {node} Display length feature node 4880 * @memberof DataTable#oApi 4881 */ 4882 function _fnFeatureHtmlLength ( settings ) 4883 { 4884 var 4885 classes = settings.oClasses, 4886 tableId = settings.sTableId, 4887 menu = settings.aLengthMenu, 4888 d2 = Array.isArray( menu[0] ), 4889 lengths = d2 ? menu[0] : menu, 4890 language = d2 ? menu[1] : menu; 4891 4892 var select = $('<select/>', { 4893 'name': tableId+'_length', 4894 'aria-controls': tableId, 4895 'class': classes.sLengthSelect 4896 } ); 4897 4898 for ( var i=0, ien=lengths.length ; i<ien ; i++ ) { 4899 select[0][ i ] = new Option( 4900 typeof language[i] === 'number' ? 4901 settings.fnFormatNumber( language[i] ) : 4902 language[i], 4903 lengths[i] 4904 ); 4905 } 4906 4907 var div = $('<div><label/></div>').addClass( classes.sLength ); 4908 if ( ! settings.aanFeatures.l ) { 4909 div[0].id = tableId+'_length'; 4910 } 4911 4912 div.children().append( 4913 settings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML ) 4914 ); 4915 4916 // Can't use `select` variable as user might provide their own and the 4917 // reference is broken by the use of outerHTML 4918 $('select', div) 4919 .val( settings._iDisplayLength ) 4920 .on( 'change.DT', function(e) { 4921 _fnLengthChange( settings, $(this).val() ); 4922 _fnDraw( settings ); 4923 } ); 4924 4925 // Update node value whenever anything changes the table's length 4926 $(settings.nTable).on( 'length.dt.DT', function (e, s, len) { 4927 if ( settings === s ) { 4928 $('select', div).val( len ); 4929 } 4930 } ); 4931 4932 return div[0]; 4933 } 4934 4935 4936 4937 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 4938 * Note that most of the paging logic is done in 4939 * DataTable.ext.pager 4940 */ 4941 4942 /** 4943 * Generate the node required for default pagination 4944 * @param {object} oSettings dataTables settings object 4945 * @returns {node} Pagination feature node 4946 * @memberof DataTable#oApi 4947 */ 4948 function _fnFeatureHtmlPaginate ( settings ) 4949 { 4950 var 4951 type = settings.sPaginationType, 4952 plugin = DataTable.ext.pager[ type ], 4953 modern = typeof plugin === 'function', 4954 redraw = function( settings ) { 4955 _fnDraw( settings ); 4956 }, 4957 node = $('<div/>').addClass( settings.oClasses.sPaging + type )[0], 4958 features = settings.aanFeatures; 4959 4960 if ( ! modern ) { 4961 plugin.fnInit( settings, node, redraw ); 4962 } 4963 4964 /* Add a draw callback for the pagination on first instance, to update the paging display */ 4965 if ( ! features.p ) 4966 { 4967 node.id = settings.sTableId+'_paginate'; 4968 4969 settings.aoDrawCallback.push( { 4970 "fn": function( settings ) { 4971 if ( modern ) { 4972 var 4973 start = settings._iDisplayStart, 4974 len = settings._iDisplayLength, 4975 visRecords = settings.fnRecordsDisplay(), 4976 all = len === -1, 4977 page = all ? 0 : Math.ceil( start / len ), 4978 pages = all ? 1 : Math.ceil( visRecords / len ), 4979 buttons = plugin(page, pages), 4980 i, ien; 4981 4982 for ( i=0, ien=features.p.length ; i<ien ; i++ ) { 4983 _fnRenderer( settings, 'pageButton' )( 4984 settings, features.p[i], i, buttons, page, pages 4985 ); 4986 } 4987 } 4988 else { 4989 plugin.fnUpdate( settings, redraw ); 4990 } 4991 }, 4992 "sName": "pagination" 4993 } ); 4994 } 4995 4996 return node; 4997 } 4998 4999 5000 /** 5001 * Alter the display settings to change the page 5002 * @param {object} settings DataTables settings object 5003 * @param {string|int} action Paging action to take: "first", "previous", 5004 * "next" or "last" or page number to jump to (integer) 5005 * @param [bool] redraw Automatically draw the update or not 5006 * @returns {bool} true page has changed, false - no change 5007 * @memberof DataTable#oApi 5008 */ 5009 function _fnPageChange ( settings, action, redraw ) 5010 { 5011 var 5012 start = settings._iDisplayStart, 5013 len = settings._iDisplayLength, 5014 records = settings.fnRecordsDisplay(); 5015 5016 if ( records === 0 || len === -1 ) 5017 { 5018 start = 0; 5019 } 5020 else if ( typeof action === "number" ) 5021 { 5022 start = action * len; 5023 5024 if ( start > records ) 5025 { 5026 start = 0; 5027 } 5028 } 5029 else if ( action == "first" ) 5030 { 5031 start = 0; 5032 } 5033 else if ( action == "previous" ) 5034 { 5035 start = len >= 0 ? 5036 start - len : 5037 0; 5038 5039 if ( start < 0 ) 5040 { 5041 start = 0; 5042 } 5043 } 5044 else if ( action == "next" ) 5045 { 5046 if ( start + len < records ) 5047 { 5048 start += len; 5049 } 5050 } 5051 else if ( action == "last" ) 5052 { 5053 start = Math.floor( (records-1) / len) * len; 5054 } 5055 else 5056 { 5057 _fnLog( settings, 0, "Unknown paging action: "+action, 5 ); 5058 } 5059 5060 var changed = settings._iDisplayStart !== start; 5061 settings._iDisplayStart = start; 5062 5063 if ( changed ) { 5064 _fnCallbackFire( settings, null, 'page', [settings] ); 5065 5066 if ( redraw ) { 5067 _fnDraw( settings ); 5068 } 5069 } 5070 5071 return changed; 5072 } 5073 5074 5075 5076 /** 5077 * Generate the node required for the processing node 5078 * @param {object} settings dataTables settings object 5079 * @returns {node} Processing element 5080 * @memberof DataTable#oApi 5081 */ 5082 function _fnFeatureHtmlProcessing ( settings ) 5083 { 5084 return $('<div/>', { 5085 'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null, 5086 'class': settings.oClasses.sProcessing 5087 } ) 5088 .html( settings.oLanguage.sProcessing ) 5089 .append('<div><div></div><div></div><div></div><div></div></div>') 5090 .insertBefore( settings.nTable )[0]; 5091 } 5092 5093 5094 /** 5095 * Display or hide the processing indicator 5096 * @param {object} settings dataTables settings object 5097 * @param {bool} show Show the processing indicator (true) or not (false) 5098 * @memberof DataTable#oApi 5099 */ 5100 function _fnProcessingDisplay ( settings, show ) 5101 { 5102 if ( settings.oFeatures.bProcessing ) { 5103 $(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' ); 5104 } 5105 5106 _fnCallbackFire( settings, null, 'processing', [settings, show] ); 5107 } 5108 5109 /** 5110 * Add any control elements for the table - specifically scrolling 5111 * @param {object} settings dataTables settings object 5112 * @returns {node} Node to add to the DOM 5113 * @memberof DataTable#oApi 5114 */ 5115 function _fnFeatureHtmlTable ( settings ) 5116 { 5117 var table = $(settings.nTable); 5118 5119 // Scrolling from here on in 5120 var scroll = settings.oScroll; 5121 5122 if ( scroll.sX === '' && scroll.sY === '' ) { 5123 return settings.nTable; 5124 } 5125 5126 var scrollX = scroll.sX; 5127 var scrollY = scroll.sY; 5128 var classes = settings.oClasses; 5129 var caption = table.children('caption'); 5130 var captionSide = caption.length ? caption[0]._captionSide : null; 5131 var headerClone = $( table[0].cloneNode(false) ); 5132 var footerClone = $( table[0].cloneNode(false) ); 5133 var footer = table.children('tfoot'); 5134 var _div = '<div/>'; 5135 var size = function ( s ) { 5136 return !s ? null : _fnStringToCss( s ); 5137 }; 5138 5139 if ( ! footer.length ) { 5140 footer = null; 5141 } 5142 5143 /* 5144 * The HTML structure that we want to generate in this function is: 5145 * div - scroller 5146 * div - scroll head 5147 * div - scroll head inner 5148 * table - scroll head table 5149 * thead - thead 5150 * div - scroll body 5151 * table - table (master table) 5152 * thead - thead clone for sizing 5153 * tbody - tbody 5154 * div - scroll foot 5155 * div - scroll foot inner 5156 * table - scroll foot table 5157 * tfoot - tfoot 5158 */ 5159 var scroller = $( _div, { 'class': classes.sScrollWrapper } ) 5160 .append( 5161 $(_div, { 'class': classes.sScrollHead } ) 5162 .css( { 5163 overflow: 'hidden', 5164 position: 'relative', 5165 border: 0, 5166 width: scrollX ? size(scrollX) : '100%' 5167 } ) 5168 .append( 5169 $(_div, { 'class': classes.sScrollHeadInner } ) 5170 .css( { 5171 'box-sizing': 'content-box', 5172 width: scroll.sXInner || '100%' 5173 } ) 5174 .append( 5175 headerClone 5176 .removeAttr('id') 5177 .css( 'margin-left', 0 ) 5178 .append( captionSide === 'top' ? caption : null ) 5179 .append( 5180 table.children('thead') 5181 ) 5182 ) 5183 ) 5184 ) 5185 .append( 5186 $(_div, { 'class': classes.sScrollBody } ) 5187 .css( { 5188 position: 'relative', 5189 overflow: 'auto', 5190 width: size( scrollX ) 5191 } ) 5192 .append( table ) 5193 ); 5194 5195 if ( footer ) { 5196 scroller.append( 5197 $(_div, { 'class': classes.sScrollFoot } ) 5198 .css( { 5199 overflow: 'hidden', 5200 border: 0, 5201 width: scrollX ? size(scrollX) : '100%' 5202 } ) 5203 .append( 5204 $(_div, { 'class': classes.sScrollFootInner } ) 5205 .append( 5206 footerClone 5207 .removeAttr('id') 5208 .css( 'margin-left', 0 ) 5209 .append( captionSide === 'bottom' ? caption : null ) 5210 .append( 5211 table.children('tfoot') 5212 ) 5213 ) 5214 ) 5215 ); 5216 } 5217 5218 var children = scroller.children(); 5219 var scrollHead = children[0]; 5220 var scrollBody = children[1]; 5221 var scrollFoot = footer ? children[2] : null; 5222 5223 // When the body is scrolled, then we also want to scroll the headers 5224 if ( scrollX ) { 5225 $(scrollBody).on( 'scroll.DT', function (e) { 5226 var scrollLeft = this.scrollLeft; 5227 5228 scrollHead.scrollLeft = scrollLeft; 5229 5230 if ( footer ) { 5231 scrollFoot.scrollLeft = scrollLeft; 5232 } 5233 } ); 5234 } 5235 5236 $(scrollBody).css('max-height', scrollY); 5237 if (! scroll.bCollapse) { 5238 $(scrollBody).css('height', scrollY); 5239 } 5240 5241 settings.nScrollHead = scrollHead; 5242 settings.nScrollBody = scrollBody; 5243 settings.nScrollFoot = scrollFoot; 5244 5245 // On redraw - align columns 5246 settings.aoDrawCallback.push( { 5247 "fn": _fnScrollDraw, 5248 "sName": "scrolling" 5249 } ); 5250 5251 return scroller[0]; 5252 } 5253 5254 5255 5256 /** 5257 * Update the header, footer and body tables for resizing - i.e. column 5258 * alignment. 5259 * 5260 * Welcome to the most horrible function DataTables. The process that this 5261 * function follows is basically: 5262 * 1. Re-create the table inside the scrolling div 5263 * 2. Take live measurements from the DOM 5264 * 3. Apply the measurements to align the columns 5265 * 4. Clean up 5266 * 5267 * @param {object} settings dataTables settings object 5268 * @memberof DataTable#oApi 5269 */ 5270 function _fnScrollDraw ( settings ) 5271 { 5272 // Given that this is such a monster function, a lot of variables are use 5273 // to try and keep the minimised size as small as possible 5274 var 5275 scroll = settings.oScroll, 5276 scrollX = scroll.sX, 5277 scrollXInner = scroll.sXInner, 5278 scrollY = scroll.sY, 5279 barWidth = scroll.iBarWidth, 5280 divHeader = $(settings.nScrollHead), 5281 divHeaderStyle = divHeader[0].style, 5282 divHeaderInner = divHeader.children('div'), 5283 divHeaderInnerStyle = divHeaderInner[0].style, 5284 divHeaderTable = divHeaderInner.children('table'), 5285 divBodyEl = settings.nScrollBody, 5286 divBody = $(divBodyEl), 5287 divBodyStyle = divBodyEl.style, 5288 divFooter = $(settings.nScrollFoot), 5289 divFooterInner = divFooter.children('div'), 5290 divFooterTable = divFooterInner.children('table'), 5291 header = $(settings.nTHead), 5292 table = $(settings.nTable), 5293 tableEl = table[0], 5294 tableStyle = tableEl.style, 5295 footer = settings.nTFoot ? $(settings.nTFoot) : null, 5296 browser = settings.oBrowser, 5297 ie67 = browser.bScrollOversize, 5298 dtHeaderCells = _pluck( settings.aoColumns, 'nTh' ), 5299 headerTrgEls, footerTrgEls, 5300 headerSrcEls, footerSrcEls, 5301 headerCopy, footerCopy, 5302 headerWidths=[], footerWidths=[], 5303 headerContent=[], footerContent=[], 5304 idx, correction, sanityWidth, 5305 zeroOut = function(nSizer) { 5306 var style = nSizer.style; 5307 style.paddingTop = "0"; 5308 style.paddingBottom = "0"; 5309 style.borderTopWidth = "0"; 5310 style.borderBottomWidth = "0"; 5311 style.height = 0; 5312 }; 5313 5314 // If the scrollbar visibility has changed from the last draw, we need to 5315 // adjust the column sizes as the table width will have changed to account 5316 // for the scrollbar 5317 var scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight; 5318 5319 if ( settings.scrollBarVis !== scrollBarVis && settings.scrollBarVis !== undefined ) { 5320 settings.scrollBarVis = scrollBarVis; 5321 _fnAdjustColumnSizing( settings ); 5322 return; // adjust column sizing will call this function again 5323 } 5324 else { 5325 settings.scrollBarVis = scrollBarVis; 5326 } 5327 5328 /* 5329 * 1. Re-create the table inside the scrolling div 5330 */ 5331 5332 // Remove the old minimised thead and tfoot elements in the inner table 5333 table.children('thead, tfoot').remove(); 5334 5335 if ( footer ) { 5336 footerCopy = footer.clone().prependTo( table ); 5337 footerTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized 5338 footerSrcEls = footerCopy.find('tr'); 5339 footerCopy.find('[id]').removeAttr('id'); 5340 } 5341 5342 // Clone the current header and footer elements and then place it into the inner table 5343 headerCopy = header.clone().prependTo( table ); 5344 headerTrgEls = header.find('tr'); // original header is in its own table 5345 headerSrcEls = headerCopy.find('tr'); 5346 headerCopy.find('th, td').removeAttr('tabindex'); 5347 headerCopy.find('[id]').removeAttr('id'); 5348 5349 5350 /* 5351 * 2. Take live measurements from the DOM - do not alter the DOM itself! 5352 */ 5353 5354 // Remove old sizing and apply the calculated column widths 5355 // Get the unique column headers in the newly created (cloned) header. We want to apply the 5356 // calculated sizes to this header 5357 if ( ! scrollX ) 5358 { 5359 divBodyStyle.width = '100%'; 5360 divHeader[0].style.width = '100%'; 5361 } 5362 5363 $.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) { 5364 idx = _fnVisibleToColumnIndex( settings, i ); 5365 el.style.width = settings.aoColumns[idx].sWidth; 5366 } ); 5367 5368 if ( footer ) { 5369 _fnApplyToChildren( function(n) { 5370 n.style.width = ""; 5371 }, footerSrcEls ); 5372 } 5373 5374 // Size the table as a whole 5375 sanityWidth = table.outerWidth(); 5376 if ( scrollX === "" ) { 5377 // No x scrolling 5378 tableStyle.width = "100%"; 5379 5380 // IE7 will make the width of the table when 100% include the scrollbar 5381 // - which is shouldn't. When there is a scrollbar we need to take this 5382 // into account. 5383 if ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight || 5384 divBody.css('overflow-y') == "scroll") 5385 ) { 5386 tableStyle.width = _fnStringToCss( table.outerWidth() - barWidth); 5387 } 5388 5389 // Recalculate the sanity width 5390 sanityWidth = table.outerWidth(); 5391 } 5392 else if ( scrollXInner !== "" ) { 5393 // legacy x scroll inner has been given - use it 5394 tableStyle.width = _fnStringToCss(scrollXInner); 5395 5396 // Recalculate the sanity width 5397 sanityWidth = table.outerWidth(); 5398 } 5399 5400 // Hidden header should have zero height, so remove padding and borders. Then 5401 // set the width based on the real headers 5402 5403 // Apply all styles in one pass 5404 _fnApplyToChildren( zeroOut, headerSrcEls ); 5405 5406 // Read all widths in next pass 5407 _fnApplyToChildren( function(nSizer) { 5408 var style = window.getComputedStyle ? 5409 window.getComputedStyle(nSizer).width : 5410 _fnStringToCss( $(nSizer).width() ); 5411 5412 headerContent.push( nSizer.innerHTML ); 5413 headerWidths.push( style ); 5414 }, headerSrcEls ); 5415 5416 // Apply all widths in final pass 5417 _fnApplyToChildren( function(nToSize, i) { 5418 nToSize.style.width = headerWidths[i]; 5419 }, headerTrgEls ); 5420 5421 $(headerSrcEls).css('height', 0); 5422 5423 /* Same again with the footer if we have one */ 5424 if ( footer ) 5425 { 5426 _fnApplyToChildren( zeroOut, footerSrcEls ); 5427 5428 _fnApplyToChildren( function(nSizer) { 5429 footerContent.push( nSizer.innerHTML ); 5430 footerWidths.push( _fnStringToCss( $(nSizer).css('width') ) ); 5431 }, footerSrcEls ); 5432 5433 _fnApplyToChildren( function(nToSize, i) { 5434 nToSize.style.width = footerWidths[i]; 5435 }, footerTrgEls ); 5436 5437 $(footerSrcEls).height(0); 5438 } 5439 5440 5441 /* 5442 * 3. Apply the measurements 5443 */ 5444 5445 // "Hide" the header and footer that we used for the sizing. We need to keep 5446 // the content of the cell so that the width applied to the header and body 5447 // both match, but we want to hide it completely. We want to also fix their 5448 // width to what they currently are 5449 _fnApplyToChildren( function(nSizer, i) { 5450 nSizer.innerHTML = '<div class="dataTables_sizing">'+headerContent[i]+'</div>'; 5451 nSizer.childNodes[0].style.height = "0"; 5452 nSizer.childNodes[0].style.overflow = "hidden"; 5453 nSizer.style.width = headerWidths[i]; 5454 }, headerSrcEls ); 5455 5456 if ( footer ) 5457 { 5458 _fnApplyToChildren( function(nSizer, i) { 5459 nSizer.innerHTML = '<div class="dataTables_sizing">'+footerContent[i]+'</div>'; 5460 nSizer.childNodes[0].style.height = "0"; 5461 nSizer.childNodes[0].style.overflow = "hidden"; 5462 nSizer.style.width = footerWidths[i]; 5463 }, footerSrcEls ); 5464 } 5465 5466 // Sanity check that the table is of a sensible width. If not then we are going to get 5467 // misalignment - try to prevent this by not allowing the table to shrink below its min width 5468 if ( Math.round(table.outerWidth()) < Math.round(sanityWidth) ) 5469 { 5470 // The min width depends upon if we have a vertical scrollbar visible or not */ 5471 correction = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight || 5472 divBody.css('overflow-y') == "scroll")) ? 5473 sanityWidth+barWidth : 5474 sanityWidth; 5475 5476 // IE6/7 are a law unto themselves... 5477 if ( ie67 && (divBodyEl.scrollHeight > 5478 divBodyEl.offsetHeight || divBody.css('overflow-y') == "scroll") 5479 ) { 5480 tableStyle.width = _fnStringToCss( correction-barWidth ); 5481 } 5482 5483 // And give the user a warning that we've stopped the table getting too small 5484 if ( scrollX === "" || scrollXInner !== "" ) { 5485 _fnLog( settings, 1, 'Possible column misalignment', 6 ); 5486 } 5487 } 5488 else 5489 { 5490 correction = '100%'; 5491 } 5492 5493 // Apply to the container elements 5494 divBodyStyle.width = _fnStringToCss( correction ); 5495 divHeaderStyle.width = _fnStringToCss( correction ); 5496 5497 if ( footer ) { 5498 settings.nScrollFoot.style.width = _fnStringToCss( correction ); 5499 } 5500 5501 5502 /* 5503 * 4. Clean up 5504 */ 5505 if ( ! scrollY ) { 5506 /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting 5507 * the scrollbar height from the visible display, rather than adding it on. We need to 5508 * set the height in order to sort this. Don't want to do it in any other browsers. 5509 */ 5510 if ( ie67 ) { 5511 divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth ); 5512 } 5513 } 5514 5515 /* Finally set the width's of the header and footer tables */ 5516 var iOuterWidth = table.outerWidth(); 5517 divHeaderTable[0].style.width = _fnStringToCss( iOuterWidth ); 5518 divHeaderInnerStyle.width = _fnStringToCss( iOuterWidth ); 5519 5520 // Figure out if there are scrollbar present - if so then we need a the header and footer to 5521 // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar) 5522 var bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll"; 5523 var padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' ); 5524 divHeaderInnerStyle[ padding ] = bScrolling ? barWidth+"px" : "0px"; 5525 5526 if ( footer ) { 5527 divFooterTable[0].style.width = _fnStringToCss( iOuterWidth ); 5528 divFooterInner[0].style.width = _fnStringToCss( iOuterWidth ); 5529 divFooterInner[0].style[padding] = bScrolling ? barWidth+"px" : "0px"; 5530 } 5531 5532 // Correct DOM ordering for colgroup - comes before the thead 5533 table.children('colgroup').insertBefore( table.children('thead') ); 5534 5535 /* Adjust the position of the header in case we loose the y-scrollbar */ 5536 divBody.trigger('scroll'); 5537 5538 // If sorting or filtering has occurred, jump the scrolling back to the top 5539 // only if we aren't holding the position 5540 if ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) { 5541 divBodyEl.scrollTop = 0; 5542 } 5543 } 5544 5545 5546 5547 /** 5548 * Apply a given function to the display child nodes of an element array (typically 5549 * TD children of TR rows 5550 * @param {function} fn Method to apply to the objects 5551 * @param array {nodes} an1 List of elements to look through for display children 5552 * @param array {nodes} an2 Another list (identical structure to the first) - optional 5553 * @memberof DataTable#oApi 5554 */ 5555 function _fnApplyToChildren( fn, an1, an2 ) 5556 { 5557 var index=0, i=0, iLen=an1.length; 5558 var nNode1, nNode2; 5559 5560 while ( i < iLen ) { 5561 nNode1 = an1[i].firstChild; 5562 nNode2 = an2 ? an2[i].firstChild : null; 5563 5564 while ( nNode1 ) { 5565 if ( nNode1.nodeType === 1 ) { 5566 if ( an2 ) { 5567 fn( nNode1, nNode2, index ); 5568 } 5569 else { 5570 fn( nNode1, index ); 5571 } 5572 5573 index++; 5574 } 5575 5576 nNode1 = nNode1.nextSibling; 5577 nNode2 = an2 ? nNode2.nextSibling : null; 5578 } 5579 5580 i++; 5581 } 5582 } 5583 5584 5585 5586 var __re_html_remove = /<.*?>/g; 5587 5588 5589 /** 5590 * Calculate the width of columns for the table 5591 * @param {object} oSettings dataTables settings object 5592 * @memberof DataTable#oApi 5593 */ 5594 function _fnCalculateColumnWidths ( oSettings ) 5595 { 5596 var 5597 table = oSettings.nTable, 5598 columns = oSettings.aoColumns, 5599 scroll = oSettings.oScroll, 5600 scrollY = scroll.sY, 5601 scrollX = scroll.sX, 5602 scrollXInner = scroll.sXInner, 5603 columnCount = columns.length, 5604 visibleColumns = _fnGetColumns( oSettings, 'bVisible' ), 5605 headerCells = $('th', oSettings.nTHead), 5606 tableWidthAttr = table.getAttribute('width'), // from DOM element 5607 tableContainer = table.parentNode, 5608 userInputs = false, 5609 i, column, columnIdx, width, outerWidth, 5610 browser = oSettings.oBrowser, 5611 ie67 = browser.bScrollOversize; 5612 5613 var styleWidth = table.style.width; 5614 if ( styleWidth && styleWidth.indexOf('%') !== -1 ) { 5615 tableWidthAttr = styleWidth; 5616 } 5617 5618 /* Convert any user input sizes into pixel sizes */ 5619 for ( i=0 ; i<visibleColumns.length ; i++ ) { 5620 column = columns[ visibleColumns[i] ]; 5621 5622 if ( column.sWidth !== null ) { 5623 column.sWidth = _fnConvertToWidth( column.sWidthOrig, tableContainer ); 5624 5625 userInputs = true; 5626 } 5627 } 5628 5629 /* If the number of columns in the DOM equals the number that we have to 5630 * process in DataTables, then we can use the offsets that are created by 5631 * the web- browser. No custom sizes can be set in order for this to happen, 5632 * nor scrolling used 5633 */ 5634 if ( ie67 || ! userInputs && ! scrollX && ! scrollY && 5635 columnCount == _fnVisbleColumns( oSettings ) && 5636 columnCount == headerCells.length 5637 ) { 5638 for ( i=0 ; i<columnCount ; i++ ) { 5639 var colIdx = _fnVisibleToColumnIndex( oSettings, i ); 5640 5641 if ( colIdx !== null ) { 5642 columns[ colIdx ].sWidth = _fnStringToCss( headerCells.eq(i).width() ); 5643 } 5644 } 5645 } 5646 else 5647 { 5648 // Otherwise construct a single row, worst case, table with the widest 5649 // node in the data, assign any user defined widths, then insert it into 5650 // the DOM and allow the browser to do all the hard work of calculating 5651 // table widths 5652 var tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table 5653 .css( 'visibility', 'hidden' ) 5654 .removeAttr( 'id' ); 5655 5656 // Clean up the table body 5657 tmpTable.find('tbody tr').remove(); 5658 var tr = $('<tr/>').appendTo( tmpTable.find('tbody') ); 5659 5660 // Clone the table header and footer - we can't use the header / footer 5661 // from the cloned table, since if scrolling is active, the table's 5662 // real header and footer are contained in different table tags 5663 tmpTable.find('thead, tfoot').remove(); 5664 tmpTable 5665 .append( $(oSettings.nTHead).clone() ) 5666 .append( $(oSettings.nTFoot).clone() ); 5667 5668 // Remove any assigned widths from the footer (from scrolling) 5669 tmpTable.find('tfoot th, tfoot td').css('width', ''); 5670 5671 // Apply custom sizing to the cloned header 5672 headerCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] ); 5673 5674 for ( i=0 ; i<visibleColumns.length ; i++ ) { 5675 column = columns[ visibleColumns[i] ]; 5676 5677 headerCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ? 5678 _fnStringToCss( column.sWidthOrig ) : 5679 ''; 5680 5681 // For scrollX we need to force the column width otherwise the 5682 // browser will collapse it. If this width is smaller than the 5683 // width the column requires, then it will have no effect 5684 if ( column.sWidthOrig && scrollX ) { 5685 $( headerCells[i] ).append( $('<div/>').css( { 5686 width: column.sWidthOrig, 5687 margin: 0, 5688 padding: 0, 5689 border: 0, 5690 height: 1 5691 } ) ); 5692 } 5693 } 5694 5695 // Find the widest cell for each column and put it into the table 5696 if ( oSettings.aoData.length ) { 5697 for ( i=0 ; i<visibleColumns.length ; i++ ) { 5698 columnIdx = visibleColumns[i]; 5699 column = columns[ columnIdx ]; 5700 5701 $( _fnGetWidestNode( oSettings, columnIdx ) ) 5702 .clone( false ) 5703 .append( column.sContentPadding ) 5704 .appendTo( tr ); 5705 } 5706 } 5707 5708 // Tidy the temporary table - remove name attributes so there aren't 5709 // duplicated in the dom (radio elements for example) 5710 $('[name]', tmpTable).removeAttr('name'); 5711 5712 // Table has been built, attach to the document so we can work with it. 5713 // A holding element is used, positioned at the top of the container 5714 // with minimal height, so it has no effect on if the container scrolls 5715 // or not. Otherwise it might trigger scrolling when it actually isn't 5716 // needed 5717 var holder = $('<div/>').css( scrollX || scrollY ? 5718 { 5719 position: 'absolute', 5720 top: 0, 5721 left: 0, 5722 height: 1, 5723 right: 0, 5724 overflow: 'hidden' 5725 } : 5726 {} 5727 ) 5728 .append( tmpTable ) 5729 .appendTo( tableContainer ); 5730 5731 // When scrolling (X or Y) we want to set the width of the table as 5732 // appropriate. However, when not scrolling leave the table width as it 5733 // is. This results in slightly different, but I think correct behaviour 5734 if ( scrollX && scrollXInner ) { 5735 tmpTable.width( scrollXInner ); 5736 } 5737 else if ( scrollX ) { 5738 tmpTable.css( 'width', 'auto' ); 5739 tmpTable.removeAttr('width'); 5740 5741 // If there is no width attribute or style, then allow the table to 5742 // collapse 5743 if ( tmpTable.width() < tableContainer.clientWidth && tableWidthAttr ) { 5744 tmpTable.width( tableContainer.clientWidth ); 5745 } 5746 } 5747 else if ( scrollY ) { 5748 tmpTable.width( tableContainer.clientWidth ); 5749 } 5750 else if ( tableWidthAttr ) { 5751 tmpTable.width( tableWidthAttr ); 5752 } 5753 5754 // Get the width of each column in the constructed table - we need to 5755 // know the inner width (so it can be assigned to the other table's 5756 // cells) and the outer width so we can calculate the full width of the 5757 // table. This is safe since DataTables requires a unique cell for each 5758 // column, but if ever a header can span multiple columns, this will 5759 // need to be modified. 5760 var total = 0; 5761 for ( i=0 ; i<visibleColumns.length ; i++ ) { 5762 var cell = $(headerCells[i]); 5763 var border = cell.outerWidth() - cell.width(); 5764 5765 // Use getBounding... where possible (not IE8-) because it can give 5766 // sub-pixel accuracy, which we then want to round up! 5767 var bounding = browser.bBounding ? 5768 Math.ceil( headerCells[i].getBoundingClientRect().width ) : 5769 cell.outerWidth(); 5770 5771 // Total is tracked to remove any sub-pixel errors as the outerWidth 5772 // of the table might not equal the total given here (IE!). 5773 total += bounding; 5774 5775 // Width for each column to use 5776 columns[ visibleColumns[i] ].sWidth = _fnStringToCss( bounding - border ); 5777 } 5778 5779 table.style.width = _fnStringToCss( total ); 5780 5781 // Finished with the table - ditch it 5782 holder.remove(); 5783 } 5784 5785 // If there is a width attr, we want to attach an event listener which 5786 // allows the table sizing to automatically adjust when the window is 5787 // resized. Use the width attr rather than CSS, since we can't know if the 5788 // CSS is a relative value or absolute - DOM read is always px. 5789 if ( tableWidthAttr ) { 5790 table.style.width = _fnStringToCss( tableWidthAttr ); 5791 } 5792 5793 if ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) { 5794 var bindResize = function () { 5795 $(window).on('resize.DT-'+oSettings.sInstance, _fnThrottle( function () { 5796 _fnAdjustColumnSizing( oSettings ); 5797 } ) ); 5798 }; 5799 5800 // IE6/7 will crash if we bind a resize event handler on page load. 5801 // To be removed in 1.11 which drops IE6/7 support 5802 if ( ie67 ) { 5803 setTimeout( bindResize, 1000 ); 5804 } 5805 else { 5806 bindResize(); 5807 } 5808 5809 oSettings._reszEvt = true; 5810 } 5811 } 5812 5813 5814 /** 5815 * Throttle the calls to a function. Arguments and context are maintained for 5816 * the throttled function 5817 * @param {function} fn Function to be called 5818 * @param {int} [freq=200] call frequency in mS 5819 * @returns {function} wrapped function 5820 * @memberof DataTable#oApi 5821 */ 5822 var _fnThrottle = DataTable.util.throttle; 5823 5824 5825 /** 5826 * Convert a CSS unit width to pixels (e.g. 2em) 5827 * @param {string} width width to be converted 5828 * @param {node} parent parent to get the with for (required for relative widths) - optional 5829 * @returns {int} width in pixels 5830 * @memberof DataTable#oApi 5831 */ 5832 function _fnConvertToWidth ( width, parent ) 5833 { 5834 if ( ! width ) { 5835 return 0; 5836 } 5837 5838 var n = $('<div/>') 5839 .css( 'width', _fnStringToCss( width ) ) 5840 .appendTo( parent || document.body ); 5841 5842 var val = n[0].offsetWidth; 5843 n.remove(); 5844 5845 return val; 5846 } 5847 5848 5849 /** 5850 * Get the widest node 5851 * @param {object} settings dataTables settings object 5852 * @param {int} colIdx column of interest 5853 * @returns {node} widest table node 5854 * @memberof DataTable#oApi 5855 */ 5856 function _fnGetWidestNode( settings, colIdx ) 5857 { 5858 var idx = _fnGetMaxLenString( settings, colIdx ); 5859 if ( idx < 0 ) { 5860 return null; 5861 } 5862 5863 var data = settings.aoData[ idx ]; 5864 return ! data.nTr ? // Might not have been created when deferred rendering 5865 $('<td/>').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] : 5866 data.anCells[ colIdx ]; 5867 } 5868 5869 5870 /** 5871 * Get the maximum strlen for each data column 5872 * @param {object} settings dataTables settings object 5873 * @param {int} colIdx column of interest 5874 * @returns {string} max string length for each column 5875 * @memberof DataTable#oApi 5876 */ 5877 function _fnGetMaxLenString( settings, colIdx ) 5878 { 5879 var s, max=-1, maxIdx = -1; 5880 5881 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) { 5882 s = _fnGetCellData( settings, i, colIdx, 'display' )+''; 5883 s = s.replace( __re_html_remove, '' ); 5884 s = s.replace( / /g, ' ' ); 5885 5886 if ( s.length > max ) { 5887 max = s.length; 5888 maxIdx = i; 5889 } 5890 } 5891 5892 return maxIdx; 5893 } 5894 5895 5896 /** 5897 * Append a CSS unit (only if required) to a string 5898 * @param {string} value to css-ify 5899 * @returns {string} value with css unit 5900 * @memberof DataTable#oApi 5901 */ 5902 function _fnStringToCss( s ) 5903 { 5904 if ( s === null ) { 5905 return '0px'; 5906 } 5907 5908 if ( typeof s == 'number' ) { 5909 return s < 0 ? 5910 '0px' : 5911 s+'px'; 5912 } 5913 5914 // Check it has a unit character already 5915 return s.match(/\d$/) ? 5916 s+'px' : 5917 s; 5918 } 5919 5920 5921 5922 function _fnSortFlatten ( settings ) 5923 { 5924 var 5925 i, iLen, k, kLen, 5926 aSort = [], 5927 aiOrig = [], 5928 aoColumns = settings.aoColumns, 5929 aDataSort, iCol, sType, srcCol, 5930 fixed = settings.aaSortingFixed, 5931 fixedObj = $.isPlainObject( fixed ), 5932 nestedSort = [], 5933 add = function ( a ) { 5934 if ( a.length && ! Array.isArray( a[0] ) ) { 5935 // 1D array 5936 nestedSort.push( a ); 5937 } 5938 else { 5939 // 2D array 5940 $.merge( nestedSort, a ); 5941 } 5942 }; 5943 5944 // Build the sort array, with pre-fix and post-fix options if they have been 5945 // specified 5946 if ( Array.isArray( fixed ) ) { 5947 add( fixed ); 5948 } 5949 5950 if ( fixedObj && fixed.pre ) { 5951 add( fixed.pre ); 5952 } 5953 5954 add( settings.aaSorting ); 5955 5956 if (fixedObj && fixed.post ) { 5957 add( fixed.post ); 5958 } 5959 5960 for ( i=0 ; i<nestedSort.length ; i++ ) 5961 { 5962 srcCol = nestedSort[i][0]; 5963 aDataSort = aoColumns[ srcCol ].aDataSort; 5964 5965 for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ ) 5966 { 5967 iCol = aDataSort[k]; 5968 sType = aoColumns[ iCol ].sType || 'string'; 5969 5970 if ( nestedSort[i]._idx === undefined ) { 5971 nestedSort[i]._idx = $.inArray( nestedSort[i][1], aoColumns[iCol].asSorting ); 5972 } 5973 5974 aSort.push( { 5975 src: srcCol, 5976 col: iCol, 5977 dir: nestedSort[i][1], 5978 index: nestedSort[i]._idx, 5979 type: sType, 5980 formatter: DataTable.ext.type.order[ sType+"-pre" ] 5981 } ); 5982 } 5983 } 5984 5985 return aSort; 5986 } 5987 5988 /** 5989 * Change the order of the table 5990 * @param {object} oSettings dataTables settings object 5991 * @memberof DataTable#oApi 5992 * @todo This really needs split up! 5993 */ 5994 function _fnSort ( oSettings ) 5995 { 5996 var 5997 i, ien, iLen, j, jLen, k, kLen, 5998 sDataType, nTh, 5999 aiOrig = [], 6000 oExtSort = DataTable.ext.type.order, 6001 aoData = oSettings.aoData, 6002 aoColumns = oSettings.aoColumns, 6003 aDataSort, data, iCol, sType, oSort, 6004 formatters = 0, 6005 sortCol, 6006 displayMaster = oSettings.aiDisplayMaster, 6007 aSort; 6008 6009 // Resolve any column types that are unknown due to addition or invalidation 6010 // @todo Can this be moved into a 'data-ready' handler which is called when 6011 // data is going to be used in the table? 6012 _fnColumnTypes( oSettings ); 6013 6014 aSort = _fnSortFlatten( oSettings ); 6015 6016 for ( i=0, ien=aSort.length ; i<ien ; i++ ) { 6017 sortCol = aSort[i]; 6018 6019 // Track if we can use the fast sort algorithm 6020 if ( sortCol.formatter ) { 6021 formatters++; 6022 } 6023 6024 // Load the data needed for the sort, for each cell 6025 _fnSortData( oSettings, sortCol.col ); 6026 } 6027 6028 /* No sorting required if server-side or no sorting array */ 6029 if ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 ) 6030 { 6031 // Create a value - key array of the current row positions such that we can use their 6032 // current position during the sort, if values match, in order to perform stable sorting 6033 for ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) { 6034 aiOrig[ displayMaster[i] ] = i; 6035 } 6036 6037 /* Do the sort - here we want multi-column sorting based on a given data source (column) 6038 * and sorting function (from oSort) in a certain direction. It's reasonably complex to 6039 * follow on it's own, but this is what we want (example two column sorting): 6040 * fnLocalSorting = function(a,b){ 6041 * var iTest; 6042 * iTest = oSort['string-asc']('data11', 'data12'); 6043 * if (iTest !== 0) 6044 * return iTest; 6045 * iTest = oSort['numeric-desc']('data21', 'data22'); 6046 * if (iTest !== 0) 6047 * return iTest; 6048 * return oSort['numeric-asc']( aiOrig[a], aiOrig[b] ); 6049 * } 6050 * Basically we have a test for each sorting column, if the data in that column is equal, 6051 * test the next column. If all columns match, then we use a numeric sort on the row 6052 * positions in the original data array to provide a stable sort. 6053 * 6054 * Note - I know it seems excessive to have two sorting methods, but the first is around 6055 * 15% faster, so the second is only maintained for backwards compatibility with sorting 6056 * methods which do not have a pre-sort formatting function. 6057 */ 6058 if ( formatters === aSort.length ) { 6059 // All sort types have formatting functions 6060 displayMaster.sort( function ( a, b ) { 6061 var 6062 x, y, k, test, sort, 6063 len=aSort.length, 6064 dataA = aoData[a]._aSortData, 6065 dataB = aoData[b]._aSortData; 6066 6067 for ( k=0 ; k<len ; k++ ) { 6068 sort = aSort[k]; 6069 6070 x = dataA[ sort.col ]; 6071 y = dataB[ sort.col ]; 6072 6073 test = x<y ? -1 : x>y ? 1 : 0; 6074 if ( test !== 0 ) { 6075 return sort.dir === 'asc' ? test : -test; 6076 } 6077 } 6078 6079 x = aiOrig[a]; 6080 y = aiOrig[b]; 6081 return x<y ? -1 : x>y ? 1 : 0; 6082 } ); 6083 } 6084 else { 6085 // Depreciated - remove in 1.11 (providing a plug-in option) 6086 // Not all sort types have formatting methods, so we have to call their sorting 6087 // methods. 6088 displayMaster.sort( function ( a, b ) { 6089 var 6090 x, y, k, l, test, sort, fn, 6091 len=aSort.length, 6092 dataA = aoData[a]._aSortData, 6093 dataB = aoData[b]._aSortData; 6094 6095 for ( k=0 ; k<len ; k++ ) { 6096 sort = aSort[k]; 6097 6098 x = dataA[ sort.col ]; 6099 y = dataB[ sort.col ]; 6100 6101 fn = oExtSort[ sort.type+"-"+sort.dir ] || oExtSort[ "string-"+sort.dir ]; 6102 test = fn( x, y ); 6103 if ( test !== 0 ) { 6104 return test; 6105 } 6106 } 6107 6108 x = aiOrig[a]; 6109 y = aiOrig[b]; 6110 return x<y ? -1 : x>y ? 1 : 0; 6111 } ); 6112 } 6113 } 6114 6115 /* Tell the draw function that we have sorted the data */ 6116 oSettings.bSorted = true; 6117 } 6118 6119 6120 function _fnSortAria ( settings ) 6121 { 6122 var label; 6123 var nextSort; 6124 var columns = settings.aoColumns; 6125 var aSort = _fnSortFlatten( settings ); 6126 var oAria = settings.oLanguage.oAria; 6127 6128 // ARIA attributes - need to loop all columns, to update all (removing old 6129 // attributes as needed) 6130 for ( var i=0, iLen=columns.length ; i<iLen ; i++ ) 6131 { 6132 var col = columns[i]; 6133 var asSorting = col.asSorting; 6134 var sTitle = col.ariaTitle || col.sTitle.replace( /<.*?>/g, "" ); 6135 var th = col.nTh; 6136 6137 // IE7 is throwing an error when setting these properties with jQuery's 6138 // attr() and removeAttr() methods... 6139 th.removeAttribute('aria-sort'); 6140 6141 /* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */ 6142 if ( col.bSortable ) { 6143 if ( aSort.length > 0 && aSort[0].col == i ) { 6144 th.setAttribute('aria-sort', aSort[0].dir=="asc" ? "ascending" : "descending" ); 6145 nextSort = asSorting[ aSort[0].index+1 ] || asSorting[0]; 6146 } 6147 else { 6148 nextSort = asSorting[0]; 6149 } 6150 6151 label = sTitle + ( nextSort === "asc" ? 6152 oAria.sSortAscending : 6153 oAria.sSortDescending 6154 ); 6155 } 6156 else { 6157 label = sTitle; 6158 } 6159 6160 th.setAttribute('aria-label', label); 6161 } 6162 } 6163 6164 6165 /** 6166 * Function to run on user sort request 6167 * @param {object} settings dataTables settings object 6168 * @param {node} attachTo node to attach the handler to 6169 * @param {int} colIdx column sorting index 6170 * @param {boolean} [append=false] Append the requested sort to the existing 6171 * sort if true (i.e. multi-column sort) 6172 * @param {function} [callback] callback function 6173 * @memberof DataTable#oApi 6174 */ 6175 function _fnSortListener ( settings, colIdx, append, callback ) 6176 { 6177 var col = settings.aoColumns[ colIdx ]; 6178 var sorting = settings.aaSorting; 6179 var asSorting = col.asSorting; 6180 var nextSortIdx; 6181 var next = function ( a, overflow ) { 6182 var idx = a._idx; 6183 if ( idx === undefined ) { 6184 idx = $.inArray( a[1], asSorting ); 6185 } 6186 6187 return idx+1 < asSorting.length ? 6188 idx+1 : 6189 overflow ? 6190 null : 6191 0; 6192 }; 6193 6194 // Convert to 2D array if needed 6195 if ( typeof sorting[0] === 'number' ) { 6196 sorting = settings.aaSorting = [ sorting ]; 6197 } 6198 6199 // If appending the sort then we are multi-column sorting 6200 if ( append && settings.oFeatures.bSortMulti ) { 6201 // Are we already doing some kind of sort on this column? 6202 var sortIdx = $.inArray( colIdx, _pluck(sorting, '0') ); 6203 6204 if ( sortIdx !== -1 ) { 6205 // Yes, modify the sort 6206 nextSortIdx = next( sorting[sortIdx], true ); 6207 6208 if ( nextSortIdx === null && sorting.length === 1 ) { 6209 nextSortIdx = 0; // can't remove sorting completely 6210 } 6211 6212 if ( nextSortIdx === null ) { 6213 sorting.splice( sortIdx, 1 ); 6214 } 6215 else { 6216 sorting[sortIdx][1] = asSorting[ nextSortIdx ]; 6217 sorting[sortIdx]._idx = nextSortIdx; 6218 } 6219 } 6220 else { 6221 // No sort on this column yet 6222 sorting.push( [ colIdx, asSorting[0], 0 ] ); 6223 sorting[sorting.length-1]._idx = 0; 6224 } 6225 } 6226 else if ( sorting.length && sorting[0][0] == colIdx ) { 6227 // Single column - already sorting on this column, modify the sort 6228 nextSortIdx = next( sorting[0] ); 6229 6230 sorting.length = 1; 6231 sorting[0][1] = asSorting[ nextSortIdx ]; 6232 sorting[0]._idx = nextSortIdx; 6233 } 6234 else { 6235 // Single column - sort only on this column 6236 sorting.length = 0; 6237 sorting.push( [ colIdx, asSorting[0] ] ); 6238 sorting[0]._idx = 0; 6239 } 6240 6241 // Run the sort by calling a full redraw 6242 _fnReDraw( settings ); 6243 6244 // callback used for async user interaction 6245 if ( typeof callback == 'function' ) { 6246 callback( settings ); 6247 } 6248 } 6249 6250 6251 /** 6252 * Attach a sort handler (click) to a node 6253 * @param {object} settings dataTables settings object 6254 * @param {node} attachTo node to attach the handler to 6255 * @param {int} colIdx column sorting index 6256 * @param {function} [callback] callback function 6257 * @memberof DataTable#oApi 6258 */ 6259 function _fnSortAttachListener ( settings, attachTo, colIdx, callback ) 6260 { 6261 var col = settings.aoColumns[ colIdx ]; 6262 6263 _fnBindAction( attachTo, {}, function (e) { 6264 /* If the column is not sortable - don't to anything */ 6265 if ( col.bSortable === false ) { 6266 return; 6267 } 6268 6269 // If processing is enabled use a timeout to allow the processing 6270 // display to be shown - otherwise to it synchronously 6271 if ( settings.oFeatures.bProcessing ) { 6272 _fnProcessingDisplay( settings, true ); 6273 6274 setTimeout( function() { 6275 _fnSortListener( settings, colIdx, e.shiftKey, callback ); 6276 6277 // In server-side processing, the draw callback will remove the 6278 // processing display 6279 if ( _fnDataSource( settings ) !== 'ssp' ) { 6280 _fnProcessingDisplay( settings, false ); 6281 } 6282 }, 0 ); 6283 } 6284 else { 6285 _fnSortListener( settings, colIdx, e.shiftKey, callback ); 6286 } 6287 } ); 6288 } 6289 6290 6291 /** 6292 * Set the sorting classes on table's body, Note: it is safe to call this function 6293 * when bSort and bSortClasses are false 6294 * @param {object} oSettings dataTables settings object 6295 * @memberof DataTable#oApi 6296 */ 6297 function _fnSortingClasses( settings ) 6298 { 6299 var oldSort = settings.aLastSort; 6300 var sortClass = settings.oClasses.sSortColumn; 6301 var sort = _fnSortFlatten( settings ); 6302 var features = settings.oFeatures; 6303 var i, ien, colIdx; 6304 6305 if ( features.bSort && features.bSortClasses ) { 6306 // Remove old sorting classes 6307 for ( i=0, ien=oldSort.length ; i<ien ; i++ ) { 6308 colIdx = oldSort[i].src; 6309 6310 // Remove column sorting 6311 $( _pluck( settings.aoData, 'anCells', colIdx ) ) 6312 .removeClass( sortClass + (i<2 ? i+1 : 3) ); 6313 } 6314 6315 // Add new column sorting 6316 for ( i=0, ien=sort.length ; i<ien ; i++ ) { 6317 colIdx = sort[i].src; 6318 6319 $( _pluck( settings.aoData, 'anCells', colIdx ) ) 6320 .addClass( sortClass + (i<2 ? i+1 : 3) ); 6321 } 6322 } 6323 6324 settings.aLastSort = sort; 6325 } 6326 6327 6328 // Get the data to sort a column, be it from cache, fresh (populating the 6329 // cache), or from a sort formatter 6330 function _fnSortData( settings, idx ) 6331 { 6332 // Custom sorting function - provided by the sort data type 6333 var column = settings.aoColumns[ idx ]; 6334 var customSort = DataTable.ext.order[ column.sSortDataType ]; 6335 var customData; 6336 6337 if ( customSort ) { 6338 customData = customSort.call( settings.oInstance, settings, idx, 6339 _fnColumnIndexToVisible( settings, idx ) 6340 ); 6341 } 6342 6343 // Use / populate cache 6344 var row, cellData; 6345 var formatter = DataTable.ext.type.order[ column.sType+"-pre" ]; 6346 6347 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) { 6348 row = settings.aoData[i]; 6349 6350 if ( ! row._aSortData ) { 6351 row._aSortData = []; 6352 } 6353 6354 if ( ! row._aSortData[idx] || customSort ) { 6355 cellData = customSort ? 6356 customData[i] : // If there was a custom sort function, use data from there 6357 _fnGetCellData( settings, i, idx, 'sort' ); 6358 6359 row._aSortData[ idx ] = formatter ? 6360 formatter( cellData ) : 6361 cellData; 6362 } 6363 } 6364 } 6365 6366 6367 6368 /** 6369 * Save the state of a table 6370 * @param {object} oSettings dataTables settings object 6371 * @memberof DataTable#oApi 6372 */ 6373 function _fnSaveState ( settings ) 6374 { 6375 if (settings._bLoadingState) { 6376 return; 6377 } 6378 6379 /* Store the interesting variables */ 6380 var state = { 6381 time: +new Date(), 6382 start: settings._iDisplayStart, 6383 length: settings._iDisplayLength, 6384 order: $.extend( true, [], settings.aaSorting ), 6385 search: _fnSearchToCamel( settings.oPreviousSearch ), 6386 columns: $.map( settings.aoColumns, function ( col, i ) { 6387 return { 6388 visible: col.bVisible, 6389 search: _fnSearchToCamel( settings.aoPreSearchCols[i] ) 6390 }; 6391 } ) 6392 }; 6393 6394 settings.oSavedState = state; 6395 _fnCallbackFire( settings, "aoStateSaveParams", 'stateSaveParams', [settings, state] ); 6396 6397 if ( settings.oFeatures.bStateSave && !settings.bDestroying ) 6398 { 6399 settings.fnStateSaveCallback.call( settings.oInstance, settings, state ); 6400 } 6401 } 6402 6403 6404 /** 6405 * Attempt to load a saved table state 6406 * @param {object} oSettings dataTables settings object 6407 * @param {object} oInit DataTables init object so we can override settings 6408 * @param {function} callback Callback to execute when the state has been loaded 6409 * @memberof DataTable#oApi 6410 */ 6411 function _fnLoadState ( settings, oInit, callback ) 6412 { 6413 if ( ! settings.oFeatures.bStateSave ) { 6414 callback(); 6415 return; 6416 } 6417 6418 var loaded = function(state) { 6419 _fnImplementState(settings, state, callback); 6420 } 6421 6422 var state = settings.fnStateLoadCallback.call( settings.oInstance, settings, loaded ); 6423 6424 if ( state !== undefined ) { 6425 _fnImplementState( settings, state, callback ); 6426 } 6427 // otherwise, wait for the loaded callback to be executed 6428 6429 return true; 6430 } 6431 6432 function _fnImplementState ( settings, s, callback) { 6433 var i, ien; 6434 var columns = settings.aoColumns; 6435 settings._bLoadingState = true; 6436 6437 // When StateRestore was introduced the state could now be implemented at any time 6438 // Not just initialisation. To do this an api instance is required in some places 6439 var api = settings._bInitComplete ? new DataTable.Api(settings) : null; 6440 6441 if ( ! s || ! s.time ) { 6442 settings._bLoadingState = false; 6443 callback(); 6444 return; 6445 } 6446 6447 // Allow custom and plug-in manipulation functions to alter the saved data set and 6448 // cancelling of loading by returning false 6449 var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, s] ); 6450 if ( $.inArray( false, abStateLoad ) !== -1 ) { 6451 settings._bLoadingState = false; 6452 callback(); 6453 return; 6454 } 6455 6456 // Reject old data 6457 var duration = settings.iStateDuration; 6458 if ( duration > 0 && s.time < +new Date() - (duration*1000) ) { 6459 settings._bLoadingState = false; 6460 callback(); 6461 return; 6462 } 6463 6464 // Number of columns have changed - all bets are off, no restore of settings 6465 if ( s.columns && columns.length !== s.columns.length ) { 6466 settings._bLoadingState = false; 6467 callback(); 6468 return; 6469 } 6470 6471 // Store the saved state so it might be accessed at any time 6472 settings.oLoadedState = $.extend( true, {}, s ); 6473 6474 // Page Length 6475 if ( s.length !== undefined ) { 6476 // If already initialised just set the value directly so that the select element is also updated 6477 if (api) { 6478 api.page.len(s.length) 6479 } 6480 else { 6481 settings._iDisplayLength = s.length; 6482 } 6483 } 6484 6485 // Restore key features - todo - for 1.11 this needs to be done by 6486 // subscribed events 6487 if ( s.start !== undefined ) { 6488 if(api === null) { 6489 settings._iDisplayStart = s.start; 6490 settings.iInitDisplayStart = s.start; 6491 } 6492 else { 6493 _fnPageChange(settings, s.start/settings._iDisplayLength); 6494 } 6495 } 6496 6497 // Order 6498 if ( s.order !== undefined ) { 6499 settings.aaSorting = []; 6500 $.each( s.order, function ( i, col ) { 6501 settings.aaSorting.push( col[0] >= columns.length ? 6502 [ 0, col[1] ] : 6503 col 6504 ); 6505 } ); 6506 } 6507 6508 // Search 6509 if ( s.search !== undefined ) { 6510 $.extend( settings.oPreviousSearch, _fnSearchToHung( s.search ) ); 6511 } 6512 6513 // Columns 6514 if ( s.columns ) { 6515 for ( i=0, ien=s.columns.length ; i<ien ; i++ ) { 6516 var col = s.columns[i]; 6517 6518 // Visibility 6519 if ( col.visible !== undefined ) { 6520 // If the api is defined, the table has been initialised so we need to use it rather than internal settings 6521 if (api) { 6522 // Don't redraw the columns on every iteration of this loop, we will do this at the end instead 6523 api.column(i).visible(col.visible, false); 6524 } 6525 else { 6526 columns[i].bVisible = col.visible; 6527 } 6528 } 6529 6530 // Search 6531 if ( col.search !== undefined ) { 6532 $.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) ); 6533 } 6534 } 6535 6536 // If the api is defined then we need to adjust the columns once the visibility has been changed 6537 if (api) { 6538 api.columns.adjust(); 6539 } 6540 } 6541 6542 settings._bLoadingState = false; 6543 _fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, s] ); 6544 callback(); 6545 }; 6546 6547 6548 /** 6549 * Return the settings object for a particular table 6550 * @param {node} table table we are using as a dataTable 6551 * @returns {object} Settings object - or null if not found 6552 * @memberof DataTable#oApi 6553 */ 6554 function _fnSettingsFromNode ( table ) 6555 { 6556 var settings = DataTable.settings; 6557 var idx = $.inArray( table, _pluck( settings, 'nTable' ) ); 6558 6559 return idx !== -1 ? 6560 settings[ idx ] : 6561 null; 6562 } 6563 6564 6565 /** 6566 * Log an error message 6567 * @param {object} settings dataTables settings object 6568 * @param {int} level log error messages, or display them to the user 6569 * @param {string} msg error message 6570 * @param {int} tn Technical note id to get more information about the error. 6571 * @memberof DataTable#oApi 6572 */ 6573 function _fnLog( settings, level, msg, tn ) 6574 { 6575 msg = 'DataTables warning: '+ 6576 (settings ? 'table id='+settings.sTableId+' - ' : '')+msg; 6577 6578 if ( tn ) { 6579 msg += '. For more information about this error, please see '+ 6580 'http://datatables.net/tn/'+tn; 6581 } 6582 6583 if ( ! level ) { 6584 // Backwards compatibility pre 1.10 6585 var ext = DataTable.ext; 6586 var type = ext.sErrMode || ext.errMode; 6587 6588 if ( settings ) { 6589 _fnCallbackFire( settings, null, 'error', [ settings, tn, msg ] ); 6590 } 6591 6592 if ( type == 'alert' ) { 6593 alert( msg ); 6594 } 6595 else if ( type == 'throw' ) { 6596 throw new Error(msg); 6597 } 6598 else if ( typeof type == 'function' ) { 6599 type( settings, tn, msg ); 6600 } 6601 } 6602 else if ( window.console && console.log ) { 6603 console.log( msg ); 6604 } 6605 } 6606 6607 6608 /** 6609 * See if a property is defined on one object, if so assign it to the other object 6610 * @param {object} ret target object 6611 * @param {object} src source object 6612 * @param {string} name property 6613 * @param {string} [mappedName] name to map too - optional, name used if not given 6614 * @memberof DataTable#oApi 6615 */ 6616 function _fnMap( ret, src, name, mappedName ) 6617 { 6618 if ( Array.isArray( name ) ) { 6619 $.each( name, function (i, val) { 6620 if ( Array.isArray( val ) ) { 6621 _fnMap( ret, src, val[0], val[1] ); 6622 } 6623 else { 6624 _fnMap( ret, src, val ); 6625 } 6626 } ); 6627 6628 return; 6629 } 6630 6631 if ( mappedName === undefined ) { 6632 mappedName = name; 6633 } 6634 6635 if ( src[name] !== undefined ) { 6636 ret[mappedName] = src[name]; 6637 } 6638 } 6639 6640 6641 /** 6642 * Extend objects - very similar to jQuery.extend, but deep copy objects, and 6643 * shallow copy arrays. The reason we need to do this, is that we don't want to 6644 * deep copy array init values (such as aaSorting) since the dev wouldn't be 6645 * able to override them, but we do want to deep copy arrays. 6646 * @param {object} out Object to extend 6647 * @param {object} extender Object from which the properties will be applied to 6648 * out 6649 * @param {boolean} breakRefs If true, then arrays will be sliced to take an 6650 * independent copy with the exception of the `data` or `aaData` parameters 6651 * if they are present. This is so you can pass in a collection to 6652 * DataTables and have that used as your data source without breaking the 6653 * references 6654 * @returns {object} out Reference, just for convenience - out === the return. 6655 * @memberof DataTable#oApi 6656 * @todo This doesn't take account of arrays inside the deep copied objects. 6657 */ 6658 function _fnExtend( out, extender, breakRefs ) 6659 { 6660 var val; 6661 6662 for ( var prop in extender ) { 6663 if ( extender.hasOwnProperty(prop) ) { 6664 val = extender[prop]; 6665 6666 if ( $.isPlainObject( val ) ) { 6667 if ( ! $.isPlainObject( out[prop] ) ) { 6668 out[prop] = {}; 6669 } 6670 $.extend( true, out[prop], val ); 6671 } 6672 else if ( breakRefs && prop !== 'data' && prop !== 'aaData' && Array.isArray(val) ) { 6673 out[prop] = val.slice(); 6674 } 6675 else { 6676 out[prop] = val; 6677 } 6678 } 6679 } 6680 6681 return out; 6682 } 6683 6684 6685 /** 6686 * Bind an event handers to allow a click or return key to activate the callback. 6687 * This is good for accessibility since a return on the keyboard will have the 6688 * same effect as a click, if the element has focus. 6689 * @param {element} n Element to bind the action to 6690 * @param {object} oData Data object to pass to the triggered function 6691 * @param {function} fn Callback function for when the event is triggered 6692 * @memberof DataTable#oApi 6693 */ 6694 function _fnBindAction( n, oData, fn ) 6695 { 6696 $(n) 6697 .on( 'click.DT', oData, function (e) { 6698 $(n).trigger('blur'); // Remove focus outline for mouse users 6699 fn(e); 6700 } ) 6701 .on( 'keypress.DT', oData, function (e){ 6702 if ( e.which === 13 ) { 6703 e.preventDefault(); 6704 fn(e); 6705 } 6706 } ) 6707 .on( 'selectstart.DT', function () { 6708 /* Take the brutal approach to cancelling text selection */ 6709 return false; 6710 } ); 6711 } 6712 6713 6714 /** 6715 * Register a callback function. Easily allows a callback function to be added to 6716 * an array store of callback functions that can then all be called together. 6717 * @param {object} oSettings dataTables settings object 6718 * @param {string} sStore Name of the array storage for the callbacks in oSettings 6719 * @param {function} fn Function to be called back 6720 * @param {string} sName Identifying name for the callback (i.e. a label) 6721 * @memberof DataTable#oApi 6722 */ 6723 function _fnCallbackReg( oSettings, sStore, fn, sName ) 6724 { 6725 if ( fn ) 6726 { 6727 oSettings[sStore].push( { 6728 "fn": fn, 6729 "sName": sName 6730 } ); 6731 } 6732 } 6733 6734 6735 /** 6736 * Fire callback functions and trigger events. Note that the loop over the 6737 * callback array store is done backwards! Further note that you do not want to 6738 * fire off triggers in time sensitive applications (for example cell creation) 6739 * as its slow. 6740 * @param {object} settings dataTables settings object 6741 * @param {string} callbackArr Name of the array storage for the callbacks in 6742 * oSettings 6743 * @param {string} eventName Name of the jQuery custom event to trigger. If 6744 * null no trigger is fired 6745 * @param {array} args Array of arguments to pass to the callback function / 6746 * trigger 6747 * @memberof DataTable#oApi 6748 */ 6749 function _fnCallbackFire( settings, callbackArr, eventName, args ) 6750 { 6751 var ret = []; 6752 6753 if ( callbackArr ) { 6754 ret = $.map( settings[callbackArr].slice().reverse(), function (val, i) { 6755 return val.fn.apply( settings.oInstance, args ); 6756 } ); 6757 } 6758 6759 if ( eventName !== null ) { 6760 var e = $.Event( eventName+'.dt' ); 6761 6762 $(settings.nTable).trigger( e, args ); 6763 6764 ret.push( e.result ); 6765 } 6766 6767 return ret; 6768 } 6769 6770 6771 function _fnLengthOverflow ( settings ) 6772 { 6773 var 6774 start = settings._iDisplayStart, 6775 end = settings.fnDisplayEnd(), 6776 len = settings._iDisplayLength; 6777 6778 /* If we have space to show extra rows (backing up from the end point - then do so */ 6779 if ( start >= end ) 6780 { 6781 start = end - len; 6782 } 6783 6784 // Keep the start record on the current page 6785 start -= (start % len); 6786 6787 if ( len === -1 || start < 0 ) 6788 { 6789 start = 0; 6790 } 6791 6792 settings._iDisplayStart = start; 6793 } 6794 6795 6796 function _fnRenderer( settings, type ) 6797 { 6798 var renderer = settings.renderer; 6799 var host = DataTable.ext.renderer[type]; 6800 6801 if ( $.isPlainObject( renderer ) && renderer[type] ) { 6802 // Specific renderer for this type. If available use it, otherwise use 6803 // the default. 6804 return host[renderer[type]] || host._; 6805 } 6806 else if ( typeof renderer === 'string' ) { 6807 // Common renderer - if there is one available for this type use it, 6808 // otherwise use the default 6809 return host[renderer] || host._; 6810 } 6811 6812 // Use the default 6813 return host._; 6814 } 6815 6816 6817 /** 6818 * Detect the data source being used for the table. Used to simplify the code 6819 * a little (ajax) and to make it compress a little smaller. 6820 * 6821 * @param {object} settings dataTables settings object 6822 * @returns {string} Data source 6823 * @memberof DataTable#oApi 6824 */ 6825 function _fnDataSource ( settings ) 6826 { 6827 if ( settings.oFeatures.bServerSide ) { 6828 return 'ssp'; 6829 } 6830 else if ( settings.ajax || settings.sAjaxSource ) { 6831 return 'ajax'; 6832 } 6833 return 'dom'; 6834 } 6835 6836 6837 6838 6839 /** 6840 * Computed structure of the DataTables API, defined by the options passed to 6841 * `DataTable.Api.register()` when building the API. 6842 * 6843 * The structure is built in order to speed creation and extension of the Api 6844 * objects since the extensions are effectively pre-parsed. 6845 * 6846 * The array is an array of objects with the following structure, where this 6847 * base array represents the Api prototype base: 6848 * 6849 * [ 6850 * { 6851 * name: 'data' -- string - Property name 6852 * val: function () {}, -- function - Api method (or undefined if just an object 6853 * methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result 6854 * propExt: [ ... ] -- array - Array of Api object definitions to extend the property 6855 * }, 6856 * { 6857 * name: 'row' 6858 * val: {}, 6859 * methodExt: [ ... ], 6860 * propExt: [ 6861 * { 6862 * name: 'data' 6863 * val: function () {}, 6864 * methodExt: [ ... ], 6865 * propExt: [ ... ] 6866 * }, 6867 * ... 6868 * ] 6869 * } 6870 * ] 6871 * 6872 * @type {Array} 6873 * @ignore 6874 */ 6875 var __apiStruct = []; 6876 6877 6878 /** 6879 * `Array.prototype` reference. 6880 * 6881 * @type object 6882 * @ignore 6883 */ 6884 var __arrayProto = Array.prototype; 6885 6886 6887 /** 6888 * Abstraction for `context` parameter of the `Api` constructor to allow it to 6889 * take several different forms for ease of use. 6890 * 6891 * Each of the input parameter types will be converted to a DataTables settings 6892 * object where possible. 6893 * 6894 * @param {string|node|jQuery|object} mixed DataTable identifier. Can be one 6895 * of: 6896 * 6897 * * `string` - jQuery selector. Any DataTables' matching the given selector 6898 * with be found and used. 6899 * * `node` - `TABLE` node which has already been formed into a DataTable. 6900 * * `jQuery` - A jQuery object of `TABLE` nodes. 6901 * * `object` - DataTables settings object 6902 * * `DataTables.Api` - API instance 6903 * @return {array|null} Matching DataTables settings objects. `null` or 6904 * `undefined` is returned if no matching DataTable is found. 6905 * @ignore 6906 */ 6907 var _toSettings = function ( mixed ) 6908 { 6909 var idx, jq; 6910 var settings = DataTable.settings; 6911 var tables = $.map( settings, function (el, i) { 6912 return el.nTable; 6913 } ); 6914 6915 if ( ! mixed ) { 6916 return []; 6917 } 6918 else if ( mixed.nTable && mixed.oApi ) { 6919 // DataTables settings object 6920 return [ mixed ]; 6921 } 6922 else if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) { 6923 // Table node 6924 idx = $.inArray( mixed, tables ); 6925 return idx !== -1 ? [ settings[idx] ] : null; 6926 } 6927 else if ( mixed && typeof mixed.settings === 'function' ) { 6928 return mixed.settings().toArray(); 6929 } 6930 else if ( typeof mixed === 'string' ) { 6931 // jQuery selector 6932 jq = $(mixed); 6933 } 6934 else if ( mixed instanceof $ ) { 6935 // jQuery object (also DataTables instance) 6936 jq = mixed; 6937 } 6938 6939 if ( jq ) { 6940 return jq.map( function(i) { 6941 idx = $.inArray( this, tables ); 6942 return idx !== -1 ? settings[idx] : null; 6943 } ).toArray(); 6944 } 6945 }; 6946 6947 6948 /** 6949 * DataTables API class - used to control and interface with one or more 6950 * DataTables enhanced tables. 6951 * 6952 * The API class is heavily based on jQuery, presenting a chainable interface 6953 * that you can use to interact with tables. Each instance of the API class has 6954 * a "context" - i.e. the tables that it will operate on. This could be a single 6955 * table, all tables on a page or a sub-set thereof. 6956 * 6957 * Additionally the API is designed to allow you to easily work with the data in 6958 * the tables, retrieving and manipulating it as required. This is done by 6959 * presenting the API class as an array like interface. The contents of the 6960 * array depend upon the actions requested by each method (for example 6961 * `rows().nodes()` will return an array of nodes, while `rows().data()` will
6962 * return an array of objects or arrays depending upon your table's 6963 * configuration). The API object has a number of array like methods (`push`, 6964 * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`, 6965 * `unique` etc) to assist your working with the data held in a table. 6966 * 6967 * Most methods (those which return an Api instance) are chainable, which means 6968 * the return from a method call also has all of the methods available that the 6969 * top level object had. For example, these two calls are equivalent: 6970 * 6971 * // Not chained 6972 * api.row.add( {...} ); 6973 * api.draw(); 6974 * 6975 * // Chained 6976 * api.row.add( {...} ).draw(); 6977 * 6978 * @class DataTable.Api 6979 * @param {array|object|string|jQuery} context DataTable identifier. This is 6980 * used to define which DataTables enhanced tables this API will operate on. 6981 * Can be one of: 6982 * 6983 * * `string` - jQuery selector. Any DataTables' matching the given selector 6984 * with be found and used. 6985 * * `node` - `TABLE` node which has already been formed into a DataTable. 6986 * * `jQuery` - A jQuery object of `TABLE` nodes. 6987 * * `object` - DataTables settings object 6988 * @param {array} [data] Data to initialise the Api instance with. 6989 * 6990 * @example 6991 * // Direct initialisation during DataTables construction 6992 * var api = $('#example').DataTable(); 6993 * 6994 * @example 6995 * // Initialisation using a DataTables jQuery object 6996 * var api = $('#example').dataTable().api(); 6997 * 6998 * @example 6999 * // Initialisation as a constructor 7000 * var api = new $.fn.DataTable.Api( 'table.dataTable' ); 7001 */ 7002 _Api = function ( context, data ) 7003 { 7004 if ( ! (this instanceof _Api) ) { 7005 return new _Api( context, data ); 7006 } 7007 7008 var settings = []; 7009 var ctxSettings = function ( o ) { 7010 var a = _toSettings( o ); 7011 if ( a ) { 7012 settings.push.apply( settings, a ); 7013 } 7014 }; 7015 7016 if ( Array.isArray( context ) ) { 7017 for ( var i=0, ien=context.length ; i<ien ; i++ ) { 7018 ctxSettings( context[i] ); 7019 } 7020 } 7021 else { 7022 ctxSettings( context ); 7023 } 7024 7025 // Remove duplicates 7026 this.context = _unique( settings ); 7027 7028 // Initial data 7029 if ( data ) { 7030 $.merge( this, data ); 7031 } 7032 7033 // selector 7034 this.selector = { 7035 rows: null, 7036 cols: null, 7037 opts: null 7038 }; 7039 7040 _Api.extend( this, this, __apiStruct ); 7041 }; 7042 7043 DataTable.Api = _Api; 7044 7045 // Don't destroy the existing prototype, just extend it. Required for jQuery 2's 7046 // isPlainObject. 7047 $.extend( _Api.prototype, { 7048 any: function () 7049 { 7050 return this.count() !== 0; 7051 }, 7052 7053 7054 concat: __arrayProto.concat, 7055 7056 7057 context: [], // array of table settings objects 7058 7059 7060 count: function () 7061 { 7062 return this.flatten().length; 7063 }, 7064 7065 7066 each: function ( fn ) 7067 { 7068 for ( var i=0, ien=this.length ; i<ien; i++ ) { 7069 fn.call( this, this[i], i, this ); 7070 } 7071 7072 return this; 7073 }, 7074 7075 7076 eq: function ( idx ) 7077 { 7078 var ctx = this.context; 7079 7080 return ctx.length > idx ? 7081 new _Api( ctx[idx], this[idx] ) : 7082 null; 7083 }, 7084 7085 7086 filter: function ( fn ) 7087 { 7088 var a = []; 7089 7090 if ( __arrayProto.filter ) { 7091 a = __arrayProto.filter.call( this, fn, this ); 7092 } 7093 else { 7094 // Compatibility for browsers without EMCA-252-5 (JS 1.6) 7095 for ( var i=0, ien=this.length ; i<ien ; i++ ) { 7096 if ( fn.call( this, this[i], i, this ) ) { 7097 a.push( this[i] ); 7098 } 7099 } 7100 } 7101 7102 return new _Api( this.context, a ); 7103 }, 7104 7105 7106 flatten: function () 7107 { 7108 var a = []; 7109 return new _Api( this.context, a.concat.apply( a, this.toArray() ) ); 7110 }, 7111 7112 7113 join: __arrayProto.join, 7114 7115 7116 indexOf: __arrayProto.indexOf || function (obj, start) 7117 { 7118 for ( var i=(start || 0), ien=this.length ; i<ien ; i++ ) { 7119 if ( this[i] === obj ) { 7120 return i; 7121 } 7122 } 7123 return -1; 7124 }, 7125 7126 iterator: function ( flatten, type, fn, alwaysNew ) { 7127 var 7128 a = [], ret, 7129 i, ien, j, jen, 7130 context = this.context, 7131 rows, items, item, 7132 selector = this.selector; 7133 7134 // Argument shifting 7135 if ( typeof flatten === 'string' ) { 7136 alwaysNew = fn; 7137 fn = type; 7138 type = flatten; 7139 flatten = false; 7140 } 7141 7142 for ( i=0, ien=context.length ; i<ien ; i++ ) { 7143 var apiInst = new _Api( context[i] ); 7144 7145 if ( type === 'table' ) { 7146 ret = fn.call( apiInst, context[i], i ); 7147 7148 if ( ret !== undefined ) { 7149 a.push( ret ); 7150 } 7151 } 7152 else if ( type === 'columns' || type === 'rows' ) { 7153 // this has same length as context - one entry for each table 7154 ret = fn.call( apiInst, context[i], this[i], i ); 7155 7156 if ( ret !== undefined ) { 7157 a.push( ret ); 7158 } 7159 } 7160 else if ( type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) { 7161 // columns and rows share the same structure. 7162 // 'this' is an array of column indexes for each context 7163 items = this[i]; 7164 7165 if ( type === 'column-rows' ) { 7166 rows = _selector_row_indexes( context[i], selector.opts ); 7167 } 7168 7169 for ( j=0, jen=items.length ; j<jen ; j++ ) { 7170 item = items[j];
vendor: 73,613 bytes, lines 7171-9856
7171 7172 if ( type === 'cell' ) { 7173 ret = fn.call( apiInst, context[i], item.row, item.column, i, j ); 7174 } 7175 else { 7176 ret = fn.call( apiInst, context[i], item, i, j, rows ); 7177 } 7178 7179 if ( ret !== undefined ) { 7180 a.push( ret ); 7181 } 7182 } 7183 } 7184 } 7185 7186 if ( a.length || alwaysNew ) { 7187 var api = new _Api( context, flatten ? a.concat.apply( [], a ) : a ); 7188 var apiSelector = api.selector; 7189 apiSelector.rows = selector.rows; 7190 apiSelector.cols = selector.cols; 7191 apiSelector.opts = selector.opts; 7192 return api; 7193 } 7194 return this; 7195 }, 7196 7197 7198 lastIndexOf: __arrayProto.lastIndexOf || function (obj, start) 7199 { 7200 // Bit cheeky... 7201 return this.indexOf.apply( this.toArray.reverse(), arguments ); 7202 }, 7203 7204 7205 length: 0, 7206 7207 7208 map: function ( fn ) 7209 { 7210 var a = []; 7211 7212 if ( __arrayProto.map ) { 7213 a = __arrayProto.map.call( this, fn, this ); 7214 } 7215 else { 7216 // Compatibility for browsers without EMCA-252-5 (JS 1.6) 7217 for ( var i=0, ien=this.length ; i<ien ; i++ ) { 7218 a.push( fn.call( this, this[i], i ) ); 7219 } 7220 } 7221 7222 return new _Api( this.context, a ); 7223 }, 7224 7225 7226 pluck: function ( prop ) 7227 { 7228 let fn = DataTable.util.get(prop); 7229 7230 return this.map( function ( el ) { 7231 return fn(el); 7232 } ); 7233 }, 7234 7235 pop: __arrayProto.pop, 7236 7237 7238 push: __arrayProto.push, 7239 7240 7241 // Does not return an API instance 7242 reduce: __arrayProto.reduce || function ( fn, init ) 7243 { 7244 return _fnReduce( this, fn, init, 0, this.length, 1 ); 7245 }, 7246 7247 7248 reduceRight: __arrayProto.reduceRight || function ( fn, init ) 7249 { 7250 return _fnReduce( this, fn, init, this.length-1, -1, -1 ); 7251 }, 7252 7253 7254 reverse: __arrayProto.reverse, 7255 7256 7257 // Object with rows, columns and opts 7258 selector: null, 7259 7260 7261 shift: __arrayProto.shift, 7262 7263 7264 slice: function () { 7265 return new _Api( this.context, this ); 7266 }, 7267 7268 7269 sort: __arrayProto.sort, // ? name - order? 7270 7271 7272 splice: __arrayProto.splice, 7273 7274 7275 toArray: function () 7276 { 7277 return __arrayProto.slice.call( this ); 7278 }, 7279 7280 7281 to$: function () 7282 { 7283 return $( this ); 7284 }, 7285 7286 7287 toJQuery: function () 7288 { 7289 return $( this ); 7290 }, 7291 7292 7293 unique: function () 7294 { 7295 return new _Api( this.context, _unique(this) ); 7296 }, 7297 7298 7299 unshift: __arrayProto.unshift 7300 } ); 7301 7302 7303 _Api.extend = function ( scope, obj, ext ) 7304 { 7305 // Only extend API instances and static properties of the API 7306 if ( ! ext.length || ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) { 7307 return; 7308 } 7309 7310 var 7311 i, ien, 7312 struct, 7313 methodScoping = function ( scope, fn, struc ) { 7314 return function () { 7315 var ret = fn.apply( scope, arguments ); 7316 7317 // Method extension 7318 _Api.extend( ret, ret, struc.methodExt ); 7319 return ret; 7320 }; 7321 }; 7322 7323 for ( i=0, ien=ext.length ; i<ien ; i++ ) { 7324 struct = ext[i]; 7325 7326 // Value 7327 obj[ struct.name ] = struct.type === 'function' ? 7328 methodScoping( scope, struct.val, struct ) : 7329 struct.type === 'object' ? 7330 {} : 7331 struct.val; 7332 7333 obj[ struct.name ].__dt_wrapper = true; 7334 7335 // Property extension 7336 _Api.extend( scope, obj[ struct.name ], struct.propExt ); 7337 } 7338 }; 7339 7340 7341 // @todo - Is there need for an augment function? 7342 // _Api.augment = function ( inst, name ) 7343 // { 7344 // // Find src object in the structure from the name 7345 // var parts = name.split('.'); 7346 7347 // _Api.extend( inst, obj ); 7348 // }; 7349 7350 7351 // [ 7352 // { 7353 // name: 'data' -- string - Property name 7354 // val: function () {}, -- function - Api method (or undefined if just an object 7355 // methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result 7356 // propExt: [ ... ] -- array - Array of Api object definitions to extend the property 7357 // }, 7358 // { 7359 // name: 'row' 7360 // val: {}, 7361 // methodExt: [ ... ], 7362 // propExt: [ 7363 // { 7364 // name: 'data' 7365 // val: function () {}, 7366 // methodExt: [ ... ], 7367 // propExt: [ ... ] 7368 // }, 7369 // ... 7370 // ] 7371 // } 7372 // ] 7373 7374 _Api.register = _api_register = function ( name, val ) 7375 { 7376 if ( Array.isArray( name ) ) { 7377 for ( var j=0, jen=name.length ; j<jen ; j++ ) { 7378 _Api.register( name[j], val ); 7379 } 7380 return; 7381 } 7382 7383 var 7384 i, ien, 7385 heir = name.split('.'), 7386 struct = __apiStruct, 7387 key, method; 7388 7389 var find = function ( src, name ) { 7390 for ( var i=0, ien=src.length ; i<ien ; i++ ) { 7391 if ( src[i].name === name ) { 7392 return src[i]; 7393 } 7394 } 7395 return null; 7396 }; 7397 7398 for ( i=0, ien=heir.length ; i<ien ; i++ ) { 7399 method = heir[i].indexOf('()') !== -1; 7400 key = method ? 7401 heir[i].replace('()', '') : 7402 heir[i]; 7403 7404 var src = find( struct, key ); 7405 if ( ! src ) { 7406 src = { 7407 name: key, 7408 val: {}, 7409 methodExt: [], 7410 propExt: [], 7411 type: 'object' 7412 }; 7413 struct.push( src ); 7414 } 7415 7416 if ( i === ien-1 ) { 7417 src.val = val; 7418 src.type = typeof val === 'function' ? 7419 'function' : 7420 $.isPlainObject( val ) ? 7421 'object' : 7422 'other'; 7423 } 7424 else { 7425 struct = method ? 7426 src.methodExt : 7427 src.propExt; 7428 } 7429 } 7430 }; 7431 7432 _Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) { 7433 _Api.register( pluralName, val ); 7434 7435 _Api.register( singularName, function () { 7436 var ret = val.apply( this, arguments ); 7437 7438 if ( ret === this ) { 7439 // Returned item is the API instance that was passed in, return it 7440 return this; 7441 } 7442 else if ( ret instanceof _Api ) { 7443 // New API instance returned, want the value from the first item 7444 // in the returned array for the singular result. 7445 return ret.length ? 7446 Array.isArray( ret[0] ) ? 7447 new _Api( ret.context, ret[0] ) : // Array results are 'enhanced' 7448 ret[0] : 7449 undefined; 7450 } 7451 7452 // Non-API return - just fire it back 7453 return ret; 7454 } ); 7455 }; 7456 7457 7458 /** 7459 * Selector for HTML tables. Apply the given selector to the give array of 7460 * DataTables settings objects. 7461 * 7462 * @param {string|integer} [selector] jQuery selector string or integer 7463 * @param {array} Array of DataTables settings objects to be filtered 7464 * @return {array} 7465 * @ignore 7466 */ 7467 var __table_selector = function ( selector, a ) 7468 { 7469 if ( Array.isArray(selector) ) { 7470 return $.map( selector, function (item) { 7471 return __table_selector(item, a); 7472 } ); 7473 } 7474 7475 // Integer is used to pick out a table by index 7476 if ( typeof selector === 'number' ) { 7477 return [ a[ selector ] ]; 7478 } 7479 7480 // Perform a jQuery selector on the table nodes 7481 var nodes = $.map( a, function (el, i) { 7482 return el.nTable; 7483 } ); 7484 7485 return $(nodes) 7486 .filter( selector ) 7487 .map( function (i) { 7488 // Need to translate back from the table node to the settings 7489 var idx = $.inArray( this, nodes ); 7490 return a[ idx ]; 7491 } ) 7492 .toArray(); 7493 }; 7494 7495 7496 7497 /** 7498 * Context selector for the API's context (i.e. the tables the API instance 7499 * refers to. 7500 * 7501 * @name DataTable.Api#tables 7502 * @param {string|integer} [selector] Selector to pick which tables the iterator 7503 * should operate on. If not given, all tables in the current context are 7504 * used. This can be given as a jQuery selector (for example `':gt(0)'`) to 7505 * select multiple tables or as an integer to select a single table. 7506 * @returns {DataTable.Api} Returns a new API instance if a selector is given. 7507 */ 7508 _api_register( 'tables()', function ( selector ) { 7509 // A new instance is created if there was a selector specified 7510 return selector !== undefined && selector !== null ? 7511 new _Api( __table_selector( selector, this.context ) ) : 7512 this; 7513 } ); 7514 7515 7516 _api_register( 'table()', function ( selector ) { 7517 var tables = this.tables( selector ); 7518 var ctx = tables.context; 7519 7520 // Truncate to the first matched table 7521 return ctx.length ? 7522 new _Api( ctx[0] ) : 7523 tables; 7524 } ); 7525 7526 7527 _api_registerPlural( 'tables().nodes()', 'table().node()' , function () { 7528 return this.iterator( 'table', function ( ctx ) { 7529 return ctx.nTable; 7530 }, 1 ); 7531 } ); 7532 7533 7534 _api_registerPlural( 'tables().body()', 'table().body()' , function () { 7535 return this.iterator( 'table', function ( ctx ) { 7536 return ctx.nTBody; 7537 }, 1 ); 7538 } ); 7539 7540 7541 _api_registerPlural( 'tables().header()', 'table().header()' , function () { 7542 return this.iterator( 'table', function ( ctx ) { 7543 return ctx.nTHead; 7544 }, 1 ); 7545 } ); 7546 7547 7548 _api_registerPlural( 'tables().footer()', 'table().footer()' , function () { 7549 return this.iterator( 'table', function ( ctx ) { 7550 return ctx.nTFoot; 7551 }, 1 ); 7552 } ); 7553 7554 7555 _api_registerPlural( 'tables().containers()', 'table().container()' , function () { 7556 return this.iterator( 'table', function ( ctx ) { 7557 return ctx.nTableWrapper; 7558 }, 1 ); 7559 } ); 7560 7561 7562 7563 /** 7564 * Redraw the tables in the current context. 7565 */ 7566 _api_register( 'draw()', function ( paging ) { 7567 return this.iterator( 'table', function ( settings ) { 7568 if ( paging === 'page' ) { 7569 _fnDraw( settings ); 7570 } 7571 else { 7572 if ( typeof paging === 'string' ) { 7573 paging = paging === 'full-hold' ? 7574 false : 7575 true; 7576 } 7577 7578 _fnReDraw( settings, paging===false ); 7579 } 7580 } ); 7581 } ); 7582 7583 7584 7585 /** 7586 * Get the current page index. 7587 * 7588 * @return {integer} Current page index (zero based) 7589 *//** 7590 * Set the current page. 7591 * 7592 * Note that if you attempt to show a page which does not exist, DataTables will 7593 * not throw an error, but rather reset the paging. 7594 * 7595 * @param {integer|string} action The paging action to take. This can be one of: 7596 * * `integer` - The page index to jump to 7597 * * `string` - An action to take: 7598 * * `first` - Jump to first page. 7599 * * `next` - Jump to the next page 7600 * * `previous` - Jump to previous page 7601 * * `last` - Jump to the last page. 7602 * @returns {DataTables.Api} this 7603 */ 7604 _api_register( 'page()', function ( action ) { 7605 if ( action === undefined ) { 7606 return this.page.info().page; // not an expensive call 7607 } 7608 7609 // else, have an action to take on all tables 7610 return this.iterator( 'table', function ( settings ) { 7611 _fnPageChange( settings, action ); 7612 } ); 7613 } ); 7614 7615 7616 /** 7617 * Paging information for the first table in the current context. 7618 * 7619 * If you require paging information for another table, use the `table()` method 7620 * with a suitable selector. 7621 * 7622 * @return {object} Object with the following properties set: 7623 * * `page` - Current page index (zero based - i.e. the first page is `0`) 7624 * * `pages` - Total number of pages 7625 * * `start` - Display index for the first record shown on the current page 7626 * * `end` - Display index for the last record shown on the current page 7627 * * `length` - Display length (number of records). Note that generally `start 7628 * + length = end`, but this is not always true, for example if there are 7629 * only 2 records to show on the final page, with a length of 10. 7630 * * `recordsTotal` - Full data set length 7631 * * `recordsDisplay` - Data set length once the current filtering criterion 7632 * are applied. 7633 */ 7634 _api_register( 'page.info()', function ( action ) { 7635 if ( this.context.length === 0 ) { 7636 return undefined; 7637 } 7638 7639 var 7640 settings = this.context[0], 7641 start = settings._iDisplayStart, 7642 len = settings.oFeatures.bPaginate ? settings._iDisplayLength : -1, 7643 visRecords = settings.fnRecordsDisplay(), 7644 all = len === -1; 7645 7646 return { 7647 "page": all ? 0 : Math.floor( start / len ), 7648 "pages": all ? 1 : Math.ceil( visRecords / len ), 7649 "start": start, 7650 "end": settings.fnDisplayEnd(), 7651 "length": len, 7652 "recordsTotal": settings.fnRecordsTotal(), 7653 "recordsDisplay": visRecords, 7654 "serverSide": _fnDataSource( settings ) === 'ssp' 7655 }; 7656 } ); 7657 7658 7659 /** 7660 * Get the current page length. 7661 * 7662 * @return {integer} Current page length. Note `-1` indicates that all records 7663 * are to be shown. 7664 *//** 7665 * Set the current page length. 7666 * 7667 * @param {integer} Page length to set. Use `-1` to show all records. 7668 * @returns {DataTables.Api} this 7669 */ 7670 _api_register( 'page.len()', function ( len ) { 7671 // Note that we can't call this function 'length()' because `length` 7672 // is a Javascript property of functions which defines how many arguments 7673 // the function expects. 7674 if ( len === undefined ) { 7675 return this.context.length !== 0 ? 7676 this.context[0]._iDisplayLength : 7677 undefined; 7678 } 7679 7680 // else, set the page length 7681 return this.iterator( 'table', function ( settings ) { 7682 _fnLengthChange( settings, len ); 7683 } ); 7684 } ); 7685 7686 7687 7688 var __reload = function ( settings, holdPosition, callback ) { 7689 // Use the draw event to trigger a callback 7690 if ( callback ) { 7691 var api = new _Api( settings ); 7692 7693 api.one( 'draw', function () { 7694 callback( api.ajax.json() ); 7695 } ); 7696 } 7697 7698 if ( _fnDataSource( settings ) == 'ssp' ) { 7699 _fnReDraw( settings, holdPosition ); 7700 } 7701 else { 7702 _fnProcessingDisplay( settings, true ); 7703 7704 // Cancel an existing request 7705 var xhr = settings.jqXHR; 7706 if ( xhr && xhr.readyState !== 4 ) { 7707 xhr.abort(); 7708 } 7709 7710 // Trigger xhr 7711 _fnBuildAjax( settings, [], function( json ) { 7712 _fnClearTable( settings ); 7713 7714 var data = _fnAjaxDataSrc( settings, json ); 7715 for ( var i=0, ien=data.length ; i<ien ; i++ ) { 7716 _fnAddData( settings, data[i] ); 7717 } 7718 7719 _fnReDraw( settings, holdPosition ); 7720 _fnProcessingDisplay( settings, false ); 7721 } ); 7722 } 7723 }; 7724 7725 7726 /** 7727 * Get the JSON response from the last Ajax request that DataTables made to the 7728 * server. Note that this returns the JSON from the first table in the current 7729 * context. 7730 * 7731 * @return {object} JSON received from the server. 7732 */ 7733 _api_register( 'ajax.json()', function () { 7734 var ctx = this.context; 7735 7736 if ( ctx.length > 0 ) { 7737 return ctx[0].json; 7738 } 7739 7740 // else return undefined; 7741 } ); 7742 7743 7744 /** 7745 * Get the data submitted in the last Ajax request 7746 */ 7747 _api_register( 'ajax.params()', function () { 7748 var ctx = this.context; 7749 7750 if ( ctx.length > 0 ) { 7751 return ctx[0].oAjaxData; 7752 } 7753 7754 // else return undefined; 7755 } ); 7756 7757 7758 /** 7759 * Reload tables from the Ajax data source. Note that this function will 7760 * automatically re-draw the table when the remote data has been loaded. 7761 * 7762 * @param {boolean} [reset=true] Reset (default) or hold the current paging 7763 * position. A full re-sort and re-filter is performed when this method is 7764 * called, which is why the pagination reset is the default action. 7765 * @returns {DataTables.Api} this 7766 */ 7767 _api_register( 'ajax.reload()', function ( callback, resetPaging ) { 7768 return this.iterator( 'table', function (settings) { 7769 __reload( settings, resetPaging===false, callback ); 7770 } ); 7771 } ); 7772 7773 7774 /** 7775 * Get the current Ajax URL. Note that this returns the URL from the first 7776 * table in the current context. 7777 * 7778 * @return {string} Current Ajax source URL 7779 *//** 7780 * Set the Ajax URL. Note that this will set the URL for all tables in the 7781 * current context. 7782 * 7783 * @param {string} url URL to set. 7784 * @returns {DataTables.Api} this 7785 */ 7786 _api_register( 'ajax.url()', function ( url ) { 7787 var ctx = this.context; 7788 7789 if ( url === undefined ) { 7790 // get 7791 if ( ctx.length === 0 ) { 7792 return undefined; 7793 } 7794 ctx = ctx[0]; 7795 7796 return ctx.ajax ? 7797 $.isPlainObject( ctx.ajax ) ? 7798 ctx.ajax.url : 7799 ctx.ajax : 7800 ctx.sAjaxSource; 7801 } 7802 7803 // set 7804 return this.iterator( 'table', function ( settings ) { 7805 if ( $.isPlainObject( settings.ajax ) ) { 7806 settings.ajax.url = url; 7807 } 7808 else { 7809 settings.ajax = url; 7810 } 7811 // No need to consider sAjaxSource here since DataTables gives priority 7812 // to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any 7813 // value of `sAjaxSource` redundant. 7814 } ); 7815 } ); 7816 7817 7818 /** 7819 * Load data from the newly set Ajax URL. Note that this method is only 7820 * available when `ajax.url()` is used to set a URL. Additionally, this method 7821 * has the same effect as calling `ajax.reload()` but is provided for 7822 * convenience when setting a new URL. Like `ajax.reload()` it will 7823 * automatically redraw the table once the remote data has been loaded. 7824 * 7825 * @returns {DataTables.Api} this 7826 */ 7827 _api_register( 'ajax.url().load()', function ( callback, resetPaging ) { 7828 // Same as a reload, but makes sense to present it for easy access after a 7829 // url change 7830 return this.iterator( 'table', function ( ctx ) { 7831 __reload( ctx, resetPaging===false, callback ); 7832 } ); 7833 } ); 7834 7835 7836 7837 7838 var _selector_run = function ( type, selector, selectFn, settings, opts ) 7839 { 7840 var 7841 out = [], res, 7842 a, i, ien, j, jen, 7843 selectorType = typeof selector; 7844 7845 // Can't just check for isArray here, as an API or jQuery instance might be 7846 // given with their array like look 7847 if ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) { 7848 selector = [ selector ]; 7849 } 7850 7851 for ( i=0, ien=selector.length ; i<ien ; i++ ) { 7852 // Only split on simple strings - complex expressions will be jQuery selectors 7853 a = selector[i] && selector[i].split && ! selector[i].match(/[\[\(:]/) ? 7854 selector[i].split(',') : 7855 [ selector[i] ]; 7856 7857 for ( j=0, jen=a.length ; j<jen ; j++ ) { 7858 res = selectFn( typeof a[j] === 'string' ? (a[j]).trim() : a[j] ); 7859 7860 if ( res && res.length ) { 7861 out = out.concat( res ); 7862 } 7863 } 7864 } 7865 7866 // selector extensions 7867 var ext = _ext.selector[ type ]; 7868 if ( ext.length ) { 7869 for ( i=0, ien=ext.length ; i<ien ; i++ ) { 7870 out = ext[i]( settings, opts, out ); 7871 } 7872 } 7873 7874 return _unique( out ); 7875 }; 7876 7877 7878 var _selector_opts = function ( opts ) 7879 { 7880 if ( ! opts ) { 7881 opts = {}; 7882 } 7883 7884 // Backwards compatibility for 1.9- which used the terminology filter rather 7885 // than search 7886 if ( opts.filter && opts.search === undefined ) { 7887 opts.search = opts.filter; 7888 } 7889 7890 return $.extend( { 7891 search: 'none', 7892 order: 'current', 7893 page: 'all' 7894 }, opts ); 7895 }; 7896 7897 7898 var _selector_first = function ( inst ) 7899 { 7900 // Reduce the API instance to the first item found 7901 for ( var i=0, ien=inst.length ; i<ien ; i++ ) { 7902 if ( inst[i].length > 0 ) { 7903 // Assign the first element to the first item in the instance 7904 // and truncate the instance and context 7905 inst[0] = inst[i]; 7906 inst[0].length = 1; 7907 inst.length = 1; 7908 inst.context = [ inst.context[i] ]; 7909 7910 return inst; 7911 } 7912 } 7913 7914 // Not found - return an empty instance 7915 inst.length = 0; 7916 return inst; 7917 }; 7918 7919 7920 var _selector_row_indexes = function ( settings, opts ) 7921 { 7922 var 7923 i, ien, tmp, a=[], 7924 displayFiltered = settings.aiDisplay, 7925 displayMaster = settings.aiDisplayMaster; 7926 7927 var 7928 search = opts.search, // none, applied, removed 7929 order = opts.order, // applied, current, index (original - compatibility with 1.9) 7930 page = opts.page; // all, current 7931 7932 if ( _fnDataSource( settings ) == 'ssp' ) { 7933 // In server-side processing mode, most options are irrelevant since 7934 // rows not shown don't exist and the index order is the applied order 7935 // Removed is a special case - for consistency just return an empty 7936 // array 7937 return search === 'removed' ? 7938 [] : 7939 _range( 0, displayMaster.length ); 7940 } 7941 else if ( page == 'current' ) { 7942 // Current page implies that order=current and filter=applied, since it is 7943 // fairly senseless otherwise, regardless of what order and search actually 7944 // are 7945 for ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) { 7946 a.push( displayFiltered[i] ); 7947 } 7948 } 7949 else if ( order == 'current' || order == 'applied' ) { 7950 if ( search == 'none') { 7951 a = displayMaster.slice(); 7952 } 7953 else if ( search == 'applied' ) { 7954 a = displayFiltered.slice(); 7955 } 7956 else if ( search == 'removed' ) { 7957 // O(n+m) solution by creating a hash map 7958 var displayFilteredMap = {}; 7959 7960 for ( var i=0, ien=displayFiltered.length ; i<ien ; i++ ) { 7961 displayFilteredMap[displayFiltered[i]] = null; 7962 } 7963 7964 a = $.map( displayMaster, function (el) { 7965 return ! displayFilteredMap.hasOwnProperty(el) ? 7966 el : 7967 null; 7968 } ); 7969 } 7970 } 7971 else if ( order == 'index' || order == 'original' ) { 7972 for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) { 7973 if ( search == 'none' ) { 7974 a.push( i ); 7975 } 7976 else { // applied | removed 7977 tmp = $.inArray( i, displayFiltered ); 7978 7979 if ((tmp === -1 && search == 'removed') || 7980 (tmp >= 0 && search == 'applied') ) 7981 { 7982 a.push( i ); 7983 } 7984 } 7985 } 7986 } 7987 7988 return a; 7989 }; 7990 7991 7992 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 7993 * Rows 7994 * 7995 * {} - no selector - use all available rows 7996 * {integer} - row aoData index 7997 * {node} - TR node 7998 * {string} - jQuery selector to apply to the TR elements 7999 * {array} - jQuery array of nodes, or simply an array of TR nodes 8000 * 8001 */ 8002 var __row_selector = function ( settings, selector, opts ) 8003 { 8004 var rows; 8005 var run = function ( sel ) { 8006 var selInt = _intVal( sel ); 8007 var i, ien; 8008 var aoData = settings.aoData; 8009 8010 // Short cut - selector is a number and no options provided (default is 8011 // all records, so no need to check if the index is in there, since it 8012 // must be - dev error if the index doesn't exist). 8013 if ( selInt !== null && ! opts ) { 8014 return [ selInt ]; 8015 } 8016 8017 if ( ! rows ) { 8018 rows = _selector_row_indexes( settings, opts ); 8019 } 8020 8021 if ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) { 8022 // Selector - integer 8023 return [ selInt ]; 8024 } 8025 else if ( sel === null || sel === undefined || sel === '' ) { 8026 // Selector - none 8027 return rows; 8028 } 8029 8030 // Selector - function 8031 if ( typeof sel === 'function' ) { 8032 return $.map( rows, function (idx) { 8033 var row = aoData[ idx ]; 8034 return sel( idx, row._aData, row.nTr ) ? idx : null; 8035 } ); 8036 } 8037 8038 // Selector - node 8039 if ( sel.nodeName ) { 8040 var rowIdx = sel._DT_RowIndex; // Property added by DT for fast lookup 8041 var cellIdx = sel._DT_CellIndex; 8042 8043 if ( rowIdx !== undefined ) { 8044 // Make sure that the row is actually still present in the table 8045 return aoData[ rowIdx ] && aoData[ rowIdx ].nTr === sel ? 8046 [ rowIdx ] : 8047 []; 8048 } 8049 else if ( cellIdx ) { 8050 return aoData[ cellIdx.row ] && aoData[ cellIdx.row ].nTr === sel.parentNode ? 8051 [ cellIdx.row ] : 8052 []; 8053 } 8054 else { 8055 var host = $(sel).closest('*[data-dt-row]'); 8056 return host.length ? 8057 [ host.data('dt-row') ] : 8058 []; 8059 } 8060 } 8061 8062 // ID selector. Want to always be able to select rows by id, regardless 8063 // of if the tr element has been created or not, so can't rely upon 8064 // jQuery here - hence a custom implementation. This does not match 8065 // Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything, 8066 // but to select it using a CSS selector engine (like Sizzle or 8067 // querySelect) it would need to need to be escaped for some characters. 8068 // DataTables simplifies this for row selectors since you can select 8069 // only a row. A # indicates an id any anything that follows is the id - 8070 // unescaped. 8071 if ( typeof sel === 'string' && sel.charAt(0) === '#' ) { 8072 // get row index from id 8073 var rowObj = settings.aIds[ sel.replace( /^#/, '' ) ]; 8074 if ( rowObj !== undefined ) { 8075 return [ rowObj.idx ]; 8076 } 8077 8078 // need to fall through to jQuery in case there is DOM id that 8079 // matches 8080 } 8081 8082 // Get nodes in the order from the `rows` array with null values removed 8083 var nodes = _removeEmpty( 8084 _pluck_order( settings.aoData, rows, 'nTr' ) 8085 ); 8086 8087 // Selector - jQuery selector string, array of nodes or jQuery object/ 8088 // As jQuery's .filter() allows jQuery objects to be passed in filter, 8089 // it also allows arrays, so this will cope with all three options 8090 return $(nodes) 8091 .filter( sel ) 8092 .map( function () { 8093 return this._DT_RowIndex; 8094 } ) 8095 .toArray(); 8096 }; 8097 8098 return _selector_run( 'row', selector, run, settings, opts ); 8099 }; 8100 8101 8102 _api_register( 'rows()', function ( selector, opts ) { 8103 // argument shifting 8104 if ( selector === undefined ) { 8105 selector = ''; 8106 } 8107 else if ( $.isPlainObject( selector ) ) { 8108 opts = selector; 8109 selector = ''; 8110 } 8111 8112 opts = _selector_opts( opts ); 8113 8114 var inst = this.iterator( 'table', function ( settings ) { 8115 return __row_selector( settings, selector, opts ); 8116 }, 1 ); 8117 8118 // Want argument shifting here and in __row_selector? 8119 inst.selector.rows = selector; 8120 inst.selector.opts = opts; 8121 8122 return inst; 8123 } ); 8124 8125 _api_register( 'rows().nodes()', function () { 8126 return this.iterator( 'row', function ( settings, row ) { 8127 return settings.aoData[ row ].nTr || undefined; 8128 }, 1 ); 8129 } ); 8130 8131 _api_register( 'rows().data()', function () { 8132 return this.iterator( true, 'rows', function ( settings, rows ) { 8133 return _pluck_order( settings.aoData, rows, '_aData' ); 8134 }, 1 ); 8135 } ); 8136 8137 _api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) { 8138 return this.iterator( 'row', function ( settings, row ) { 8139 var r = settings.aoData[ row ]; 8140 return type === 'search' ? r._aFilterData : r._aSortData; 8141 }, 1 ); 8142 } ); 8143 8144 _api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) { 8145 return this.iterator( 'row', function ( settings, row ) { 8146 _fnInvalidate( settings, row, src ); 8147 } ); 8148 } ); 8149 8150 _api_registerPlural( 'rows().indexes()', 'row().index()', function () { 8151 return this.iterator( 'row', function ( settings, row ) { 8152 return row; 8153 }, 1 ); 8154 } ); 8155 8156 _api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) { 8157 var a = []; 8158 var context = this.context; 8159 8160 // `iterator` will drop undefined values, but in this case we want them 8161 for ( var i=0, ien=context.length ; i<ien ; i++ ) { 8162 for ( var j=0, jen=this[i].length ; j<jen ; j++ ) { 8163 var id = context[i].rowIdFn( context[i].aoData[ this[i][j] ]._aData ); 8164 a.push( (hash === true ? '#' : '' )+ id ); 8165 } 8166 } 8167 8168 return new _Api( context, a ); 8169 } ); 8170 8171 _api_registerPlural( 'rows().remove()', 'row().remove()', function () { 8172 var that = this; 8173 8174 this.iterator( 'row', function ( settings, row, thatIdx ) { 8175 var data = settings.aoData; 8176 var rowData = data[ row ]; 8177 var i, ien, j, jen; 8178 var loopRow, loopCells; 8179 8180 data.splice( row, 1 ); 8181 8182 // Update the cached indexes 8183 for ( i=0, ien=data.length ; i<ien ; i++ ) { 8184 loopRow = data[i]; 8185 loopCells = loopRow.anCells; 8186 8187 // Rows 8188 if ( loopRow.nTr !== null ) { 8189 loopRow.nTr._DT_RowIndex = i; 8190 } 8191 8192 // Cells 8193 if ( loopCells !== null ) { 8194 for ( j=0, jen=loopCells.length ; j<jen ; j++ ) { 8195 loopCells[j]._DT_CellIndex.row = i; 8196 } 8197 } 8198 } 8199 8200 // Delete from the display arrays 8201 _fnDeleteIndex( settings.aiDisplayMaster, row ); 8202 _fnDeleteIndex( settings.aiDisplay, row ); 8203 _fnDeleteIndex( that[ thatIdx ], row, false ); // maintain local indexes 8204 8205 // For server-side processing tables - subtract the deleted row from the count 8206 if ( settings._iRecordsDisplay > 0 ) { 8207 settings._iRecordsDisplay--; 8208 } 8209 8210 // Check for an 'overflow' they case for displaying the table 8211 _fnLengthOverflow( settings ); 8212 8213 // Remove the row's ID reference if there is one 8214 var id = settings.rowIdFn( rowData._aData ); 8215 if ( id !== undefined ) { 8216 delete settings.aIds[ id ]; 8217 } 8218 } ); 8219 8220 this.iterator( 'table', function ( settings ) { 8221 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) { 8222 settings.aoData[i].idx = i; 8223 } 8224 } ); 8225 8226 return this; 8227 } ); 8228 8229 8230 _api_register( 'rows.add()', function ( rows ) { 8231 var newRows = this.iterator( 'table', function ( settings ) { 8232 var row, i, ien; 8233 var out = []; 8234 8235 for ( i=0, ien=rows.length ; i<ien ; i++ ) { 8236 row = rows[i]; 8237 8238 if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) { 8239 out.push( _fnAddTr( settings, row )[0] ); 8240 } 8241 else { 8242 out.push( _fnAddData( settings, row ) ); 8243 } 8244 } 8245 8246 return out; 8247 }, 1 ); 8248 8249 // Return an Api.rows() extended instance, so rows().nodes() etc can be used 8250 var modRows = this.rows( -1 ); 8251 modRows.pop(); 8252 $.merge( modRows, newRows ); 8253 8254 return modRows; 8255 } ); 8256 8257 8258 8259 8260 8261 /** 8262 * 8263 */ 8264 _api_register( 'row()', function ( selector, opts ) { 8265 return _selector_first( this.rows( selector, opts ) ); 8266 } ); 8267 8268 8269 _api_register( 'row().data()', function ( data ) { 8270 var ctx = this.context; 8271 8272 if ( data === undefined ) { 8273 // Get 8274 return ctx.length && this.length ? 8275 ctx[0].aoData[ this[0] ]._aData : 8276 undefined; 8277 } 8278 8279 // Set 8280 var row = ctx[0].aoData[ this[0] ]; 8281 row._aData = data; 8282 8283 // If the DOM has an id, and the data source is an array 8284 if ( Array.isArray( data ) && row.nTr && row.nTr.id ) { 8285 _fnSetObjectDataFn( ctx[0].rowId )( data, row.nTr.id ); 8286 } 8287 8288 // Automatically invalidate 8289 _fnInvalidate( ctx[0], this[0], 'data' ); 8290 8291 return this; 8292 } ); 8293 8294 8295 _api_register( 'row().node()', function () { 8296 var ctx = this.context; 8297 8298 return ctx.length && this.length ? 8299 ctx[0].aoData[ this[0] ].nTr || null : 8300 null; 8301 } ); 8302 8303 8304 _api_register( 'row.add()', function ( row ) { 8305 // Allow a jQuery object to be passed in - only a single row is added from 8306 // it though - the first element in the set 8307 if ( row instanceof $ && row.length ) { 8308 row = row[0]; 8309 } 8310 8311 var rows = this.iterator( 'table', function ( settings ) { 8312 if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) { 8313 return _fnAddTr( settings, row )[0]; 8314 } 8315 return _fnAddData( settings, row ); 8316 } ); 8317 8318 // Return an Api.rows() extended instance, with the newly added row selected 8319 return this.row( rows[0] ); 8320 } ); 8321 8322 8323 $(document).on('plugin-init.dt', function (e, context) { 8324 var api = new _Api( context ); 8325 8326 api.on( 'stateSaveParams', function ( e, settings, d ) { 8327 // This could be more compact with the API, but it is a lot faster as a simple 8328 // internal loop 8329 var idFn = settings.rowIdFn; 8330 var data = settings.aoData; 8331 var ids = []; 8332 8333 for (var i=0 ; i<data.length ; i++) { 8334 if (data[i]._detailsShow) { 8335 ids.push( '#' + idFn(data[i]._aData) ); 8336 } 8337 } 8338 8339 d.childRows = ids; 8340 }) 8341 8342 var loaded = api.state.loaded(); 8343 8344 if ( loaded && loaded.childRows ) { 8345 api 8346 .rows( $.map(loaded.childRows, function (id){ 8347 return id.replace(/:/g, '\\:') 8348 }) ) 8349 .every( function () { 8350 _fnCallbackFire( context, null, 'requestChild', [ this ] ) 8351 }); 8352 } 8353 }); 8354 8355 var __details_add = function ( ctx, row, data, klass ) 8356 { 8357 // Convert to array of TR elements 8358 var rows = []; 8359 var addRow = function ( r, k ) { 8360 // Recursion to allow for arrays of jQuery objects 8361 if ( Array.isArray( r ) || r instanceof $ ) { 8362 for ( var i=0, ien=r.length ; i<ien ; i++ ) { 8363 addRow( r[i], k ); 8364 } 8365 return; 8366 } 8367 8368 // If we get a TR element, then just add it directly - up to the dev 8369 // to add the correct number of columns etc 8370 if ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) { 8371 rows.push( r ); 8372 } 8373 else { 8374 // Otherwise create a row with a wrapper 8375 var created = $('<tr><td></td></tr>').addClass( k ); 8376 $('td', created) 8377 .addClass( k ) 8378 .html( r ) 8379 [0].colSpan = _fnVisbleColumns( ctx ); 8380 8381 rows.push( created[0] ); 8382 } 8383 }; 8384 8385 addRow( data, klass ); 8386 8387 if ( row._details ) { 8388 row._details.detach(); 8389 } 8390 8391 row._details = $(rows); 8392 8393 // If the children were already shown, that state should be retained 8394 if ( row._detailsShow ) { 8395 row._details.insertAfter( row.nTr ); 8396 } 8397 }; 8398 8399 8400 // Make state saving of child row details async to allow them to be batch processed 8401 var __details_state = DataTable.util.throttle( 8402 function (ctx) { 8403 _fnSaveState( ctx[0] ) 8404 }, 8405 500 8406 ); 8407 8408 8409 var __details_remove = function ( api, idx ) 8410 { 8411 var ctx = api.context; 8412 8413 if ( ctx.length ) { 8414 var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ]; 8415 8416 if ( row && row._details ) { 8417 row._details.remove(); 8418 8419 row._detailsShow = undefined; 8420 row._details = undefined; 8421 $( row.nTr ).removeClass( 'dt-hasChild' ); 8422 __details_state( ctx ); 8423 } 8424 } 8425 }; 8426 8427 8428 var __details_display = function ( api, show ) { 8429 var ctx = api.context; 8430 8431 if ( ctx.length && api.length ) { 8432 var row = ctx[0].aoData[ api[0] ]; 8433 8434 if ( row._details ) { 8435 row._detailsShow = show; 8436 8437 if ( show ) { 8438 row._details.insertAfter( row.nTr ); 8439 $( row.nTr ).addClass( 'dt-hasChild' ); 8440 } 8441 else { 8442 row._details.detach(); 8443 $( row.nTr ).removeClass( 'dt-hasChild' ); 8444 } 8445 8446 _fnCallbackFire( ctx[0], null, 'childRow', [ show, api.row( api[0] ) ] ) 8447 8448 __details_events( ctx[0] ); 8449 __details_state( ctx ); 8450 } 8451 } 8452 }; 8453 8454 8455 var __details_events = function ( settings ) 8456 { 8457 var api = new _Api( settings ); 8458 var namespace = '.dt.DT_details'; 8459 var drawEvent = 'draw'+namespace; 8460 var colvisEvent = 'column-sizing'+namespace; 8461 var destroyEvent = 'destroy'+namespace; 8462 var data = settings.aoData; 8463 8464 api.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent ); 8465 8466 if ( _pluck( data, '_details' ).length > 0 ) { 8467 // On each draw, insert the required elements into the document 8468 api.on( drawEvent, function ( e, ctx ) { 8469 if ( settings !== ctx ) { 8470 return; 8471 } 8472 8473 api.rows( {page:'current'} ).eq(0).each( function (idx) { 8474 // Internal data grab 8475 var row = data[ idx ]; 8476 8477 if ( row._detailsShow ) { 8478 row._details.insertAfter( row.nTr ); 8479 } 8480 } ); 8481 } ); 8482 8483 // Column visibility change - update the colspan 8484 api.on( colvisEvent, function ( e, ctx, idx, vis ) { 8485 if ( settings !== ctx ) { 8486 return; 8487 } 8488 8489 // Update the colspan for the details rows (note, only if it already has 8490 // a colspan) 8491 var row, visible = _fnVisbleColumns( ctx ); 8492 8493 for ( var i=0, ien=data.length ; i<ien ; i++ ) { 8494 row = data[i]; 8495 8496 if ( row._details ) { 8497 row._details.children('td[colspan]').attr('colspan', visible ); 8498 } 8499 } 8500 } ); 8501 8502 // Table destroyed - nuke any child rows 8503 api.on( destroyEvent, function ( e, ctx ) { 8504 if ( settings !== ctx ) { 8505 return; 8506 } 8507 8508 for ( var i=0, ien=data.length ; i<ien ; i++ ) { 8509 if ( data[i]._details ) { 8510 __details_remove( api, i ); 8511 } 8512 } 8513 } ); 8514 } 8515 }; 8516 8517 // Strings for the method names to help minification 8518 var _emp = ''; 8519 var _child_obj = _emp+'row().child'; 8520 var _child_mth = _child_obj+'()'; 8521 8522 // data can be: 8523 // tr 8524 // string 8525 // jQuery or array of any of the above 8526 _api_register( _child_mth, function ( data, klass ) { 8527 var ctx = this.context; 8528 8529 if ( data === undefined ) { 8530 // get 8531 return ctx.length && this.length ? 8532 ctx[0].aoData[ this[0] ]._details : 8533 undefined; 8534 } 8535 else if ( data === true ) { 8536 // show 8537 this.child.show(); 8538 } 8539 else if ( data === false ) { 8540 // remove 8541 __details_remove( this ); 8542 } 8543 else if ( ctx.length && this.length ) { 8544 // set 8545 __details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass ); 8546 } 8547 8548 return this; 8549 } ); 8550 8551 8552 _api_register( [ 8553 _child_obj+'.show()', 8554 _child_mth+'.show()' // only when `child()` was called with parameters (without 8555 ], function ( show ) { // it returns an object and this method is not executed) 8556 __details_display( this, true ); 8557 return this; 8558 } ); 8559 8560 8561 _api_register( [ 8562 _child_obj+'.hide()', 8563 _child_mth+'.hide()' // only when `child()` was called with parameters (without 8564 ], function () { // it returns an object and this method is not executed) 8565 __details_display( this, false ); 8566 return this; 8567 } ); 8568 8569 8570 _api_register( [ 8571 _child_obj+'.remove()', 8572 _child_mth+'.remove()' // only when `child()` was called with parameters (without 8573 ], function () { // it returns an object and this method is not executed) 8574 __details_remove( this ); 8575 return this; 8576 } ); 8577 8578 8579 _api_register( _child_obj+'.isShown()', function () { 8580 var ctx = this.context; 8581 8582 if ( ctx.length && this.length ) { 8583 // _detailsShown as false or undefined will fall through to return false 8584 return ctx[0].aoData[ this[0] ]._detailsShow || false; 8585 } 8586 return false; 8587 } ); 8588 8589 8590 8591 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 8592 * Columns 8593 * 8594 * {integer} - column index (>=0 count from left, <0 count from right) 8595 * "{integer}:visIdx" - visible column index (i.e. translate to column index) (>=0 count from left, <0 count from right) 8596 * "{integer}:visible" - alias for {integer}:visIdx (>=0 count from left, <0 count from right) 8597 * "{string}:name" - column name 8598 * "{string}" - jQuery selector on column header nodes 8599 * 8600 */ 8601 8602 // can be an array of these items, comma separated list, or an array of comma 8603 // separated lists 8604 8605 var __re_column_selector = /^([^:]+):(name|visIdx|visible)$/; 8606 8607 8608 // r1 and r2 are redundant - but it means that the parameters match for the 8609 // iterator callback in columns().data() 8610 var __columnData = function ( settings, column, r1, r2, rows ) { 8611 var a = []; 8612 for ( var row=0, ien=rows.length ; row<ien ; row++ ) { 8613 a.push( _fnGetCellData( settings, rows[row], column ) ); 8614 } 8615 return a; 8616 }; 8617 8618 8619 var __column_selector = function ( settings, selector, opts ) 8620 { 8621 var 8622 columns = settings.aoColumns, 8623 names = _pluck( columns, 'sName' ), 8624 nodes = _pluck( columns, 'nTh' ); 8625 8626 var run = function ( s ) { 8627 var selInt = _intVal( s ); 8628 8629 // Selector - all 8630 if ( s === '' ) { 8631 return _range( columns.length ); 8632 } 8633 8634 // Selector - index 8635 if ( selInt !== null ) { 8636 return [ selInt >= 0 ? 8637 selInt : // Count from left 8638 columns.length + selInt // Count from right (+ because its a negative value) 8639 ]; 8640 } 8641 8642 // Selector = function 8643 if ( typeof s === 'function' ) { 8644 var rows = _selector_row_indexes( settings, opts ); 8645 8646 return $.map( columns, function (col, idx) { 8647 return s( 8648 idx, 8649 __columnData( settings, idx, 0, 0, rows ), 8650 nodes[ idx ] 8651 ) ? idx : null; 8652 } ); 8653 } 8654 8655 // jQuery or string selector 8656 var match = typeof s === 'string' ? 8657 s.match( __re_column_selector ) : 8658 ''; 8659 8660 if ( match ) { 8661 switch( match[2] ) { 8662 case 'visIdx': 8663 case 'visible': 8664 var idx = parseInt( match[1], 10 ); 8665 // Visible index given, convert to column index 8666 if ( idx < 0 ) { 8667 // Counting from the right 8668 var visColumns = $.map( columns, function (col,i) { 8669 return col.bVisible ? i : null; 8670 } ); 8671 return [ visColumns[ visColumns.length + idx ] ]; 8672 } 8673 // Counting from the left 8674 return [ _fnVisibleToColumnIndex( settings, idx ) ]; 8675 8676 case 'name': 8677 // match by name. `names` is column index complete and in order 8678 return $.map( names, function (name, i) { 8679 return name === match[1] ? i : null; 8680 } ); 8681 8682 default: 8683 return []; 8684 } 8685 } 8686 8687 // Cell in the table body 8688 if ( s.nodeName && s._DT_CellIndex ) { 8689 return [ s._DT_CellIndex.column ]; 8690 } 8691 8692 // jQuery selector on the TH elements for the columns 8693 var jqResult = $( nodes ) 8694 .filter( s ) 8695 .map( function () { 8696 return $.inArray( this, nodes ); // `nodes` is column index complete and in order 8697 } ) 8698 .toArray(); 8699 8700 if ( jqResult.length || ! s.nodeName ) { 8701 return jqResult; 8702 } 8703 8704 // Otherwise a node which might have a `dt-column` data attribute, or be 8705 // a child or such an element 8706 var host = $(s).closest('*[data-dt-column]'); 8707 return host.length ? 8708 [ host.data('dt-column') ] : 8709 []; 8710 }; 8711 8712 return _selector_run( 'column', selector, run, settings, opts ); 8713 }; 8714 8715 8716 var __setColumnVis = function ( settings, column, vis ) { 8717 var 8718 cols = settings.aoColumns, 8719 col = cols[ column ], 8720 data = settings.aoData, 8721 row, cells, i, ien, tr; 8722 8723 // Get 8724 if ( vis === undefined ) { 8725 return col.bVisible; 8726 } 8727 8728 // Set 8729 // No change 8730 if ( col.bVisible === vis ) { 8731 return; 8732 } 8733 8734 if ( vis ) { 8735 // Insert column 8736 // Need to decide if we should use appendChild or insertBefore 8737 var insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 ); 8738 8739 for ( i=0, ien=data.length ; i<ien ; i++ ) { 8740 tr = data[i].nTr; 8741 cells = data[i].anCells; 8742 8743 if ( tr ) { 8744 // insertBefore can act like appendChild if 2nd arg is null 8745 tr.insertBefore( cells[ column ], cells[ insertBefore ] || null ); 8746 } 8747 } 8748 } 8749 else { 8750 // Remove column 8751 $( _pluck( settings.aoData, 'anCells', column ) ).detach(); 8752 } 8753 8754 // Common actions 8755 col.bVisible = vis; 8756 }; 8757 8758 8759 _api_register( 'columns()', function ( selector, opts ) { 8760 // argument shifting 8761 if ( selector === undefined ) { 8762 selector = ''; 8763 } 8764 else if ( $.isPlainObject( selector ) ) { 8765 opts = selector; 8766 selector = ''; 8767 } 8768 8769 opts = _selector_opts( opts ); 8770 8771 var inst = this.iterator( 'table', function ( settings ) { 8772 return __column_selector( settings, selector, opts ); 8773 }, 1 ); 8774 8775 // Want argument shifting here and in _row_selector? 8776 inst.selector.cols = selector; 8777 inst.selector.opts = opts; 8778 8779 return inst; 8780 } ); 8781 8782 _api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) { 8783 return this.iterator( 'column', function ( settings, column ) { 8784 return settings.aoColumns[column].nTh; 8785 }, 1 ); 8786 } ); 8787 8788 _api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) { 8789 return this.iterator( 'column', function ( settings, column ) { 8790 return settings.aoColumns[column].nTf; 8791 }, 1 ); 8792 } ); 8793 8794 _api_registerPlural( 'columns().data()', 'column().data()', function () { 8795 return this.iterator( 'column-rows', __columnData, 1 ); 8796 } ); 8797 8798 _api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () { 8799 return this.iterator( 'column', function ( settings, column ) { 8800 return settings.aoColumns[column].mData; 8801 }, 1 ); 8802 } ); 8803 8804 _api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) { 8805 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) { 8806 return _pluck_order( settings.aoData, rows, 8807 type === 'search' ? '_aFilterData' : '_aSortData', column 8808 ); 8809 }, 1 ); 8810 } ); 8811 8812 _api_registerPlural( 'columns().nodes()', 'column().nodes()', function () { 8813 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) { 8814 return _pluck_order( settings.aoData, rows, 'anCells', column ) ; 8815 }, 1 ); 8816 } ); 8817 8818 _api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) { 8819 var that = this; 8820 var ret = this.iterator( 'column', function ( settings, column ) { 8821 if ( vis === undefined ) { 8822 return settings.aoColumns[ column ].bVisible; 8823 } // else 8824 __setColumnVis( settings, column, vis ); 8825 } ); 8826 8827 // Group the column visibility changes 8828 if ( vis !== undefined ) { 8829 this.iterator( 'table', function ( settings ) { 8830 // Redraw the header after changes 8831 _fnDrawHead( settings, settings.aoHeader ); 8832 _fnDrawHead( settings, settings.aoFooter ); 8833 8834 // Update colspan for no records display. Child rows and extensions will use their own 8835 // listeners to do this - only need to update the empty table item here 8836 if ( ! settings.aiDisplay.length ) { 8837 $(settings.nTBody).find('td[colspan]').attr('colspan', _fnVisbleColumns(settings)); 8838 } 8839 8840 _fnSaveState( settings ); 8841 8842 // Second loop once the first is done for events 8843 that.iterator( 'column', function ( settings, column ) { 8844 _fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis, calc] ); 8845 } ); 8846 8847 if ( calc === undefined || calc ) { 8848 that.columns.adjust(); 8849 } 8850 }); 8851 } 8852 8853 return ret; 8854 } ); 8855 8856 _api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) { 8857 return this.iterator( 'column', function ( settings, column ) { 8858 return type === 'visible' ? 8859 _fnColumnIndexToVisible( settings, column ) : 8860 column; 8861 }, 1 ); 8862 } ); 8863 8864 _api_register( 'columns.adjust()', function () { 8865 return this.iterator( 'table', function ( settings ) { 8866 _fnAdjustColumnSizing( settings ); 8867 }, 1 ); 8868 } ); 8869 8870 _api_register( 'column.index()', function ( type, idx ) { 8871 if ( this.context.length !== 0 ) { 8872 var ctx = this.context[0]; 8873 8874 if ( type === 'fromVisible' || type === 'toData' ) { 8875 return _fnVisibleToColumnIndex( ctx, idx ); 8876 } 8877 else if ( type === 'fromData' || type === 'toVisible' ) { 8878 return _fnColumnIndexToVisible( ctx, idx ); 8879 } 8880 } 8881 } ); 8882 8883 _api_register( 'column()', function ( selector, opts ) { 8884 return _selector_first( this.columns( selector, opts ) ); 8885 } ); 8886 8887 var __cell_selector = function ( settings, selector, opts ) 8888 { 8889 var data = settings.aoData; 8890 var rows = _selector_row_indexes( settings, opts ); 8891 var cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) ); 8892 var allCells = $(_flatten( [], cells )); 8893 var row; 8894 var columns = settings.aoColumns.length; 8895 var a, i, ien, j, o, host; 8896 8897 var run = function ( s ) { 8898 var fnSelector = typeof s === 'function'; 8899 8900 if ( s === null || s === undefined || fnSelector ) { 8901 // All cells and function selectors 8902 a = []; 8903 8904 for ( i=0, ien=rows.length ; i<ien ; i++ ) { 8905 row = rows[i]; 8906 8907 for ( j=0 ; j<columns ; j++ ) { 8908 o = { 8909 row: row, 8910 column: j 8911 }; 8912 8913 if ( fnSelector ) { 8914 // Selector - function 8915 host = data[ row ]; 8916 8917 if ( s( o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null ) ) { 8918 a.push( o ); 8919 } 8920 } 8921 else { 8922 // Selector - all 8923 a.push( o ); 8924 } 8925 } 8926 } 8927 8928 return a; 8929 } 8930 8931 // Selector - index 8932 if ( $.isPlainObject( s ) ) { 8933 // Valid cell index and its in the array of selectable rows 8934 return s.column !== undefined && s.row !== undefined && $.inArray( s.row, rows ) !== -1 ? 8935 [s] : 8936 []; 8937 } 8938 8939 // Selector - jQuery filtered cells 8940 var jqResult = allCells 8941 .filter( s ) 8942 .map( function (i, el) { 8943 return { // use a new object, in case someone changes the values 8944 row: el._DT_CellIndex.row, 8945 column: el._DT_CellIndex.column 8946 }; 8947 } ) 8948 .toArray(); 8949 8950 if ( jqResult.length || ! s.nodeName ) { 8951 return jqResult; 8952 } 8953 8954 // Otherwise the selector is a node, and there is one last option - the 8955 // element might be a child of an element which has dt-row and dt-column 8956 // data attributes 8957 host = $(s).closest('*[data-dt-row]'); 8958 return host.length ? 8959 [ { 8960 row: host.data('dt-row'), 8961 column: host.data('dt-column') 8962 } ] : 8963 []; 8964 }; 8965 8966 return _selector_run( 'cell', selector, run, settings, opts ); 8967 }; 8968 8969 8970 8971 8972 _api_register( 'cells()', function ( rowSelector, columnSelector, opts ) { 8973 // Argument shifting 8974 if ( $.isPlainObject( rowSelector ) ) { 8975 // Indexes 8976 if ( rowSelector.row === undefined ) { 8977 // Selector options in first parameter 8978 opts = rowSelector; 8979 rowSelector = null; 8980 } 8981 else { 8982 // Cell index objects in first parameter 8983 opts = columnSelector; 8984 columnSelector = null; 8985 } 8986 } 8987 if ( $.isPlainObject( columnSelector ) ) { 8988 opts = columnSelector; 8989 columnSelector = null; 8990 } 8991 8992 // Cell selector 8993 if ( columnSelector === null || columnSelector === undefined ) { 8994 return this.iterator( 'table', function ( settings ) { 8995 return __cell_selector( settings, rowSelector, _selector_opts( opts ) ); 8996 } ); 8997 } 8998 8999 // The default built in options need to apply to row and columns 9000 var internalOpts = opts ? { 9001 page: opts.page, 9002 order: opts.order, 9003 search: opts.search 9004 } : {}; 9005 9006 // Row + column selector 9007 var columns = this.columns( columnSelector, internalOpts ); 9008 var rows = this.rows( rowSelector, internalOpts ); 9009 var i, ien, j, jen; 9010 9011 var cellsNoOpts = this.iterator( 'table', function ( settings, idx ) { 9012 var a = []; 9013 9014 for ( i=0, ien=rows[idx].length ; i<ien ; i++ ) { 9015 for ( j=0, jen=columns[idx].length ; j<jen ; j++ ) { 9016 a.push( { 9017 row: rows[idx][i], 9018 column: columns[idx][j] 9019 } ); 9020 } 9021 } 9022 9023 return a; 9024 }, 1 ); 9025 9026 // There is currently only one extension which uses a cell selector extension 9027 // It is a _major_ performance drag to run this if it isn't needed, so this is 9028 // an extension specific check at the moment 9029 var cells = opts && opts.selected ? 9030 this.cells( cellsNoOpts, opts ) : 9031 cellsNoOpts; 9032 9033 $.extend( cells.selector, { 9034 cols: columnSelector, 9035 rows: rowSelector, 9036 opts: opts 9037 } ); 9038 9039 return cells; 9040 } ); 9041 9042 9043 _api_registerPlural( 'cells().nodes()', 'cell().node()', function () { 9044 return this.iterator( 'cell', function ( settings, row, column ) { 9045 var data = settings.aoData[ row ]; 9046 9047 return data && data.anCells ? 9048 data.anCells[ column ] : 9049 undefined; 9050 }, 1 ); 9051 } ); 9052 9053 9054 _api_register( 'cells().data()', function () { 9055 return this.iterator( 'cell', function ( settings, row, column ) { 9056 return _fnGetCellData( settings, row, column ); 9057 }, 1 ); 9058 } ); 9059 9060 9061 _api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) { 9062 type = type === 'search' ? '_aFilterData' : '_aSortData'; 9063 9064 return this.iterator( 'cell', function ( settings, row, column ) { 9065 return settings.aoData[ row ][ type ][ column ]; 9066 }, 1 ); 9067 } ); 9068 9069 9070 _api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) { 9071 return this.iterator( 'cell', function ( settings, row, column ) { 9072 return _fnGetCellData( settings, row, column, type ); 9073 }, 1 ); 9074 } ); 9075 9076 9077 _api_registerPlural( 'cells().indexes()', 'cell().index()', function () { 9078 return this.iterator( 'cell', function ( settings, row, column ) { 9079 return { 9080 row: row, 9081 column: column, 9082 columnVisible: _fnColumnIndexToVisible( settings, column ) 9083 }; 9084 }, 1 ); 9085 } ); 9086 9087 9088 _api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) { 9089 return this.iterator( 'cell', function ( settings, row, column ) { 9090 _fnInvalidate( settings, row, src, column ); 9091 } ); 9092 } ); 9093 9094 9095 9096 _api_register( 'cell()', function ( rowSelector, columnSelector, opts ) { 9097 return _selector_first( this.cells( rowSelector, columnSelector, opts ) ); 9098 } ); 9099 9100 9101 _api_register( 'cell().data()', function ( data ) { 9102 var ctx = this.context; 9103 var cell = this[0]; 9104 9105 if ( data === undefined ) { 9106 // Get 9107 return ctx.length && cell.length ? 9108 _fnGetCellData( ctx[0], cell[0].row, cell[0].column ) : 9109 undefined; 9110 } 9111 9112 // Set 9113 _fnSetCellData( ctx[0], cell[0].row, cell[0].column, data ); 9114 _fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column ); 9115 9116 return this; 9117 } ); 9118 9119 9120 9121 /** 9122 * Get current ordering (sorting) that has been applied to the table. 9123 * 9124 * @returns {array} 2D array containing the sorting information for the first 9125 * table in the current context. Each element in the parent array represents 9126 * a column being sorted upon (i.e. multi-sorting with two columns would have 9127 * 2 inner arrays). The inner arrays may have 2 or 3 elements. The first is 9128 * the column index that the sorting condition applies to, the second is the 9129 * direction of the sort (`desc` or `asc`) and, optionally, the third is the 9130 * index of the sorting order from the `column.sorting` initialisation array. 9131 *//** 9132 * Set the ordering for the table. 9133 * 9134 * @param {integer} order Column index to sort upon. 9135 * @param {string} direction Direction of the sort to be applied (`asc` or `desc`) 9136 * @returns {DataTables.Api} this 9137 *//** 9138 * Set the ordering for the table. 9139 * 9140 * @param {array} order 1D array of sorting information to be applied. 9141 * @param {array} [...] Optional additional sorting conditions 9142 * @returns {DataTables.Api} this 9143 *//** 9144 * Set the ordering for the table. 9145 * 9146 * @param {array} order 2D array of sorting information to be applied. 9147 * @returns {DataTables.Api} this 9148 */ 9149 _api_register( 'order()', function ( order, dir ) { 9150 var ctx = this.context; 9151 9152 if ( order === undefined ) { 9153 // get 9154 return ctx.length !== 0 ? 9155 ctx[0].aaSorting : 9156 undefined; 9157 } 9158 9159 // set 9160 if ( typeof order === 'number' ) { 9161 // Simple column / direction passed in 9162 order = [ [ order, dir ] ]; 9163 } 9164 else if ( order.length && ! Array.isArray( order[0] ) ) { 9165 // Arguments passed in (list of 1D arrays) 9166 order = Array.prototype.slice.call( arguments ); 9167 } 9168 // otherwise a 2D array was passed in 9169 9170 return this.iterator( 'table', function ( settings ) { 9171 settings.aaSorting = order.slice(); 9172 } ); 9173 } ); 9174 9175 9176 /** 9177 * Attach a sort listener to an element for a given column 9178 * 9179 * @param {node|jQuery|string} node Identifier for the element(s) to attach the 9180 * listener to. This can take the form of a single DOM node, a jQuery 9181 * collection of nodes or a jQuery selector which will identify the node(s). 9182 * @param {integer} column the column that a click on this node will sort on 9183 * @param {function} [callback] callback function when sort is run 9184 * @returns {DataTables.Api} this 9185 */ 9186 _api_register( 'order.listener()', function ( node, column, callback ) { 9187 return this.iterator( 'table', function ( settings ) { 9188 _fnSortAttachListener( settings, node, column, callback ); 9189 } ); 9190 } ); 9191 9192 9193 _api_register( 'order.fixed()', function ( set ) { 9194 if ( ! set ) { 9195 var ctx = this.context; 9196 var fixed = ctx.length ? 9197 ctx[0].aaSortingFixed : 9198 undefined; 9199 9200 return Array.isArray( fixed ) ? 9201 { pre: fixed } : 9202 fixed; 9203 } 9204 9205 return this.iterator( 'table', function ( settings ) { 9206 settings.aaSortingFixed = $.extend( true, {}, set ); 9207 } ); 9208 } ); 9209 9210 9211 // Order by the selected column(s) 9212 _api_register( [ 9213 'columns().order()', 9214 'column().order()' 9215 ], function ( dir ) { 9216 var that = this; 9217 9218 return this.iterator( 'table', function ( settings, i ) { 9219 var sort = []; 9220 9221 $.each( that[i], function (j, col) { 9222 sort.push( [ col, dir ] ); 9223 } ); 9224 9225 settings.aaSorting = sort; 9226 } ); 9227 } ); 9228 9229 9230 9231 _api_register( 'search()', function ( input, regex, smart, caseInsen ) { 9232 var ctx = this.context; 9233 9234 if ( input === undefined ) { 9235 // get 9236 return ctx.length !== 0 ? 9237 ctx[0].oPreviousSearch.sSearch : 9238 undefined; 9239 } 9240 9241 // set 9242 return this.iterator( 'table', function ( settings ) { 9243 if ( ! settings.oFeatures.bFilter ) { 9244 return; 9245 } 9246 9247 _fnFilterComplete( settings, $.extend( {}, settings.oPreviousSearch, { 9248 "sSearch": input+"", 9249 "bRegex": regex === null ? false : regex, 9250 "bSmart": smart === null ? true : smart, 9251 "bCaseInsensitive": caseInsen === null ? true : caseInsen 9252 } ), 1 ); 9253 } ); 9254 } ); 9255 9256 9257 _api_registerPlural( 9258 'columns().search()', 9259 'column().search()', 9260 function ( input, regex, smart, caseInsen ) { 9261 return this.iterator( 'column', function ( settings, column ) { 9262 var preSearch = settings.aoPreSearchCols; 9263 9264 if ( input === undefined ) { 9265 // get 9266 return preSearch[ column ].sSearch; 9267 } 9268 9269 // set 9270 if ( ! settings.oFeatures.bFilter ) { 9271 return; 9272 } 9273 9274 $.extend( preSearch[ column ], { 9275 "sSearch": input+"", 9276 "bRegex": regex === null ? false : regex, 9277 "bSmart": smart === null ? true : smart, 9278 "bCaseInsensitive": caseInsen === null ? true : caseInsen 9279 } ); 9280 9281 _fnFilterComplete( settings, settings.oPreviousSearch, 1 ); 9282 } ); 9283 } 9284 ); 9285 9286 /* 9287 * State API methods 9288 */ 9289 9290 _api_register( 'state()', function () { 9291 return this.context.length ? 9292 this.context[0].oSavedState : 9293 null; 9294 } ); 9295 9296 9297 _api_register( 'state.clear()', function () { 9298 return this.iterator( 'table', function ( settings ) { 9299 // Save an empty object 9300 settings.fnStateSaveCallback.call( settings.oInstance, settings, {} ); 9301 } ); 9302 } ); 9303 9304 9305 _api_register( 'state.loaded()', function () { 9306 return this.context.length ? 9307 this.context[0].oLoadedState : 9308 null; 9309 } ); 9310 9311 9312 _api_register( 'state.save()', function () { 9313 return this.iterator( 'table', function ( settings ) { 9314 _fnSaveState( settings ); 9315 } ); 9316 } ); 9317 9318 9319 9320 /** 9321 * Provide a common method for plug-ins to check the version of DataTables being 9322 * used, in order to ensure compatibility. 9323 * 9324 * @param {string} version Version string to check for, in the format "X.Y.Z". 9325 * Note that the formats "X" and "X.Y" are also acceptable. 9326 * @returns {boolean} true if this version of DataTables is greater or equal to 9327 * the required version, or false if this version of DataTales is not 9328 * suitable 9329 * @static 9330 * @dtopt API-Static 9331 * 9332 * @example 9333 * alert( $.fn.dataTable.versionCheck( '1.9.0' ) ); 9334 */ 9335 DataTable.versionCheck = DataTable.fnVersionCheck = function( version ) 9336 { 9337 var aThis = DataTable.version.split('.'); 9338 var aThat = version.split('.'); 9339 var iThis, iThat; 9340 9341 for ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) { 9342 iThis = parseInt( aThis[i], 10 ) || 0; 9343 iThat = parseInt( aThat[i], 10 ) || 0; 9344 9345 // Parts are the same, keep comparing 9346 if (iThis === iThat) { 9347 continue; 9348 } 9349 9350 // Parts are different, return immediately 9351 return iThis > iThat; 9352 } 9353 9354 return true; 9355 }; 9356 9357 9358 /** 9359 * Check if a `<table>` node is a DataTable table already or not. 9360 * 9361 * @param {node|jquery|string} table Table node, jQuery object or jQuery 9362 * selector for the table to test. Note that if more than more than one 9363 * table is passed on, only the first will be checked 9364 * @returns {boolean} true the table given is a DataTable, or false otherwise 9365 * @static 9366 * @dtopt API-Static 9367 * 9368 * @example 9369 * if ( ! $.fn.DataTable.isDataTable( '#example' ) ) { 9370 * $('#example').dataTable(); 9371 * } 9372 */ 9373 DataTable.isDataTable = DataTable.fnIsDataTable = function ( table ) 9374 { 9375 var t = $(table).get(0); 9376 var is = false; 9377 9378 if ( table instanceof DataTable.Api ) { 9379 return true; 9380 } 9381 9382 $.each( DataTable.settings, function (i, o) { 9383 var head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null; 9384 var foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null; 9385 9386 if ( o.nTable === t || head === t || foot === t ) { 9387 is = true; 9388 } 9389 } ); 9390 9391 return is; 9392 }; 9393 9394 9395 /** 9396 * Get all DataTable tables that have been initialised - optionally you can 9397 * select to get only currently visible tables. 9398 * 9399 * @param {boolean} [visible=false] Flag to indicate if you want all (default) 9400 * or visible tables only. 9401 * @returns {array} Array of `table` nodes (not DataTable instances) which are 9402 * DataTables 9403 * @static 9404 * @dtopt API-Static 9405 * 9406 * @example 9407 * $.each( $.fn.dataTable.tables(true), function () { 9408 * $(table).DataTable().columns.adjust(); 9409 * } ); 9410 */ 9411 DataTable.tables = DataTable.fnTables = function ( visible ) 9412 { 9413 var api = false; 9414 9415 if ( $.isPlainObject( visible ) ) { 9416 api = visible.api; 9417 visible = visible.visible; 9418 } 9419 9420 var a = $.map( DataTable.settings, function (o) { 9421 if ( !visible || (visible && $(o.nTable).is(':visible')) ) { 9422 return o.nTable; 9423 } 9424 } ); 9425 9426 return api ? 9427 new _Api( a ) : 9428 a; 9429 }; 9430 9431 9432 /** 9433 * Convert from camel case parameters to Hungarian notation. This is made public 9434 * for the extensions to provide the same ability as DataTables core to accept 9435 * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase 9436 * parameters. 9437 * 9438 * @param {object} src The model object which holds all parameters that can be 9439 * mapped. 9440 * @param {object} user The object to convert from camel case to Hungarian. 9441 * @param {boolean} force When set to `true`, properties which already have a 9442 * Hungarian value in the `user` object will be overwritten. Otherwise they 9443 * won't be. 9444 */ 9445 DataTable.camelToHungarian = _fnCamelToHungarian; 9446 9447 9448 9449 /** 9450 * 9451 */ 9452 _api_register( '$()', function ( selector, opts ) { 9453 var 9454 rows = this.rows( opts ).nodes(), // Get all rows 9455 jqRows = $(rows); 9456 9457 return $( [].concat( 9458 jqRows.filter( selector ).toArray(), 9459 jqRows.find( selector ).toArray() 9460 ) ); 9461 } ); 9462 9463 9464 // jQuery functions to operate on the tables 9465 $.each( [ 'on', 'one', 'off' ], function (i, key) { 9466 _api_register( key+'()', function ( /* event, handler */ ) { 9467 var args = Array.prototype.slice.call(arguments); 9468 9469 // Add the `dt` namespace automatically if it isn't already present 9470 args[0] = $.map( args[0].split( /\s/ ), function ( e ) { 9471 return ! e.match(/\.dt\b/) ? 9472 e+'.dt' : 9473 e; 9474 } ).join( ' ' ); 9475 9476 var inst = $( this.tables().nodes() ); 9477 inst[key].apply( inst, args ); 9478 return this; 9479 } ); 9480 } ); 9481 9482 9483 _api_register( 'clear()', function () { 9484 return this.iterator( 'table', function ( settings ) { 9485 _fnClearTable( settings ); 9486 } ); 9487 } ); 9488 9489 9490 _api_register( 'settings()', function () { 9491 return new _Api( this.context, this.context ); 9492 } ); 9493 9494 9495 _api_register( 'init()', function () { 9496 var ctx = this.context; 9497 return ctx.length ? ctx[0].oInit : null; 9498 } ); 9499 9500 9501 _api_register( 'data()', function () { 9502 return this.iterator( 'table', function ( settings ) { 9503 return _pluck( settings.aoData, '_aData' ); 9504 } ).flatten(); 9505 } ); 9506 9507 9508 _api_register( 'destroy()', function ( remove ) { 9509 remove = remove || false; 9510 9511 return this.iterator( 'table', function ( settings ) { 9512 var classes = settings.oClasses; 9513 var table = settings.nTable; 9514 var tbody = settings.nTBody; 9515 var thead = settings.nTHead; 9516 var tfoot = settings.nTFoot; 9517 var jqTable = $(table); 9518 var jqTbody = $(tbody); 9519 var jqWrapper = $(settings.nTableWrapper); 9520 var rows = $.map( settings.aoData, function (r) { return r.nTr; } ); 9521 var i, ien; 9522 9523 // Flag to note that the table is currently being destroyed - no action 9524 // should be taken 9525 settings.bDestroying = true; 9526 9527 // Fire off the destroy callbacks for plug-ins etc 9528 _fnCallbackFire( settings, "aoDestroyCallback", "destroy", [settings] ); 9529 9530 // If not being removed from the document, make all columns visible 9531 if ( ! remove ) { 9532 new _Api( settings ).columns().visible( true ); 9533 } 9534 9535 // Blitz all `DT` namespaced events (these are internal events, the 9536 // lowercase, `dt` events are user subscribed and they are responsible 9537 // for removing them 9538 jqWrapper.off('.DT').find(':not(tbody *)').off('.DT'); 9539 $(window).off('.DT-'+settings.sInstance); 9540 9541 // When scrolling we had to break the table up - restore it 9542 if ( table != thead.parentNode ) { 9543 jqTable.children('thead').detach(); 9544 jqTable.append( thead ); 9545 } 9546 9547 if ( tfoot && table != tfoot.parentNode ) { 9548 jqTable.children('tfoot').detach(); 9549 jqTable.append( tfoot ); 9550 } 9551 9552 settings.aaSorting = []; 9553 settings.aaSortingFixed = []; 9554 _fnSortingClasses( settings ); 9555 9556 $( rows ).removeClass( settings.asStripeClasses.join(' ') ); 9557 9558 $('th, td', thead).removeClass( classes.sSortable+' '+ 9559 classes.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone 9560 ); 9561 9562 // Add the TR elements back into the table in their original order 9563 jqTbody.children().detach(); 9564 jqTbody.append( rows ); 9565 9566 var orig = settings.nTableWrapper.parentNode; 9567 9568 // Remove the DataTables generated nodes, events and classes 9569 var removedMethod = remove ? 'remove' : 'detach'; 9570 jqTable[ removedMethod ](); 9571 jqWrapper[ removedMethod ](); 9572 9573 // If we need to reattach the table to the document 9574 if ( ! remove && orig ) { 9575 // insertBefore acts like appendChild if !arg[1] 9576 orig.insertBefore( table, settings.nTableReinsertBefore ); 9577 9578 // Restore the width of the original table - was read from the style property, 9579 // so we can restore directly to that 9580 jqTable 9581 .css( 'width', settings.sDestroyWidth ) 9582 .removeClass( classes.sTable ); 9583 9584 // If the were originally stripe classes - then we add them back here. 9585 // Note this is not fool proof (for example if not all rows had stripe 9586 // classes - but it's a good effort without getting carried away 9587 ien = settings.asDestroyStripes.length; 9588 9589 if ( ien ) { 9590 jqTbody.children().each( function (i) { 9591 $(this).addClass( settings.asDestroyStripes[i % ien] ); 9592 } ); 9593 } 9594 } 9595 9596 /* Remove the settings object from the settings array */ 9597 var idx = $.inArray( settings, DataTable.settings ); 9598 if ( idx !== -1 ) { 9599 DataTable.settings.splice( idx, 1 ); 9600 } 9601 } ); 9602 } ); 9603 9604 9605 // Add the `every()` method for rows, columns and cells in a compact form 9606 $.each( [ 'column', 'row', 'cell' ], function ( i, type ) { 9607 _api_register( type+'s().every()', function ( fn ) { 9608 var opts = this.selector.opts; 9609 var api = this; 9610 9611 return this.iterator( type, function ( settings, arg1, arg2, arg3, arg4 ) { 9612 // Rows and columns: 9613 // arg1 - index 9614 // arg2 - table counter 9615 // arg3 - loop counter 9616 // arg4 - undefined 9617 // Cells: 9618 // arg1 - row index 9619 // arg2 - column index 9620 // arg3 - table counter 9621 // arg4 - loop counter 9622 fn.call( 9623 api[ type ]( 9624 arg1, 9625 type==='cell' ? arg2 : opts, 9626 type==='cell' ? opts : undefined 9627 ), 9628 arg1, arg2, arg3, arg4 9629 ); 9630 } ); 9631 } ); 9632 } ); 9633 9634 9635 // i18n method for extensions to be able to use the language object from the 9636 // DataTable 9637 _api_register( 'i18n()', function ( token, def, plural ) { 9638 var ctx = this.context[0]; 9639 var resolved = _fnGetObjectDataFn( token )( ctx.oLanguage ); 9640 9641 if ( resolved === undefined ) { 9642 resolved = def; 9643 } 9644 9645 if ( plural !== undefined && $.isPlainObject( resolved ) ) { 9646 resolved = resolved[ plural ] !== undefined ? 9647 resolved[ plural ] : 9648 resolved._; 9649 } 9650 9651 return resolved.replace( '%d', plural ); // nb: plural might be undefined, 9652 } ); 9653 /** 9654 * Version string for plug-ins to check compatibility. Allowed format is 9655 * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used 9656 * only for non-release builds. See http://semver.org/ for more information. 9657 * @member 9658 * @type string 9659 * @default Version number 9660 */ 9661 DataTable.version = "1.12.1"; 9662 9663 /** 9664 * Private data store, containing all of the settings objects that are 9665 * created for the tables on a given page. 9666 * 9667 * Note that the `DataTable.settings` object is aliased to 9668 * `jQuery.fn.dataTableExt` through which it may be accessed and 9669 * manipulated, or `jQuery.fn.dataTable.settings`. 9670 * @member 9671 * @type array 9672 * @default [] 9673 * @private 9674 */ 9675 DataTable.settings = []; 9676 9677 /** 9678 * Object models container, for the various models that DataTables has 9679 * available to it. These models define the objects that are used to hold 9680 * the active state and configuration of the table. 9681 * @namespace 9682 */ 9683 DataTable.models = {}; 9684 9685 9686 9687 /** 9688 * Template object for the way in which DataTables holds information about 9689 * search information for the global filter and individual column filters. 9690 * @namespace 9691 */ 9692 DataTable.models.oSearch = { 9693 /** 9694 * Flag to indicate if the filtering should be case insensitive or not 9695 * @type boolean 9696 * @default true 9697 */ 9698 "bCaseInsensitive": true, 9699 9700 /** 9701 * Applied search term 9702 * @type string 9703 * @default <i>Empty string</i> 9704 */ 9705 "sSearch": "", 9706 9707 /** 9708 * Flag to indicate if the search term should be interpreted as a 9709 * regular expression (true) or not (false) and therefore and special 9710 * regex characters escaped. 9711 * @type boolean 9712 * @default false 9713 */ 9714 "bRegex": false, 9715 9716 /** 9717 * Flag to indicate if DataTables is to use its smart filtering or not. 9718 * @type boolean 9719 * @default true 9720 */ 9721 "bSmart": true, 9722 9723 /** 9724 * Flag to indicate if DataTables should only trigger a search when 9725 * the return key is pressed. 9726 * @type boolean 9727 * @default false 9728 */ 9729 "return": false 9730 }; 9731 9732 9733 9734 9735 /** 9736 * Template object for the way in which DataTables holds information about 9737 * each individual row. This is the object format used for the settings 9738 * aoData array. 9739 * @namespace 9740 */ 9741 DataTable.models.oRow = { 9742 /** 9743 * TR element for the row 9744 * @type node 9745 * @default null 9746 */ 9747 "nTr": null, 9748 9749 /** 9750 * Array of TD elements for each row. This is null until the row has been 9751 * created. 9752 * @type array nodes 9753 * @default [] 9754 */ 9755 "anCells": null, 9756 9757 /** 9758 * Data object from the original data source for the row. This is either 9759 * an array if using the traditional form of DataTables, or an object if 9760 * using mData options. The exact type will depend on the passed in 9761 * data from the data source, or will be an array if using DOM a data 9762 * source. 9763 * @type array|object 9764 * @default [] 9765 */ 9766 "_aData": [], 9767 9768 /** 9769 * Sorting data cache - this array is ostensibly the same length as the 9770 * number of columns (although each index is generated only as it is 9771 * needed), and holds the data that is used for sorting each column in the 9772 * row. We do this cache generation at the start of the sort in order that 9773 * the formatting of the sort data need be done only once for each cell 9774 * per sort. This array should not be read from or written to by anything 9775 * other than the master sorting methods. 9776 * @type array 9777 * @default null 9778 * @private 9779 */ 9780 "_aSortData": null, 9781 9782 /** 9783 * Per cell filtering data cache. As per the sort data cache, used to 9784 * increase the performance of the filtering in DataTables 9785 * @type array 9786 * @default null 9787 * @private 9788 */ 9789 "_aFilterData": null, 9790 9791 /** 9792 * Filtering data cache. This is the same as the cell filtering cache, but 9793 * in this case a string rather than an array. This is easily computed with 9794 * a join on `_aFilterData`, but is provided as a cache so the join isn't 9795 * needed on every search (memory traded for performance) 9796 * @type array 9797 * @default null 9798 * @private 9799 */ 9800 "_sFilterRow": null, 9801 9802 /** 9803 * Cache of the class name that DataTables has applied to the row, so we 9804 * can quickly look at this variable rather than needing to do a DOM check 9805 * on className for the nTr property. 9806 * @type string 9807 * @default <i>Empty string</i> 9808 * @private 9809 */ 9810 "_sRowStripe": "", 9811 9812 /** 9813 * Denote if the original data source was from the DOM, or the data source 9814 * object. This is used for invalidating data, so DataTables can 9815 * automatically read data from the original source, unless uninstructed 9816 * otherwise. 9817 * @type string 9818 * @default null 9819 * @private 9820 */ 9821 "src": null, 9822 9823 /** 9824 * Index in the aoData array. This saves an indexOf lookup when we have the 9825 * object, but want to know the index 9826 * @type integer 9827 * @default -1 9828 * @private 9829 */ 9830 "idx": -1 9831 }; 9832 9833 9834 /** 9835 * Template object for the column information object in DataTables. This object 9836 * is held in the settings aoColumns array and contains all the information that 9837 * DataTables needs about each individual column. 9838 * 9839 * Note that this object is related to {@link DataTable.defaults.column} 9840 * but this one is the internal data store for DataTables's cache of columns. 9841 * It should NOT be manipulated outside of DataTables. Any configuration should 9842 * be done through the initialisation options. 9843 * @namespace 9844 */ 9845 DataTable.models.oColumn = { 9846 /** 9847 * Column index. This could be worked out on-the-fly with $.inArray, but it 9848 * is faster to just hold it as a variable 9849 * @type integer 9850 * @default null 9851 */ 9852 "idx": null, 9853 9854 /** 9855 * A list of the columns that sorting should occur on when this column 9856 * is sorted. That this property is an array allows multi-column s
9856orting 9857 * to be defined for a column (for example first name / last name columns 9858 * would benefit from this). The values are integers pointing to the 9859 * columns to be sorted on (typically it will be a single integer pointing 9860 * at itself, but that doesn't need to be the case). 9861 * @type array 9862 */ 9863 "aDataSort": null, 9864 9865 /** 9866 * Define the sorting directions that are applied to the column, in sequence 9867 * as the column is repeatedly sorted upon - i.e. the first value is used 9868 * as the sorting direction when the column if first sorted (clicked on). 9869 * Sort it again (click again) and it will move on to the next index. 9870 * Repeat until loop. 9871 * @type array 9872 */ 9873 "asSorting": null, 9874 9875 /** 9876 * Flag to indicate if the column is searchable, and thus should be included 9877 * in the filtering or not. 9878 * @type boolean 9879 */ 9880 "bSearchable": null, 9881 9882 /** 9883 * Flag to indicate if the column is sortable or not. 9884 * @type boolean 9885 */ 9886 "bSortable": null, 9887 9888 /** 9889 * Flag to indicate if the column is currently visible in the table or not 9890 * @type boolean 9891 */ 9892 "bVisible": null, 9893 9894 /** 9895 * Store for manual type assignment using the `column.type` option. This 9896 * is held in store so we can manipulate the column's `sType` property. 9897 * @type string 9898 * @default null 9899 * @private 9900 */ 9901 "_sManualType": null, 9902 9903 /** 9904 * Flag to indicate if HTML5 data attributes should be used as the data 9905 * source for filtering or sorting. True is either are. 9906 * @type boolean 9907 * @default false 9908 * @private 9909 */ 9910 "_bAttrSrc": false, 9911 9912 /** 9913 * Developer definable function that is called whenever a cell is created (Ajax source, 9914 * etc) or processed for input (DOM source). This can be used as a compliment to mRender 9915 * allowing you to modify the DOM element (add background colour for example) when the 9916 * element is available. 9917 * @type function 9918 * @param {element} nTd The TD node that has been created 9919 * @param {*} sData The Data for the cell 9920 * @param {array|object} oData The data for the whole row 9921 * @param {int} iRow The row index for the aoData data store 9922 * @default null 9923 */ 9924 "fnCreatedCell": null, 9925 9926 /** 9927 * Function to get data from a cell in a column. You should <b>never</b> 9928 * access data directly through _aData internally in DataTables - always use 9929 * the method attached to this property. It allows mData to function as 9930 * required. This function is automatically assigned by the column 9931 * initialisation method 9932 * @type function 9933 * @param {array|object} oData The data array/object for the array 9934 * (i.e. aoData[]._aData) 9935 * @param {string} sSpecific The specific data type you want to get - 9936 * 'display', 'type' 'filter' 'sort' 9937 * @returns {*} The data for the cell from the given row's data 9938 * @default null 9939 */ 9940 "fnGetData": null, 9941 9942 /** 9943 * Function to set data for a cell in the column. You should <b>never</b> 9944 * set the data directly to _aData internally in DataTables - always use 9945 * this method. It allows mData to function as required. This function 9946 * is automatically assigned by the column initialisation method 9947 * @type function 9948 * @param {array|object} oData The data array/object for the array 9949 * (i.e. aoData[]._aData) 9950 * @param {*} sValue Value to set 9951 * @default null 9952 */ 9953 "fnSetData": null, 9954 9955 /** 9956 * Property to read the value for the cells in the column from the data 9957 * source array / object. If null, then the default content is used, if a 9958 * function is given then the return from the function is used. 9959 * @type function|int|string|null 9960 * @default null 9961 */ 9962 "mData": null, 9963 9964 /** 9965 * Partner property to mData which is used (only when defined) to get 9966 * the data - i.e. it is basically the same as mData, but without the 9967 * 'set' option, and also the data fed to it is the result from mData. 9968 * This is the rendering method to match the data method of mData. 9969 * @type function|int|string|null 9970 * @default null 9971 */ 9972 "mRender": null, 9973 9974 /** 9975 * Unique header TH/TD element for this column - this is what the sorting 9976 * listener is attached to (if sorting is enabled.) 9977 * @type node 9978 * @default null 9979 */ 9980 "nTh": null, 9981 9982 /** 9983 * Unique footer TH/TD element for this column (if there is one). Not used
9984 * in DataTables as such, but can be used for plug-ins to reference the 9985 * footer for each column. 9986 * @type node 9987 * @default null 9988 */ 9989 "nTf": null, 9990 9991 /** 9992 * The class to apply to all TD elements in the table's TBODY for the column 9993 * @type string 9994 * @default null 9995 */ 9996 "sClass": null, 9997 9998 /** 9999 * When DataTables calculates the column widths to assign to each column, 10000 * it finds the longest string in each column and then constructs a 10001 * temporary table and reads the widths from that. The problem with this 10002 * is that "mmm" is much wider then "iiii", but the latter is a longer 10003 * string - thus the calculation can go wrong (doing it properly and putting 10004 * it into an DOM object and measuring that is horribly(!) slow). Thus as 10005 * a "work around" we provide this option. It will append its value to the 10006 * text that is found to be the longest string for the column - i.e. padding. 10007 * @type string 10008 */ 10009 "sContentPadding": null, 10010 10011 /** 10012 * Allows a default value to be given for a column's data, and will be used 10013 * whenever a null data source is encountered (this can be because mData 10014 * is set to null, or because the data source itself is null). 10015 * @type string 10016 * @default null 10017 */ 10018 "sDefaultContent": null, 10019 10020 /** 10021 * Name for the column, allowing reference to the column by name as well as 10022 * by index (needs a lookup to work by name). 10023 * @type string 10024 */ 10025 "sName": null, 10026 10027 /** 10028 * Custom sorting data type - defines which of the available plug-ins in 10029 * afnSortData the custom sorting will use - if any is defined. 10030 * @type string 10031 * @default std 10032 */ 10033 "sSortDataType": 'std', 10034 10035 /** 10036 * Class to be applied to the header element when sorting on this column 10037 * @type string 10038 * @default null 10039 */ 10040 "sSortingClass": null, 10041 10042 /** 10043 * Class to be applied to the header element when sorting on this column - 10044 * when jQuery UI theming is used. 10045 * @type string 10046 * @default null 10047 */ 10048 "sSortingClassJUI": null, 10049 10050 /** 10051 * Title of the column - what is seen in the TH element (nTh). 10052 * @type string 10053 */ 10054 "sTitle": null, 10055 10056 /** 10057 * Column sorting and filtering type 10058 * @type string 10059 * @default null 10060 */ 10061 "sType": null, 10062 10063 /** 10064 * Width of the column 10065 * @type string 10066 * @default null 10067 */ 10068 "sWidth": null, 10069 10070 /** 10071 * Width of the column when it was first "encountered" 10072 * @type string 10073 * @default null 10074 */ 10075 "sWidthOrig": null 10076 }; 10077 10078 10079 /* 10080 * Developer note: The properties of the object below are given in Hungarian 10081 * notation, that was used as the interface for DataTables prior to v1.10, however 10082 * from v1.10 onwards the primary interface is camel case. In order to avoid 10083 * breaking backwards compatibility utterly with this change, the Hungarian 10084 * version is still, internally the primary interface, but is is not documented 10085 * - hence the @name tags in each doc comment. This allows a Javascript function 10086 * to create a map from Hungarian notation to camel case (going the other direction 10087 * would require each property to be listed, which would add around 3K to the size 10088 * of DataTables, while this method is about a 0.5K hit). 10089 * 10090 * Ultimately this does pave the way for Hungarian notation to be dropped 10091 * completely, but that is a massive amount of work and will break current 10092 * installs (therefore is on-hold until v2). 10093 */ 10094 10095 /** 10096 * Initialisation options that can be given to DataTables at initialisation 10097 * time. 10098 * @namespace 10099 */ 10100 DataTable.defaults = { 10101 /** 10102 * An array of data to use for the table, passed in at initialisation which 10103 * will be used in preference to any data which is already in the DOM. This is 10104 * particularly useful for constructing tables purely in Javascript, for 10105 * example with a custom Ajax call. 10106 * @type array 10107 * @default null 10108 * 10109 * @dtopt Option 10110 * @name DataTable.defaults.data 10111 * 10112 * @example 10113 * // Using a 2D array data source 10114 * $(document).ready( function () { 10115 * $('#example').dataTable( { 10116 * "data": [ 10117 * ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'], 10118 * ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'], 10119 * ], 10120 * "columns": [ 10121 * { "title": "Engine" }, 10122 * { "title": "Browser" }, 10123 * { "title": "Platform" }, 10124 * { "title": "Version" }, 10125 * { "title": "Grade" } 10126 * ] 10127 * } ); 10128 * } ); 10129 * 10130 * @example 10131 * // Using an array of objects as a data source (`data`) 10132 * $(document).ready( function () { 10133 * $('#example').dataTable( { 10134 * "data": [ 10135 * {
10136 * "engine": "Trident", 10137 * "browser": "Internet Explorer 4.0", 10138 * "platform": "Win 95+", 10139 * "version": 4, 10140 * "grade": "X" 10141 * }, 10142 * { 10143 * "engine": "Trident", 10144 * "browser": "Internet Explorer 5.0", 10145 * "platform": "Win 95+", 10146 * "version": 5, 10147 * "grade": "C" 10148 * } 10149 * ], 10150 * "columns": [ 10151 * { "title": "Engine", "data": "engine" }, 10152 * { "title": "Browser", "data": "browser" }, 10153 * { "title": "Platform", "data": "platform" }, 10154 * { "title": "Version", "data": "version" }, 10155 * { "title": "Grade", "data": "grade" } 10156 * ] 10157 * } ); 10158 * } ); 10159 */ 10160 "aaData": null, 10161 10162 10163 /** 10164 * If ordering is enabled, then DataTables will perform a first pass sort on 10165 * initialisation. You can define which column(s) the sort is performed 10166 * upon, and the sorting direction, with this variable. The `sorting` array 10167 * should contain an array for each column to be sorted initially containing 10168 * the column's index and a direction string ('asc' or 'desc'). 10169 * @type array 10170 * @default [[0,'asc']] 10171 * 10172 * @dtopt Option 10173 * @name DataTable.defaults.order 10174 * 10175 * @example 10176 * // Sort by 3rd column first, and then 4th column 10177 * $(document).ready( function() { 10178 * $('#example').dataTable( { 10179 * "order": [[2,'asc'], [3,'desc']] 10180 * } ); 10181 * } ); 10182 * 10183 * // No initial sorting 10184 * $(document).ready( function() { 10185 * $('#example').dataTable( { 10186 * "order": [] 10187 * } ); 10188 * } ); 10189 */ 10190 "aaSorting": [[0,'asc']], 10191 10192 10193 /** 10194 * This parameter is basically identical to the `sorting` parameter, but 10195 * cannot be overridden by user interaction with the table. What this means 10196 * is that you could have a column (visible or hidden) which the sorting 10197 * will always be forced on first - any sorting after that (from the user) 10198 * will then be performed as required. This can be useful for grouping rows 10199 * together. 10200 * @type array 10201 * @default null 10202 * 10203 * @dtopt Option 10204 * @name DataTable.defaults.orderFixed 10205 * 10206 * @example 10207 * $(document).ready( function() { 10208 * $('#example').dataTable( { 10209 * "orderFixed": [[0,'asc']] 10210 * } ); 10211 * } ) 10212 */ 10213 "aaSortingFixed": [], 10214 10215 10216 /** 10217 * DataTables can be instructed to load data to display in the table from a 10218 * Ajax source. This option defines how that Ajax call is made and where to. 10219 * 10220 * The `ajax` property has three different modes of operation, depending on 10221 * how it is defined. These are: 10222 * 10223 * * `string` - Set the URL from where the data should be loaded from. 10224 * * `object` - Define properties for `jQuery.ajax`. 10225 * * `function` - Custom data get function 10226 * 10227 * `string` 10228 * -------- 10229 * 10230 * As a string, the `ajax` property simply defines the URL from which 10231 * DataTables will load data. 10232 * 10233 * `object` 10234 * -------- 10235 * 10236 * As an object, the parameters in the object are passed to 10237 * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control 10238 * of the Ajax request. DataTables has a number of default parameters which 10239 * you can override using this option. Please refer to the jQuery 10240 * documentation for a full description of the options available, although 10241 * the following parameters provide additional options in DataTables or 10242 * require special consideration: 10243 * 10244 * * `data` - As with jQuery, `data` can be provided as an object, but it 10245 * can also be used as a function to manipulate the data DataTables sends 10246 * to the server. The function takes a single parameter, an object of 10247 * parameters with the values that DataTables has readied for sending. An 10248 * object may be returned which will be merged into the DataTables 10249 * defaults, or you can add the items to the object that was passed in and 10250 * not return anything from the function. This supersedes `fnServerParams` 10251 * from DataTables 1.9-. 10252 * 10253 * * `dataSrc` - By default DataTables will look for the property `data` (or 10254 * `aaData` for compatibility with DataTables 1.9-) when obtaining data 10255 * from an Ajax source or for server-side processing - this parameter 10256 * allows that property to be changed. You can use Javascript dotted 10257 * object notation to get a data source for multiple levels of nesting, or 10258 * it my be used as a function. As a function it takes a single parameter, 10259 * the JSON returned from the server, which can be manipulated as 10260 * required, with the returned value being that used by DataTables as the 10261 * data source for the table. This supersedes `sAjaxDataProp` from 10262 * DataTables 1.9-. 10263 * 10264 * * `success` - Should not be overridden it is used internally in 10265 * DataTables. To manipulate / transform the data returned by the server 10266 * use `ajax.dataSrc`, or use `ajax` as a function (see below). 10267 * 10268 * `function` 10269 * ---------- 10270 * 10271 * As a function, making the Ajax call is left up to yourself allowing 10272 * complete control of the Ajax request. Indeed, if desired, a method other 10273 * than Ajax could be used to obtain the required data, such as Web storage 10274 * or an AIR database. 10275 * 10276 * The function is given four parameters and no return is required. The 10277 * parameters are: 10278 * 10279 * 1. _object_ - Data to send to the server 10280 * 2. _function_ - Callback function that must be executed when the required 10281 * data has been obtained. That data should be passed into the callback 10282 * as the only parameter 10283 * 3. _object_ - DataTables settings object for the table 10284 * 10285 * Note that this supersedes `fnServerData` from DataTables 1.9-. 10286 * 10287 * @type string|object|function 10288 * @default null 10289 * 10290 * @dtopt Option 10291 * @name DataTable.defaults.ajax
10292 * @since 1.10.0 10293 * 10294 * @example 10295 * // Get JSON data from a file via Ajax. 10296 * // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default). 10297 * $('#example').dataTable( { 10298 * "ajax": "data.json" 10299 * } ); 10300 * 10301 * @example 10302 * // Get JSON data from a file via Ajax, using `dataSrc` to change 10303 * // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`) 10304 * $('#example').dataTable( { 10305 * "ajax": { 10306 * "url": "data.json", 10307 * "dataSrc": "tableData" 10308 * } 10309 * } ); 10310 * 10311 * @example 10312 * // Get JSON data from a file via Ajax, using `dataSrc` to read data 10313 * // from a plain array rather than an array in an object 10314 * $('#example').dataTable( { 10315 * "ajax": { 10316 * "url": "data.json", 10317 * "dataSrc": "" 10318 * } 10319 * } ); 10320 * 10321 * @example 10322 * // Manipulate the data returned from the server - add a link to data 10323 * // (note this can, should, be done using `render` for the column - this 10324 * // is just a simple example of how the data can be manipulated). 10325 * $('#example').dataTable( { 10326 * "ajax": { 10327 * "url": "data.json", 10328 * "dataSrc": function ( json ) { 10329 * for ( var i=0, ien=json.length ; i<ien ; i++ ) { 10330 * json[i][0] = '<a href="/message/'+json[i][0]+'>View message</a>'; 10331 * } 10332 * return json; 10333 * } 10334 * } 10335 * } ); 10336 * 10337 * @example 10338 * // Add data to the request 10339 * $('#example').dataTable( { 10340 * "ajax": { 10341 * "url": "data.json", 10342 * "data": function ( d ) { 10343 * return { 10344 * "extra_search": $('#extra').val() 10345 * }; 10346 * } 10347 * } 10348 * } ); 10349 * 10350 * @example 10351 * // Send request as POST 10352 * $('#example').dataTable( { 10353 * "ajax": { 10354 * "url": "data.json", 10355 * "type": "POST" 10356 * } 10357 * } ); 10358 * 10359 * @example 10360 * // Get the data from localStorage (could interface with a form for 10361 * // adding, editing and removing rows). 10362 * $('#example').dataTable( { 10363 * "ajax": function (data, callback, settings) { 10364 * callback( 10365 * JSON.parse( localStorage.getItem('dataTablesData') ) 10366 * ); 10367 * } 10368 * } ); 10369 */ 10370 "ajax": null, 10371 10372 10373 /** 10374 * This parameter allows you to readily specify the entries in the length drop 10375 * down menu that DataTables shows when pagination is enabled. It can be 10376 * either a 1D array of options which will be used for both the displayed 10377 * option and the value, or a 2D array which will use the array in the first 10378 * position as the value, and the array in the second position as the 10379 * displayed options (useful for language strings such as 'All'). 10380 * 10381 * Note that the `pageLength` property will be automatically set to the 10382 * first value given in this array, unless `pageLength` is also provided. 10383 * @type array 10384 * @default [ 10, 25, 50, 100 ] 10385 * 10386 * @dtopt Option 10387 * @name DataTable.defaults.lengthMenu 10388 * 10389 * @example 10390 * $(document).ready( function() { 10391 * $('#example').dataTable( { 10392 * "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]] 10393 * } ); 10394 * } ); 10395 */ 10396 "aLengthMenu": [ 10, 25, 50, 100 ], 10397 10398 10399 /** 10400 * The `columns` option in the initialisation parameter allows you to define 10401 * details about the way individual columns behave. For a full list of 10402 * column options that can be set, please see 10403 * {@link DataTable.defaults.column}. Note that if you use `columns` to 10404 * define your columns, you must have an entry in the array for every single 10405 * column that you have in your table (these can be null if you don't which 10406 * to specify any options). 10407 * @member 10408 * 10409 * @name DataTable.defaults.column 10410 */ 10411 "aoColumns": null, 10412 10413 /** 10414 * Very similar to `columns`, `columnDefs` allows you to target a specific 10415 * column, multiple columns, or all columns, using the `targets` property of 10416 * each object in the array. This allows great flexibility when creating 10417 * tables, as the `columnDefs` arrays can be of any length, targeting the 10418 * columns you specifically want. `columnDefs` may use any of the column 10419 * options available: {@link DataTable.defaults.column}, but it _must_ 10420 * have `targets` defined in each object in the array. Values in the `targets` 10421 * array may be: 10422 * <ul> 10423 * <li>
10423a string - class name will be matched on the TH for the column</li> 10424 * <li>0 or a positive integer - column index counting from the left</li> 10425 * <li>a negative integer - column index counting from the right</li> 10426 * <li>the string "_all" - all columns (i.e. assign a default)</li> 10427 * </ul> 10428 * @member 10429 * 10430 * @name DataTable.defaults.columnDefs 10431 */ 10432 "aoColumnDefs": null, 10433 10434 10435 /** 10436 * Basically the same as `search`, this parameter defines the individual column 10437 * filtering state at initialisation time. The array must be of the same size 10438 * as the number of columns, and each element be an object with the parameters 10439 * `search` and `escapeRegex` (the latter is optional). 'null' is also 10440 * accepted and the default will be used. 10441 * @type array 10442 * @default [] 10443 * 10444 * @dtopt Option 10445 * @name DataTable.defaults.searchCols 10446 * 10447 * @example 10448 * $(document).ready( function() { 10449 * $('#example').dataTable( { 10450 * "searchCols": [ 10451 * null, 10452 * { "search": "My filter" }, 10453 * null, 10454 * { "search": "^[0-9]", "escapeRegex": false } 10455 * ] 10456 * } ); 10457 * } ) 10458 */ 10459 "aoSearchCols": [], 10460 10461 10462 /** 10463 * An array of CSS classes that should be applied to displayed rows. This 10464 * array may be of any length, and DataTables will apply each class 10465 * sequentially, looping when required. 10466 * @type array 10467 * @default null <i>
10467Will take the values determined by the `oClasses.stripe*` 10468 * options</i> 10469 * 10470 * @dtopt Option 10471 * @name DataTable.defaults.stripeClasses 10472 * 10473 * @example 10474 * $(document).ready( function() { 10475 * $('#example').dataTable( { 10476 * "stripeClasses": [ 'strip1', 'strip2', 'strip3' ] 10477 * } ); 10478 * } ) 10479 */ 10480 "asStripeClasses": null, 10481 10482 10483 /** 10484 * Enable or disable automatic column width calculation. This can be disabled 10485 * as an optimisation (it takes some time to calculate the widths) if the 10486 * tables widths are passed in using `columns`. 10487 * @type boolean 10488 * @default true 10489 * 10490 * @dtopt Features 10491 * @name DataTable.defaults.autoWidth 10492 * 10493 * @example 10494 * $(document).ready( function () { 10495 * $('#example').dataTable( { 10496 * "autoWidth": false 10497 * } ); 10498 * } ); 10499 */ 10500 "bAutoWidth": true, 10501 10502 10503 /** 10504 * Deferred rendering can provide DataTables with a huge speed boost when you 10505 * are using an Ajax or JS data source for the table. This option, when set to 10506 * true, will cause DataTables to defer the creation of the table elements for 10507 * each row until they are needed for a draw - saving a significant amount of 10508 * time. 10509 * @type boolean 10510 * @default false 10511 * 10512 * @dtopt Features 10513 * @name DataTable.defaults.deferRender 10514 * 10515 * @example 10516 * $(document).ready( function() { 10517 * $('#example').dataTable( { 10518 * "ajax": "sources/arrays.txt", 10519 * "deferRender": true 10520 * } ); 10521 * } ); 10522 */ 10523 "bDeferRender": false, 10524 10525 10526 /** 10527 * Replace a DataTable which matches the given selector and replace it with 10528 * one which has the properties of the new initialisation object passed. If no 10529 * table matches the selector, then the new DataTable will be constructed as 10530 * per normal. 10531 * @type boolean 10532 * @default false 10533 * 10534 * @dtopt Options 10535 * @name DataTable.defaults.destroy 10536 * 10537 * @example 10538 * $(document).ready( function() { 10539 * $('#example').dataTable( { 10540 * "srollY": "200px", 10541 * "paginate": false 10542 * } ); 10543 * 10544 * // Some time later.... 10545 * $('#example').dataTable( { 10546 * "filter": false, 10547 * "destroy": true 10548 * } ); 10549 * } ); 10550 */ 10551 "bDestroy": false, 10552 10553 10554 /** 10555 * Enable or disable filtering of data. Filtering in DataTables is "smart" in 10556 * that it allows the end user to input multiple words (space separated) and 10557 * will match a row containing those words, even if not in the order that was 10558 * specified (this allow matching across multiple columns). Note that if you 10559 * wish to use filtering in DataTables this must remain 'true' - to remove the 10560 * default filtering input box and retain filtering abilities, please use 10561 * {@link DataTable.defaults.dom}. 10562 * @type boolean 10563 * @default true 10564 * 10565 * @dtopt Features 10566 * @name DataTable.defaults.searching 10567 * 10568 * @example 10569 * $(document).ready( function () { 10570 * $('#example').dataTable( { 10571 * "searching": false 10572 * } ); 10573 * } ); 10574 */ 10575 "bFilter": true, 10576 10577 10578 /** 10579 * Enable or disable the table information display. This shows information 10580 * about the data that is currently visible on the page, including information 10581 * about filtered data if that action is being performed. 10582 * @type boolean 10583 * @default true 10584 * 10585 * @dtopt Features 10586 * @name DataTable.defaults.info 10587 * 10588 * @example 10589 * $(document).ready( function () { 10590 * $('#example').dataTable( { 10591 * "info": false 10592 * } ); 10593 * } ); 10594 */ 10595 "bInfo": true, 10596 10597 10598 /** 10599 * Allows the end user to select the size of a formatted page from a select 10600 * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`). 10601 * @type boolean 10602 * @default true 10603 * 10604 * @dtopt Features 10605 * @name DataTable.defaults.lengthChange 10606 * 10607 * @example 10608 * $(document).ready( function () { 10609 * $('#example').dataTable( { 10610 * "lengthChange": false 10611 * } ); 10612 * } ); 10613 */ 10614 "bLengthChange": true, 10615 10616 10617 /** 10618 * Enable or disable pagination. 10619 * @type boolean 10620 * @default true 10621 * 10622 * @dtopt Features 10623 * @name DataTable.defaults.paging 10624 * 10625 * @example 10626 * $(document).ready( function () { 10627 * $('#example').dataTable( { 10628 * "paging": false 10629 * } ); 10630 * } ); 10631 */ 10632 "bPaginate": true, 10633 10634 10635 /** 10636 * Enable or disable the display of a 'processing' indicator when the table is 10637 * being processed (e.g. a sort). This is particularly useful for tables with 10638 * large amounts of data where it can take a noticeable amount of time to sort 10639 * the entries. 10640 * @type boolean 10641 * @default false 10642 * 10643 * @dtopt Features 10644 * @name DataTable.defaults.processing 10645 * 10646 * @example 10647 * $(document).ready( function () { 10648 * $('#example').dataTable( { 10649 * "processing": true 10650 * } ); 10651 * } ); 10652 */ 10653 "bProcessing": false, 10654 10655 10656 /** 10657 * Retrieve the DataTables object for the given selector. Note that if the 10658 * table has already been initialised, this parameter will cause DataTables 10659 * to simply return the object that has already been set up - it will not take 10660 * account of any changes you might have made to the initialisation object 10661 * passed to DataTables (setting this parameter to true is an acknowledgement 10662 * that you understand this). `destroy` can be used to reinitialise a table if 10663 * you need. 10664 * @type boolean 10665 * @default false 10666 * 10667 * @dtopt Options 10668 * @name DataTable.defaults.retrieve 10669 * 10670 * @example 10671 * $(document).ready( function() { 10672 * initTable(); 10673 * tableActions(); 10674 * } ); 10675 * 10676 * function initTable () 10677 * { 10678 * return $('#example').dataTable( { 10679 * "scrollY": "200px", 10680 * "paginate": false, 10681 * "retrieve": true 10682 * } ); 10683 * } 10684 * 10685 * function tableActions () 10686 * { 10687 * var table = initTable(); 10688 * // perform API operations with oTable 10689 * } 10690 */ 10691 "bRetrieve": false, 10692 10693 10694 /** 10695 * When vertical (y) scrolling is enabled, DataTables will force the height of
10696 * the table's viewport to the given height at all times (useful for layout). 10697 * However, this can look odd when filtering data down to a small data set, 10698 * and the footer is left "floating" further down. This parameter (when 10699 * enabled) will cause DataTables to collapse the table's viewport down when 10700 * the result set will fit within the given Y height. 10701 * @type boolean 10702 * @default false 10703 * 10704 * @dtopt Options 10705 * @name DataTable.defaults.scrollCollapse 10706 * 10707 * @example 10708 * $(document).ready( function() { 10709 * $('#example').dataTable( { 10710 * "scrollY": "200", 10711 * "scrollCollapse": true 10712 * } ); 10713 * } ); 10714 */ 10715 "bScrollCollapse": false, 10716 10717 10718 /** 10719 * Configure DataTables to use server-side processing. Note that the 10720 * `ajax` parameter must also be given in order to give DataTables a 10721 * source to obtain the required data for each draw. 10722 * @type boolean 10723 * @default false 10724 * 10725 * @dtopt Features 10726 * @dtopt Server-side 10727 * @name DataTable.defaults.serverSide 10728 * 10729 * @example 10730 * $(document).ready( function () { 10731 * $('#example').dataTable( { 10732 * "serverSide": true, 10733 * "ajax": "xhr.php" 10734 * } ); 10735 * } ); 10736 */ 10737 "bServerSide": false, 10738 10739 10740 /** 10741 * Enable or disable sorting of columns. Sorting of individual columns can be 10742 * disabled by the `sortable` option for each column. 10743 * @type boolean 10744 * @default true 10745 * 10746 * @dtopt Features 10747 * @name DataTable.defaults.ordering 10748 * 10749 * @example 10750 * $(document).ready( function () { 10751 * $('#example').dataTable( { 10752 * "ordering": false 10753 * } ); 10754 * } ); 10755 */ 10756 "bSort": true, 10757 10758 10759 /** 10760 * Enable or display DataTables' ability to sort multiple columns at the 10761 * same time (activated by shift-click by the user). 10762 * @type boolean 10763 * @default true 10764 * 10765 * @dtopt Options 10766 * @name DataTable.defaults.orderMulti 10767 * 10768 * @example 10769 * // Disable multiple column sorting ability 10770 * $(document).ready( function () { 10771 * $('#example').dataTable( { 10772 * "orderMulti": false 10773 * } ); 10774 * } ); 10775 */ 10776 "bSortMulti": true, 10777 10778 10779 /** 10780 * Allows control over whether DataTables should use the top (true) unique 10781 * cell that is found for a single column, or the bottom (false - default). 10782 * This is useful when using complex headers. 10783 * @type boolean 10784 * @default false 10785 * 10786 * @dtopt Options 10787 * @name DataTable.defaults.orderCellsTop 10788 * 10789 * @example 10790 * $(document).ready( function() { 10791 * $('#example').dataTable( { 10792 * "orderCellsTop": true 10793 * } ); 10794 * } ); 10795 */ 10796 "bSortCellsTop": false, 10797 10798 10799 /** 10800 * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and 10801 * `sorting\_3` to the columns which are currently being sorted on. This is 10802 * presented as a feature switch as it can increase processing time (while 10803 * classes are removed and added) so for large data sets you might want to 10804 * turn this off. 10805 * @type boolean 10806 * @default true 10807 * 10808 * @dtopt Features 10809 * @name DataTable.defaults.orderClasses 10810 * 10811 * @example 10812 * $(document).ready( function () { 10813 * $('#example').dataTable( { 10814 * "orderClasses": false 10815 * } ); 10816 * } ); 10817 */ 10818 "bSortClasses": true, 10819 10820 10821 /** 10822 * Enable or disable state saving. When enabled HTML5 `localStorage` will be 10823 * used to save table display information such as pagination information, 10824 * display length, filtering and sorting. As such when the end user reloads 10825 * the page the display display will match what thy had previously set up. 10826 * 10827 * Due to the use of `localStorage` the default state saving is not supported 10828 * in IE6 or 7. If state saving is required in those browsers, use 10829 * `stateSaveCallback` to provide a storage solution such as cookies. 10830 * @type boolean 10831 * @default false 10832 * 10833 * @dtopt Features 10834 * @name DataTable.defaults.stateSave 10835 * 10836 * @example 10837 * $(document).ready( function () { 10838 * $('#example').dataTable( { 10839 * "stateSave": true 10840 * } ); 10841 * } ); 10842 */ 10843 "bStateSave": false, 10844 10845 10846 /** 10847 * This function is called when a TR element is created (and all TD child 10848 * elements have been inserted), or registered if using a DOM source, allowing 10849 * manipulation of the TR element (adding classes etc). 10850 * @type function 10851 * @param {node} row "TR" element for the current row 10852 * @param {array} data Raw data array for this row 10853 * @param {int} dataIndex The index of this row in the internal aoData array 10854 * 10855 * @dtopt Callbacks 10856 * @name DataTable.defaults.createdRow 10857 * 10858 * @example 10859 * $(document).ready( function() { 10860 * $('#example').dataTable( { 10861 * "createdRow": function( row, data, dataIndex ) { 10862 * // Bold the grade for all 'A' grade browsers 10863 * if ( data[4] == "A" ) 10864 * { 10865 * $('td:eq(4)', row).html( '<b>A</b>' ); 10866 * } 10867 * } 10868 * } ); 10869 * } ); 10870 */ 10871 "fnCreatedRow": null, 10872 10873 10874 /** 10875 * This function is called on every 'draw' event, and allows you to 10876 * dynamically modify any aspect you want about the created DOM. 10877 * @type function 10878 * @param {object} settings DataTables settings object 10879 * 10880 * @dtopt Callbacks 10881 * @name DataTable.defaults.drawCallback 10882 * 10883 * @example 10884 * $(document).ready( function() { 10885 * $('#example').dataTable( { 10886 * "drawCallback": function( settings ) { 10887 * alert( 'DataTables has redrawn the table' ); 10888 * } 10889 * } ); 10890 * } ); 10891 */ 10892 "fnDrawCallback": null, 10893 10894 10895 /** 10896 * Identical to fnHeaderCallback() but for the table footer this function 10897 * allows you to modify the table footer on every 'draw' event. 10898 * @type function 10899 * @param {node} foot "TR" element for the footer 10900 * @param {array} data Full table data (as derived from the original HTML) 10901 * @param {int} start Index for the current display starting point in the 10902 * display array 10903 * @param {int} end Index for the current display ending point in the 10904 * display array 10905 * @param {array int} display Index array to translate the visual position 10906 * to the full data array 10907 * 10908 * @dtopt Callbacks 10909 * @name DataTable.defaults.footerCallback 10910 * 10911 * @example 10912 * $(document).ready( function() { 10913 * $('#example').dataTable( { 10914 * "footerCallback": function( tfoot, data, start, end, display ) { 10915 * tfoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+start; 10916 * } 10917 * } ); 10918 * } ) 10919 */ 10920 "fnFooterCallback": null, 10921 10922 10923 /** 10924 * When rendering large numbers in the information element for the table 10925 * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers 10926 * to have a comma separator for the 'thousands' units (e.g. 1 million is 10927 * rendered as "1,000,000") to help readability for the end user. This 10928 * function will override the default method DataTables uses. 10929 * @type function 10930 * @member 10931 * @param {int} toFormat number to be formatted 10932 * @returns {string} formatted string for DataTables to show the number 10933 * 10934 * @dtopt Callbacks 10935 * @name DataTable.defaults.formatNumber 10936 * 10937 * @example 10938 * // Format a number using a single quote for the separator (note that
10939 * // this can also be done with the language.thousands option) 10940 * $(document).ready( function() { 10941 * $('#example').dataTable( { 10942 * "formatNumber": function ( toFormat ) { 10943 * return toFormat.toString().replace( 10944 * /\B(?=(\d{3})+(?!\d))/g, "'" 10945 * ); 10946 * }; 10947 * } ); 10948 * } ); 10949 */ 10950 "fnFormatNumber": function ( toFormat ) { 10951 return toFormat.toString().replace( 10952 /\B(?=(\d{3})+(?!\d))/g, 10953 this.oLanguage.sThousands 10954 ); 10955 }, 10956 10957 10958 /** 10959 * This function is called on every 'draw' event, and allows you to 10960 * dynamically modify the header row. This can be used to calculate and 10961 * display useful information about the table. 10962 * @type function 10963 * @param {node} head "TR" element for the header 10964 * @param {array} data Full table data (as derived from the original HTML) 10965 * @param {int} start Index for the current display starting point in the 10966 * display array 10967 * @param {int} end Index for the current display ending point in the 10968 * display array 10969 * @param {array int} display Index array to translate the visual position 10970 * to the full data array 10971 * 10972 * @dtopt Callbacks 10973 * @name DataTable.defaults.headerCallback 10974 * 10975 * @example 10976 * $(document).ready( function() { 10977 * $('#example').dataTable( { 10978 * "fheaderCallback": function( head, data, start, end, display ) { 10979 * head.getElementsByTagName('th')[0].innerHTML = "Displaying "+(end-start)+" records"; 10980 * } 10981 * } ); 10982 * } ) 10983 */ 10984 "fnHeaderCallback": null, 10985 10986 10987 /** 10988 * The information element can be used to convey information about the current 10989 * state of the table. Although the internationalisation options presented by 10990 * DataTables are quite capable of dealing with most customisations, there may 10991 * be times where you wish to customise the string further. This callback 10992 * allows you to do exactly that. 10993 * @type function 10994 * @param {object} oSettings DataTables settings object 10995 * @param {int} start Starting position in data for the draw 10996 * @param {int} end End position in data for the draw 10997 * @param {int} max Total number of rows in the table (regardless of 10998 * filtering) 10999 * @param {int} total Total number of rows in the data set, after filtering 11000 * @param {string} pre The string that DataTables has formatted using it's 11001 * own rules 11002 * @returns {string} The string to be displayed in the information element. 11003 * 11004 * @dtopt Callbacks 11005 * @name DataTable.defaults.infoCallback 11006 * 11007 * @example 11008 * $('#example').dataTable( { 11009 * "infoCallback": function( settings, start, end, max, total, pre ) { 11010 * return start +" to "+ end; 11011 * } 11012 * } ); 11013 */ 11014 "fnInfoCallback": null, 11015 11016 11017 /** 11018 * Called when the table has been initialised. Normally DataTables will 11019 * initialise sequentially and there will be no need for this function, 11020 * however, this does not hold true when using external language information 11021 * since that is obtained using an async XHR call. 11022 * @type function 11023 * @param {object} settings DataTables settings object 11024 * @param {object} json The JSON object request from the server - only 11025 * present if client-side Ajax sourced data is used 11026 * 11027 * @dtopt Callbacks 11028 * @name DataTable.defaults.initComplete 11029 * 11030 * @example 11031 * $(document).ready( function() { 11032 * $('#example').dataTable( { 11033 * "initComplete": function(settings, json) { 11034 * alert( 'DataTables has finished its initialisation.' ); 11035 * } 11036 * } ); 11037 * } ) 11038 */ 11039 "fnInitComplete": null, 11040 11041 11042 /** 11043 * Called at the very start of each table draw and can be used to cancel the 11044 * draw by returning false, any other return (including undefined) results in 11045 * the full draw occurring). 11046 * @type function 11047 * @param {object} settings DataTables settings object 11048 * @returns {boolean} False will cancel the draw, anything else (including no 11049 * return) will allow it to complete. 11050 * 11051 * @dtopt Callbacks 11052 * @name DataTable.defaults.preDrawCallback 11053 * 11054 * @example 11055 * $(document).ready( function() { 11056 * $('#example').dataTable( { 11057 * "preDrawCallback": function( settings ) { 11058 * if ( $('#test').val() == 1 ) { 11059 * return false; 11060 * } 11061 * } 11062 * } ); 11063 * } ); 11064 */ 11065 "fnPreDrawCallback": null, 11066 11067 11068 /** 11069 * This function allows you to 'post process' each row after it have been 11070 * generated for each table draw, but before it is rendered on screen. This 11071 * function might be used for setting the row class name etc. 11072 * @type function 11073 * @param {node} row "TR" element for the current row 11074 * @param {array} data Raw data array for this row 11075 * @param {int} displayIndex The display index for the current table draw 11076 * @param {int} displayIndexFull The index of the data in the full list of 11077 * rows (after filtering) 11078 * 11079 * @dtopt Callbacks 11080 * @name DataTable.defaults.rowCallback 11081 * 11082 * @example 11083 * $(document).ready( function() { 11084 * $('#example').dataTable( { 11085 * "rowCallback": function( row, data, displayIndex, displayIndexFull ) { 11086 * // Bold the grade for all 'A' grade browsers 11087 * if ( data[4] == "A" ) { 11088 * $('td:eq(4)', row).html( '<b>A</b>' ); 11089 * } 11090 * } 11091 * } ); 11092 * } ); 11093 */ 11094 "fnRowCallback": null, 11095 11096 11097 /** 11098 * __Deprecated__ The functionality provided by this parameter has now been 11099 * superseded by that provided through `ajax`, which should be used instead. 11100 * 11101 * This parameter allows you to override the default function which obtains 11102 * the data from the server so something more suitable for your application. 11103 * For example you could use POST data, or pull information from a Gears or 11104 * AIR database. 11105 * @type function 11106 * @member 11107 * @param {string} source HTTP source to obtain the data from (`ajax`) 11108 * @param {array}
11108 data A key/value pair object containing the data to send 11109 * to the server 11110 * @param {function} callback to be called on completion of the data get 11111 * process that will draw the data on the page. 11112 * @param {object} settings DataTables settings object 11113 * 11114 * @dtopt Callbacks 11115 * @dtopt Server-side 11116 * @name DataTable.defaults.serverData 11117 * 11118 * @deprecated 1.10. Please use `ajax` for this functionality now. 11119 */ 11120 "fnServerData": null, 11121 11122 11123 /** 11124 * __Deprecated__ The functionality provided by this parameter has now been 11125 * superseded by that provided through `ajax`, which should be used instead. 11126 * 11127 * It is often useful to send extra data to the server when making an Ajax 11128 * request - for example custom filtering information, and this callback 11129 * function makes it trivial to send extra information to the server. The 11130 * passed in parameter is the data set that has been constructed by 11131 * DataTables, and you can add to this or modify it as you require. 11132 * @type function 11133 * @param {array} data Data array (array of objects which are name/value 11134 * pairs) that has been constructed by DataTables and will be sent to the 11135 * server. In the case of Ajax sourced data with server-side processing 11136 * this will be an empty array, for server-side processing there will be a 11137 * significant number of parameters! 11138 * @returns {undefined} Ensure that you modify the data array passed in, 11139 * as this is passed by reference. 11140 * 11141 * @dtopt Callbacks 11142 * @dtopt Server-side 11143 * @name DataTable.defaults.serverParams 11144 * 11145 * @deprecated 1.10. Please use `ajax` for this functionality now. 11146 */ 11147 "fnServerParams": null, 11148 11149 11150 /** 11151 * Load the table state. With this function you can define from where, and how, the 11152 * state of a table is loaded. By default DataTables will load from `localStorage` 11153 * but you might wish to use a server-side database or cookies. 11154 * @type function 11155 * @member 11156 * @param {object} settings DataTables settings object 11157 * @param {object} callback Callback that can be executed when done. It 11158 * should be passed the loaded state object. 11159 * @return {object} The DataTables state object to be loaded 11160 * 11161 * @dtopt Callbacks 11162 * @name DataTable.defaults.stateLoadCallback 11163 * 11164 * @example 11165 * $(document).ready( function() { 11166 * $('#example').dataTable( { 11167 * "stateSave": true, 11168 * "stateLoadCallback": function (settings, callback) { 11169 * $.ajax( { 11170 * "url": "/state_load", 11171 * "dataType": "json", 11172 * "success": function (json) { 11173 * callback( json ); 11174 * } 11175 * } ); 11176 * } 11177 * } ); 11178 * } ); 11179 */ 11180 "fnStateLoadCallback": function ( settings ) { 11181 try { 11182 return JSON.parse( 11183 (settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem( 11184 'DataTables_'+settings.sInstance+'_'+location.pathname 11185 ) 11186 ); 11187 } catch (e) { 11188 return {}; 11189 } 11190 }, 11191 11192 11193 /** 11194 * Callback which allows modification of the saved state prior to loading that state. 11195 * This callback is called when the table is loading state from the stored data, but 11196 * prior to the settings object being modified by the saved state. Note that for 11197 * plug-in authors, you should use the `stateLoadParams` event to load parameters for 11198 * a plug-in. 11199 * @type function 11200 * @param {object} settings DataTables settings object 11201 * @param {object} data The state object that is to be loaded 11202 * 11203 * @dtopt Callbacks 11204 * @name DataTable.defaults.stateLoadParams 11205 * 11206 * @example 11207 * // Remove a saved filter, so filtering is never loaded 11208 * $(document).ready( function() { 11209 * $('#example').dataTable( { 11210 * "stateSave": true, 11211 * "stateLoadParams": function (settings, data) { 11212 * data.oSearch.sSearch = ""; 11213 * } 11214 * } ); 11215 * } ); 11216 * 11217 * @example 11218 * // Disallow state loading by returning false 11219 * $(document).ready( function() { 11220 * $('#example').dataTable( { 11221 * "stateSave": true, 11222 * "stateLoadParams": function (settings, data) { 11223 * return false; 11224 * } 11225 * } ); 11226 * } ); 11227 */ 11228 "fnStateLoadParams": null, 11229 11230 11231 /** 11232 * Callback that is called when the state has been loaded from the state saving method 11233 * and the DataTables settings object has been modified as a result of the loaded state. 11234 * @type function 11235 * @param {object} settings DataTables settings object 11236 * @param {object} data The state object that was loaded 11237 * 11238 * @dtopt Callbacks 11239 * @name DataTable.defaults.stateLoaded 11240 * 11241 * @example 11242 * // Show an alert with the filtering value that was saved 11243 * $(document).ready( function() { 11244 * $('#example').dataTable( { 11245 * "stateSave": true, 11246 * "stateLoaded": function (settings, data) { 11247 * alert( 'Saved filter was: '+data.oSearch.sSearch ); 11248 * } 11249 * } ); 11250 * } ); 11251 */ 11252 "fnStateLoaded": null, 11253 11254 11255 /** 11256 * Save the table state. This function allows you to define where and how the state 11257 * information for the table is stored By default DataTables will use `localStorage` 11258 * but you might wish to use a server-side database or cookies. 11259 * @type function 11260 * @member 11261 * @param {object} settings DataTables settings object 11262 * @param {object} data The state object to be saved 11263 * 11264 * @dtopt Callbacks 11265 * @name DataTable.defaults.stateSaveCallback 11266 * 11267 * @example 11268 * $(document).ready( function() { 11269 * $('#example').dataTable( { 11270 * "stateSave": true, 11271 * "stateSaveCallback": function (settings, data) { 11272 * // Send an Ajax request to the server with the state object 11273 * $.ajax( { 11274 * "url": "/state_save", 11275 * "data": data, 11276 * "dataType": "json", 11277 * "method": "POST" 11278 * "success": function () {} 11279 * } ); 11280 * } 11281 * } ); 11282 * } ); 11283 */ 11284 "fnStateSaveCallback": function ( settings, data ) { 11285 try {
11286 (settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem( 11287 'DataTables_'+settings.sInstance+'_'+location.pathname, 11288 JSON.stringify( data ) 11289 ); 11290 } catch (e) {} 11291 }, 11292 11293 11294 /** 11295 * Callback which allows modification of the state to be saved. Called when the table 11296 * has changed state a new state save is required. This method allows modification of 11297 * the state saving object prior to actually doing the save, including addition or 11298 * other state properties or modification. Note that for plug-in authors, you should 11299 * use the `stateSaveParams` event to save parameters for a plug-in. 11300 * @type function 11301 * @param {object} settings DataTables settings object 11302 * @param {object} data The state object to be saved 11303 * 11304 * @dtopt Callbacks 11305 * @name DataTable.defaults.stateSaveParams 11306 * 11307 * @example 11308 * // Remove a saved filter, so filtering is never saved 11309 * $(document).ready( function() { 11310 * $('#example').dataTable( { 11311 * "stateSave": true, 11312 * "stateSaveParams": function (settings, data) { 11313 * data.oSearch.sSearch = ""; 11314 * } 11315 * } ); 11316 * } ); 11317 */ 11318 "fnStateSaveParams": null, 11319 11320 11321 /** 11322 * Duration for which the saved state information is considered valid. After this period 11323 * has elapsed the state will be returned to the default. 11324 * Value is given in seconds. 11325 * @type int 11326 * @default 7200 <i>(2 hours)</i> 11327 * 11328 * @dtopt Options 11329 * @name DataTable.defaults.stateDuration 11330 * 11331 * @example 11332 * $(document).ready( function() { 11333 * $('#example').dataTable( { 11334 * "stateDuration": 60*60*24; // 1 day 11335 * } ); 11336 * } ) 11337 */ 11338 "iStateDuration": 7200, 11339 11340 11341 /** 11342 * When enabled DataTables will not make a request to the server for the first 11343 * page draw - rather it will use the data already on the page (no sorting etc 11344 * will be applied to it), thus saving on an XHR at load time. `deferLoading` 11345 * is used to indicate that deferred loading is required, but it is also used 11346 * to tell DataTables how many records there are in the full table (allowing 11347 * the information element and pagination to be displayed correctly). In the case 11348 * where a filtering is applied to the table on initial load, this can be 11349 * indicated by giving the parameter as an array, where the first element is 11350 * the number of records available after filtering and the second element is the 11351 * number of records without filtering (allowing the table information element 11352 * to be shown correctly). 11353 * @type int | array 11354 * @default null 11355 * 11356 * @dtopt Options 11357 * @name DataTable.defaults.deferLoading 11358 * 11359 * @example 11360 * // 57 records available in the table, no filtering applied 11361 * $(document).ready( function() { 11362 * $('#example').dataTable( { 11363 * "serverSide": true, 11364 * "ajax": "scripts/server_processing.php", 11365 * "deferLoading": 57 11366 * } ); 11367 * } ); 11368 * 11369 * @example 11370 * // 57 records after filtering, 100 without filtering (an initial filter applied) 11371 * $(document).ready( function() { 11372 * $('#example').dataTable( { 11373 * "serverSide": true, 11374 * "ajax": "scripts/server_processing.php", 11375 * "deferLoading": [ 57, 100 ], 11376 * "search": { 11377 * "search": "my_filter" 11378 * } 11379 * } ); 11380 * } ); 11381 */ 11382 "iDeferLoading": null, 11383 11384 11385 /** 11386 * Number of rows to display on a single page when using pagination. If 11387 * feature enabled (`lengthChange`) then the end user will be able to override 11388 * this to a custom setting using a pop-up menu. 11389 * @type int 11390 * @default 10 11391 * 11392 * @dtopt Options 11393 * @name DataTable.defaults.pageLength 11394 * 11395 * @example 11396 * $(document).ready( function() { 11397 * $('#example').dataTable( { 11398 * "pageLength": 50 11399 * } ); 11400 * } ) 11401 */ 11402 "iDisplayLength": 10, 11403 11404 11405 /** 11406 * Define the starting point for data display when using DataTables with 11407 * pagination. Note that this parameter is the number of records, rather than 11408 * the page number, so if you have 10 records per page and want to start on 11409 * the third page, it should be "20". 11410 * @type int 11411 * @default 0 11412 * 11413 * @dtopt Options 11414 * @name DataTable.defaults.displayStart
11415 * 11416 * @example 11417 * $(document).ready( function() { 11418 * $('#example').dataTable( { 11419 * "displayStart": 20 11420 * } ); 11421 * } ) 11422 */ 11423 "iDisplayStart": 0, 11424 11425 11426 /** 11427 * By default DataTables allows keyboard navigation of the table (sorting, paging, 11428 * and filtering) by adding a `tabindex` attribute to the required elements. This 11429 * allows you to tab through the controls and press the enter key to activate them. 11430 * The tabindex is default 0, meaning that the tab follows the flow of the document. 11431 * You can overrule this using this parameter if you wish. Use a value of -1 to 11432 * disable built-in keyboard navigation. 11433 * @type int 11434 * @default 0 11435 * 11436 * @dtopt Options 11437 * @name DataTable.defaults.tabIndex 11438 * 11439 * @example 11440 * $(document).ready( function() { 11441 * $('#example').dataTable( { 11442 * "tabIndex": 1 11443 * } ); 11444 * } ); 11445 */ 11446 "iTabIndex": 0, 11447 11448 11449 /** 11450 * Classes that DataTables assigns to the various components and features 11451 * that it adds to the HTML table. This allows classes to be configured 11452 * during initialisation in addition to through the static 11453 * {@link DataTable.ext.oStdClasses} object). 11454 * @namespace 11455 * @name DataTable.defaults.classes 11456 */ 11457 "oClasses": {}, 11458 11459 11460 /** 11461 * All strings that DataTables uses in the user interface that it creates 11462 * are defined in this object, allowing you to modified them individually or 11463 * completely replace them all as required. 11464 * @namespace 11465 * @name DataTable.defaults.language 11466 */ 11467 "oLanguage": { 11468 /** 11469 * Strings that are used for WAI-ARIA labels and controls only (these are not 11470 * actually visible on the page, but will be read by screenreaders, and thus 11471 * must be internationalised as well). 11472 * @namespace 11473 * @name DataTable.defaults.language.aria 11474 */ 11475 "oAria": { 11476 /** 11477 * ARIA label that is added to the table headers when the column may be 11478 * sorted ascending by activing the column (click or return when focused). 11479 * Note that the column header is prefixed to this string. 11480 * @type string 11481 * @default : activate to sort column ascending 11482 * 11483 * @dtopt Language 11484 * @name DataTable.defaults.language.aria.sortAscending 11485 * 11486 * @example 11487 * $(document).ready( function() { 11488 * $('#example').dataTable( { 11489 * "language": { 11490 * "aria": { 11491 * "sortAscending": " - click/return to sort ascending" 11492 * } 11493 * } 11494 * } ); 11495 * } ); 11496 */ 11497 "sSortAscending": ": activate to sort column ascending", 11498 11499 /** 11500 * ARIA label that is added to the table headers when the column may be 11501 * sorted descending by activing the column (click or return when focused). 11502 * Note that the column header is prefixed to this string. 11503 * @type string 11504 * @default : activate to sort column ascending 11505 * 11506 * @dtopt Language 11507 * @name DataTable.defaults.language.aria.sortDescending 11508 * 11509 * @example 11510 * $(document).ready( function() { 11511 * $('#example').dataTable( { 11512 * "language": { 11513 * "aria": { 11514 * "sortDescending": " - click/return to sort descending" 11515 * } 11516 * } 11517 * } ); 11518 * } ); 11519 */ 11520 "sSortDescending": ": activate to sort column descending" 11521 }, 11522 11523 /** 11524 * Pagination string used by DataTables for the built-in pagination 11525 * control types. 11526 * @namespace 11527 * @name DataTable.defaults.language.paginate 11528 */ 11529 "oPaginate": { 11530 /** 11531 * Text to use when using the 'full_numbers' type of pagination for the 11532 * button to take the user to the first page. 11533 * @type string 11534 * @default First 11535 * 11536 * @dtopt Language 11537 * @name DataTable.defaults.language.paginate.first 11538 * 11539 * @example 11540 * $(document).ready( function() { 11541 * $('#example').dataTable( { 11542 * "language": { 11543 * "paginate": { 11544 * "first": "First page" 11545 * } 11546 * } 11547 * } ); 11548 * } ); 11549 */ 11550 "sFirst": "First", 11551 11552 11553 /** 11554 * Text to use when using the 'full_numbers' type of pagination for the 11555 * button to take the user to the last page. 11556 * @type string 11557 * @default Last 11558 * 11559 * @dtopt Language 11560 * @name DataTable.defaults.language.paginate.last 11561 * 11562 * @example 11563 * $(document).ready( function() { 11564 * $('#example').dataTable( { 11565 * "language": { 11566 * "paginate": { 11567 * "last": "Last page" 11568 * } 11569 * } 11570 * } ); 11571 * } ); 11572 */ 11573 "sLast": "Last", 11574 11575 11576 /** 11577 * Text to use for the 'next' pagination button (to take the user to the 11578 * next page). 11579 * @type string 11580 * @default Next 11581 * 11582 * @dtopt Language 11583 * @name DataTable.defaults.language.paginate.next 11584 * 11585 * @example 11586 * $(document).ready( function() { 11587 * $('#example').dataTable( { 11588 * "language": { 11589 * "paginate": { 11590 * "next": "Next page" 11591 * } 11592 * } 11593 * } ); 11594 * } ); 11595 */ 11596 "sNext": "Next", 11597 11598 11599 /** 11600 * Text to use for the 'previous' pagination button (to take the user to 11601 * the previous page). 11602 * @type string 11603 * @default Previous 11604 * 11605 * @dtopt Language 11606 * @name DataTable.defaults.language.paginate.previous 11607 * 11608 * @example 11609 * $(document).ready( function() { 11610 * $('#example').dataTable( { 11611 * "language": { 11612 * "paginate": { 11613 * "previous": "Previous page" 11614 * } 11615 * } 11616 * } ); 11617 * } ); 11618 */ 11619 "sPrevious": "Previous" 11620 }, 11621 11622 /** 11623 * This string is shown in preference to `zeroRecords` when the table is 11624 * empty of data (regardless of filtering). Note that this is an optional 11625 * parameter - if it is not given, the value of `zeroRecords` will be used 11626 * instead (either the default or given value). 11627 * @type string 11628 * @default No data available in table 11629 * 11630 * @dtopt Language 11631 * @name DataTable.defaults.language.emptyTable 11632 * 11633 * @example 11634 * $(document).ready( function() { 11635 * $('#example').dataTable( { 11636 * "language": { 11637 * "emptyTable": "No data available in table" 11638 * } 11639 * } ); 11640 * } ); 11641 */ 11642 "sEmptyTable": "No data available in table", 11643 11644 11645 /** 11646 * This string gives information to the end user about the information 11647 * that is current on display on the page. The following tokens can be 11648 * used in the string and will be dynamically replaced as the table 11649 * display updates. This tokens can be placed anywhere in the string, or 11650 * removed as needed by the language requires: 11651 * 11652 * * `\_START\_` - Display index of the first record on the current page 11653 * * `\_END\_` - Display index of the last record on the current page 11654 * * `\_TOTAL\_` - Number of records in the table after filtering 11655 * * `\_MAX\_` - Number of records in the table without filtering 11656 * * `\_PAGE\_` - Current page number 11657 * * `\_PAGES\_` - Total number of pages of data in the table 11658 * 11659 * @type string 11660 * @default Showing _START_ to _END_ of _TOTAL_ entries 11661 * 11662 * @dtopt Language 11663 * @name DataTable.defaults.language.info 11664 * 11665 * @example 11666 * $(document).ready( function() { 11667 * $('#example').dataTable( { 11668 * "language": { 11669 * "info": "Showing page _PAGE_ of _PAGES_" 11670 * } 11671 * } ); 11672 * } ); 11673 */ 11674 "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries", 11675 11676 11677 /**
11678 * Display information string for when the table is empty. Typically the 11679 * format of this string should match `info`. 11680 * @type string 11681 * @default Showing 0 to 0 of 0 entries 11682 * 11683 * @dtopt Language 11684 * @name DataTable.defaults.language.infoEmpty 11685 * 11686 * @example 11687 * $(document).ready( function() { 11688 * $('#example').dataTable( { 11689 * "language": { 11690 * "infoEmpty": "No entries to show" 11691 * } 11692 * } ); 11693 * } ); 11694 */ 11695 "sInfoEmpty": "Showing 0 to 0 of 0 entries", 11696 11697 11698 /** 11699 * When a user filters the information in a table, this string is appended 11700 * to the information (`info`) to give an idea of how strong the filtering 11701 * is. The variable _MAX_ is dynamically updated. 11702 * @type string 11703 * @default (filtered from _MAX_ total entries) 11704 * 11705 * @dtopt Language 11706 * @name DataTable.defaults.language.infoFiltered 11707 * 11708 * @example 11709 * $(document).ready( function() { 11710 * $('#example').dataTable( { 11711 * "language": { 11712 * "infoFiltered": " - filtering from _MAX_ records" 11713 * } 11714 * } ); 11715 * } ); 11716 */ 11717 "sInfoFiltered": "(filtered from _MAX_ total entries)", 11718 11719 11720 /** 11721 * If can be useful to append extra information to the info string at times, 11722 * and this variable does exactly that. This information will be appended to 11723 * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are 11724 * being used) at all times. 11725 * @type string 11726 * @default <i>Empty string</i> 11727 * 11728 * @dtopt Language 11729 * @name DataTable.defaults.language.infoPostFix 11730 * 11731 * @example 11732 * $(document).ready( function() { 11733 * $('#example').dataTable( { 11734 * "language": { 11735 * "infoPostFix": "All records shown are derived from real information." 11736 * } 11737 * } ); 11738 * } ); 11739 */ 11740 "sInfoPostFix": "", 11741 11742 11743 /** 11744 * This decimal place operator is a little different from the other 11745 * language options since DataTables doesn't output floating point 11746 * numbers, so it won't ever use this for display of a number. Rather, 11747 * what this parameter does is modify the sort methods of the table so 11748 * that numbers which are in a format which has a character other than 11749 * a period (`.`) as a decimal place will be sorted numerically. 11750 * 11751 * Note that numbers with different decimal places cannot be shown in 11752 * the same table and still be sortable, the table must be consistent. 11753 * However, multiple different tables on the page can use different 11754 * decimal place characters. 11755 * @type string 11756 * @default 11757 * 11758 * @dtopt Language 11759 * @name DataTable.defaults.language.decimal 11760 * 11761 * @example 11762 * $(document).ready( function() { 11763 * $('#example').dataTable( { 11764 * "language": { 11765 * "decimal": "," 11766 * "thousands": "." 11767 * } 11768 * } ); 11769 * } ); 11770 */ 11771 "sDecimal": "", 11772 11773 11774 /** 11775 * DataTables has a build in number formatter (`formatNumber`) which is 11776 * used to format large numbers that are used in the table information. 11777 * By default a comma is used, but this can be trivially changed to any 11778 * character you wish with this parameter. 11779 * @type string 11780 * @default , 11781 * 11782 * @dtopt Language 11783 * @name DataTable.defaults.language.thousands 11784 * 11785 * @example 11786 * $(document).ready( function() { 11787 * $('#example').dataTable( { 11788 * "language": { 11789 * "thousands": "'" 11790 * } 11791 * } ); 11792 * } ); 11793 */ 11794 "sThousands": ",", 11795 11796 11797 /** 11798 * Detail the action that will be taken when the drop down menu for the 11799 * pagination length option is changed. The '_MENU_' variable is replaced 11800 * with a default select list of 10, 25, 50 and 100, and can be replaced 11801 * with a custom select box if required. 11802 * @type string 11803 * @default Show _MENU_ entries 11804 * 11805 * @dtopt Language 11806 * @name DataTable.defaults.language.lengthMenu 11807 * 11808 * @example 11809 * // Language change only 11810 * $(document).ready( function() { 11811 * $('#example').dataTable( { 11812 * "language": {
11813 * "lengthMenu": "Display _MENU_ records" 11814 * } 11815 * } ); 11816 * } ); 11817 * 11818 * @example 11819 * // Language and options change 11820 * $(document).ready( function() { 11821 * $('#example').dataTable( { 11822 * "language": { 11823 * "lengthMenu": 'Display <select>'+ 11824 * '<option value="10">10</option>'+ 11825 * '<option value="20">20</option>'+ 11826 * '<option value="30">30</option>'+ 11827 * '<option value="40">40</option>'+ 11828 * '<option value="50">50</option>'+ 11829 * '<option value="-1">All</option>'+ 11830 * '</select> records' 11831 * } 11832 * } ); 11833 * } ); 11834 */ 11835 "sLengthMenu": "Show _MENU_ entries", 11836 11837 11838 /** 11839 * When using Ajax sourced data and during the first draw when DataTables is 11840 * gathering the data, this message is shown in an empty row in the table to 11841 * indicate to the end user the the data is being loaded. Note that this 11842 * parameter is not used when loading data by server-side processing, just 11843 * Ajax sourced data with client-side processing. 11844 * @type string 11845 * @default Loading... 11846 * 11847 * @dtopt Language 11848 * @name DataTable.defaults.language.loadingRecords 11849 * 11850 * @example 11851 * $(document).ready( function() { 11852 * $('#example').dataTable( { 11853 * "language": { 11854 * "loadingRecords": "Please wait - loading..." 11855 * } 11856 * } ); 11857 * } ); 11858 */ 11859 "sLoadingRecords": "Loading...", 11860 11861 11862 /** 11863 * Text which is displayed when the table is processing a user action 11864 * (usually a sort command or similar). 11865 * @type string 11866 * 11867 * @dtopt Language 11868 * @name DataTable.defaults.language.processing 11869 * 11870 * @example 11871 * $(document).ready( function() { 11872 * $('#example').dataTable( { 11873 * "language": { 11874 * "processing": "DataTables is currently busy" 11875 * } 11876 * } ); 11877 * } ); 11878 */ 11879 "sProcessing": "", 11880 11881 11882 /** 11883 * Details the actions that will be taken when the user types into the 11884 * filtering input text box. The variable "_INPUT_", if used in the string, 11885 * is replaced with the HTML text box for the filtering input allowing 11886 * control over where it appears in the string. If "_INPUT_" is not given 11887 * then the input box is appended to the string automatically. 11888 * @type string 11889 * @default Search: 11890 * 11891 * @dtopt Language 11892 * @name DataTable.defaults.language.search 11893 * 11894 * @example 11895 * // Input text box will be appended at the end automatically 11896 * $(document).ready( function() { 11897 * $('#example').dataTable( { 11898 * "language": { 11899 * "search": "Filter records:" 11900 * } 11901 * } ); 11902 * } ); 11903 * 11904 * @example 11905 * // Specify where the filter should appear 11906 * $(document).ready( function() { 11907 * $('#example').dataTable( { 11908 * "language": { 11909 * "search": "Apply filter _INPUT_ to table" 11910 * } 11911 * } ); 11912 * } ); 11913 */ 11914 "sSearch": "Search:", 11915 11916 11917 /** 11918 * Assign a `placeholder` attribute to the search `input` element 11919 * @type string 11920 * @default 11921 * 11922 * @dtopt Language 11923 * @name DataTable.defaults.language.searchPlaceholder 11924 */ 11925 "sSearchPlaceholder": "", 11926 11927 11928 /** 11929 * All of the language information can be stored in a file on the 11930 * server-side, which DataTables will look up if this parameter is passed. 11931 * It must store the URL of the language file, which is in a JSON format, 11932 * and the object has the same properties as the oLanguage object in the 11933 * initialiser object (i.e. the above parameters). Please refer to one of 11934 * the example language files to see how this works in action. 11935 * @type string 11936 * @default <i>Empty string - i.e. disabled</i> 11937 * 11938 * @dtopt Language 11939 * @name DataTable.defaults.language.url 11940 * 11941 * @example 11942 * $(document).ready( function() { 11943 * $('#example').dataTable( { 11944 * "language": { 11945 * "url": "http://www.sprymedia.co.uk/dataTables/lang.txt" 11946 * } 11947 * } ); 11948 * } ); 11949 */ 11950 "sUrl": "", 11951 11952 11953 /** 11954 * Text shown inside the table records when the is no information to be 11955 * displayed after filtering. `emptyTable` is shown when there is simply no 11956 * information in the table at all (regardless of filtering). 11957 * @type string
11958 * @default No matching records found 11959 * 11960 * @dtopt Language 11961 * @name DataTable.defaults.language.zeroRecords 11962 * 11963 * @example 11964 * $(document).ready( function() { 11965 * $('#example').dataTable( { 11966 * "language": { 11967 * "zeroRecords": "No records to display" 11968 * } 11969 * } ); 11970 * } ); 11971 */ 11972 "sZeroRecords": "No matching records found" 11973 }, 11974 11975 11976 /** 11977 * This parameter allows you to have define the global filtering state at 11978 * initialisation time. As an object the `search` parameter must be 11979 * defined, but all other parameters are optional. When `regex` is true, 11980 * the search string will be treated as a regular expression, when false 11981 * (default) it will be treated as a straight string. When `smart` 11982 * DataTables will use it's smart filtering methods (to word match at 11983 * any point in the data), when false this will not be done. 11984 * @namespace 11985 * @extends DataTable.models.oSearch 11986 * 11987 * @dtopt Options 11988 * @name DataTable.defaults.search 11989 * 11990 * @example 11991 * $(document).ready( function() { 11992 * $('#example').dataTable( { 11993 * "search": {"search": "Initial search"} 11994 * } ); 11995 * } ) 11996 */ 11997 "oSearch": $.extend( {}, DataTable.models.oSearch ), 11998 11999 12000 /** 12001 * __Deprecated__ The functionality provided by this parameter has now been 12002 * superseded by that provided through `ajax`, which should be used instead. 12003 * 12004 * By default DataTables will look for the property `data` (or `aaData` for 12005 * compatibility with DataTables 1.9-) when obtaining data from an Ajax 12006 * source or for server-side processing - this parameter allows that 12007 * property to be changed. You can use Javascript dotted object notation to 12008 * get a data source for multiple levels of nesting. 12009 * @type string 12010 * @default data 12011 * 12012 * @dtopt Options 12013 * @dtopt Server-side 12014 * @name DataTable.defaults.ajaxDataProp 12015 * 12016 * @deprecated 1.10. Please use `ajax` for this functionality now. 12017 */ 12018 "sAjaxDataProp": "data", 12019 12020 12021 /** 12022 * __Deprecated__ The functionality provided by this parameter has now been 12023 * superseded by that provided through `ajax`, which should be used instead. 12024 * 12025 * You can instruct DataTables to load data from an external 12026 * source using this parameter (use aData if you want to pass data in you 12027 * already have). Simply provide a url a JSON object can be obtained from. 12028 * @type string 12029 * @default null 12030 * 12031 * @dtopt Options 12032 * @dtopt Server-side 12033 * @name DataTable.defaults.ajaxSource 12034 * 12035 * @deprecated 1.10. Please use `ajax` for this functionality now. 12036 */ 12037 "sAjaxSource": null, 12038 12039 12040 /** 12041 * This initialisation variable allows you to specify exactly where in the 12042 * DOM you want DataTables to inject the various controls it adds to the page 12043 * (for example you might want the pagination controls at the top of the 12044 * table). DIV elements (with or without a custom class) can also be added to 12045 * aid styling. The follow syntax is used: 12046 * <ul> 12047 * <li>The following options are allowed: 12048 * <ul> 12049 * <li>'l' - Length changing</li> 12050 * <li>'f' - Filtering input</li> 12051 * <li>'t' - The table!</li> 12052 * <li>'i' - Information</li> 12053 * <li>'p' - Pagination</li> 12054 * <li>'r' - pRocessing</li> 12055 * </ul> 12056 * </li> 12057 * <li>The following constants are allowed: 12058 * <ul> 12059 * <li>'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li> 12060 * <li>'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li> 12061 * </ul> 12062 * </li> 12063 * <li>The following syntax is expected: 12064 * <ul> 12065 * <li>'<' and '>' - div elements</li> 12066 * <li>'<"class" and '>' - div with a class</li> 12067 * <li>'<"#id" and '>' - div with an ID</li> 12068 * </ul> 12069 * </li> 12070 * <li>Examples: 12071 * <ul> 12072 * <li>'<"wrapper"flipt>'</li> 12073 * <li>'<lf<t>ip>'</li> 12074 * </ul> 12075 * </li> 12076 * </ul> 12077 * @type string 12078 * @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b> 12079 * <"H"lfr>t<"F"ip> <i>(when `jQueryUI` is true)</i> 12080 * 12081 * @dtopt Options 12082 * @name DataTable.defaults.dom 12083 * 12084 * @example 12085 * $(document).ready( function() { 12086 * $('#example').dataTable( { 12087 * "dom": '<"top"i>rt<"bottom"flp><"clear">'
12088 * } ); 12089 * } ); 12090 */ 12091 "sDom": "lfrtip", 12092 12093 12094 /** 12095 * Search delay option. This will throttle full table searches that use the 12096 * DataTables provided search input element (it does not effect calls to 12097 * `dt-api search()`, providing a delay before the search is made. 12098 * @type integer 12099 * @default 0 12100 * 12101 * @dtopt Options 12102 * @name DataTable.defaults.searchDelay 12103 * 12104 * @example 12105 * $(document).ready( function() { 12106 * $('#example').dataTable( { 12107 * "searchDelay": 200 12108 * } ); 12109 * } ) 12110 */ 12111 "searchDelay": null, 12112 12113 12114 /** 12115 * DataTables features six different built-in options for the buttons to 12116 * display for pagination control: 12117 * 12118 * * `numbers` - Page number buttons only 12119 * * `simple` - 'Previous' and 'Next' buttons only 12120 * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers 12121 * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons 12122 * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus page numbers 12123 * * `first_last_numbers` - 'First' and 'Last' buttons, plus page numbers 12124 * 12125 * Further methods can be added using {@link DataTable.ext.oPagination}. 12126 * @type string 12127 * @default simple_numbers 12128 * 12129 * @dtopt Options 12130 * @name DataTable.defaults.pagingType 12131 * 12132 * @example 12133 * $(document).ready( function() { 12134 * $('#example').dataTable( { 12135 * "pagingType": "full_numbers" 12136 * } ); 12137 * } ) 12138 */ 12139 "sPaginationType": "simple_numbers", 12140 12141 12142 /** 12143 * Enable horizontal scrolling. When a table is too wide to fit into a 12144 * certain layout, or you have a large number of columns in the table, you 12145 * can enable x-scrolling to show the table in a viewport, which can be 12146 * scrolled. This property can be `true` which will allow the table to 12147 * scroll horizontally when needed, or any CSS unit, or a number (in which 12148 * case it will be treated as a pixel measurement). Setting as simply `true` 12149 * is recommended. 12150 * @type boolean|string 12151 * @default <i>blank string - i.e. disabled</i> 12152 * 12153 * @dtopt Features 12154 * @name DataTable.defaults.scrollX 12155 * 12156 * @example 12157 * $(document).ready( function() { 12158 * $('#example').dataTable( { 12159 * "scrollX": true, 12160 * "scrollCollapse": true 12161 * } ); 12162 * } ); 12163 */ 12164 "sScrollX": "", 12165 12166 12167 /** 12168 * This property can be used to force a DataTable to use more width than it 12169 * might otherwise do when x-scrolling is enabled. For example if you have a 12170 * table which requires to be well spaced, this parameter is useful for 12171 * "over-sizing" the table, and thus forcing scrolling. This property can by 12172 * any CSS unit, or a number (in which case it will be treated as a pixel 12173 * measurement). 12174 * @type string 12175 * @default <i>blank string - i.e. disabled</i> 12176 * 12177 * @dtopt Options 12178 * @name DataTable.defaults.scrollXInner 12179 * 12180 * @example 12181 * $(document).ready( function() { 12182 * $('#example').dataTable( { 12183 * "scrollX": "100%", 12184 * "scrollXInner": "110%" 12185 * } ); 12186 * } ); 12187 */ 12188 "sScrollXInner": "", 12189 12190 12191 /** 12192 * Enable vertical scrolling. Vertical scrolling will constrain the DataTable 12193 * to the given height, and enable scrolling for any data which overflows the 12194 * current viewport. This can be used as an alternative to paging to display 12195 * a lot of data in a small area (although paging and scrolling can both be 12196 * enabled at the same time). This property can be any CSS unit, or a number 12197 * (in which case it will be treated as a pixel measurement). 12198 * @type string 12199 * @default <i>blank string - i.e. disabled</i> 12200 * 12201 * @dtopt Features 12202 * @name DataTable.defaults.scrollY 12203 * 12204 * @example 12205 * $(document).ready( function() { 12206 * $('#example').dataTable( { 12207 * "scrollY": "200px", 12208 * "paginate": false 12209 * } ); 12210 * } ); 12211 */ 12212 "sScrollY": "", 12213 12214 12215 /** 12216 * __Deprecated__ The functionality provided by this parameter has now been 12217 * superseded by that provided through `ajax`, which should be used instead. 12218 * 12219 * Set the HTTP method that is used to make the Ajax call for server-side 12220 * processing or Ajax sourced data. 12221 * @type string 12222 * @default GET 12223 * 12224 * @dtopt Options 12225 * @dtopt Server-side 12226 * @name DataTable.defaults.serverMethod 12227 * 12228 * @deprecated 1.10. Please use `ajax` for this functionality now. 12229 */ 12230 "sServerMethod": "GET", 12231 12232 12233 /** 12234 * DataTables makes use of renderers when displaying HTML elements for 12235 * a table. These renderers can be added or modified by plug-ins to 12236 * generate suitable mark-up for a site. For example the Bootstrap 12237 * integration plug-in for DataTables uses a paging button renderer to 12238 * display pagination buttons in the mark-up required by Bootstrap. 12239 * 12240 * For further information about the renderers available see 12241 * DataTable.ext.renderer 12242 * @type string|object 12243 * @default null 12244 * 12245 * @name DataTable.defaults.renderer 12246 * 12247 */ 12248 "renderer": null, 12249 12250 12251 /** 12252 * Set the data property name that DataTables should use to get a row's id 12253 * to set as the `id` property in the node. 12254 * @type string 12255 * @default DT_RowId 12256 * 12257 * @name DataTable.defaults.rowId 12258 */ 12259 "rowId": "DT_RowId" 12260 }; 12261 12262 _fnHungarianMap( DataTable.defaults ); 12263 12264 12265 12266 /* 12267 * Developer note - See note in model.defaults.js about the use of Hungarian 12268 * notation and camel case. 12269 */ 12270 12271 /** 12272 * Column options that can be given to DataTables at initialisation time. 12273 * @namespace 12274 */ 12275 DataTable.defaults.column = { 12276 /** 12277 * Define which column(s) an order will occur on for this column. This 12278 * allows a column's ordering to take multiple columns into account when
12279 * doing a sort or use the data from a different column. For example first 12280 * name / last name columns make sense to do a multi-column sort over the 12281 * two columns. 12282 * @type array|int 12283 * @default null <i>Takes the value of the column index automatically</i> 12284 * 12285 * @name DataTable.defaults.column.orderData 12286 * @dtopt Columns 12287 * 12288 * @example 12289 * // Using `columnDefs` 12290 * $(document).ready( function() { 12291 * $('#example').dataTable( { 12292 * "columnDefs": [ 12293 * { "orderData": [ 0, 1 ], "targets": [ 0 ] }, 12294 * { "orderData": [ 1, 0 ], "targets": [ 1 ] }, 12295 * { "orderData": 2, "targets": [ 2 ] } 12296 * ] 12297 * } ); 12298 * } ); 12299 * 12300 * @example 12301 * // Using `columns` 12302 * $(document).ready( function() { 12303 * $('#example').dataTable( { 12304 * "columns": [ 12305 * { "orderData": [ 0, 1 ] }, 12306 * { "orderData": [ 1, 0 ] }, 12307 * { "orderData": 2 }, 12308 * null, 12309 * null 12310 * ] 12311 * } ); 12312 * } ); 12313 */ 12314 "aDataSort": null, 12315 "iDataSort": -1, 12316 12317 12318 /** 12319 * You can control the default ordering direction, and even alter the 12320 * behaviour of the sort handler (i.e. only allow ascending ordering etc) 12321 * using this parameter. 12322 * @type array 12323 * @default [ 'asc', 'desc' ] 12324 * 12325 * @name DataTable.defaults.column.orderSequence 12326 * @dtopt Columns 12327 * 12328 * @example 12329 * // Using `columnDefs` 12330 * $(document).ready( function() { 12331 * $('#example').dataTable( { 12332 * "columnDefs": [ 12333 * { "orderSequence": [ "asc" ], "targets": [ 1 ] }, 12334 * { "orderSequence": [ "desc", "asc", "asc" ], "targets": [ 2 ] }, 12335 * { "orderSequence": [ "desc" ], "targets": [ 3 ] } 12336 * ] 12337 * } ); 12338 * } ); 12339 * 12340 * @example 12341 * // Using `columns` 12342 * $(document).ready( function() { 12343 * $('#example').dataTable( { 12344 * "columns": [ 12345 * null, 12346 * { "orderSequence": [ "asc" ] }, 12347 * { "orderSequence": [ "desc", "asc", "asc" ] }, 12348 * { "orderSequence": [ "desc" ] }, 12349 * null 12350 * ] 12351 * } ); 12352 * } ); 12353 */ 12354 "asSorting": [ 'asc', 'desc' ], 12355 12356 12357 /** 12358 * Enable or disable filtering on the data in this column. 12359 * @type boolean 12360 * @default true 12361 * 12362 * @name DataTable.defaults.column.searchable 12363 * @dtopt Columns 12364 * 12365 * @example 12366 * // Using `columnDefs` 12367 * $(document).ready( function() { 12368 * $('#example').dataTable( { 12369 * "columnDefs": [ 12370 * { "searchable": false, "targets": [ 0 ] } 12371 * ] } ); 12372 * } ); 12373 * 12374 * @example 12375 * // Using `columns` 12376 * $(document).ready( function() { 12377 * $('#example').dataTable( { 12378 * "columns": [ 12379 * { "searchable": false }, 12380 * null, 12381 * null, 12382 * null, 12383 * null 12384 * ] } ); 12385 * } ); 12386 */ 12387 "bSearchable": true, 12388 12389 12390 /** 12391 * Enable or disable ordering on this column. 12392 * @type boolean 12393 * @default true 12394 * 12395 * @name DataTable.defaults.column.orderable 12396 * @dtopt Columns 12397 * 12398 * @example 12399 * // Using `columnDefs` 12400 * $(document).ready( function() { 12401 * $('#example').dataTable( { 12402 * "columnDefs": [ 12403 * { "orderable": false, "targets": [ 0 ] } 12404 * ] } ); 12405 * } ); 12406 * 12407 * @example 12408 * // Using `columns` 12409 * $(document).ready( function() { 12410 * $('#example').dataTable( { 12411 * "columns": [ 12412 * { "orderable": false }, 12413 * null, 12414 * null, 12415 * null, 12416 * null 12417 * ] } ); 12418 * } ); 12419 */ 12420 "bSortable": true, 12421 12422 12423 /** 12424 * Enable or disable the display of this column. 12425 * @type boolean 12426 * @default true 12427 * 12428 * @name DataTable.defaults.column.visible 12429 * @dtopt Columns 12430 * 12431 * @example 12432 * // Using `columnDefs` 12433 * $(document).ready( function() { 12434 * $('#example').dataTable( { 12435 * "columnDefs": [ 12436 * { "visible": false, "targets": [ 0 ] } 12437 * ] } ); 12438 * } ); 12439 * 12440 * @example 12441 * // Using `columns` 12442 * $(document).ready( function() { 12443 * $('#example').dataTable( { 12444 * "columns": [ 12445 * { "visible": false }, 12446 * null, 12447 * null, 12448 * null, 12449 * null 12450 * ] } ); 12451 * } ); 12452 */ 12453 "bVisible": true, 12454 12455 12456 /** 12457 * Developer definable function that is called whenever a cell is created (Ajax source, 12458 * etc) or processed for input (DOM source). This can be used as a compliment to mRender 12459 * allowing you to modify the DOM element (add background colour for example) when the 12460 * element is available. 12461 * @type function 12462 * @param {element} td The TD node that has been created 12463 * @param {*} cellData The Data for the cell 12464 * @param {array|object} rowData The data for the whole row 12465 * @param {int} row The row index for the aoData data store 12466 * @param {int} col The column index for aoColumns 12467 * 12468 * @name DataTable.defaults.column.createdCell 12469 * @dtopt Columns 12470 * 12471 * @example 12472 * $(document).ready( function() { 12473 * $('#example').dataTable( { 12474 * "columnDefs": [ { 12475 * "targets": [3], 12476 * "createdCell": function (td, cellData, rowData, row, c
12476ol) { 12477 * if ( cellData == "1.7" ) { 12478 * $(td).css('color', 'blue') 12479 * } 12480 * } 12481 * } ] 12482 * }); 12483 * } ); 12484 */ 12485 "fnCreatedCell": null, 12486 12487 12488 /** 12489 * This parameter has been replaced by `data` in DataTables to ensure naming 12490 * consistency. `dataProp` can still be used, as there is backwards 12491 * compatibility in DataTables for this option, but it is strongly 12492 * recommended that you use `data` in preference to `dataProp`. 12493 * @name DataTable.defaults.column.dataProp 12494 */ 12495 12496 12497 /** 12498 * This property can be used to read data from any data source property, 12499 * including deeply nested objects / properties. `data` can be given in a 12500 * number of different ways which effect its behaviour: 12501 * 12502 * * `integer` - treated as an array index for the data source. This is the 12503 * default that DataTables uses (incrementally increased for each column). 12504 * * `string` - read an object property from the data source. There are 12505 * three 'special' options that can be used in the string to alter how 12506 * DataTables reads the data from the source object: 12507 * * `.` - Dotted Javascript notation. Just as you use a `.` in 12508 * Javascript to read from nested objects, so to can the options 12509 * specified in `data`. For example: `browser.version` or 12510 * `browser.name`. If your object parameter name contains a period, use 12511 * `\\` to escape it - i.e. `first\\.name`. 12512 * * `[]` - Array notation. DataTables can automatically combine data 12513 * from and array source, joining the data with the characters provided 12514 * between the two brackets. For example: `name[, ]` would provide a 12515 * comma-space separated list from the source array. If no characters 12516 * are provided between the brackets, the original array source is 12517 * returned. 12518 * * `()` - Function notation. Adding `()` to the end of a parameter will 12519 * execute a function of the name given. For example: `browser()` for a 12520 * simple function on the data source, `browser.version()` for a 12521 * function in a nested property or even `browser().version` to get an 12522 * object property if the function called returns an object. Note that 12523 * function notation is recommended for use in `render` rather than 12524 * `data` as it is much simpler to use as a renderer. 12525 * * `null` - use the original data source for the row rather than plucking 12526 * data directly from it. This action has effects on two other 12527 * initialisation options: 12528 * * `defaultContent` - When null is given as the `data` option and 12529 * `defaultContent` is specified for the column, the value defined by 12530 * `defaultContent` will be used for the cell. 12531 * * `render` - When null is used for the `data` option and the `render` 12532 * option is specified for the column, the whole data source for the 12533 * row is used for the renderer. 12534 * * `function` - the function given will be executed whenever DataTables 12535 * needs to set or get the data for a cell in the column. The function 12536 * takes three parameters: 12537 * * Parameters: 12538 * * `{array|object}` The data source for the row 12539 * * `{string}` The type call data requested - this will be 'set' when 12540 * setting data or 'filter', 'display', 'type', 'sort' or undefined 12541 * when gathering data. Note that when `undefined` is given for the 12542 * type DataTables expects to get the raw data for the object back< 12543 * * `{*}` Data to set when the second parameter is 'set'. 12544 * * Return: 12545 * * The return value from the function is not required when 'set' is 12546 * the type of call, but otherwise the return is what will be used 12547 * for the data requested. 12548 * 12549 * Note that `data` is a getter and setter option. If you just require 12550 * formatting of data for output, you will likely want to use `render` which 12551 * is simply a getter and thus simpler to use. 12552 * 12553 * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The 12554 * name change reflects the flexibility of this property and is consistent 12555 * with the naming of mRender. If 'mDataProp' is given, then it will still 12556 * be used by DataTables, as it automatically maps the old name to the new 12557 * if required. 12558 * 12559 * @type string|int|function|null 12560 * @default null <i>Use automatically calculated column index</i> 12561 * 12562 * @name DataTable.defaults.column.data 12563 * @dtopt Columns 12564 * 12565 * @example 12566 * // Read table data from objects 12567 * // JSON structure for each row: 12568 * // { 12569 * // "engine": {value}, 12570 * // "browser": {value}, 12571 * // "platform": {value}, 12572 * // "version": {value}, 12573 * // "grade": {value} 12574 * // } 12575 * $(document).ready( function() { 12576 * $('#example').dataTable( { 12577 * "ajaxSource": "sources/objects.txt", 12578 * "columns": [ 12579 * { "data": "engine" }, 12580 * { "data": "browser" }, 12581 * { "data": "platform" }, 12582 * { "data": "version" }, 12583 * { "data": "grade" } 12584 * ] 12585 * } ); 12586 * } ); 12587 * 12588 * @example 12589 * // Read information from deeply nested objects 12590 * // JSON structure for each row: 12591 * // { 12592 * // "engine": {value}, 12593 * // "browser": {value}, 12594 * // "platform": { 12595 * // "inner": {value} 12596 * // }, 12597 * // "details": [ 12598 * // {value}, {value} 12599 * // ] 12600 * // } 12601 * $(document).ready( function() { 12602 * $('#example').dataTable( { 12603 * "ajaxSource": "sources/deep.txt", 12604 * "columns": [ 12605 * { "data": "engine" }, 12606 * { "data": "browser" }, 12607 * { "data": "platform.inner" }, 12608 * { "data": "details.0" }, 12609 * { "data": "details.1" } 12610 * ] 12611 * } ); 12612 * } ); 12613 * 12614 * @example 12615 * // Using `data` as a function to provide different information for 12616 * // sorting, filtering and display. In this case, currency (price) 12617 * $(document).ready( function() { 12618 * $('#example').dataTable( { 12619 * "columnDefs": [ { 12620 * "targets": [ 0 ], 12621 * "data": function ( source, type, val ) { 12622 * if (type === 'set') { 12623 * source.price = val; 12624 * // Store the computed display and filter values for efficiency 12625 * source.price_display = val=="" ? "" : "$"+numberFormat(val); 12626 * source.price_filter = val=="" ? "" : "$"+numberFormat(val)+" "+val; 12627 * return; 12628 * } 12629 * else if (type === 'display') { 12630 * return source.price_display; 12631 * } 12632 * else if (type === 'filter') { 12633 * return source.price_filter; 12634 * } 12635 * // 'sort', 'type' and undefined all just use the integer 12636 * return source.price; 12637 * } 12638 * } ] 12639 * } ); 12640 * } ); 12641 * 12642 * @example 12643 * // Using default content 12644 * $(document).ready( function() { 12645 * $('#example').dataTable( { 12646 * "columnDefs": [ { 12647 * "targets": [ 0 ], 12648 * "data": null, 12649 * "defaultContent": "Click to edit" 12650 * } ] 12651 * } ); 12652 * } ); 12653 * 12654 * @example 12655 * // Using array notation - outputting a list from an array 12656 * $(document).ready( function() { 12657 * $('#example').dataTable( { 12658 * "columnDefs": [ { 12659 * "targets": [ 0 ], 12660 * "data": "name[, ]" 12661 * } ] 12662 * } ); 12663 * } ); 12664 * 12665 */ 12666 "mData": null, 12667 12668 12669 /** 12670 * This property is the rendering partner to `data` and it is suggested that 12671 * when you want to manipulate data for display (including filtering, 12672 * sorting etc) without altering the underlying data for the table, use this 12673 * property. `render` can be considered to be the the read only companion to 12674 * `data` which is read / write (then as such more complex). Like `data` 12675 * this option can be given in a number of different ways to effect its 12676 * behaviour: 12677 * 12678 * * `integer` - treated as an array index for the data source. This is the 12679 * default that DataTables uses (incrementally increased for each column). 12680 * * `string` - read an object property from the data source. There are 12681 * three 'special' options that can be used in the string to alter how 12682 * DataTables reads the data from the source object: 12683 * * `.` - Dotted Javascript notation. Just as you use a `.` in 12684 * Javascript to read from nested objects, so to can the options 12685 * specified in `data`. For example: `browser.version` or 12686 * `browser.name`. If your object parameter name contains a period, use 12687 * `\\` to escape it - i.e. `first\\.name`. 12688 * * `[]` - Array notation. DataTables can automatically combine data 12689 * from and array source, joining the data with the characters provided 12690 * between the two brackets. For example: `name[, ]` would provide a 12691 * comma-space separated list from the source array. If no characters 12692 * are provided between the brackets, the original array source is 12693 * returned. 12694 * * `()` - Function notation. Adding `()` to the end of a parameter will 12695 * execute a function of the name given. For example: `browser()` for a 12696 * simple function on the data source, `browser.version()` for a 12697 * function in a nested property or even `browser().version` to get an 12698 * object property if the function called returns an object. 12699 * * `object` - use different data for the different data types requested by 12700 * DataTables ('filter', 'display', 'type' or 'sort'). The property names 12701 * of the object is the data type the property refers to and the value can 12702 * defined using an integer, string or function using the same rules as 12703 * `render` normally does. Note that an `_` option _must_ be specified. 12704 * This is the default value to use if you haven't specified a value for 12705 * the data type requested by DataTables. 12706 * * `function` - the function given will be executed whenever DataTables 12707 * needs to set or get the data for a cell in the column. The function 12708 * takes three parameters: 12709 * * Parameters: 12710 * * {array|object} The data source for the row (based on `data`) 12711 * * {string} The type call data requested - this will be 'filter', 12712 * 'display', 'type' or 'sort'. 12713 * * {array|object} The full data source for the row (not based on 12714 * `data`) 12715 * * Return: 12716 * * The return value from the function is what will be used for the 12717 * data requested. 12718 * 12719 * @type string|int|function|object|null 12720 * @default null Use the data source value. 12721 * 12722 * @name DataTable.defaults.column.render 12723 * @dtopt Columns 12724 * 12725 * @example 12726 * // Create a comma separated list from an array of objects 12727 * $(document).ready( function() { 12728 * $('#example').dataTable( { 12729 * "ajaxSource": "sources/deep.txt", 12730 * "columns": [ 12731 * { "data": "engine" }, 12732 * { "data": "browser" }, 12733 * { 12734 * "data": "platform", 12735 * "render": "[, ].name" 12736 * } 12737 * ] 12738 * } ); 12739 * } ); 12740 * 12741 * @example 12742 * // Execute a function to obtain data 12743 * $(document).ready( function() { 12744 * $('#example').dataTable( { 12745 * "columnDefs": [ { 12746 * "targets": [ 0 ], 12747 * "data": null, // Use the full data source object for the renderer's source 12748 * "render": "browserName()" 12749 * } ] 12750 * } ); 12751 * } ); 12752 * 12753 * @example 12754 * // As an object, extracting different data for the different types 12755 * // This would be used with a data source such as: 12756 * // { "phone": 5552368, "phone_filter": "5552368 555-2368", "phone_display": "555-2368" } 12757 * // Here the `phone` integer is used for sorting and type detection, while `phone_filter` 12758 * // (which has both forms) is used for filtering for if a user inputs either format, while 12759 * // the formatted phone number is the one that is shown in the table. 12760 * $(document).ready( function() { 12761 * $('#example').dataTable( { 12762 * "columnDefs": [ { 12763 * "targets": [ 0 ], 12764 * "data": null, // Use the full data source object for the renderer's source 12765 * "render": { 12766 * "_": "phone", 12767 * "filter": "phone_filter", 12768 * "display": "phone_display" 12769 * } 12770 * } ] 12771 * } ); 12772 * } ); 12773 * 12774 * @example 12775 * // Use as a function to create a link from the data source 12776 * $(document).ready( function() { 12777 * $('#example').dataTable( { 12778 * "columnDefs": [ { 12779 * "targets": [ 0 ], 12780 * "data": "download_link", 12781 * "render": function ( data, type, full ) { 12782 * return '<a href="'+data+'">Download</a>'; 12783 * } 12784 * } ] 12785 * } ); 12786 * } ); 12787 */ 12788 "mRender": null, 12789 12790 12791 /** 12792 * Change the cell type created for the column - either TD cells or TH cells. This 12793 * can be useful as TH cells have semantic meaning in the table body, allowing them 12794 * to act as a header for a row (you may wish to add scope='row' to the TH elements). 12795 * @type string 12796 * @default td 12797 * 12798 * @name DataTable.defaults.column.cellType
12799 * @dtopt Columns 12800 * 12801 * @example 12802 * // Make the first column use TH cells 12803 * $(document).ready( function() { 12804 * $('#example').dataTable( { 12805 * "columnDefs": [ { 12806 * "targets": [ 0 ], 12807 * "cellType": "th" 12808 * } ] 12809 * } ); 12810 * } ); 12811 */ 12812 "sCellType": "td", 12813 12814 12815 /** 12816 * Class to give to each cell in this column. 12817 * @type string 12818 * @default <i>Empty string</i> 12819 * 12820 * @name DataTable.defaults.column.class 12821 * @dtopt Columns 12822 * 12823 * @example 12824 * // Using `columnDefs` 12825 * $(document).ready( function() { 12826 * $('#example').dataTable( { 12827 * "columnDefs": [ 12828 * { "class": "my_class", "targets": [ 0 ] } 12829 * ] 12830 * } ); 12831 * } ); 12832 * 12833 * @example 12834 * // Using `columns` 12835 * $(document).ready( function() { 12836 * $('#example').dataTable( { 12837 * "columns": [ 12838 * { "class": "my_class" }, 12839 * null, 12840 * null, 12841 * null, 12842 * null 12843 * ] 12844 * } ); 12845 * } ); 12846 */ 12847 "sClass": "", 12848 12849 /** 12850 * When DataTables calculates the column widths to assign to each column, 12851 * it finds the longest string in each column and then constructs a 12852 * temporary table and reads the widths from that. The problem with this 12853 * is that "mmm" is much wider then "iiii", but the latter is a longer 12854 * string - thus the calculation can go wrong (doing it properly and putting 12855 * it into an DOM object and measuring that is horribly(!) slow). Thus as 12856 * a "work around" we provide this option. It will append its value to the 12857 * text that is found to be the longest string for the column - i.e. padding. 12858 * Generally you shouldn't need this! 12859 * @type string 12860 * @default <i>Empty string<i> 12861 * 12862 * @name DataTable.defaults.column.contentPadding 12863 * @dtopt Columns 12864 * 12865 * @example 12866 * // Using `columns` 12867 * $(document).ready( function() { 12868 * $('#example').dataTable( { 12869 * "columns": [ 12870 * null, 12871 * null, 12872 * null, 12873 * { 12874 * "contentPadding": "mmm" 12875 * } 12876 * ] 12877 * } ); 12878 * } ); 12879 */ 12880 "sContentPadding": "", 12881 12882 12883 /** 12884 * Allows a default value to be given for a column's data, and will be used 12885 * whenever a null data source is encountered (this can be because `data` 12886 * is set to null, or because the data source itself is null). 12887 * @type string 12888 * @default null 12889 * 12890 * @name DataTable.defaults.column.defaultContent 12891 * @dtopt Columns 12892 * 12893 * @example 12894 * // Using `columnDefs` 12895 * $(document).ready( function() { 12896 * $('#example').dataTable( { 12897 * "columnDefs": [ 12898 * { 12899 * "data": null, 12900 * "defaultContent": "Edit", 12901 * "targets": [ -1 ] 12902 * } 12903 * ] 12904 * } ); 12905 * } ); 12906 * 12907 * @example 12908 * // Using `columns` 12909 * $(document).ready( function() { 12910 * $('#example').dataTable( { 12911 * "columns": [ 12912 * null, 12913 * null, 12914 * null, 12915 * { 12916 * "data": null, 12917 * "defaultContent": "Edit" 12918 * } 12919 * ] 12920 * } ); 12921 * } ); 12922 */ 12923 "sDefaultContent": null, 12924 12925 12926 /** 12927 * This parameter is only used in DataTables' server-side processing. It can 12928 * be exceptionally useful to know what columns are being displayed on the 12929 * client side, and to map these to database fields. When defined, the names 12930 * also allow DataTables to reorder information from the server if it comes 12931 * back in an unexpected order (i.e. if you switch your columns around on the 12932 * client-side, your server-side code does not also need updating). 12933 * @type string 12934 * @default <i>Empty string</i> 12935 * 12936 * @name DataTable.defaults.column.name 12937 * @dtopt Columns 12938 * 12939 * @example 12940 * // Using `columnDefs` 12941 * $(document).ready( function() { 12942 * $('#example').dataTable( { 12943 * "columnDefs": [ 12944 * { "name": "engine", "targets": [ 0 ] }, 12945 * { "name": "browser", "targets": [ 1 ] }, 12946 * { "name": "platform", "targets": [ 2 ] }, 12947 * { "name": "version", "targets": [ 3 ] }, 12948 * { "name": "grade", "targets": [ 4 ] } 12949 * ] 12950 * } ); 12951 * } ); 12952 * 12953 * @example 12954 * // Using `columns` 12955 * $(document).ready( function() { 12956 * $('#example').dataTable( { 12957 * "columns": [ 12958 * { "name": "engine" }, 12959 * { "name": "browser" }, 12960 * { "name": "platform" }, 12961 * { "name": "version" }, 12962 * { "name": "grade" } 12963 * ] 12964 * } ); 12965 * } ); 12966 */ 12967 "sName": "", 12968 12969 12970 /** 12971 * Defines a data source type for the ordering which can be used to read 12972 * real-time information from the table (updating the internally cached 12973 * version) prior to ordering. This allows ordering to occur on user 12974 * editable elements such as form inputs. 12975 * @type string 12976 * @default std 12977 * 12978 * @name DataTable.defaults.column.orderDataType 12979 * @dtopt Columns 12980 * 12981 * @example 12982 * // Using `columnDefs` 12983 * $(document).ready( function() { 12984 * $('#example').dataTable( { 12985 * "columnDefs": [ 12986 * { "orderDataType": "dom-text", "targets": [ 2, 3 ] }, 12987 * { "type": "numeric", "targets": [ 3 ] }, 12988 * { "orderDataType": "dom-select", "targets": [ 4 ] }, 12989 * { "orderDataType": "dom-checkbox", "targets": [ 5 ] } 12990 * ] 12991 * } ); 12992 * } ); 12993 * 12994 * @example 12995 * // Using `columns` 12996 * $(document).ready( function() { 12997 * $('#example').dataTable( { 12998 * "columns": [ 12999 * null, 13000 * null, 13001 * { "orderDataType": "dom-text" }, 13002 * { "orderDataType": "dom-text", "type": "numeric" }, 13003 * { "orderDataType": "dom-select" }, 13004 * { "orderDataType": "dom-checkbox" } 13005 * ] 13006 * } ); 13007 * } ); 13008 */ 13009 "sSortDataType": "std", 13010 13011 13012 /** 13013 * The title of this column. 13014 * @type string 13015 * @default null <i>Derived from the 'TH' value for this column in the 13016 * original HTML table.</i> 13017 * 13018 * @name DataTable.defaults.column.title 13019 * @dtopt Columns 13020 * 13021 * @example 13022 * // Using `columnDefs` 13023 * $(document).ready( function() { 13024 * $('#example').dataTable( { 13025 * "columnDefs": [ 13026 * { "title": "My column title", "targets": [ 0 ] } 13027 * ] 13028 * } ); 13029 * } ); 13030 * 13031 * @example 13032 * // Using `columns` 13033 * $(document).ready( function() { 13034 * $('#example').dataTable( { 13035 * "columns": [ 13036 * { "title": "My column title" }, 13037 * null, 13038 * null, 13039 * null, 13040 * null 13041 * ] 13042 * } ); 13043 * } ); 13044 */ 13045 "sTitle": null, 13046 13047 13048 /** 13049 * The type allows you to specify how the data for this column will be
13050 * ordered. Four types (string, numeric, date and html (which will strip 13051 * HTML tags before ordering)) are currently available. Note that only date 13052 * formats understood by Javascript's Date() object will be accepted as type 13053 * date. For example: "Mar 26, 2008 5:03 PM". May take the values: 'string', 13054 * 'numeric', 'date' or 'html' (by default). Further types can be adding 13055 * through plug-ins. 13056 * @type string 13057 * @default null <i>Auto-detected from raw data</i> 13058 * 13059 * @name DataTable.defaults.column.type 13060 * @dtopt Columns 13061 * 13062 * @example 13063 * // Using `columnDefs` 13064 * $(document).ready( function() { 13065 * $('#example').dataTable( { 13066 * "columnDefs": [ 13067 * { "type": "html", "targets": [ 0 ] } 13068 * ] 13069 * } ); 13070 * } ); 13071 * 13072 * @example 13073 * // Using `columns` 13074 * $(document).ready( function() { 13075 * $('#example').dataTable( { 13076 * "columns": [ 13077 * { "type": "html" }, 13078 * null, 13079 * null, 13080 * null, 13081 * null 13082 * ] 13083 * } ); 13084 * } ); 13085 */ 13086 "sType": null, 13087 13088 13089 /** 13090 * Defining the width of the column, this parameter may take any CSS value 13091 * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not 13092 * been given a specific width through this interface ensuring that the table 13093 * remains readable. 13094 * @type string 13095 * @default null <i>Automatic</i> 13096 * 13097 * @name DataTable.defaults.column.width 13098 * @dtopt Columns 13099 * 13100 * @example 13101 * // Using `columnDefs` 13102 * $(document).ready( function() { 13103 * $('#example').dataTable( { 13104 * "columnDefs": [ 13105 * { "width": "20%", "targets": [ 0 ] } 13106 * ] 13107 * } ); 13108 * } ); 13109 * 13110 * @example 13111 * // Using `columns` 13112 * $(document).ready( function() { 13113 * $('#example').dataTable( { 13114 * "columns": [ 13115 * { "width": "20%" }, 13116 * null, 13117 * null, 13118 * null, 13119 * null 13120 * ] 13121 * } ); 13122 * } ); 13123 */ 13124 "sWidth": null 13125 }; 13126 13127 _fnHungarianMap( DataTable.defaults.column ); 13128 13129 13130 13131 /** 13132 * DataTables settings object - this holds all the information needed for a 13133 * given table, including configuration, data and current application of the 13134 * table options. DataTables does not have a single instance for each DataTable 13135 * with the settings attached to that instance, but rather instances of the 13136 * DataTable "class" are created on-the-fly as needed (typically by a 13137 * $().dataTable() call) and the settings object is then applied to that 13138 * instance. 13139 * 13140 * Note that this object is related to {@link DataTable.defaults} but this 13141 * one is the internal data store for DataTables's cache of columns. It should 13142 * NOT be manipulated outside of DataTables. Any configuration should be done 13143 * through the initialisation options. 13144 * @namespace 13145 * @todo Really should attach the settings object to individual instances so we 13146 * don't need to create new instances on each $().dataTable() call (if the 13147 * table already exists). It would also save passing oSettings around and 13148 * into every single function. However, this is a very significant 13149 * architecture change for DataTables and will almost certainly break 13150 * backwards compatibility with older installations. This is something that 13151 * will be done in 2.0. 13152 */ 13153 DataTable.models.oSettings = { 13154 /** 13155 * Primary features of DataTables and their enablement state. 13156 * @namespace 13157 */ 13158 "oFeatures": { 13159 13160 /** 13161 * Flag to say if DataTables should automatically try to calculate the 13162 * optimum table and columns widths (true) or not (false). 13163 * Note that this parameter will be set by the initialisation routine. To 13164 * set a default use {@link DataTable.defaults}. 13165 * @type boolean 13166 */ 13167 "bAutoWidth": null, 13168 13169 /** 13170 * Delay the creation of TR and TD elements until they are actually 13171 * needed by a driven page draw. This can give a significant speed 13172 * increase for Ajax source and Javascript source data, but makes no 13173 * difference at all for DOM and server-side processing tables. 13174 * Note that this parameter will be set by the initialisation routine. To 13175 * set a default use {@link DataTable.defaults}. 13176 * @type boolean 13177 */ 13178 "bDeferRender": null, 13179 13180 /** 13181 * Enable filtering on the table or not. Note that if this is disabled 13182 * then there is no filtering at all on the table, including fnFilter. 13183 * To just remove the filtering input use sDom and remove the 'f' option. 13184 * Note that this parameter will be set by the initialisation routine. To 13185 * set a default use {@link DataTable.defaults}. 13186 * @type boolean 13187 */ 13188 "bFilter": null, 13189 13190 /** 13191 * Table information element (the 'Showing x of y records' div) enable 13192 * flag. 13193 * Note that this parameter will be set by the initialisation routine. To 13194 * set a default use {@link DataTable.defaults}. 13195 * @type boolean 13196 */ 13197 "bInfo": null, 13198 13199 /** 13200 * Present a user control allowing the end user to change the page size 13201 * when pagination is enabled. 13202 * Note that this parameter will be set by the initialisation routine. To 13203 * set a default use {@link DataTable.defaults}. 13204 * @type boolean 13205 */ 13206 "bLengthChange": null, 13207 13208 /** 13209 * Pagination enabled or not. Note that if this is disabled then length 13210 * changing must also be disabled. 13211 * Note that this parameter will be set by the initialisation routine. To 13212 * set a default use {@link DataTable.defaults}. 13213 * @type boolean 13214 */ 13215 "bPaginate": null, 13216 13217 /** 13218 * Processing indicator enable flag whenever DataTables is enacting a 13219 * user request - typically an Ajax request for server-side processing. 13220 * Note that this parameter will be set by the initialisation routine. To 13221 * set a default use {@link DataTable.defaults}. 13222 * @type boolean 13223 */ 13224 "bProcessing": null, 13225 13226 /** 13227 * Server-side processing enabled flag - when enabled DataTables will 13228 * get all data from the server for every draw - there is no filtering, 13229 * sorting or paging done on the client-side. 13230 * Note that this parameter will be set by the initialisation routine. To 13231 * set a default use {@link DataTable.defaults}. 13232 * @type boolean 13233 */ 13234 "bServerSide": null, 13235 13236 /** 13237 * Sorting enablement flag. 13238 * Note that this parameter will be set by the initialisation routine. To 13239 * set a default use {@link DataTable.defaults}. 13240 * @type boolean 13241 */ 13242 "bSort": null, 13243 13244 /**
vendor: 10,013 bytes, lines 13245-13653
13245 * Multi-column sorting 13246 * Note that this parameter will be set by the initialisation routine. To 13247 * set a default use {@link DataTable.defaults}. 13248 * @type boolean 13249 */ 13250 "bSortMulti": null, 13251 13252 /** 13253 * Apply a class to the columns which are being sorted to provide a 13254 * visual highlight or not. This can slow things down when enabled since 13255 * there is a lot of DOM interaction. 13256 * Note that this parameter will be set by the initialisation routine. To 13257 * set a default use {@link DataTable.defaults}. 13258 * @type boolean 13259 */ 13260 "bSortClasses": null, 13261 13262 /** 13263 * State saving enablement flag. 13264 * Note that this parameter will be set by the initialisation routine. To 13265 * set a default use {@link DataTable.defaults}. 13266 * @type boolean 13267 */ 13268 "bStateSave": null 13269 }, 13270 13271 13272 /** 13273 * Scrolling settings for a table. 13274 * @namespace 13275 */ 13276 "oScroll": { 13277 /** 13278 * When the table is shorter in height than sScrollY, collapse the 13279 * table container down to the height of the table (when true). 13280 * Note that this parameter will be set by the initialisation routine. To 13281 * set a default use {@link DataTable.defaults}. 13282 * @type boolean 13283 */ 13284 "bCollapse": null, 13285 13286 /** 13287 * Width of the scrollbar for the web-browser's platform. Calculated 13288 * during table initialisation. 13289 * @type int 13290 * @default 0 13291 */ 13292 "iBarWidth": 0, 13293 13294 /** 13295 * Viewport width for horizontal scrolling. Horizontal scrolling is 13296 * disabled if an empty string. 13297 * Note that this parameter will be set by the initialisation routine. To 13298 * set a default use {@link DataTable.defaults}. 13299 * @type string 13300 */ 13301 "sX": null, 13302 13303 /** 13304 * Width to expand the table to when using x-scrolling. Typically you 13305 * should not need to use this. 13306 * Note that this parameter will be set by the initialisation routine. To 13307 * set a default use {@link DataTable.defaults}. 13308 * @type string 13309 * @deprecated 13310 */ 13311 "sXInner": null, 13312 13313 /** 13314 * Viewport height for vertical scrolling. Vertical scrolling is disabled 13315 * if an empty string. 13316 * Note that this parameter will be set by the initialisation routine. To 13317 * set a default use {@link DataTable.defaults}. 13318 * @type string 13319 */ 13320 "sY": null 13321 }, 13322 13323 /** 13324 * Language information for the table. 13325 * @namespace 13326 * @extends DataTable.defaults.oLanguage 13327 */ 13328 "oLanguage": { 13329 /** 13330 * Information callback function. See 13331 * {@link DataTable.defaults.fnInfoCallback} 13332 * @type function 13333 * @default null 13334 */ 13335 "fnInfoCallback": null 13336 }, 13337 13338 /** 13339 * Browser support parameters 13340 * @namespace 13341 */ 13342 "oBrowser": { 13343 /** 13344 * Indicate if the browser incorrectly calculates width:100% inside a 13345 * scrolling element (IE6/7) 13346 * @type boolean 13347 * @default false 13348 */ 13349 "bScrollOversize": false, 13350 13351 /** 13352 * Determine if the vertical scrollbar is on the right or left of the 13353 * scrolling container - needed for rtl language layout, although not 13354 * all browsers move the scrollbar (Safari). 13355 * @type boolean 13356 * @default false 13357 */ 13358 "bScrollbarLeft": false, 13359 13360 /** 13361 * Flag for if `getBoundingClientRect` is fully supported or not 13362 * @type boolean 13363 * @default false 13364 */ 13365 "bBounding": false, 13366 13367 /** 13368 * Browser scrollbar width 13369 * @type integer 13370 * @default 0 13371 */ 13372 "barWidth": 0 13373 }, 13374 13375 13376 "ajax": null, 13377 13378 13379 /** 13380 * Array referencing the nodes which are used for the features. The 13381 * parameters of this object match what is allowed by sDom - i.e. 13382 * <ul> 13383 * <li>'l' - Length changing</li> 13384 * <li>'f' - Filtering input</li> 13385 * <li>'t' - The table!</li> 13386 * <li>'i' - Information</li> 13387 * <li>'p' - Pagination</li> 13388 * <li>'r' - pRocessing</li> 13389 * </ul> 13390 * @type array 13391 * @default [] 13392 */ 13393 "aanFeatures": [], 13394 13395 /** 13396 * Store data information - see {@link DataTable.models.oRow} for detailed 13397 * information. 13398 * @type array 13399 * @default [] 13400 */ 13401 "aoData": [], 13402 13403 /** 13404 * Array of indexes which are in the current display (after filtering etc) 13405 * @type array 13406 * @default [] 13407 */ 13408 "aiDisplay": [], 13409 13410 /** 13411 * Array of indexes for display - no filtering 13412 * @type array 13413 * @default [] 13414 */ 13415 "aiDisplayMaster": [], 13416 13417 /** 13418 * Map of row ids to data indexes 13419 * @type object 13420 * @default {} 13421 */ 13422 "aIds": {}, 13423 13424 /** 13425 * Store information about each column that is in use 13426 * @type array 13427 * @default [] 13428 */ 13429 "aoColumns": [], 13430 13431 /** 13432 * Store information about the table's header 13433 * @type array 13434 * @default [] 13435 */ 13436 "aoHeader": [], 13437 13438 /** 13439 * Store information about the table's footer 13440 * @type array 13441 * @default [] 13442 */ 13443 "aoFooter": [], 13444 13445 /** 13446 * Store the applied global search information in case we want to force a 13447 * research or compare the old search to a new one. 13448 * Note that this parameter will be set by the initialisation routine. To 13449 * set a default use {@link DataTable.defaults}. 13450 * @namespace 13451 * @extends DataTable.models.oSearch 13452 */ 13453 "oPreviousSearch": {}, 13454 13455 /** 13456 * Store the applied search for each column - see 13457 * {@link DataTable.models.oSearch} for the format that is used for the 13458 * filtering information for each column. 13459 * @type array 13460 * @default [] 13461 */ 13462 "aoPreSearchCols": [], 13463 13464 /** 13465 * Sorting that is applied to the table. Note that the inner arrays are 13466 * used in the following manner: 13467 * <ul> 13468 * <li>Index 0 - column number</li> 13469 * <li>Index 1 - current sorting direction</li> 13470 * </ul> 13471 * Note that this parameter will be set by the initialisation routine. To 13472 * set a default use {@link DataTable.defaults}. 13473 * @type array 13474 * @todo These inner arrays should really be objects 13475 */ 13476 "aaSorting": null, 13477 13478 /** 13479 * Sorting that is always applied to the table (i.e. prefixed in front of 13480 * aaSorting). 13481 * Note that this parameter will be set by the initialisation routine. To 13482 * set a default use {@link DataTable.defaults}. 13483 * @type array 13484 * @default [] 13485 */ 13486 "aaSortingFixed": [], 13487 13488 /** 13489 * Classes to use for the striping of a table. 13490 * Note that this parameter will be set by the initialisation routine. To 13491 * set a default use {@link DataTable.defaults}. 13492 * @type array 13493 * @default [] 13494 */ 13495 "asStripeClasses": null, 13496 13497 /** 13498 * If restoring a table - we should restore its striping classes as well 13499 * @type array 13500 * @default [] 13501 */ 13502 "asDestroyStripes": [], 13503 13504 /** 13505 * If restoring a table - we should restore its width 13506 * @type int 13507 * @default 0 13508 */ 13509 "sDestroyWidth": 0, 13510 13511 /** 13512 * Callback functions array for every time a row is inserted (i.e. on a draw). 13513 * @type array 13514 * @default [] 13515 */ 13516 "aoRowCallback": [], 13517 13518 /** 13519 * Callback functions for the header on each draw. 13520 * @type array 13521 * @default [] 13522 */ 13523 "aoHeaderCallback": [], 13524 13525 /** 13526 * Callback function for the footer on each draw. 13527 * @type array 13528 * @default [] 13529 */ 13530 "aoFooterCallback": [], 13531 13532 /** 13533 * Array of callback functions for draw callback functions 13534 * @type array 13535 * @default [] 13536 */ 13537 "aoDrawCallback": [], 13538 13539 /** 13540 * Array of callback functions for row created function 13541 * @type array 13542 * @default [] 13543 */ 13544 "aoRowCreatedCallback": [], 13545 13546 /** 13547 * Callback functions for just before the table is redrawn. A return of 13548 * false will be used to cancel the draw. 13549 * @type array 13550 * @default [] 13551 */ 13552 "aoPreDrawCallback": [], 13553 13554 /** 13555 * Callback functions for when the table has been initialised. 13556 * @type array 13557 * @default [] 13558 */ 13559 "aoInitComplete": [], 13560 13561 13562 /** 13563 * Callbacks for modifying the settings to be stored for state saving, prior to 13564 * saving state. 13565 * @type array 13566 * @default [] 13567 */ 13568 "aoStateSaveParams": [], 13569 13570 /** 13571 * Callbacks for modifying the settings that have been stored for state saving 13572 * prior to using the stored values to restore the state. 13573 * @type array 13574 * @default [] 13575 */ 13576 "aoStateLoadParams": [], 13577 13578 /** 13579 * Callbacks for operating on the settings object once the saved state has been 13580 * loaded 13581 * @type array 13582 * @default [] 13583 */ 13584 "aoStateLoaded": [], 13585 13586 /** 13587 * Cache the table ID for quick access 13588 * @type string 13589 * @default <i>Empty string</i> 13590 */ 13591 "sTableId": "", 13592 13593 /** 13594 * The TABLE node for the main table 13595 * @type node 13596 * @default null 13597 */ 13598 "nTable": null, 13599 13600 /** 13601 * Permanent ref to the thead element 13602 * @type node 13603 * @default null 13604 */ 13605 "nTHead": null, 13606 13607 /** 13608 * Permanent ref to the tfoot element - if it exists 13609 * @type node 13610 * @default null 13611 */ 13612 "nTFoot": null, 13613 13614 /** 13615 * Permanent ref to the tbody element 13616 * @type node 13617 * @default null 13618 */ 13619 "nTBody": null, 13620 13621 /** 13622 * Cache the wrapper node (contains all DataTables controlled elements) 13623 * @type node 13624 * @default null 13625 */ 13626 "nTableWrapper": null, 13627 13628 /** 13629 * Indicate if when using server-side processing the loading of data 13630 * should be deferred until the second draw. 13631 * Note that this parameter will be set by the initialisation routine. To 13632 * set a default use {@link DataTable.defaults}. 13633 * @type boolean 13634 * @default false 13635 */ 13636 "bDeferLoading": false, 13637 13638 /** 13639 * Indicate if all required information has been read in 13640 * @type boolean 13641 * @default false 13642 */ 13643 "bInitialised": false, 13644 13645 /** 13646 * Information about open rows. Each object in the array has the parameters 13647 * 'nTr' and 'nParent' 13648 * @type array 13649 * @default [] 13650 */ 13651 "aoOpenRows": [], 13652 13653 /**
13654 * Dictate the positioning of DataTables' control elements - see 13655 * {@link DataTable.model.oInit.sDom}. 13656 * Note that this parameter will be set by the initialisation routine. To 13657 * set a default use {@link DataTable.defaults}. 13658 * @type string 13659 * @default null 13660 */ 13661 "sDom": null, 13662 13663 /** 13664 * Search delay (in mS) 13665 * @type integer 13666 * @default null 13667 */ 13668 "searchDelay": null, 13669 13670 /** 13671 * Which type of pagination should be used. 13672 * Note that this parameter will be set by the initialisation routine. To 13673 * set a default use {@link DataTable.defaults}. 13674 * @type string 13675 * @default two_button 13676 */ 13677 "sPaginationType": "two_button", 13678 13679 /** 13680 * The state duration (for `stateSave`) in seconds. 13681 * Note that this parameter will be set by the initialisation routine. To 13682 * set a default use {@link DataTable.defaults}. 13683 * @type int 13684 * @default 0 13685 */ 13686 "iStateDuration": 0, 13687 13688 /** 13689 * Array of callback functions for state saving. Each array element is an 13690 * object with the following parameters: 13691 * <ul> 13692 * <li>function:fn - function to call. Takes two parameters, oSettings 13693 * and the JSON string to save that has been thus far created. Returns 13694 * a JSON string to be inserted into a json object 13695 * (i.e. '"param": [ 0, 1, 2]')</li> 13696 * <li>string:sName - name of callback</li> 13697 * </ul> 13698 * @type array 13699 * @default [] 13700 */ 13701 "aoStateSave": [], 13702 13703 /** 13704 * Array of callback functions for state loading. Each array element is an 13705 * object with the following parameters: 13706 * <ul> 13707 * <li>function:fn - function to call. Takes two parameters, oSettings 13708 * and the object stored. May return false to cancel state loading</li> 13709 * <li>string:sName - name of callback</li> 13710 * </ul> 13711 * @type array 13712 * @default [] 13713 */ 13714 "aoStateLoad": [], 13715 13716 /** 13717 * State that was saved. Useful for back reference 13718 * @type object 13719 * @default null 13720 */ 13721 "oSavedState": null, 13722 13723 /** 13724 * State that was loaded. Useful for back reference 13725 * @type object 13726 * @default null 13727 */ 13728 "oLoadedState": null, 13729 13730 /** 13731 * Source url for AJAX data for the table. 13732 * Note that this parameter will be set by the initialisation routine. To 13733 * set a default use {@link DataTable.defaults}. 13734 * @type string 13735 * @default null 13736 */ 13737 "sAjaxSource": null, 13738 13739 /** 13740 * Property from a given object from which to read the table data from. This 13741 * can be an empty string (when not server-side processing), in which case 13742 * it is assumed an an array is given directly. 13743 * Note that this parameter will be set by the initialisation routine. To 13744 * set a default use {@link DataTable.defaults}. 13745 * @type string 13746 */ 13747 "sAjaxDataProp": null, 13748 13749 /** 13750 * The last jQuery XHR object that was used for server-side data gathering. 13751 * This can be used for working with the XHR information in one of the 13752 * callbacks 13753 * @type object 13754 * @default null 13755 */ 13756 "jqXHR": null, 13757 13758 /** 13759 * JSON returned from the server in the last Ajax request 13760 * @type object 13761 * @default undefined 13762 */ 13763 "json": undefined, 13764 13765 /** 13766 * Data submitted as part of the last Ajax request 13767 * @type object 13768 * @default undefined 13769 */ 13770 "oAjaxData": undefined, 13771 13772 /** 13773 * Function to get the server-side data. 13774 * Note that this parameter will be set by the initialisation routine. To 13775 * set a default use {@link DataTable.defaults}. 13776 * @type function 13777 */ 13778 "fnServerData": null, 13779 13780 /** 13781 * Functions which are called prior to sending an Ajax request so extra 13782 * parameters can easily be sent to the server 13783 * @type array 13784 * @default [] 13785 */ 13786 "aoServerParams": [], 13787 13788 /** 13789 * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if 13790 * required). 13791 * Note that this parameter will be set by the initialisation routine. To 13792 * set a default use {@link DataTable.defaults}. 13793 * @type string 13794 */ 13795 "sServerMethod": null, 13796 13797 /** 13798 * Format numbers for display. 13799 * Note that this parameter will be set by the initialisation routine. To 13800 * set a default use {@link DataTable.defaults}. 13801 * @type function 13802 */ 13803 "fnFormatNumber": null, 13804 13805 /** 13806 * List of options that can be used for the user selectable length menu. 13807 * Note that this parameter will be set by the initialisation routine. To 13808 * set a default use {@link DataTable.defaults}. 13809 * @type array 13810 * @default [] 13811 */ 13812 "aLengthMenu": null, 13813 13814 /** 13815 * Counter for the draws that the table does. Also used as a tracker for 13816 * server-side processing 13817 * @type int 13818 * @default 0 13819 */ 13820 "iDraw": 0, 13821 13822 /** 13823 * Indicate if a redraw is being done - useful for Ajax 13824 * @type boolean 13825 * @default false 13826 */ 13827 "bDrawing": false, 13828 13829 /** 13830 * Draw index (iDraw) of the last error when parsing the returned data 13831 * @type int 13832 * @default -1 13833 */ 13834 "iDrawError": -1, 13835 13836 /** 13837 * Paging display length 13838 * @type int 13839 * @default 10 13840 */ 13841 "_iDisplayLength": 10, 13842 13843 /** 13844 * Paging start point - aiDisplay index 13845 * @type int 13846 * @default 0 13847 */ 13848 "_iDisplayStart": 0, 13849 13850 /** 13851 * Server-side processing - number of records in the result set 13852 * (i.e. before filtering), Use fnRecordsTotal rather than 13853 * this property to get the value of the number of records, regardless of 13854 * the server-side processing setting. 13855 * @type int 13856 * @default 0 13857 * @private 13858 */ 13859 "_iRecordsTotal": 0, 13860 13861 /** 13862 * Server-side processing - number of records in the current display set 13863 * (i.e. after filtering). Use fnRecordsDisplay rather than 13864 * this property to get the value of the number of records, regardless of 13865 * the server-side processing setting. 13866 * @type boolean 13867 * @default 0 13868 * @private 13869 */ 13870 "_iRecordsDisplay": 0, 13871 13872 /** 13873 * The classes to use for the table 13874 * @type object 13875 * @default {} 13876 */
vendor: 4,121 bytes, lines 13877-14048
13877 "oClasses": {}, 13878 13879 /** 13880 * Flag attached to the settings object so you can check in the draw 13881 * callback if filtering has been done in the draw. Deprecated in favour of 13882 * events. 13883 * @type boolean 13884 * @default false 13885 * @deprecated 13886 */ 13887 "bFiltered": false, 13888 13889 /** 13890 * Flag attached to the settings object so you can check in the draw 13891 * callback if sorting has been done in the draw. Deprecated in favour of 13892 * events. 13893 * @type boolean 13894 * @default false 13895 * @deprecated 13896 */ 13897 "bSorted": false, 13898 13899 /** 13900 * Indicate that if multiple rows are in the header and there is more than 13901 * one unique cell per column, if the top one (true) or bottom one (false) 13902 * should be used for sorting / title by DataTables. 13903 * Note that this parameter will be set by the initialisation routine. To 13904 * set a default use {@link DataTable.defaults}. 13905 * @type boolean 13906 */ 13907 "bSortCellsTop": null, 13908 13909 /** 13910 * Initialisation object that is used for the table 13911 * @type object 13912 * @default null 13913 */ 13914 "oInit": null, 13915 13916 /** 13917 * Destroy callback functions - for plug-ins to attach themselves to the 13918 * destroy so they can clean up markup and events. 13919 * @type array 13920 * @default [] 13921 */ 13922 "aoDestroyCallback": [], 13923 13924 13925 /** 13926 * Get the number of records in the current record set, before filtering 13927 * @type function 13928 */ 13929 "fnRecordsTotal": function () 13930 { 13931 return _fnDataSource( this ) == 'ssp' ? 13932 this._iRecordsTotal * 1 : 13933 this.aiDisplayMaster.length; 13934 }, 13935 13936 /** 13937 * Get the number of records in the current record set, after filtering 13938 * @type function 13939 */ 13940 "fnRecordsDisplay": function () 13941 { 13942 return _fnDataSource( this ) == 'ssp' ? 13943 this._iRecordsDisplay * 1 : 13944 this.aiDisplay.length; 13945 }, 13946 13947 /** 13948 * Get the display end point - aiDisplay index 13949 * @type function 13950 */ 13951 "fnDisplayEnd": function () 13952 { 13953 var 13954 len = this._iDisplayLength, 13955 start = this._iDisplayStart, 13956 calc = start + len, 13957 records = this.aiDisplay.length, 13958 features = this.oFeatures, 13959 paginate = features.bPaginate; 13960 13961 if ( features.bServerSide ) { 13962 return paginate === false || len === -1 ? 13963 start + records : 13964 Math.min( start+len, this._iRecordsDisplay ); 13965 } 13966 else { 13967 return ! paginate || calc>records || len===-1 ? 13968 records : 13969 calc; 13970 } 13971 }, 13972 13973 /** 13974 * The DataTables object for this table 13975 * @type object 13976 * @default null 13977 */ 13978 "oInstance": null, 13979 13980 /** 13981 * Unique identifier for each instance of the DataTables object. If there 13982 * is an ID on the table node, then it takes that value, otherwise an 13983 * incrementing internal counter is used. 13984 * @type string 13985 * @default null 13986 */ 13987 "sInstance": null, 13988 13989 /** 13990 * tabindex attribute value that is added to DataTables control elements, allowing 13991 * keyboard navigation of the table and its controls. 13992 */ 13993 "iTabIndex": 0, 13994 13995 /** 13996 * DIV container for the footer scrolling table if scrolling 13997 */ 13998 "nScrollHead": null, 13999 14000 /** 14001 * DIV container for the footer scrolling table if scrolling 14002 */ 14003 "nScrollFoot": null, 14004 14005 /** 14006 * Last applied sort 14007 * @type array 14008 * @default [] 14009 */ 14010 "aLastSort": [], 14011 14012 /** 14013 * Stored plug-in instances 14014 * @type object 14015 * @default {} 14016 */ 14017 "oPlugins": {}, 14018 14019 /** 14020 * Function used to get a row's id from the row's data 14021 * @type function 14022 * @default null 14023 */ 14024 "rowIdFn": null, 14025 14026 /** 14027 * Data location where to store a row's id 14028 * @type string 14029 * @default null 14030 */ 14031 "rowId": null 14032 }; 14033 14034 /** 14035 * Extension object for DataTables that is used to provide all extension 14036 * options. 14037 * 14038 * Note that the `DataTable.ext` object is available through 14039 * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is 14040 * also aliased to `jQuery.fn.dataTableExt` for historic reasons. 14041 * @namespace 14042 * @extends DataTable.models.ext 14043 */ 14044 14045 14046 /** 14047 * DataTables extensions 14048 *
14049 * This namespace acts as a collection area for plug-ins that can be used to 14050 * extend DataTables capabilities. Indeed many of the build in methods 14051 * use this method to provide their own capabilities (sorting methods for 14052 * example). 14053 * 14054 * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy 14055 * reasons 14056 * 14057 * @namespace 14058 */ 14059 DataTable.ext = _ext = { 14060 /** 14061 * Buttons. For use with the Buttons extension for DataTables. This is 14062 * defined here so other extensions can define buttons regardless of load 14063 * order. It is _not_ used by DataTables core. 14064 * 14065 * @type object 14066 * @default {} 14067 */ 14068 buttons: {}, 14069 14070 14071 /** 14072 * Element class names 14073 * 14074 * @type object 14075 * @default {} 14076 */ 14077 classes: {}, 14078 14079 14080 /** 14081 * DataTables build type (expanded by the download builder) 14082 * 14083 * @type string 14084 */ 14085 builder: "-source-", 14086 14087 14088 /** 14089 * Error reporting. 14090 * 14091 * How should DataTables report an error. Can take the value 'alert', 14092 * 'throw', 'none' or a function. 14093 * 14094 * @type string|function 14095 * @default alert 14096 */ 14097 errMode: "alert", 14098 14099 14100 /** 14101 * Feature plug-ins. 14102 * 14103 * This is an array of objects which describe the feature plug-ins that are 14104 * available to DataTables. These feature plug-ins are then available for 14105 * use through the `dom` initialisation option. 14106 * 14107 * Each feature plug-in is described by an object which must have the 14108 * following properties: 14109 * 14110 * * `fnInit` - function that is used to initialise the plug-in, 14111 * * `cFeature` - a character so the feature can be enabled by the `dom` 14112 * instillation option. This is case sensitive. 14113 * 14114 * The `fnInit` function has the following input parameters: 14115 * 14116 * 1. `{object}` DataTables settings object: see 14117 * {@link DataTable.models.oSettings} 14118 * 14119 * And the following return is expected: 14120 * 14121 * * {node|null} The element which contains your feature. Note that the 14122 * return may also be void if your plug-in does not require to inject any 14123 * DOM elements into DataTables control (`dom`) - for example this might 14124 * be useful when developing a plug-in which allows table control via 14125 * keyboard entry 14126 * 14127 * @type array 14128 * 14129 * @example 14130 * $.fn.dataTable.ext.features.push( { 14131 * "fnInit": function( oSettings ) { 14132 * return new TableTools( { "oDTSettings": oSettings } ); 14133 * }, 14134 * "cFeature": "T" 14135 * } ); 14136 */ 14137 feature: [], 14138 14139 14140 /** 14141 * Row searching. 14142 * 14143 * This method of searching is complimentary to the default type based 14144 * searching, and a lot more comprehensive as it allows you complete control 14145 * over the searching logic. Each element in this array is a function 14146 * (parameters described below) that is called for every row in the table, 14147 * and your logic decides if it should be included in the searching data set 14148 * or not. 14149 * 14150 * Searching functions have the following input parameters: 14151 * 14152 * 1. `{object}` DataTables settings object: see 14153 * {@link DataTable.models.oSettings} 14154 * 2. `{array|object}` Data for the row to be processed (same as the 14155 * original format that was passed in as the data source, or an array 14156 * from a DOM data source 14157 * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which 14158 * can be useful to retrieve the `TR` element if you need DOM interaction. 14159 * 14160 * And the following return is expected: 14161 * 14162 * * {boolean} Include the row in the searched result set (true) or not 14163 * (false) 14164 * 14165 * Note that as with the main search ability in DataTables, technically this 14166 * is "filtering", since it is subtractive. However, for consistency in 14167 * naming we call it searching here. 14168 * 14169 * @type array 14170 * @default [] 14171 * 14172 * @example 14173 * // The following example shows custom search being applied to the 14174 * // fourth column (i.e. the data[3] index) based on two input values 14175 * // from the end-user, matching the data in a certain range. 14176 * $.fn.dataTable.ext.search.push( 14177 * function( settings, data, dataIndex ) { 14178 * var min = document.getElementById('min').value * 1; 14179 * var max = document.getElementById('max').value * 1; 14180 * var version = data[3] == "-" ? 0 : data[3]*1; 14181 * 14182 * if ( min == "" && max == "" ) { 14183 * return true; 14184 * } 14185 * else if ( min == "" && version < max ) { 14186 * return true; 14187 * } 14188 * else if ( min < version && "" == max ) { 14189 * return true; 14190 * } 14191 * else if ( min < version && version < max ) { 14192 * return true; 14193 * } 14194 * return false; 14195 * } 14196 * ); 14197 */ 14198 search: [], 14199 14200 14201 /** 14202 * Selector extensions 14203 * 14204 * The `selector` option can be used to extend the options available for the 14205 * selector modifier options (`selector-modifier` object data type) that 14206 * each of the three built in selector types offer (row, column and cell + 14207 * their plural counterparts). For example the Select extension uses this 14208 * mechanism to provide an option to select only rows, columns and cells 14209 * that have been marked as selected by the end user (`{selected: true}`), 14210 * which can be used in conjunction with the existing built in selector 14211 * options. 14212 * 14213 * Each property is an array to which functions can be pushed. The functions 14214 * take three attributes: 14215 * 14216 * * Settings object for the host table 14217 * * Options object (`selector-modifier` object type) 14218 * * Array of selected item indexes 14219 * 14220 * The return is an array of the resulting item indexes after the custom 14221 * selector has been applied. 14222 * 14223 * @type object 14224 */ 14225 selector: { 14226 cell: [], 14227 column: [], 14228 row: [] 14229 }, 14230 14231 14232 /** 14233 * Internal functions, exposed for used in plug-ins. 14234 * 14235 * Please note that you should not need to use the internal methods for 14236 * anything other than a plug-in (and even then, try to avoid if possible). 14237 * The internal function may change between releases. 14238 * 14239 * @type object 14240 * @default {} 14241 */ 14242 internal: {}, 14243 14244 14245 /** 14246 * Legacy configuration options. Enable and disable legacy options that 14247 * are available in DataTables. 14248 * 14249 * @type object 14250 */ 14251 legacy: { 14252 /** 14253 * Enable / disable DataTables 1.9 compatible server-side processing 14254 * requests 14255 * 14256 * @type boolean 14257 * @default null 14258 */ 14259 ajax: null 14260 }, 14261 14262 14263 /** 14264 * Pagination plug-in methods. 14265 * 14266 * Each entry in this object is a function and defines which buttons should 14267 * be shown by the pagination rendering method that is used for the table: 14268 * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the 14269 * buttons are displayed in the document, while the functions here tell it 14270 * what buttons to display. This is done by returning an array of button 14271 * descriptions (what each button will do). 14272 * 14273 * Pagination types (the four built in options and any additional plug-in 14274 * options defined here) can be used through the `paginationType` 14275 * initialisation parameter. 14276 * 14277 * The functions defined take two parameters: 14278 * 14279 * 1. `{int} page` The current page index 14280 * 2. `{int} pages` The number of pages in the table 14281 * 14282 * Each function is expected to return an array where each element of the 14283 * array can be one of: 14284 * 14285 * * `first` - Jump to first page when activated 14286 * * `last` - Jump to last page when activated 14287 * * `previous` - Show previous page when activated 14288 * * `next` - Show next page when activated 14289 * * `{int}` - Show page of the index given 14290 * * `{array}` - A nested array containing the above elements to add a 14291 * containing 'DIV' element (might be useful for styling). 14292 * 14293 * Note that DataTables v1.9- used this object slightly differently whereby 14294 * an object with two functions would be defined for each plug-in. That 14295 * ability is still supported by DataTables 1.10+ to provide backwards 14296 * compatibility, but this option of use is now decremented and no longer 14297 * documented in DataTables 1.10+. 14298 * 14299 * @type object 14300 * @default {} 14301 * 14302 * @example 14303 * // Show previous, next and current page buttons only 14304 * $.fn.dataTableExt.oPagination.current = function ( page, pages ) { 14305 * return [ 'previous', page, 'next' ]; 14306 * }; 14307 */ 14308 pager: {}, 14309 14310 14311 renderer: { 14312 pageButton: {}, 14313 header: {} 14314 }, 14315 14316 14317 /** 14318 * Ordering plug-ins - custom data source 14319 *
14320 * The extension options for ordering of data available here is complimentary 14321 * to the default type based ordering that DataTables typically uses. It 14322 * allows much greater control over the the data that is being used to 14323 * order a column, but is necessarily therefore more complex. 14324 * 14325 * This type of ordering is useful if you want to do ordering based on data 14326 * live from the DOM (for example the contents of an 'input' element) rather 14327 * than just the static string that DataTables knows of. 14328 * 14329 * The way these plug-ins work is that you create an array of the values you 14330 * wish to be ordering for the column in question and then return that 14331 * array. The data in the array much be in the index order of the rows in 14332 * the table (not the currently ordering order!). Which order data gathering 14333 * function is run here depends on the `dt-init columns.orderDataType` 14334 * parameter that is used for the column (if any). 14335 * 14336 * The functions defined take two parameters: 14337 * 14338 * 1. `{object}` DataTables settings object: see 14339 * {@link DataTable.models.oSettings} 14340 * 2. `{int}` Target column index 14341 * 14342 * Each function is expected to return an array: 14343 * 14344 * * `{array}` Data for the column to be ordering upon 14345 * 14346 * @type array 14347 * 14348 * @example 14349 * // Ordering using `input` node values 14350 * $.fn.dataTable.ext.order['dom-text'] = function ( settings, col ) 14351 * { 14352 * return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) { 14353 * return $('input', td).val(); 14354 * } ); 14355 * } 14356 */ 14357 order: {}, 14358 14359 14360 /** 14361 * Type based plug-ins. 14362 * 14363 * Each column in DataTables has a type assigned to it, either by automatic 14364 * detection or by direct assignment using the `type` option for the column. 14365 * The type of a column will effect how it is ordering and search (plug-ins 14366 * can also make use of the column type if required). 14367 * 14368 * @namespace 14369 */ 14370 type: { 14371 /** 14372 * Type detection functions. 14373 * 14374 * The functions defined in this object are used to automatically detect 14375 * a column's type, making initialisation of DataTables super easy, even 14376 * when complex data is in the table. 14377 * 14378 * The functions defined take two parameters: 14379 * 14380 * 1. `{*}` Data from the column cell to be analysed 14381 * 2. `{settings}` DataTables settings object. This can be used to 14382 * perform context specific type detection - for example detection 14383 * based on language settings such as using a comma for a decimal 14384 * place. Generally speaking the options from the settings will not 14385 * be required 14386 * 14387 * Each function is expected to return: 14388 * 14389 * * `{string|null}` Data type detected, or null if unknown (and thus 14390 * pass it on to the other type detection functions. 14391 * 14392 * @type array 14393 * 14394 * @example 14395 * // Currency type detection plug-in: 14396 * $.fn.dataTable.ext.type.detect.push( 14397 * function ( data, settings ) { 14398 * // Check the numeric part 14399 * if ( ! data.substring(1).match(/[0-9]/) ) { 14400 * return null; 14401 * } 14402 * 14403 * // Check prefixed by currency 14404 * if ( data.charAt(0) == '$' || data.charAt(0) == '£' ) { 14405 * return 'currency'; 14406 * } 14407 * return null; 14408 * } 14409 * ); 14410 */ 14411 detect: [], 14412 14413 14414 /** 14415 * Type based search formatting. 14416 * 14417 * The type based searching functions can be used to pre-format the 14418 * data to be search on. For example, it can be used to strip HTML 14419 * tags or to de-format telephone numbers for numeric only searching. 14420 * 14421 * Note that is a search is not defined for a column of a given type, 14422 * no search formatting will be performed. 14423 * 14424 * Pre-processing of searching data plug-ins - When you assign the sType 14425 * for a column (or have it automatically detected for you by DataTables 14426 * or a type detection plug-in), you will typically be using this for 14427 * custom sorting, but it can also be used to provide custom searching 14428 * by allowing you to pre-processing the data and returning the data in 14429 * the format that should be searched upon. This is done by adding 14430 * functions this object with a parameter name which matches the sType 14431 * for that target column. This is the corollary of <i>afnSortData</i> 14432 * for searching data. 14433 * 14434 * The functions defined take a single parameter: 14435 * 14436 * 1. `{*}` Data from the column cell to be prepared for searching 14437 * 14438 * Each function is expected to return: 14439 * 14440 * * `{string|null}` Formatted string that will be used for the searching. 14441 * 14442 * @type object 14443 * @default {} 14444 * 14445 * @example 14446 * $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) { 14447 * return d.replace(/\n/g," ").replace( /<.*?>/g, "" ); 14448 * } 14449 */ 14450 search: {}, 14451 14452 14453 /** 14454 * Type based ordering. 14455 * 14456 * The column type tells DataTables what ordering to apply to the table 14457 * when a column is sorted upon. The order for each type that is defined, 14458 * is defined by the functions available in this object. 14459 * 14460 * Each ordering option can be described by three properties added to 14461 * this object: 14462 * 14463 * * `{type}-pre` - Pre-formatting function 14464 * * `{type}-asc` - Ascending order function 14465 * * `{type}-desc` - Descending order function 14466 * 14467 * All three can be used together, only `{type}-pre` or only 14468 * `{type}-asc` and `{type}-desc` together. It is generally recommended 14469 * that only `{type}-pre` is used, as this provides the optimal 14470 * implementation in terms of speed, although the others are provided 14471 * for compatibility with existing Javascript sort functions. 14472 * 14473 * `{type}-pre`: Functions defined take a single parameter: 14474 * 14475 * 1. `{*}` Data from the column cell to be prepared for ordering 14476 * 14477 * And return: 14478 * 14479 * * `{*}` Data to be sorted upon 14480 * 14481 * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort 14482 * functions, taking two parameters: 14483 * 14484 * 1. `{*}` Data to compare to the second parameter 14485 * 2. `{*}` Data to compare to the first parameter 14486 * 14487 * And returning: 14488 * 14489 * * `{*}` Ordering match: <0 if first parameter should be sorted lower 14490 * than the second parameter, ===0 if the two parameters are equal and 14491 * >0 if the first parameter should be sorted height than the second 14492 * parameter. 14493 * 14494 * @type object 14495 * @default {} 14496 * 14497 * @example 14498 * // Numeric ordering of formatted numbers with a pre-formatter 14499 * $.extend( $.fn.dataTable.ext.type.order, { 14500 * "string-pre": function(x) { 14501 * a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" ); 14502 * return parseFloat( a ); 14503 * } 14504 * } ); 14505 * 14506 * @example 14507 * // Case-sensitive string ordering, with no pre-formatting method 14508 * $.extend( $.fn.dataTable.ext.order, { 14509 * "string-case-asc": function(x,y) { 14510 * return ((x < y) ? -1 : ((x > y) ? 1 : 0)); 14511 * }, 14512 * "string-case-desc": function(x,y) { 14513 * return ((x < y) ? 1 : ((x > y) ? -1 : 0)); 14514 * } 14515 * } ); 14516 */ 14517 order: {} 14518 }, 14519 14520 /** 14521 * Unique DataTables instance counter 14522 * 14523 * @type int 14524 * @private 14525 */ 14526 _unique: 0, 14527 14528 14529 // 14530 // Depreciated 14531 // The following properties are retained for backwards compatibility only. 14532 // The should not be used in new projects and will be removed in a future 14533 // version 14534 // 14535 14536 /** 14537 * Version check function. 14538 * @type function 14539 * @depreciated Since 1.10 14540 */ 14541 fnVersionCheck: DataTable.fnVersionCheck, 14542 14543 14544 /** 14545 * Index for what 'this' index API functions should use 14546 * @type int 14547 * @deprecated Since v1.10 14548 */ 14549 iApiIndex: 0, 14550 14551 14552 /** 14553 * jQuery UI class container 14554 * @type object 14555 * @deprecated Since v1.10 14556 */ 14557 oJUIClasses: {}, 14558 14559 14560 /** 14561 * Software version 14562 * @type string 14563 * @deprecated Since v1.10 14564 */
vendor: 28,324 bytes, lines 14565-15580
14565 sVersion: DataTable.version 14566 }; 14567 14568 14569 // 14570 // Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts 14571 // 14572 $.extend( _ext, { 14573 afnFiltering: _ext.search, 14574 aTypes: _ext.type.detect, 14575 ofnSearch: _ext.type.search, 14576 oSort: _ext.type.order, 14577 afnSortData: _ext.order, 14578 aoFeatures: _ext.feature, 14579 oApi: _ext.internal, 14580 oStdClasses: _ext.classes, 14581 oPagination: _ext.pager 14582 } ); 14583 14584 14585 $.extend( DataTable.ext.classes, { 14586 "sTable": "dataTable", 14587 "sNoFooter": "no-footer", 14588 14589 /* Paging buttons */ 14590 "sPageButton": "paginate_button", 14591 "sPageButtonActive": "current", 14592 "sPageButtonDisabled": "disabled", 14593 14594 /* Striping classes */ 14595 "sStripeOdd": "odd", 14596 "sStripeEven": "even", 14597 14598 /* Empty row */ 14599 "sRowEmpty": "dataTables_empty", 14600 14601 /* Features */ 14602 "sWrapper": "dataTables_wrapper", 14603 "sFilter": "dataTables_filter", 14604 "sInfo": "dataTables_info", 14605 "sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */ 14606 "sLength": "dataTables_length", 14607 "sProcessing": "dataTables_processing", 14608 14609 /* Sorting */ 14610 "sSortAsc": "sorting_asc", 14611 "sSortDesc": "sorting_desc", 14612 "sSortable": "sorting", /* Sortable in both directions */ 14613 "sSortableAsc": "sorting_desc_disabled", 14614 "sSortableDesc": "sorting_asc_disabled", 14615 "sSortableNone": "sorting_disabled", 14616 "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */ 14617 14618 /* Filtering */ 14619 "sFilterInput": "", 14620 14621 /* Page length */ 14622 "sLengthSelect": "", 14623 14624 /* Scrolling */ 14625 "sScrollWrapper": "dataTables_scroll", 14626 "sScrollHead": "dataTables_scrollHead", 14627 "sScrollHeadInner": "dataTables_scrollHeadInner", 14628 "sScrollBody": "dataTables_scrollBody", 14629 "sScrollFoot": "dataTables_scrollFoot", 14630 "sScrollFootInner": "dataTables_scrollFootInner", 14631 14632 /* Misc */ 14633 "sHeaderTH": "", 14634 "sFooterTH": "", 14635 14636 // Deprecated 14637 "sSortJUIAsc": "", 14638 "sSortJUIDesc": "", 14639 "sSortJUI": "", 14640 "sSortJUIAscAllowed": "", 14641 "sSortJUIDescAllowed": "", 14642 "sSortJUIWrapper": "", 14643 "sSortIcon": "", 14644 "sJUIHeader": "", 14645 "sJUIFooter": "" 14646 } ); 14647 14648 14649 var extPagination = DataTable.ext.pager; 14650 14651 function _numbers ( page, pages ) { 14652 var 14653 numbers = [], 14654 buttons = extPagination.numbers_length, 14655 half = Math.floor( buttons / 2 ), 14656 i = 1; 14657 14658 if ( pages <= buttons ) { 14659 numbers = _range( 0, pages ); 14660 } 14661 else if ( page <= half ) { 14662 numbers = _range( 0, buttons-2 ); 14663 numbers.push( 'ellipsis' ); 14664 numbers.push( pages-1 ); 14665 } 14666 else if ( page >= pages - 1 - half ) { 14667 numbers = _range( pages-(buttons-2), pages ); 14668 numbers.splice( 0, 0, 'ellipsis' ); // no unshift in ie6 14669 numbers.splice( 0, 0, 0 ); 14670 } 14671 else { 14672 numbers = _range( page-half+2, page+half-1 ); 14673 numbers.push( 'ellipsis' ); 14674 numbers.push( pages-1 ); 14675 numbers.splice( 0, 0, 'ellipsis' ); 14676 numbers.splice( 0, 0, 0 ); 14677 } 14678 14679 numbers.DT_el = 'span'; 14680 return numbers; 14681 } 14682 14683 14684 $.extend( extPagination, { 14685 simple: function ( page, pages ) { 14686 return [ 'previous', 'next' ]; 14687 }, 14688 14689 full: function ( page, pages ) { 14690 return [ 'first', 'previous', 'next', 'last' ]; 14691 }, 14692 14693 numbers: function ( page, pages ) { 14694 return [ _numbers(page, pages) ]; 14695 }, 14696 14697 simple_numbers: function ( page, pages ) { 14698 return [ 'previous', _numbers(page, pages), 'next' ]; 14699 }, 14700 14701 full_numbers: function ( page, pages ) { 14702 return [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ]; 14703 }, 14704 14705 first_last_numbers: function (page, pages) { 14706 return ['first', _numbers(page, pages), 'last']; 14707 }, 14708 14709 // For testing and plug-ins to use 14710 _numbers: _numbers, 14711 14712 // Number of number buttons (including ellipsis) to show. _Must be odd!_ 14713 numbers_length: 7 14714 } ); 14715 14716 14717 $.extend( true, DataTable.ext.renderer, { 14718 pageButton: { 14719 _: function ( settings, host, idx, buttons, page, pages ) { 14720 var classes = settings.oClasses; 14721 var lang = settings.oLanguage.oPaginate; 14722 var aria = settings.oLanguage.oAria.paginate || {}; 14723 var btnDisplay, btnClass, counter=0; 14724 14725 var attach = function( container, buttons ) { 14726 var i, ien, node, button, tabIndex; 14727 var disabledClass = classes.sPageButtonDisabled; 14728 var clickHandler = function ( e ) { 14729 _fnPageChange( settings, e.data.action, true ); 14730 }; 14731 14732 for ( i=0, ien=buttons.length ; i<ien ; i++ ) { 14733 button = buttons[i]; 14734 14735 if ( Array.isArray( button ) ) { 14736 var inner = $( '<'+(button.DT_el || 'div')+'/>' ) 14737 .appendTo( container ); 14738 attach( inner, button ); 14739 } 14740 else { 14741 btnDisplay = null; 14742 btnClass = button; 14743 tabIndex = settings.iTabIndex; 14744 14745 switch ( button ) { 14746 case 'ellipsis': 14747 container.append('<span class="ellipsis">…</span>'); 14748 break; 14749 14750 case 'first': 14751 btnDisplay = lang.sFirst; 14752 14753 if ( page === 0 ) { 14754 tabIndex = -1; 14755 btnClass += ' ' + disabledClass; 14756 } 14757 break; 14758 14759 case 'previous': 14760 btnDisplay = lang.sPrevious; 14761 14762 if ( page === 0 ) { 14763 tabIndex = -1; 14764 btnClass += ' ' + disabledClass; 14765 } 14766 break; 14767 14768 case 'next': 14769 btnDisplay = lang.sNext; 14770 14771 if ( pages === 0 || page === pages-1 ) { 14772 tabIndex = -1; 14773 btnClass += ' ' + disabledClass; 14774 } 14775 break; 14776 14777 case 'last': 14778 btnDisplay = lang.sLast; 14779 14780 if ( pages === 0 || page === pages-1 ) { 14781 tabIndex = -1; 14782 btnClass += ' ' + disabledClass; 14783 } 14784 break; 14785 14786 default: 14787 btnDisplay = settings.fnFormatNumber( button + 1 ); 14788 btnClass = page === button ? 14789 classes.sPageButtonActive : ''; 14790 break; 14791 } 14792 14793 if ( btnDisplay !== null ) { 14794 node = $('<a>', { 14795 'class': classes.sPageButton+' '+btnClass, 14796 'aria-controls': settings.sTableId, 14797 'aria-label': aria[ button ], 14798 'data-dt-idx': counter, 14799 'tabindex': tabIndex, 14800 'id': idx === 0 && typeof button === 'string' ? 14801 settings.sTableId +'_'+ button : 14802 null 14803 } ) 14804 .html( btnDisplay ) 14805 .appendTo( container ); 14806 14807 _fnBindAction( 14808 node, {action: button}, clickHandler 14809 ); 14810 14811 counter++; 14812 } 14813 } 14814 } 14815 }; 14816 14817 // IE9 throws an 'unknown error' if document.activeElement is used 14818 // inside an iframe or frame. Try / catch the error. Not good for 14819 // accessibility, but neither are frames. 14820 var activeEl; 14821 14822 try { 14823 // Because this approach is destroying and recreating the paging 14824 // elements, focus is lost on the select button which is bad for 14825 // accessibility. So we want to restore focus once the draw has 14826 // completed 14827 activeEl = $(host).find(document.activeElement).data('dt-idx'); 14828 } 14829 catch (e) {} 14830 14831 attach( $(host).empty(), buttons ); 14832 14833 if ( activeEl !== undefined ) { 14834 $(host).find( '[data-dt-idx='+activeEl+']' ).trigger('focus'); 14835 } 14836 } 14837 } 14838 } ); 14839 14840 14841 14842 // Built in type detection. See model.ext.aTypes for information about 14843 // what is required from this methods. 14844 $.extend( DataTable.ext.type.detect, [ 14845 // Plain numbers - first since V8 detects some plain numbers as dates 14846 // e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...). 14847 function ( d, settings ) 14848 { 14849 var decimal = settings.oLanguage.sDecimal; 14850 return _isNumber( d, decimal ) ? 'num'+decimal : null; 14851 }, 14852 14853 // Dates (only those recognised by the browser's Date.parse) 14854 function ( d, settings ) 14855 { 14856 // V8 tries _very_ hard to make a string passed into `Date.parse()` 14857 // valid, so we need to use a regex to restrict date formats. Use a 14858 // plug-in for anything other than ISO8601 style strings 14859 if ( d && !(d instanceof Date) && ! _re_date.test(d) ) { 14860 return null; 14861 } 14862 var parsed = Date.parse(d); 14863 return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null; 14864 }, 14865 14866 // Formatted numbers 14867 function ( d, settings ) 14868 { 14869 var decimal = settings.oLanguage.sDecimal; 14870 return _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null; 14871 }, 14872 14873 // HTML numeric 14874 function ( d, settings ) 14875 { 14876 var decimal = settings.oLanguage.sDecimal; 14877 return _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null; 14878 }, 14879 14880 // HTML numeric, formatted 14881 function ( d, settings ) 14882 { 14883 var decimal = settings.oLanguage.sDecimal; 14884 return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null; 14885 }, 14886 14887 // HTML (this is strict checking - there must be html) 14888 function ( d, settings ) 14889 { 14890 return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ? 14891 'html' : null; 14892 } 14893 ] ); 14894 14895 14896 14897 // Filter formatting functions. See model.ext.ofnSearch for information about 14898 // what is required from these methods. 14899 // 14900 // Note that additional search methods are added for the html numbers and 14901 // html formatted numbers by `_addNumericSort()` when we know what the decimal 14902 // place is 14903 14904 14905 $.extend( DataTable.ext.type.search, { 14906 html: function ( data ) { 14907 return _empty(data) ? 14908 data : 14909 typeof data === 'string' ? 14910 data 14911 .replace( _re_new_lines, " " ) 14912 .replace( _re_html, "" ) : 14913 ''; 14914 }, 14915 14916 string: function ( data ) { 14917 return _empty(data) ? 14918 data : 14919 typeof data === 'string' ? 14920 data.replace( _re_new_lines, " " ) : 14921 data; 14922 } 14923 } ); 14924 14925 14926 14927 var __numericReplace = function ( d, decimalPlace, re1, re2 ) { 14928 if ( d !== 0 && (!d || d === '-') ) { 14929 return -Infinity; 14930 } 14931 14932 // If a decimal place other than `.` is used, it needs to be given to the 14933 // function so we can detect it and replace with a `.` which is the only 14934 // decimal place Javascript recognises - it is not locale aware. 14935 if ( decimalPlace ) { 14936 d = _numToDecimal( d, decimalPlace ); 14937 } 14938 14939 if ( d.replace ) { 14940 if ( re1 ) { 14941 d = d.replace( re1, '' ); 14942 } 14943 14944 if ( re2 ) { 14945 d = d.replace( re2, '' ); 14946 } 14947 } 14948 14949 return d * 1; 14950 }; 14951 14952 14953 // Add the numeric 'deformatting' functions for sorting and search. This is done 14954 // in a function to provide an easy ability for the language options to add 14955 // additional methods if a non-period decimal place is used. 14956 function _addNumericSort ( decimalPlace ) { 14957 $.each( 14958 { 14959 // Plain numbers 14960 "num": function ( d ) { 14961 return __numericReplace( d, decimalPlace ); 14962 }, 14963 14964 // Formatted numbers 14965 "num-fmt": function ( d ) { 14966 return __numericReplace( d, decimalPlace, _re_formatted_numeric ); 14967 }, 14968 14969 // HTML numeric 14970 "html-num": function ( d ) { 14971 return __numericReplace( d, decimalPlace, _re_html ); 14972 }, 14973 14974 // HTML numeric, formatted 14975 "html-num-fmt": function ( d ) { 14976 return __numericReplace( d, decimalPlace, _re_html, _re_formatted_numeric ); 14977 } 14978 }, 14979 function ( key, fn ) { 14980 // Add the ordering method 14981 _ext.type.order[ key+decimalPlace+'-pre' ] = fn; 14982 14983 // For HTML types add a search formatter that will strip the HTML 14984 if ( key.match(/^html\-/) ) { 14985 _ext.type.search[ key+decimalPlace ] = _ext.type.search.html; 14986 } 14987 } 14988 ); 14989 } 14990 14991 14992 // Default sort methods 14993 $.extend( _ext.type.order, { 14994 // Dates 14995 "date-pre": function ( d ) { 14996 var ts = Date.parse( d ); 14997 return isNaN(ts) ? -Infinity : ts; 14998 }, 14999 15000 // html 15001 "html-pre": function ( a ) { 15002 return _empty(a) ? 15003 '' : 15004 a.replace ? 15005 a.replace( /<.*?>/g, "" ).toLowerCase() : 15006 a+''; 15007 }, 15008 15009 // string 15010 "string-pre": function ( a ) { 15011 // This is a little complex, but faster than always calling toString, 15012 // http://jsperf.com/tostring-v-check 15013 return _empty(a) ? 15014 '' : 15015 typeof a === 'string' ? 15016 a.toLowerCase() : 15017 ! a.toString ? 15018 '' : 15019 a.toString(); 15020 }, 15021 15022 // string-asc and -desc are retained only for compatibility with the old 15023 // sort methods 15024 "string-asc": function ( x, y ) { 15025 return ((x < y) ? -1 : ((x > y) ? 1 : 0)); 15026 }, 15027 15028 "string-desc": function ( x, y ) { 15029 return ((x < y) ? 1 : ((x > y) ? -1 : 0)); 15030 } 15031 } ); 15032 15033 15034 // Numeric sorting types - order doesn't matter here 15035 _addNumericSort( '' ); 15036 15037 15038 $.extend( true, DataTable.ext.renderer, { 15039 header: { 15040 _: function ( settings, cell, column, classes ) { 15041 // No additional mark-up required 15042 // Attach a sort listener to update on sort - note that using the 15043 // `DT` namespace will allow the event to be removed automatically 15044 // on destroy, while the `dt` namespaced event is the one we are 15045 // listening for 15046 $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) { 15047 if ( settings !== ctx ) { // need to check this this is the host 15048 return; // table, not a nested one 15049 } 15050 15051 var colIdx = column.idx; 15052 15053 cell 15054 .removeClass( 15055 classes.sSortAsc +' '+ 15056 classes.sSortDesc 15057 ) 15058 .addClass( columns[ colIdx ] == 'asc' ? 15059 classes.sSortAsc : columns[ colIdx ] == 'desc' ? 15060 classes.sSortDesc : 15061 column.sSortingClass 15062 ); 15063 } ); 15064 }, 15065 15066 jqueryui: function ( settings, cell, column, classes ) { 15067 $('<div/>') 15068 .addClass( classes.sSortJUIWrapper ) 15069 .append( cell.contents() ) 15070 .append( $('<span/>') 15071 .addClass( classes.sSortIcon+' '+column.sSortingClassJUI ) 15072 ) 15073 .appendTo( cell ); 15074 15075 // Attach a sort listener to update on sort 15076 $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) { 15077 if ( settings !== ctx ) { 15078 return; 15079 } 15080 15081 var colIdx = column.idx; 15082 15083 cell 15084 .removeClass( classes.sSortAsc +" "+classes.sSortDesc ) 15085 .addClass( columns[ colIdx ] == 'asc' ? 15086 classes.sSortAsc : columns[ colIdx ] == 'desc' ? 15087 classes.sSortDesc : 15088 column.sSortingClass 15089 ); 15090 15091 cell 15092 .find( 'span.'+classes.sSortIcon ) 15093 .removeClass( 15094 classes.sSortJUIAsc +" "+ 15095 classes.sSortJUIDesc +" "+ 15096 classes.sSortJUI +" "+ 15097 classes.sSortJUIAscAllowed +" "+ 15098 classes.sSortJUIDescAllowed 15099 ) 15100 .addClass( columns[ colIdx ] == 'asc' ? 15101 classes.sSortJUIAsc : columns[ colIdx ] == 'desc' ? 15102 classes.sSortJUIDesc : 15103 column.sSortingClassJUI 15104 ); 15105 } ); 15106 } 15107 } 15108 } ); 15109 15110 /* 15111 * Public helper functions. These aren't used internally by DataTables, or 15112 * called by any of the options passed into DataTables, but they can be used 15113 * externally by developers working with DataTables. They are helper functions 15114 * to make working with DataTables a little bit easier. 15115 */ 15116 15117 var __htmlEscapeEntities = function ( d ) { 15118 if (Array.isArray(d)) { 15119 d = d.join(','); 15120 } 15121 15122 return typeof d === 'string' ? 15123 d 15124 .replace(/&/g, '&') 15125 .replace(/</g, '<') 15126 .replace(/>/g, '>') 15127 .replace(/"/g, '"') : 15128 d; 15129 }; 15130 15131 // Common logic for moment, luxon or a date action 15132 function __mld( dt, momentFn, luxonFn, dateFn, arg1 ) { 15133 if (window.moment) { 15134 return dt[momentFn]( arg1 ); 15135 } 15136 else if (window.luxon) { 15137 return dt[luxonFn]( arg1 ); 15138 } 15139 15140 return dateFn ? dt[dateFn]( arg1 ) : dt; 15141 } 15142 15143 15144 var __mlWarning = false; 15145 function __mldObj (d, format, locale) { 15146 var dt; 15147 15148 if (window.moment) { 15149 dt = window.moment.utc( d, format, locale, true ); 15150 15151 if (! dt.isValid()) { 15152 return null; 15153 } 15154 } 15155 else if (window.luxon) { 15156 dt = format 15157 ? window.luxon.DateTime.fromFormat( d, format ) 15158 : window.luxon.DateTime.fromISO( d ); 15159 15160 if (! dt.isValid) { 15161 return null; 15162 } 15163 15164 dt.setLocale(locale); 15165 } 15166 else if (! format) { 15167 // No format given, must be ISO 15168 dt = new Date(d); 15169 } 15170 else { 15171 if (! __mlWarning) { 15172 alert('DataTables warning: Formatted date without Moment.js or Luxon - https://datatables.net/tn/17'); 15173 } 15174 15175 __mlWarning = true; 15176 } 15177 15178 return dt; 15179 } 15180 15181 // Wrapper for date, datetime and time which all operate the same way with the exception of 15182 // the output string for auto locale support 15183 function __mlHelper (localeString) { 15184 return function ( from, to, locale, def ) { 15185 // Luxon and Moment support 15186 // Argument shifting 15187 if ( arguments.length === 0 ) { 15188 locale = 'en'; 15189 to = null; // means toLocaleString 15190 from = null; // means iso8601 15191 } 15192 else if ( arguments.length === 1 ) { 15193 locale = 'en'; 15194 to = from; 15195 from = null; 15196 } 15197 else if ( arguments.length === 2 ) { 15198 locale = to; 15199 to = from; 15200 from = null; 15201 } 15202 15203 var typeName = 'datetime-' + to; 15204 15205 // Add type detection and sorting specific to this date format - we need to be able to identify 15206 // date type columns as such, rather than as numbers in extensions. Hence the need for this. 15207 if (! DataTable.ext.type.order[typeName]) { 15208 // The renderer will give the value to type detect as the type! 15209 DataTable.ext.type.detect.unshift(function (d) { 15210 return d === typeName ? typeName : false; 15211 }); 15212 15213 // The renderer gives us Moment, Luxon or Date obects for the sorting, all of which have a 15214 // `valueOf` which gives milliseconds epoch 15215 DataTable.ext.type.order[typeName + '-asc'] = function (a, b) { 15216 var x = a.valueOf(); 15217 var y = b.valueOf(); 15218 15219 return x === y 15220 ? 0 15221 : x < y 15222 ? -1 15223 : 1; 15224 } 15225 15226 DataTable.ext.type.order[typeName + '-desc'] = function (a, b) { 15227 var x = a.valueOf(); 15228 var y = b.valueOf(); 15229 15230 return x === y 15231 ? 0 15232 : x > y 15233 ? -1 15234 : 1; 15235 } 15236 } 15237 15238 return function ( d, type ) { 15239 // Allow for a default value 15240 if (d === null || d === undefined) { 15241 if (def === '--now') { 15242 // We treat everything as UTC further down, so no changes are 15243 // made, as such need to get the local date / time as if it were 15244 // UTC 15245 var local = new Date(); 15246 d = new Date( Date.UTC( 15247 local.getFullYear(), local.getMonth(), local.getDate(), 15248 local.getHours(), local.getMinutes(), local.getSeconds() 15249 ) ); 15250 } 15251 else { 15252 d = ''; 15253 } 15254 } 15255 15256 if (type === 'type') { 15257 // Typing uses the type name for fast matching 15258 return typeName; 15259 } 15260 15261 if (d === '') { 15262 return type !== 'sort' 15263 ? '' 15264 : __mldObj('0000-01-01 00:00:00', null, locale); 15265 } 15266 15267 // Shortcut. If `from` and `to` are the same, we are using the renderer to 15268 // format for ordering, not display - its already in the display format. 15269 if ( to !== null && from === to && type !== 'sort' && type !== 'type' && ! (d instanceof Date) ) { 15270 return d; 15271 } 15272 15273 var dt = __mldObj(d, from, locale); 15274 15275 if (dt === null) { 15276 return d; 15277 } 15278 15279 if (type === 'sort') { 15280 return dt; 15281 } 15282 15283 var formatted = to === null 15284 ? __mld(dt, 'toDate', 'toJSDate', '')[localeString]() 15285 : __mld(dt, 'format', 'toFormat', 'toISOString', to); 15286 15287 // XSS protection 15288 return type === 'display' ? 15289 __htmlEscapeEntities( formatted ) : 15290 formatted; 15291 }; 15292 } 15293 } 15294 15295 // Based on locale, determine standard number formatting 15296 // Fallback for legacy browsers is US English 15297 var __thousands = ','; 15298 var __decimal = '.'; 15299 15300 if (Intl) { 15301 try { 15302 var num = new Intl.NumberFormat().formatToParts(100000.1); 15303 15304 for (var i=0 ; i<num.length ; i++) { 15305 if (num[i].type === 'group') { 15306 __thousands = num[i].value; 15307 } 15308 else if (num[i].type === 'decimal') { 15309 __decimal = num[i].value; 15310 } 15311 } 15312 } 15313 catch (e) { 15314 // noop 15315 } 15316 } 15317 15318 // Formatted date time detection - use by declaring the formats you are going to use 15319 DataTable.datetime = function ( format, locale ) { 15320 var typeName = 'datetime-detect-' + format; 15321 15322 if (! locale) { 15323 locale = 'en'; 15324 } 15325 15326 if (! DataTable.ext.type.order[typeName]) { 15327 DataTable.ext.type.detect.unshift(function (d) { 15328 var dt = __mldObj(d, format, locale); 15329 return d === '' || dt ? typeName : false; 15330 }); 15331 15332 DataTable.ext.type.order[typeName + '-pre'] = function (d) { 15333 return __mldObj(d, format, locale) || 0; 15334 } 15335 } 15336 } 15337 15338 /** 15339 * Helpers for `columns.render`. 15340 * 15341 * The options defined here can be used with the `columns.render` initialisation 15342 * option to provide a display renderer. The following functions are defined: 15343 * 15344 * * `number` - Will format numeric data (defined by `columns.data`) for 15345 * display, retaining the original unformatted data for sorting and filtering. 15346 * It takes 5 parameters: 15347 * * `string` - Thousands grouping separator 15348 * * `string` - Decimal point indicator 15349 * * `integer` - Number of decimal points to show 15350 * * `string` (optional) - Prefix. 15351 * * `string` (optional) - Postfix (/suffix). 15352 * * `text` - Escape HTML to help prevent XSS attacks. It has no optional 15353 * parameters. 15354 * 15355 * @example 15356 * // Column definition using the number renderer 15357 * { 15358 * data: "salary", 15359 * render: $.fn.dataTable.render.number( '\'', '.', 0, '$' ) 15360 * } 15361 * 15362 * @namespace 15363 */ 15364 DataTable.render = { 15365 date: __mlHelper('toLocaleDateString'), 15366 datetime: __mlHelper('toLocaleString'), 15367 time: __mlHelper('toLocaleTimeString'), 15368 number: function ( thousands, decimal, precision, prefix, postfix ) { 15369 // Auto locale detection 15370 if (thousands === null || thousands === undefined) { 15371 thousands = __thousands; 15372 } 15373 15374 if (decimal === null || decimal === undefined) { 15375 decimal = __decimal; 15376 } 15377 15378 return { 15379 display: function ( d ) { 15380 if ( typeof d !== 'number' && typeof d !== 'string' ) { 15381 return d; 15382 } 15383 15384 if (d === '' || d === null) { 15385 return d; 15386 } 15387 15388 var negative = d < 0 ? '-' : ''; 15389 var flo = parseFloat( d ); 15390 15391 // If NaN then there isn't much formatting that we can do - just 15392 // return immediately, escaping any HTML (this was supposed to 15393 // be a number after all) 15394 if ( isNaN( flo ) ) { 15395 return __htmlEscapeEntities( d ); 15396 } 15397 15398 flo = flo.toFixed( precision ); 15399 d = Math.abs( flo ); 15400 15401 var intPart = parseInt( d, 10 ); 15402 var floatPart = precision ? 15403 decimal+(d - intPart).toFixed( precision ).substring( 2 ): 15404 ''; 15405 15406 // If zero, then can't have a negative prefix 15407 if (intPart === 0 && parseFloat(floatPart) === 0) { 15408 negative = ''; 15409 } 15410 15411 return negative + (prefix||'') + 15412 intPart.toString().replace( 15413 /\B(?=(\d{3})+(?!\d))/g, thousands 15414 ) + 15415 floatPart + 15416 (postfix||''); 15417 } 15418 }; 15419 }, 15420 15421 text: function () { 15422 return { 15423 display: __htmlEscapeEntities, 15424 filter: __htmlEscapeEntities 15425 }; 15426 } 15427 }; 15428 15429 15430 /* 15431 * This is really a good bit rubbish this method of exposing the internal methods 15432 * publicly... - To be fixed in 2.0 using methods on the prototype 15433 */ 15434 15435 15436 /** 15437 * Create a wrapper function for exporting an internal functions to an external API. 15438 * @param {string} fn API function name 15439 * @returns {function} wrapped function 15440 * @memberof DataTable#internal 15441 */ 15442 function _fnExternApiFunc (fn) 15443 { 15444 return function() { 15445 var args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat( 15446 Array.prototype.slice.call(arguments) 15447 ); 15448 return DataTable.ext.internal[fn].apply( this, args ); 15449 }; 15450 } 15451 15452 15453 /** 15454 * Reference to internal functions for use by plug-in developers. Note that 15455 * these methods are references to internal functions and are considered to be 15456 * private. If you use these methods, be aware that they are liable to change 15457 * between versions. 15458 * @namespace 15459 */ 15460 $.extend( DataTable.ext.internal, { 15461 _fnExternApiFunc: _fnExternApiFunc, 15462 _fnBuildAjax: _fnBuildAjax, 15463 _fnAjaxUpdate: _fnAjaxUpdate, 15464 _fnAjaxParameters: _fnAjaxParameters, 15465 _fnAjaxUpdateDraw: _fnAjaxUpdateDraw, 15466 _fnAjaxDataSrc: _fnAjaxDataSrc, 15467 _fnAddColumn: _fnAddColumn, 15468 _fnColumnOptions: _fnColumnOptions, 15469 _fnAdjustColumnSizing: _fnAdjustColumnSizing, 15470 _fnVisibleToColumnIndex: _fnVisibleToColumnIndex, 15471 _fnColumnIndexToVisible: _fnColumnIndexToVisible, 15472 _fnVisbleColumns: _fnVisbleColumns, 15473 _fnGetColumns: _fnGetColumns, 15474 _fnColumnTypes: _fnColumnTypes, 15475 _fnApplyColumnDefs: _fnApplyColumnDefs, 15476 _fnHungarianMap: _fnHungarianMap, 15477 _fnCamelToHungarian: _fnCamelToHungarian, 15478 _fnLanguageCompat: _fnLanguageCompat, 15479 _fnBrowserDetect: _fnBrowserDetect, 15480 _fnAddData: _fnAddData, 15481 _fnAddTr: _fnAddTr, 15482 _fnNodeToDataIndex: _fnNodeToDataIndex, 15483 _fnNodeToColumnIndex: _fnNodeToColumnIndex, 15484 _fnGetCellData: _fnGetCellData, 15485 _fnSetCellData: _fnSetCellData, 15486 _fnSplitObjNotation: _fnSplitObjNotation, 15487 _fnGetObjectDataFn: _fnGetObjectDataFn, 15488 _fnSetObjectDataFn: _fnSetObjectDataFn, 15489 _fnGetDataMaster: _fnGetDataMaster, 15490 _fnClearTable: _fnClearTable, 15491 _fnDeleteIndex: _fnDeleteIndex, 15492 _fnInvalidate: _fnInvalidate, 15493 _fnGetRowElements: _fnGetRowElements, 15494 _fnCreateTr: _fnCreateTr, 15495 _fnBuildHead: _fnBuildHead, 15496 _fnDrawHead: _fnDrawHead, 15497 _fnDraw: _fnDraw, 15498 _fnReDraw: _fnReDraw, 15499 _fnAddOptionsHtml: _fnAddOptionsHtml, 15500 _fnDetectHeader: _fnDetectHeader, 15501 _fnGetUniqueThs: _fnGetUniqueThs, 15502 _fnFeatureHtmlFilter: _fnFeatureHtmlFilter, 15503 _fnFilterComplete: _fnFilterComplete, 15504 _fnFilterCustom: _fnFilterCustom, 15505 _fnFilterColumn: _fnFilterColumn, 15506 _fnFilter: _fnFilter, 15507 _fnFilterCreateSearch: _fnFilterCreateSearch, 15508 _fnEscapeRegex: _fnEscapeRegex, 15509 _fnFilterData: _fnFilterData, 15510 _fnFeatureHtmlInfo: _fnFeatureHtmlInfo, 15511 _fnUpdateInfo: _fnUpdateInfo, 15512 _fnInfoMacros: _fnInfoMacros, 15513 _fnInitialise: _fnInitialise, 15514 _fnInitComplete: _fnInitComplete, 15515 _fnLengthChange: _fnLengthChange, 15516 _fnFeatureHtmlLength: _fnFeatureHtmlLength, 15517 _fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate, 15518 _fnPageChange: _fnPageChange, 15519 _fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing, 15520 _fnProcessingDisplay: _fnProcessingDisplay, 15521 _fnFeatureHtmlTable: _fnFeatureHtmlTable, 15522 _fnScrollDraw: _fnScrollDraw, 15523 _fnApplyToChildren: _fnApplyToChildren, 15524 _fnCalculateColumnWidths: _fnCalculateColumnWidths, 15525 _fnThrottle: _fnThrottle, 15526 _fnConvertToWidth: _fnConvertToWidth, 15527 _fnGetWidestNode: _fnGetWidestNode, 15528 _fnGetMaxLenString: _fnGetMaxLenString, 15529 _fnStringToCss: _fnStringToCss, 15530 _fnSortFlatten: _fnSortFlatten, 15531 _fnSort: _fnSort, 15532 _fnSortAria: _fnSortAria, 15533 _fnSortListener: _fnSortListener, 15534 _fnSortAttachListener: _fnSortAttachListener, 15535 _fnSortingClasses: _fnSortingClasses, 15536 _fnSortData: _fnSortData, 15537 _fnSaveState: _fnSaveState, 15538 _fnLoadState: _fnLoadState, 15539 _fnImplementState: _fnImplementState, 15540 _fnSettingsFromNode: _fnSettingsFromNode, 15541 _fnLog: _fnLog, 15542 _fnMap: _fnMap, 15543 _fnBindAction: _fnBindAction, 15544 _fnCallbackReg: _fnCallbackReg, 15545 _fnCallbackFire: _fnCallbackFire, 15546 _fnLengthOverflow: _fnLengthOverflow, 15547 _fnRenderer: _fnRenderer, 15548 _fnDataSource: _fnDataSource, 15549 _fnRowAttributes: _fnRowAttributes, 15550 _fnExtend: _fnExtend, 15551 _fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant 15552 // in 1.10, so this dead-end function is 15553 // added to prevent errors 15554 } ); 15555 15556 15557 // jQuery access 15558 $.fn.dataTable = DataTable; 15559 15560 // Provide access to the host jQuery object (circular reference) 15561 DataTable.$ = $; 15562 15563 // Legacy aliases 15564 $.fn.dataTableSettings = DataTable.settings; 15565 $.fn.dataTableExt = DataTable.ext; 15566 15567 // With a capital `D` we return a DataTables API instance rather than a 15568 // jQuery object 15569 $.fn.DataTable = function ( opts ) { 15570 return $(this).dataTable( opts ).api(); 15571 }; 15572 15573 // All properties that are available to $.fn.dataTable should also be 15574 // available on $.fn.DataTable 15575 $.each( DataTable, function ( prop, val ) { 15576 $.fn.DataTable[ prop ] = val; 15577 } ); 15578 15579 return DataTable; 15580}));
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.