vendor: 447,282 bytes, lines 1-15278
1/*! DataTables 1.10.12 2 * ©2008-2015 SpryMedia Ltd - datatables.net/license 3 */ 4 5/** 6 * @summary DataTables 7 * @description Paginate, search and order HTML tables 8 * @version 1.10.12 9 * @file jquery.dataTables.js 10 * @author SpryMedia Ltd (www.sprymedia.co.uk) 11 * @contact www.sprymedia.co.uk/contact 12 * @copyright Copyright 2008-2015 SpryMedia Ltd. 13 * 14 * This source file is free software, available under the following license: 15 * MIT license - http://datatables.net/license 16 * 17 * This source file is distributed in the hope that it will be useful, but 18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 19 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. 20 * 21 * For details please refer to: http://www.datatables.net 22 */ 23 24/*jslint evil: true, undef: true, browser: true */ 25/*globals $,require,jQuery,define,_selector_run,_selector_opts,_selector_first,_selector_row_indexes,_ext,_Api,_api_register,_api_registerPlural,_re_new_lines,_re_html,_re_formatted_numeric,_re_escape_regex,_empty,_intVal,_numToDecimal,_isNumber,_isHtml,_htmlNumeric,_pluck,_pluck_order,_range,_stripHtml,_unique,_fnBuildAjax,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnAjaxDataSrc,_fnAddColumn,_fnColumnOptions,_fnAdjustColumnSizing,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnVisbleColumns,_fnGetColumns,_fnColumnTypes,_fnApplyColumnDefs,_fnHungarianMap,_fnCamelToHungarian,_fnLanguageCompat,_fnBrowserDetect,_fnAddData,_fnAddTr,_fnNodeToDataIndex,_fnNodeToColumnIndex,_fnGetCellData,_fnSetCellData,_fnSplitObjNotation,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnGetDataMaster,_fnClearTable,_fnDeleteIndex,_fnInvalidate,_fnGetRowElements,_fnCreateTr,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAddOptionsHtml,_fnDetectHeader,_fnGetUniqueThs,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnFilterCreateSearch,_fnEscapeRegex,_fnFilterData,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnInfoMacros,_fnInitialise,_fnInitComplete,_fnLengthChange,_fnFeatureHtmlLength,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnFeatureHtmlTable,_fnScrollDraw,_fnApplyToChildren,_fnCalculateColumnWidths,_fnThrottle,_fnConvertToWidth,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/ 26 27(function( factory ) { 28 "use strict"; 29 30 if ( typeof define === 'function' && define.amd ) { 31 // AMD 32 define( ['jquery'], function ( $ ) { 33 return factory( $, window, document ); 34 } ); 35 } 36 else if ( typeof exports === 'object' ) { 37 // CommonJS 38 module.exports = function (root, $) { 39 if ( ! root ) { 40 // CommonJS environments without a window global must pass a 41 // root. This will give an error otherwise 42 root = window; 43 } 44 45 if ( ! $ ) { 46 $ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window 47 require('jquery') : 48 require('jquery')( root ); 49 } 50 51 return factory( $, root, root.document ); 52 }; 53 } 54 else { 55 // Browser 56 factory( jQuery, window, document ); 57 } 58} 59(function( $, window, document, undefined ) { 60 "use strict"; 61 62 /** 63 * DataTables is a plug-in for the jQuery Javascript library. It is a highly 64 * flexible tool, based upon the foundations of progressive enhancement, 65 * which will add advanced interaction controls to any HTML table. For a 66 * full list of features please refer to 67 * [DataTables.net](href="http://datatables.net). 68 * 69 * Note that the `DataTable` object is not a global variable but is aliased 70 * to `jQuery.fn.DataTable` and `jQuery.fn.dataTable` through which it may 71 * be accessed. 72 * 73 * @class 74 * @param {object} [init={}] Configuration object for DataTables. Options 75 * are defined by {@link DataTable.defaults} 76 * @requires jQuery 1.7+ 77 * 78 * @example 79 * // Basic initialisation 80 * $(document).ready( function { 81 * $('#example').dataTable(); 82 * } ); 83 * 84 * @example 85 * // Initialisation with configuration options - in this case, disable 86 * // pagination and sorting. 87 * $(document).ready( function { 88 * $('#example').dataTable( { 89 * "paginate": false, 90 * "sort": false 91 * } ); 92 * } ); 93 */ 94 var DataTable = function ( options ) 95 { 96 /** 97 * Perform a jQuery selector action on the table's TR elements (from the tbody) and 98 * return the resulting jQuery object. 99 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on 100 * @param {object} [oOpts] Optional parameters for modifying the rows to be included 101 * @param {string} [oOpts.filter=none] Select TR elements that meet the current filter 102 * criterion ("applied") or all TR elements (i.e. no filter). 103 * @param {string} [oOpts.order=current] Order of the TR elements in the processed array. 104 * Can be either 'current', whereby the current sorting of the table is used, or 105 * 'original' whereby the original order the data was read into the table is used. 106 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page 107 * ("current") or not ("all"). If 'current' is given, then order is assumed to be 108 * 'current' and filter is 'applied', regardless of what they might be given as. 109 * @returns {object} jQuery object, filtered by the given selector. 110 * @dtopt API 111 * @deprecated Since v1.10 112 * 113 * @example 114 * $(document).ready(function() { 115 * var oTable = $('#example').dataTable(); 116 * 117 * // Highlight every second row 118 * oTable.$('tr:odd').css('backgroundColor', 'blue'); 119 * } ); 120 * 121 * @example 122 * $(document).ready(function() { 123 * var oTable = $('#example').dataTable(); 124 * 125 * // Filter to rows with 'Webkit' in them, add a background colour and then 126 * // remove the filter, thus highlighting the 'Webkit' rows only. 127 * oTable.fnFilter('Webkit'); 128 * oTable.$('tr', {"search": "applied"}).css('backgroundColor', 'blue'); 129 * oTable.fnFilter(''); 130 * } ); 131 */ 132 this.$ = function ( sSelector, oOpts ) 133 { 134 return this.api(true).$( sSelector, oOpts ); 135 }; 136 137 138 /** 139 * Almost identical to $ in operation, but in this case returns the data for the matched 140 * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes 141 * rather than any descendants, so the data can be obtained for the row/cell. If matching 142 * rows are found, the data returned is the original data array/object that was used to 143 * create the row (or a generated array if from a DOM source). 144 * 145 * This method is often useful in-combination with $ where both functions are given the 146 * same parameters and the array indexes will match identically. 147 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on 148 * @param {object} [oOpts] Optional parameters for modifying the rows to be included 149 * @param {string} [oOpts.filter=none] Select elements that meet the current filter 150 * criterion ("applied") or all elements (i.e. no filter). 151 * @param {string} [oOpts.order=current] Order of the data in the processed array. 152 * Can be either 'current', whereby the current sorting of the table is used, or 153 * 'original' whereby the original order the data was read into the table is used. 154 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page 155 * ("current") or not ("all"). If 'current' is given, then order is assumed to be 156 * 'current' and filter is 'applied', regardless of what they might be given as. 157 * @returns {array} Data for the matched elements. If any elements, as a result of the 158 * selector, were not TR, TD or TH elements in the DataTable, they will have a null 159 * entry in the array. 160 * @dtopt API 161 * @deprecated Since v1.10 162 * 163 * @example 164 * $(document).ready(function() { 165 * var oTable = $('#example').dataTable(); 166 * 167 * // Get the data from the first row in the table 168 * var data = oTable._('tr:first'); 169 * 170 * // Do something useful with the data 171 * alert( "First cell is: "+data[0] ); 172 * } ); 173 * 174 * @example 175 * $(document).ready(function() { 176 * var oTable = $('#example').dataTable(); 177 * 178 * // Filter to 'Webkit' and get all data for 179 * oTable.fnFilter('Webkit'); 180 * var data = oTable._('tr', {"search": "applied"}); 181 * 182 * // Do something with the data 183 * alert( data.length+" rows matched the search" ); 184 * } ); 185 */ 186 this._ = function ( sSelector, oOpts ) 187 { 188 return this.api(true).rows( sSelector, oOpts ).data(); 189 }; 190 191 192 /** 193 * Create a DataTables Api instance, with the currently selected tables for 194 * the Api's context. 195 * @param {boolean} [traditional=false] Set the API instance's context to be 196 * only the table referred to by the `DataTable.ext.iApiIndex` option, as was 197 * used in the API presented by DataTables 1.9- (i.e. the traditional mode), 198 * or if all tables captured in the jQuery object should be used. 199 * @return {DataTables.Api} 200 */ 201 this.api = function ( traditional ) 202 { 203 return traditional ? 204 new _Api( 205 _fnSettingsFromNode( this[ _ext.iApiIndex ] ) 206 ) : 207 new _Api( this ); 208 }; 209 210 211 /** 212 * Add a single new row or multiple rows of data to the table. Please note 213 * that this is suitable for client-side processing only - if you are using 214 * server-side processing (i.e. "bServerSide": true), then to add data, you 215 * must add it to the data source, i.e. the server-side, through an Ajax call. 216 * @param {array|object} data The data to be added to the table. This can be: 217 * <ul> 218 * <li>1D array of data - add a single row with the data provided</li> 219 * <li>2D array of arrays - add multiple rows in a single call</li> 220 * <li>object - data object when using <i>mData</i></li> 221 * <li>array of objects - multiple data objects when using <i>mData</i></li> 222 * </ul> 223 * @param {bool} [redraw=true] redraw the table or not 224 * @returns {array} An array of integers, representing the list of indexes in 225 * <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to 226 * the table. 227 * @dtopt API 228 * @deprecated Since v1.10 229 * 230 * @example 231 * // Global var for counter 232 * var giCount = 2; 233 * 234 * $(document).ready(function() { 235 * $('#example').dataTable(); 236 * } ); 237 * 238 * function fnClickAddRow() { 239 * $('#example').dataTable().fnAddData( [ 240 * giCount+".1", 241 * giCount+".2", 242 * giCount+".3", 243 * giCount+".4" ] 244 * ); 245 * 246 * giCount++; 247 * } 248 */ 249 this.fnAddData = function( data, redraw ) 250 { 251 var api = this.api( true ); 252 253 /* Check if we want to add multiple rows or not */ 254 var rows = $.isArray(data) && ( $.isArray(data[0]) || $.isPlainObject(data[0]) ) ? 255 api.rows.add( data ) : 256 api.row.add( data ); 257 258 if ( redraw === undefined || redraw ) { 259 api.draw(); 260 } 261 262 return rows.flatten().toArray(); 263 }; 264 265 266 /** 267 * This function will make DataTables recalculate the column sizes, based on the data 268 * contained in the table and the sizes applied to the columns (in the DOM, CSS or 269 * through the sWidth parameter). This can be useful when the width of the table's 270 * parent element changes (for example a window resize). 271 * @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to 272 * @dtopt API 273 * @deprecated Since v1.10 274 * 275 * @example 276 * $(document).ready(function() { 277 * var oTable = $('#example').dataTable( { 278 * "sScrollY": "200px", 279 * "bPaginate": false 280 * } ); 281 * 282 * $(window).bind('resize', function () { 283 * oTable.fnAdjustColumnSizing(); 284 * } ); 285 * } ); 286 */ 287 this.fnAdjustColumnSizing = function ( bRedraw ) 288 { 289 var api = this.api( true ).columns.adjust(); 290 var settings = api.settings()[0]; 291 var scroll = settings.oScroll; 292 293 if ( bRedraw === undefined || bRedraw ) { 294 api.draw( false ); 295 } 296 else if ( scroll.sX !== "" || scroll.sY !== "" ) { 297 /* If not redrawing, but scrolling, we want to apply the new column sizes anyway */ 298 _fnScrollDraw( settings ); 299 } 300 }; 301 302 303 /** 304 * Quickly and simply clear a table 305 * @param {bool} [bRedraw=true] redraw the table or not 306 * @dtopt API 307 * @deprecated Since v1.10 308 * 309 * @example 310 * $(document).ready(function() { 311 * var oTable = $('#example').dataTable(); 312 * 313 * // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...) 314 * oTable.fnClearTable(); 315 * } ); 316 */ 317 this.fnClearTable = function( bRedraw ) 318 { 319 var api = this.api( true ).clear(); 320 321 if ( bRedraw === undefined || bRedraw ) { 322 api.draw(); 323 } 324 }; 325 326 327 /** 328 * The exact opposite of 'opening' a row, this function will close any rows which 329 * are currently 'open'. 330 * @param {node} nTr the table row to 'close' 331 * @returns {int} 0 on success, or 1 if failed (can't find the row) 332 * @dtopt API 333 * @deprecated Since v1.10 334 * 335 * @example 336 * $(document).ready(function() { 337 * var oTable; 338 * 339 * // 'open' an information row when a row is clicked on 340 * $('#example tbody tr').click( function () { 341 * if ( oTable.fnIsOpen(this) ) { 342 * oTable.fnClose( this ); 343 * } else { 344 * oTable.fnOpen( this, "Temporary row opened", "info_row" ); 345 * } 346 * } ); 347 * 348 * oTable = $('#example').dataTable(); 349 * } ); 350 */ 351 this.fnClose = function( nTr ) 352 { 353 this.api( true ).row( nTr ).child.hide(); 354 }; 355 356 357 /** 358 * Remove a row for the table 359 * @param {mixed} target The index of the row from aoData to be deleted, or 360 * the TR element you want to delete 361 * @param {function|null} [callBack] Callback function 362 * @param {bool} [redraw=true] Redraw the table or not 363 * @returns {array} The row that was deleted 364 * @dtopt API 365 * @deprecated Since v1.10 366 * 367 * @example 368 * $(document).ready(function() { 369 * var oTable = $('#example').dataTable(); 370 * 371 * // Immediately remove the first row 372 * oTable.fnDeleteRow( 0 ); 373 * } ); 374 */ 375 this.fnDeleteRow = function( target, callback, redraw ) 376 { 377 var api = this.api( true ); 378 var rows = api.rows( target ); 379 var settings = rows.settings()[0]; 380 var data = settings.aoData[ rows[0][0] ]; 381 382 rows.remove(); 383 384 if ( callback ) { 385 callback.call( this, settings, data ); 386 } 387 388 if ( redraw === undefined || redraw ) { 389 api.draw(); 390 } 391 392 return data; 393 }; 394 395 396 /** 397 * Restore the table to it's original state in the DOM by removing all of DataTables 398 * enhancements, alterations to the DOM structure of the table and event listeners. 399 * @param {boolean} [remove=false] Completely remove the table from the DOM 400 * @dtopt API 401 * @deprecated Since v1.10 402 * 403 * @example 404 * $(document).ready(function() { 405 * // This example is fairly pointless in reality, but shows how fnDestroy can be used 406 * var oTable = $('#example').dataTable(); 407 * oTable.fnDestroy(); 408 * } ); 409 */ 410 this.fnDestroy = function ( remove ) 411 { 412 this.api( true ).destroy( remove ); 413 }; 414 415 416 /** 417 * Redraw the table 418 * @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw. 419 * @dtopt API 420 * @deprecated Since v1.10 421 * 422 * @example 423 * $(document).ready(function() { 424 * var oTable = $('#example').dataTable(); 425 * 426 * // Re-draw the table - you wouldn't want to do it here, but it's an example :-) 427 * oTable.fnDraw(); 428 * } ); 429 */ 430 this.fnDraw = function( complete ) 431 { 432 // Note that this isn't an exact match to the old call to _fnDraw - it takes 433 // into account the new data, but can hold position. 434 this.api( true ).draw( complete ); 435 }; 436 437 438 /** 439 * Filter the input based on data 440 * @param {string} sInput String to filter the table on 441 * @param {int|null} [iColumn] Column to limit filtering to 442 * @param {bool} [bRegex=false] Treat as regular expression or not 443 * @param {bool} [bSmart=true] Perform smart filtering or not 444 * @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es) 445 * @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false) 446 * @dtopt API 447 * @deprecated Since v1.10 448 * 449 * @example 450 * $(document).ready(function() { 451 * var oTable = $('#example').dataTable(); 452 * 453 * // Sometime later - filter... 454 * oTable.fnFilter( 'test string' ); 455 * } ); 456 */ 457 this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive ) 458 { 459 var api = this.api( true ); 460 461 if ( iColumn === null || iColumn === undefined ) { 462 api.search( sInput, bRegex, bSmart, bCaseInsensitive ); 463 } 464 else { 465 api.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive ); 466 } 467 468 api.draw(); 469 }; 470 471 472 /** 473 * Get the data for the whole table, an individual row or an individual cell based on the 474 * provided parameters. 475 * @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as 476 * a TR node then the data source for the whole row will be returned. If given as a 477 * TD/TH cell node then iCol will be automatically calculated and the data for the 478 * cell returned. If given as an integer, then this is treated as the aoData internal 479 * data index for the row (see fnGetPosition) and the data for that row used. 480 * @param {int} [col] Optional column index that you want the data of. 481 * @returns {array|object|string} If mRow is undefined, then the data for all rows is 482 * returned. If mRow is defined, just data for that row, and is iCol is 483 * defined, only data for the designated cell is returned. 484 * @dtopt API 485 * @deprecated Since v1.10 486 * 487 * @example 488 * // Row data 489 * $(document).ready(function() { 490 * oTable = $('#example').dataTable(); 491 * 492 * oTable.$('tr').click( function () { 493 * var data = oTable.fnGetData( this ); 494 * // ... do something with the array / object of data for the row 495 * } ); 496 * } ); 497 * 498 * @example 499 * // Individual cell data 500 * $(document).ready(function() { 501 * oTable = $('#example').dataTable(); 502 * 503 * oTable.$('td').click( function () { 504 * var sData = oTable.fnGetData( this ); 505 * alert( 'The cell clicked on had the value of '+sData ); 506 * } ); 507 * } ); 508 */ 509 this.fnGetData = function( src, col ) 510 { 511 var api = this.api( true ); 512 513 if ( src !== undefined ) { 514 var type = src.nodeName ? src.nodeName.toLowerCase() : ''; 515 516 return col !== undefined || type == 'td' || type == 'th' ? 517 api.cell( src, col ).data() : 518 api.row( src ).data() || null; 519 } 520 521 return api.data().toArray(); 522 }; 523 524 525 /** 526 * Get an array of the TR nodes that are used in the table's body. Note that you will 527 * typically want to use the '$' API method in preference to this as it is more 528 * flexible. 529 * @param {int} [iRow] Optional row index for the TR element you want 530 * @returns {array|node} If iRow is undefined, returns an array of all TR elements 531 * in the table's body, or iRow is defined, just the TR element requested. 532 * @dtopt API 533 * @deprecated Since v1.10 534 * 535 * @example 536 * $(document).ready(function() { 537 * var oTable = $('#example').dataTable(); 538 * 539 * // Get the nodes from the table 540 * var nNodes = oTable.fnGetNodes( ); 541 * } ); 542 */ 543 this.fnGetNodes = function( iRow ) 544 { 545 var api = this.api( true ); 546 547 return iRow !== undefined ? 548 api.row( iRow ).node() : 549 api.rows().nodes().flatten().toArray(); 550 }; 551 552 553 /** 554 * Get the array indexes of a particular cell from it's DOM element 555 * and column index including hidden columns 556 * @param {node} node this can either be a TR, TD or TH in the table's body 557 * @returns {int} If nNode is given as a TR, then a single index is returned, or 558 * if given as a cell, an array of [row index, column index (visible), 559 * column index (all)] is given. 560 * @dtopt API 561 * @deprecated Since v1.10 562 * 563 * @example 564 * $(document).ready(function() { 565 * $('#example tbody td').click( function () { 566 * // Get the position of the current data from the node 567 * var aPos = oTable.fnGetPosition( this ); 568 * 569 * // Get the data array for this row 570 * var aData = oTable.fnGetData( aPos[0] ); 571 * 572 * // Update the data array and return the value 573 * aData[ aPos[1] ] = 'clicked'; 574 * this.innerHTML = 'clicked'; 575 * } ); 576 * 577 * // Init DataTables 578 * oTable = $('#example').dataTable(); 579 * } ); 580 */ 581 this.fnGetPosition = function( node ) 582 { 583 var api = this.api( true ); 584 var nodeName = node.nodeName.toUpperCase(); 585 586 if ( nodeName == 'TR' ) { 587 return api.row( node ).index(); 588 } 589 else if ( nodeName == 'TD' || nodeName == 'TH' ) { 590 var cell = api.cell( node ).index(); 591 592 return [ 593 cell.row, 594 cell.columnVisible, 595 cell.column 596 ]; 597 } 598 return null; 599 }; 600 601 602 /** 603 * Check to see if a row is 'open' or not. 604 * @param {node} nTr the table row to check 605 * @returns {boolean} true if the row is currently open, false otherwise 606 * @dtopt API 607 * @deprecated Since v1.10 608 * 609 * @example 610 * $(document).ready(function() { 611 * var oTable; 612 * 613 * // 'open' an information row when a row is clicked on 614 * $('#example tbody tr').click( function () { 615 * if ( oTable.fnIsOpen(this) ) { 616 * oTable.fnClose( this ); 617 * } else { 618 * oTable.fnOpen( this, "Temporary row opened", "info_row" ); 619 * } 620 * } ); 621 * 622 * oTable = $('#example').dataTable(); 623 * } ); 624 */ 625 this.fnIsOpen = function( nTr ) 626 { 627 return this.api( true ).row( nTr ).child.isShown(); 628 }; 629 630 631 /** 632 * This function will place a new row directly after a row which is currently 633 * on display on the page, with the HTML contents that is passed into the 634 * function. This can be used, for example, to ask for confirmation that a 635 * particular record should be deleted. 636 * @param {node} nTr The table row to 'open' 637 * @param {string|node|jQuery} mHtml The HTML to put into the row 638 * @param {string} sClass Class to give the new TD cell 639 * @returns {node} The row opened. Note that if the table row passed in as the 640 * first parameter, is not found in the table, this method will silently 641 * return. 642 * @dtopt API 643 * @deprecated Since v1.10 644 * 645 * @example 646 * $(document).ready(function() { 647 * var oTable; 648 * 649 * // 'open' an information row when a row is clicked on 650 * $('#example tbody tr').click( function () { 651 * if ( oTable.fnIsOpen(this) ) { 652 * oTable.fnClose( this ); 653 * } else { 654 * oTable.fnOpen( this, "Temporary row opened", "info_row" ); 655 * } 656 * } ); 657 * 658 * oTable = $('#example').dataTable(); 659 * } ); 660 */ 661 this.fnOpen = function( nTr, mHtml, sClass ) 662 { 663 return this.api( true ) 664 .row( nTr ) 665 .child( mHtml, sClass ) 666 .show() 667 .child()[0]; 668 }; 669 670 671 /** 672 * Change the pagination - provides the internal logic for pagination in a simple API 673 * function. With this function you can have a DataTables table go to the next, 674 * previous, first or last pages. 675 * @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last" 676 * or page number to jump to (integer), note that page 0 is the first page. 677 * @param {bool} [bRedraw=true] Redraw the table or not 678 * @dtopt API 679 * @deprecated Since v1.10 680 * 681 * @example 682 * $(document).ready(function() { 683 * var oTable = $('#example').dataTable(); 684 * oTable.fnPageChange( 'next' ); 685 * } ); 686 */ 687 this.fnPageChange = function ( mAction, bRedraw ) 688 { 689 var api = this.api( true ).page( mAction ); 690 691 if ( bRedraw === undefined || bRedraw ) { 692 api.draw(false); 693 } 694 }; 695 696 697 /** 698 * Show a particular column 699 * @param {int} iCol The column whose display should be changed 700 * @param {bool} bShow Show (true) or hide (false) the column 701 * @param {bool} [bRedraw=true] Redraw the table or not 702 * @dtopt API 703 * @deprecated Since v1.10 704 * 705 * @example 706 * $(document).ready(function() { 707 * var oTable = $('#example').dataTable(); 708 * 709 * // Hide the second column after initialisation 710 * oTable.fnSetColumnVis( 1, false ); 711 * } ); 712 */ 713 this.fnSetColumnVis = function ( iCol, bShow, bRedraw ) 714 { 715 var api = this.api( true ).column( iCol ).visible( bShow ); 716 717 if ( bRedraw === undefined || bRedraw ) { 718 api.columns.adjust().draw(); 719 } 720 }; 721 722 723 /** 724 * Get the settings for a particular table for external manipulation 725 * @returns {object} DataTables settings object. See 726 * {@link DataTable.models.oSettings} 727 * @dtopt API 728 * @deprecated Since v1.10 729 * 730 * @example 731 * $(document).ready(function() { 732 * var oTable = $('#example').dataTable(); 733 * var oSettings = oTable.fnSettings(); 734 * 735 * // Show an example parameter from the settings 736 * alert( oSettings._iDisplayStart ); 737 * } ); 738 */ 739 this.fnSettings = function() 740 { 741 return _fnSettingsFromNode( this[_ext.iApiIndex] ); 742 }; 743 744 745 /** 746 * Sort the table by a particular column 747 * @param {int} iCol the data index to sort on. Note that this will not match the 748 * 'display index' if you have hidden data entries 749 * @dtopt API 750 * @deprecated Since v1.10 751 * 752 * @example 753 * $(document).ready(function() { 754 * var oTable = $('#example').dataTable(); 755 * 756 * // Sort immediately with columns 0 and 1 757 * oTable.fnSort( [ [0,'asc'], [1,'asc'] ] ); 758 * } ); 759 */ 760 this.fnSort = function( aaSort ) 761 { 762 this.api( true ).order( aaSort ).draw(); 763 }; 764 765 766 /** 767 * Attach a sort listener to an element for a given column 768 * @param {node} nNode the element to attach the sort listener to 769 * @param {int} iColumn the column that a click on this node will sort on 770 * @param {function} [fnCallback] callback function when sort is run 771 * @dtopt API 772 * @deprecated Since v1.10 773 * 774 * @example 775 * $(document).ready(function() { 776 * var oTable = $('#example').dataTable(); 777 * 778 * // Sort on column 1, when 'sorter' is clicked on 779 * oTable.fnSortListener( document.getElementById('sorter'), 1 ); 780 * } ); 781 */ 782 this.fnSortListener = function( nNode, iColumn, fnCallback ) 783 { 784 this.api( true ).order.listener( nNode, iColumn, fnCallback ); 785 }; 786 787 788 /** 789 * Update a table cell or row - this method will accept either a single value to 790 * update the cell with, an array of values with one element for each column or 791 * an object in the same format as the original data source. The function is 792 * self-referencing in order to make the multi column updates easier. 793 * @param {object|array|string} mData Data to update the cell/row with 794 * @param {node|int} mRow TR element you want to update or the aoData index 795 * @param {int} [iColumn] The column to update, give as null or undefined to 796 * update a whole row. 797 * @param {bool} [bRedraw=true] Redraw the table or not 798 * @param {bool} [bAction=true] Perform pre-draw actions or not 799 * @returns {int} 0 on success, 1 on error 800 * @dtopt API 801 * @deprecated Since v1.10 802 * 803 * @example 804 * $(document).ready(function() { 805 * var oTable = $('#example').dataTable(); 806 * oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell 807 * oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row 808 * } ); 809 */ 810 this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction ) 811 { 812 var api = this.api( true ); 813 814 if ( iColumn === undefined || iColumn === null ) { 815 api.row( mRow ).data( mData ); 816 } 817 else { 818 api.cell( mRow, iColumn ).data( mData ); 819 } 820 821 if ( bAction === undefined || bAction ) { 822 api.columns.adjust(); 823 } 824 825 if ( bRedraw === undefined || bRedraw ) { 826 api.draw(); 827 } 828 return 0; 829 }; 830 831 832 /** 833 * Provide a common method for plug-ins to check the version of DataTables being used, in order 834 * to ensure compatibility. 835 * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the 836 * formats "X" and "X.Y" are also acceptable. 837 * @returns {boolean} true if this version of DataTables is greater or equal to the required 838 * version, or false if this version of DataTales is not suitable 839 * @method 840 * @dtopt API 841 * @deprecated Since v1.10 842 * 843 * @example 844 * $(document).ready(function() { 845 * var oTable = $('#example').dataTable(); 846 * alert( oTable.fnVersionCheck( '1.9.0' ) ); 847 * } ); 848 */ 849 this.fnVersionCheck = _ext.fnVersionCheck; 850 851 852 var _that = this; 853 var emptyInit = options === undefined; 854 var len = this.length; 855 856 if ( emptyInit ) { 857 options = {}; 858 } 859 860 this.oApi = this.internal = _ext.internal; 861 862 // Extend with old style plug-in API methods 863 for ( var fn in DataTable.ext.internal ) { 864 if ( fn ) { 865 this[fn] = _fnExternApiFunc(fn); 866 } 867 } 868 869 this.each(function() { 870 // For each initialisation we want to give it a clean initialisation 871 // object that can be bashed around 872 var o = {}; 873 var oInit = len > 1 ? // optimisation for single table case 874 _fnExtend( o, options, true ) : 875 options; 876 877 /*global oInit,_that,emptyInit*/ 878 var i=0, iLen, j, jLen, k, kLen; 879 var sId = this.getAttribute( 'id' ); 880 var bInitHandedOff = false; 881 var defaults = DataTable.defaults; 882 var $this = $(this); 883 884 885 /* Sanity check */ 886 if ( this.nodeName.toLowerCase() != 'table' ) 887 { 888 _fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 ); 889 return; 890 } 891 892 /* Backwards compatibility for the defaults */ 893 _fnCompatOpts( defaults ); 894 _fnCompatCols( defaults.column ); 895 896 /* Convert the camel-case defaults to Hungarian */ 897 _fnCamelToHungarian( defaults, defaults, true ); 898 _fnCamelToHungarian( defaults.column, defaults.column, true ); 899 900 /* Setting up the initialisation object */ 901 _fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ) ); 902 903 904 905 /* Check to see if we are re-initialising a table */ 906 var allSettings = DataTable.settings; 907 for ( i=0, iLen=allSettings.length ; i<iLen ; i++ ) 908 { 909 var s = allSettings[i]; 910 911 /* Base check on table node */ 912 if ( s.nTable == this || s.nTHead.parentNode == this || (s.nTFoot && s.nTFoot.parentNode == this) ) 913 { 914 var bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve; 915 var bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy; 916 917 if ( emptyInit || bRetrieve ) 918 { 919 return s.oInstance; 920 } 921 else if ( bDestroy ) 922 { 923 s.oInstance.fnDestroy(); 924 break; 925 } 926 else 927 { 928 _fnLog( s, 0, 'Cannot reinitialise DataTable', 3 ); 929 return; 930 } 931 } 932 933 /* If the element we are initialising has the same ID as a table which was previously 934 * initialised, but the table nodes don't match (from before) then we destroy the old 935 * instance by simply deleting it. This is under the assumption that the table has been 936 * destroyed by other methods. Anyone using non-id selectors will need to do this manually 937 */ 938 if ( s.sTableId == this.id ) 939 { 940 allSettings.splice( i, 1 ); 941 break; 942 } 943 } 944 945 /* Ensure the table has an ID - required for accessibility */ 946 if ( sId === null || sId === "" ) 947 { 948 sId = "DataTables_Table_"+(DataTable.ext._unique++); 949 this.id = sId; 950 } 951 952 /* Create the settings object for this table and set some of the default parameters */ 953 var oSettings = $.extend( true, {}, DataTable.models.oSettings, { 954 "sDestroyWidth": $this[0].style.width, 955 "sInstance": sId, 956 "sTableId": sId 957 } ); 958 oSettings.nTable = this; 959 oSettings.oApi = _that.internal; 960 oSettings.oInit = oInit; 961 962 allSettings.push( oSettings ); 963 964 // Need to add the instance after the instance after the settings object has been added 965 // to the settings array, so we can self reference the table instance if more than one 966 oSettings.oInstance = (_that.length===1) ? _that : $this.dataTable(); 967 968 // Backwards compatibility, before we apply all the defaults 969 _fnCompatOpts( oInit ); 970 971 if ( oInit.oLanguage ) 972 { 973 _fnLanguageCompat( oInit.oLanguage ); 974 } 975 976 // If the length menu is given, but the init display length is not, use the length menu 977 if ( oInit.aLengthMenu && ! oInit.iDisplayLength ) 978 { 979 oInit.iDisplayLength = $.isArray( oInit.aLengthMenu[0] ) ? 980 oInit.aLengthMenu[0][0] : oInit.aLengthMenu[0]; 981 } 982 983 // Apply the defaults and init options to make a single init object will all 984 // options defined from defaults and instance options. 985 oInit = _fnExtend( $.extend( true, {}, defaults ), oInit ); 986 987 988 // Map the initialisation options onto the settings object 989 _fnMap( oSettings.oFeatures, oInit, [ 990 "bPaginate", 991 "bLengthChange", 992 "bFilter", 993 "bSort", 994 "bSortMulti", 995 "bInfo", 996 "bProcessing", 997 "bAutoWidth", 998 "bSortClasses", 999 "bServerSide", 1000 "bDeferRender" 1001 ] ); 1002 _fnMap( oSettings, oInit, [ 1003 "asStripeClasses", 1004 "ajax", 1005 "fnServerData", 1006 "fnFormatNumber", 1007 "sServerMethod", 1008 "aaSorting", 1009 "aaSortingFixed", 1010 "aLengthMenu", 1011 "sPaginationType", 1012 "sAjaxSource", 1013 "sAjaxDataProp", 1014 "iStateDuration", 1015 "sDom", 1016 "bSortCellsTop", 1017 "iTabIndex", 1018 "fnStateLoadCallback", 1019 "fnStateSaveCallback", 1020 "renderer", 1021 "searchDelay", 1022 "rowId", 1023 [ "iCookieDuration", "iStateDuration" ], // backwards compat 1024 [ "oSearch", "oPreviousSearch" ], 1025 [ "aoSearchCols", "aoPreSearchCols" ], 1026 [ "iDisplayLength", "_iDisplayLength" ], 1027 [ "bJQueryUI", "bJUI" ] 1028 ] ); 1029 _fnMap( oSettings.oScroll, oInit, [ 1030 [ "sScrollX", "sX" ], 1031 [ "sScrollXInner", "sXInner" ], 1032 [ "sScrollY", "sY" ], 1033 [ "bScrollCollapse", "bCollapse" ] 1034 ] ); 1035 _fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" ); 1036 1037 /* Callback functions which are array driven */ 1038 _fnCallbackReg( oSettings, 'aoDrawCallback', oInit.fnDrawCallback, 'user' ); 1039 _fnCallbackReg( oSettings, 'aoServerParams', oInit.fnServerParams, 'user' ); 1040 _fnCallbackReg( oSettings, 'aoStateSaveParams', oInit.fnStateSaveParams, 'user' ); 1041 _fnCallbackReg( oSettings, 'aoStateLoadParams', oInit.fnStateLoadParams, 'user' ); 1042 _fnCallbackReg( oSettings, 'aoStateLoaded', oInit.fnStateLoaded, 'user' ); 1043 _fnCallbackReg( oSettings, 'aoRowCallback', oInit.fnRowCallback, 'user' ); 1044 _fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow, 'user' ); 1045 _fnCallbackReg( oSettings, 'aoHeaderCallback', oInit.fnHeaderCallback, 'user' ); 1046 _fnCallbackReg( oSettings, 'aoFooterCallback', oInit.fnFooterCallback, 'user' ); 1047 _fnCallbackReg( oSettings, 'aoInitComplete', oInit.fnInitComplete, 'user' ); 1048 _fnCallbackReg( oSettings, 'aoPreDrawCallback', oInit.fnPreDrawCallback, 'user' ); 1049 1050 oSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId ); 1051 1052 /* Browser support detection */ 1053 _fnBrowserDetect( oSettings ); 1054 1055 var oClasses = oSettings.oClasses; 1056 1057 // @todo Remove in 1.11 1058 if ( oInit.bJQueryUI ) 1059 { 1060 /* Use the JUI classes object for display. You could clone the oStdClasses object if 1061 * you want to have multiple tables with multiple independent classes 1062 */ 1063 $.extend( oClasses, DataTable.ext.oJUIClasses, oInit.oClasses ); 1064 1065 if ( oInit.sDom === defaults.sDom && defaults.sDom === "lfrtip" ) 1066 { 1067 /* Set the DOM to use a layout suitable for jQuery UI's theming */ 1068 oSettings.sDom = '<"H"lfr>t<"F"ip>'; 1069 } 1070 1071 if ( ! oSettings.renderer ) { 1072 oSettings.renderer = 'jqueryui'; 1073 } 1074 else if ( $.isPlainObject( oSettings.renderer ) && ! oSettings.renderer.header ) { 1075 oSettings.renderer.header = 'jqueryui'; 1076 } 1077 } 1078 else 1079 { 1080 $.extend( oClasses, DataTable.ext.classes, oInit.oClasses ); 1081 } 1082 $this.addClass( oClasses.sTable ); 1083 1084 1085 if ( oSettings.iInitDisplayStart === undefined ) 1086 { 1087 /* Display start point, taking into account the save saving */ 1088 oSettings.iInitDisplayStart = oInit.iDisplayStart; 1089 oSettings._iDisplayStart = oInit.iDisplayStart; 1090 } 1091 1092 if ( oInit.iDeferLoading !== null ) 1093 { 1094 oSettings.bDeferLoading = true; 1095 var tmp = $.isArray( oInit.iDeferLoading ); 1096 oSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading; 1097 oSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading; 1098 } 1099 1100 /* Language definitions */ 1101 var oLanguage = oSettings.oLanguage; 1102 $.extend( true, oLanguage, oInit.oLanguage ); 1103 1104 if ( oLanguage.sUrl !== "" ) 1105 { 1106 /* Get the language definitions from a file - because this Ajax call makes the language 1107 * get async to the remainder of this function we use bInitHandedOff to indicate that 1108 * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor 1109 */ 1110 $.ajax( { 1111 dataType: 'json', 1112 url: oLanguage.sUrl, 1113 success: function ( json ) { 1114 _fnLanguageCompat( json ); 1115 _fnCamelToHungarian( defaults.oLanguage, json ); 1116 $.extend( true, oLanguage, json ); 1117 _fnInitialise( oSettings ); 1118 }, 1119 error: function () { 1120 // Error occurred loading language file, continue on as best we can 1121 _fnInitialise( oSettings ); 1122 } 1123 } ); 1124 bInitHandedOff = true; 1125 } 1126 1127 /* 1128 * Stripes 1129 */ 1130 if ( oInit.asStripeClasses === null ) 1131 { 1132 oSettings.asStripeClasses =[ 1133 oClasses.sStripeOdd, 1134 oClasses.sStripeEven 1135 ]; 1136 } 1137 1138 /* Remove row stripe classes if they are already on the table row */ 1139 var stripeClasses = oSettings.asStripeClasses; 1140 var rowOne = $this.children('tbody').find('tr').eq(0); 1141 if ( $.inArray( true, $.map( stripeClasses, function(el, i) { 1142 return rowOne.hasClass(el); 1143 } ) ) !== -1 ) { 1144 $('tbody tr', this).removeClass( stripeClasses.join(' ') ); 1145 oSettings.asDestroyStripes = stripeClasses.slice(); 1146 } 1147 1148 /* 1149 * Columns 1150 * See if we should load columns automatically or use defined ones 1151 */ 1152 var anThs = []; 1153 var aoColumnsInit; 1154 var nThead = this.getElementsByTagName('thead'); 1155 if ( nThead.length !== 0 ) 1156 { 1157 _fnDetectHeader( oSettings.aoHeader, nThead[0] ); 1158 anThs = _fnGetUniqueThs( oSettings ); 1159 } 1160 1161 /* If not given a column array, generate one with nulls */ 1162 if ( oInit.aoColumns === null ) 1163 { 1164 aoColumnsInit = []; 1165 for ( i=0, iLen=anThs.length ; i<iLen ; i++ ) 1166 { 1167 aoColumnsInit.push( null ); 1168 } 1169 } 1170 else 1171 { 1172 aoColumnsInit = oInit.aoColumns; 1173 } 1174 1175 /* Add the columns */ 1176 for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ ) 1177 { 1178 _fnAddColumn( oSettings, anThs ? anThs[i] : null ); 1179 } 1180 1181 /* Apply the column definitions */ 1182 _fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) { 1183 _fnColumnOptions( oSettings, iCol, oDef ); 1184 } ); 1185 1186 /* HTML5 attribute detection - build an mData object automatically if the 1187 * attributes are found 1188 */ 1189 if ( rowOne.length ) { 1190 var a = function ( cell, name ) { 1191 return cell.getAttribute( 'data-'+name ) !== null ? name : null; 1192 }; 1193 1194 $( rowOne[0] ).children('th, td').each( function (i, cell) { 1195 var col = oSettings.aoColumns[i]; 1196 1197 if ( col.mData === i ) { 1198 var sort = a( cell, 'sort' ) || a( cell, 'order' ); 1199 var filter = a( cell, 'filter' ) || a( cell, 'search' ); 1200 1201 if ( sort !== null || filter !== null ) { 1202 col.mData = { 1203 _: i+'.display', 1204 sort: sort !== null ? i+'.@data-'+sort : undefined, 1205 type: sort !== null ? i+'.@data-'+sort : undefined, 1206 filter: filter !== null ? i+'.@data-'+filter : undefined 1207 }; 1208 1209 _fnColumnOptions( oSettings, i ); 1210 } 1211 } 1212 } ); 1213 } 1214 1215 var features = oSettings.oFeatures; 1216 1217 /* Must be done after everything which can be overridden by the state saving! */ 1218 if ( oInit.bStateSave ) 1219 { 1220 features.bStateSave = true; 1221 _fnLoadState( oSettings, oInit ); 1222 _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' ); 1223 } 1224 1225 1226 /* 1227 * Sorting 1228 * @todo For modularisation (1.11) this needs to do into a sort start up handler 1229 */ 1230 1231 // If aaSorting is not defined, then we use the first indicator in asSorting 1232 // in case that has been altered, so the default sort reflects that option 1233 if ( oInit.aaSorting === undefined ) 1234 { 1235 var sorting = oSettings.aaSorting; 1236 for ( i=0, iLen=sorting.length ; i<iLen ; i++ ) 1237 { 1238 sorting[i][1] = oSettings.aoColumns[ i ].asSorting[0]; 1239 } 1240 } 1241 1242 /* Do a first pass on the sorting classes (allows any size changes to be taken into 1243 * account, and also will apply sorting disabled classes if disabled 1244 */ 1245 _fnSortingClasses( oSettings ); 1246 1247 if ( features.bSort ) 1248 { 1249 _fnCallbackReg( oSettings, 'aoDrawCallback', function () { 1250 if ( oSettings.bSorted ) { 1251 var aSort = _fnSortFlatten( oSettings ); 1252 var sortedColumns = {}; 1253 1254 $.each( aSort, function (i, val) { 1255 sortedColumns[ val.src ] = val.dir; 1256 } ); 1257 1258 _fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] ); 1259 _fnSortAria( oSettings ); 1260 } 1261 } ); 1262 } 1263 1264 _fnCallbackReg( oSettings, 'aoDrawCallback', function () { 1265 if ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) { 1266 _fnSortingClasses( oSettings ); 1267 } 1268 }, 'sc' ); 1269 1270 1271 /* 1272 * Final init 1273 * Cache the header, body and footer as required, creating them if needed 1274 */ 1275 1276 // Work around for Webkit bug 83867 - store the caption-side before removing from doc 1277 var captions = $this.children('caption').each( function () { 1278 this._captionSide = $this.css('caption-side'); 1279 } ); 1280 1281 var thead = $this.children('thead'); 1282 if ( thead.length === 0 ) 1283 { 1284 thead = $('<thead/>').appendTo(this); 1285 } 1286 oSettings.nTHead = thead[0]; 1287 1288 var tbody = $this.children('tbody'); 1289 if ( tbody.length === 0 ) 1290 { 1291 tbody = $('<tbody/>').appendTo(this); 1292 } 1293 oSettings.nTBody = tbody[0]; 1294 1295 var tfoot = $this.children('tfoot'); 1296 if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") ) 1297 { 1298 // If we are a scrolling table, and no footer has been given, then we need to create 1299 // a tfoot element for the caption element to be appended to 1300 tfoot = $('<tfoot/>').appendTo(this); 1301 } 1302 1303 if ( tfoot.length === 0 || tfoot.children().length === 0 ) { 1304 $this.addClass( oClasses.sNoFooter ); 1305 } 1306 else if ( tfoot.length > 0 ) { 1307 oSettings.nTFoot = tfoot[0]; 1308 _fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot ); 1309 } 1310 1311 /* Check if there is data passing into the constructor */ 1312 if ( oInit.aaData ) 1313 { 1314 for ( i=0 ; i<oInit.aaData.length ; i++ ) 1315 { 1316 _fnAddData( oSettings, oInit.aaData[ i ] ); 1317 } 1318 } 1319 else if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' ) 1320 { 1321 /* Grab the data from the page - only do this when deferred loading or no Ajax 1322 * source since there is no point in reading the DOM data if we are then going 1323 * to replace it with Ajax data 1324 */ 1325 _fnAddTr( oSettings, $(oSettings.nTBody).children('tr') ); 1326 } 1327 1328 /* Copy the data index array */ 1329 oSettings.aiDisplay = oSettings.aiDisplayMaster.slice(); 1330 1331 /* Initialisation complete - table can be drawn */ 1332 oSettings.bInitialised = true; 1333 1334 /* Check if we need to initialise the table (it might not have been handed off to the 1335 * language processor) 1336 */ 1337 if ( bInitHandedOff === false ) 1338 { 1339 _fnInitialise( oSettings ); 1340 } 1341 } ); 1342 _that = null; 1343 return this; 1344 }; 1345 1346 1347 /* 1348 * It is useful to have variables which are scoped locally so only the 1349 * DataTables functions can access them and they don't leak into global space. 1350 * At the same time these functions are often useful over multiple files in the 1351 * core and API, so we list, or at least document, all variables which are used 1352 * by DataTables as private variables here. This also ensures that there is no 1353 * clashing of variable names and that they can easily referenced for reuse. 1354 */ 1355 1356 1357 // Defined else where 1358 // _selector_run 1359 // _selector_opts 1360 // _selector_first 1361 // _selector_row_indexes 1362 1363 var _ext; // DataTable.ext 1364 var _Api; // DataTable.Api 1365 var _api_register; // DataTable.Api.register 1366 var _api_registerPlural; // DataTable.Api.registerPlural 1367 1368 var _re_dic = {}; 1369 var _re_new_lines = /[\r\n]/g; 1370 var _re_html = /<.*?>/g; 1371 var _re_date_start = /^[\w\+\-]/; 1372 var _re_date_end = /[\w\+\-]$/; 1373 1374 // Escape regular expression special characters 1375 var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' ); 1376 1377 // http://en.wikipedia.org/wiki/Foreign_exchange_market 1378 // - \u20BD - Russian ruble. 1379 // - \u20a9 - South Korean Won 1380 // - \u20BA - Turkish Lira 1381 // - \u20B9 - Indian Rupee 1382 // - R - Brazil (R$) and South Africa 1383 // - fr - Swiss Franc 1384 // - kr - Swedish krona, Norwegian krone and Danish krone 1385 // - \u2009 is thin space and \u202F is narrow no-break space, both used in many 1386 // standards as thousands separators. 1387 var _re_formatted_numeric = /[',$£â¬Â¥%\u2009\u202F\u20BD\u20a9\u20BArfk]/gi; 1388 1389 1390 var _empty = function ( d ) { 1391 return !d || d === true || d === '-' ? true : false; 1392 }; 1393 1394 1395 var _intVal = function ( s ) { 1396 var integer = parseInt( s, 10 ); 1397 return !isNaN(integer) && isFinite(s) ? integer : null; 1398 }; 1399 1400 // Convert from a formatted number with characters other than `.` as the 1401 // decimal place, to a Javascript number 1402 var _numToDecimal = function ( num, decimalPoint ) { 1403 // Cache created regular expressions for speed as this function is called often 1404 if ( ! _re_dic[ decimalPoint ] ) { 1405 _re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' ); 1406 } 1407 return typeof num === 'string' && decimalPoint !== '.' ? 1408 num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) : 1409 num; 1410 }; 1411 1412 1413 var _isNumber = function ( d, decimalPoint, formatted ) { 1414 var strType = typeof d === 'string'; 1415 1416 // If empty return immediately so there must be a number if it is a 1417 // formatted string (this stops the string "k", or "kr", etc being detected 1418 // as a formatted number for currency 1419 if ( _empty( d ) ) { 1420 return true; 1421 } 1422 1423 if ( decimalPoint && strType ) { 1424 d = _numToDecimal( d, decimalPoint ); 1425 } 1426 1427 if ( formatted && strType ) { 1428 d = d.replace( _re_formatted_numeric, '' ); 1429 } 1430 1431 return !isNaN( parseFloat(d) ) && isFinite( d ); 1432 }; 1433 1434 1435 // A string without HTML in it can be considered to be HTML still 1436 var _isHtml = function ( d ) { 1437 return _empty( d ) || typeof d === 'string'; 1438 }; 1439 1440 1441 var _htmlNumeric = function ( d, decimalPoint, formatted ) { 1442 if ( _empty( d ) ) { 1443 return true; 1444 } 1445 1446 var html = _isHtml( d ); 1447 return ! html ? 1448 null : 1449 _isNumber( _stripHtml( d ), decimalPoint, formatted ) ? 1450 true : 1451 null; 1452 }; 1453 1454 1455 var _pluck = function ( a, prop, prop2 ) { 1456 var out = []; 1457 var i=0, ien=a.length; 1458 1459 // Could have the test in the loop for slightly smaller code, but speed 1460 // is essential here 1461 if ( prop2 !== undefined ) { 1462 for ( ; i<ien ; i++ ) { 1463 if ( a[i] && a[i][ prop ] ) { 1464 out.push( a[i][ prop ][ prop2 ] ); 1465 } 1466 } 1467 } 1468 else { 1469 for ( ; i<ien ; i++ ) { 1470 if ( a[i] ) { 1471 out.push( a[i][ prop ] ); 1472 } 1473 } 1474 } 1475 1476 return out; 1477 }; 1478 1479 1480 // Basically the same as _pluck, but rather than looping over `a` we use `order` 1481 // as the indexes to pick from `a` 1482 var _pluck_order = function ( a, order, prop, prop2 ) 1483 { 1484 var out = []; 1485 var i=0, ien=order.length; 1486 1487 // Could have the test in the loop for slightly smaller code, but speed 1488 // is essential here 1489 if ( prop2 !== undefined ) { 1490 for ( ; i<ien ; i++ ) { 1491 if ( a[ order[i] ][ prop ] ) { 1492 out.push( a[ order[i] ][ prop ][ prop2 ] ); 1493 } 1494 } 1495 } 1496 else { 1497 for ( ; i<ien ; i++ ) { 1498 out.push( a[ order[i] ][ prop ] ); 1499 } 1500 } 1501 1502 return out; 1503 }; 1504 1505 1506 var _range = function ( len, start ) 1507 { 1508 var out = []; 1509 var end; 1510 1511 if ( start === undefined ) { 1512 start = 0; 1513 end = len; 1514 } 1515 else { 1516 end = start; 1517 start = len; 1518 } 1519 1520 for ( var i=start ; i<end ; i++ ) { 1521 out.push( i ); 1522 } 1523 1524 return out; 1525 }; 1526 1527 1528 var _removeEmpty = function ( a ) 1529 { 1530 var out = []; 1531 1532 for ( var i=0, ien=a.length ; i<ien ; i++ ) { 1533 if ( a[i] ) { // careful - will remove all falsy values! 1534 out.push( a[i] ); 1535 } 1536 } 1537 1538 return out; 1539 }; 1540 1541 1542 var _stripHtml = function ( d ) { 1543 return d.replace( _re_html, '' ); 1544 }; 1545 1546 1547 /** 1548 * Find the unique elements in a source array. 1549 * 1550 * @param {array} src Source array 1551 * @return {array} Array of unique items 1552 * @ignore 1553 */ 1554 var _unique = function ( src ) 1555 { 1556 // A faster unique method is to use object keys to identify used values, 1557 // but this doesn't work with arrays or objects, which we must also 1558 // consider. See jsperf.com/compare-array-unique-versions/4 for more 1559 // information. 1560 var 1561 out = [], 1562 val, 1563 i, ien=src.length, 1564 j, k=0; 1565 1566 again: for ( i=0 ; i<ien ; i++ ) { 1567 val = src[i]; 1568 1569 for ( j=0 ; j<k ; j++ ) { 1570 if ( out[j] === val ) { 1571 continue again; 1572 } 1573 } 1574 1575 out.push( val ); 1576 k++; 1577 } 1578 1579 return out; 1580 }; 1581 1582 1583 /** 1584 * DataTables utility methods 1585 * 1586 * This namespace provides helper methods that DataTables uses internally to 1587 * create a DataTable, but which are not exclusively used only for DataTables. 1588 * These methods can be used by extension authors to save the duplication of 1589 * code. 1590 * 1591 * @namespace 1592 */ 1593 DataTable.util = { 1594 /** 1595 * Throttle the calls to a function. Arguments and context are maintained 1596 * for the throttled function. 1597 * 1598 * @param {function} fn Function to be called 1599 * @param {integer} freq Call frequency in mS 1600 * @return {function} Wrapped function 1601 */ 1602 throttle: function ( fn, freq ) { 1603 var 1604 frequency = freq !== undefined ? freq : 200, 1605 last, 1606 timer; 1607 1608 return function () { 1609 var 1610 that = this, 1611 now = +new Date(), 1612 args = arguments; 1613 1614 if ( last && now < last + frequency ) { 1615 clearTimeout( timer ); 1616 1617 timer = setTimeout( function () { 1618 last = undefined; 1619 fn.apply( that, args ); 1620 }, frequency ); 1621 } 1622 else { 1623 last = now; 1624 fn.apply( that, args ); 1625 } 1626 }; 1627 }, 1628 1629 1630 /** 1631 * Escape a string such that it can be used in a regular expression 1632 * 1633 * @param {string} val string to escape 1634 * @returns {string} escaped string 1635 */ 1636 escapeRegex: function ( val ) { 1637 return val.replace( _re_escape_regex, '\\$1' ); 1638 } 1639 }; 1640 1641 1642 1643 /** 1644 * Create a mapping object that allows camel case parameters to be looked up 1645 * for their Hungarian counterparts. The mapping is stored in a private 1646 * parameter called `_hungarianMap` which can be accessed on the source object. 1647 * @param {object} o 1648 * @memberof DataTable#oApi 1649 */ 1650 function _fnHungarianMap ( o ) 1651 { 1652 var 1653 hungarian = 'a aa ai ao as b fn i m o s ', 1654 match, 1655 newKey, 1656 map = {}; 1657 1658 $.each( o, function (key, val) { 1659 match = key.match(/^([^A-Z]+?)([A-Z])/); 1660 1661 if ( match && hungarian.indexOf(match[1]+' ') !== -1 ) 1662 { 1663 newKey = key.replace( match[0], match[2].toLowerCase() ); 1664 map[ newKey ] = key; 1665 1666 if ( match[1] === 'o' ) 1667 { 1668 _fnHungarianMap( o[key] ); 1669 } 1670 } 1671 } ); 1672 1673 o._hungarianMap = map; 1674 } 1675 1676 1677 /** 1678 * Convert from camel case parameters to Hungarian, based on a Hungarian map 1679 * created by _fnHungarianMap. 1680 * @param {object} src The model object which holds all parameters that can be 1681 * mapped. 1682 * @param {object} user The object to convert from camel case to Hungarian. 1683 * @param {boolean} force When set to `true`, properties which already have a 1684 * Hungarian value in the `user` object will be overwritten. Otherwise they 1685 * won't be. 1686 * @memberof DataTable#oApi 1687 */ 1688 function _fnCamelToHungarian ( src, user, force ) 1689 { 1690 if ( ! src._hungarianMap ) { 1691 _fnHungarianMap( src ); 1692 } 1693 1694 var hungarianKey; 1695 1696 $.each( user, function (key, val) { 1697 hungarianKey = src._hungarianMap[ key ]; 1698 1699 if ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) ) 1700 { 1701 // For objects, we need to buzz down into the object to copy parameters 1702 if ( hungarianKey.charAt(0) === 'o' ) 1703 { 1704 // Copy the camelCase options over to the hungarian 1705 if ( ! user[ hungarianKey ] ) { 1706 user[ hungarianKey ] = {}; 1707 } 1708 $.extend( true, user[hungarianKey], user[key] ); 1709 1710 _fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force ); 1711 } 1712 else { 1713 user[hungarianKey] = user[ key ]; 1714 } 1715 } 1716 } ); 1717 } 1718 1719 1720 /** 1721 * Language compatibility - when certain options are given, and others aren't, we 1722 * need to duplicate the values over, in order to provide backwards compatibility 1723 * with older language files. 1724 * @param {object} oSettings dataTables settings object 1725 * @memberof DataTable#oApi 1726 */ 1727 function _fnLanguageCompat( lang ) 1728 { 1729 var defaults = DataTable.defaults.oLanguage; 1730 var zeroRecords = lang.sZeroRecords; 1731 1732 /* Backwards compatibility - if there is no sEmptyTable given, then use the same as 1733 * sZeroRecords - assuming that is given. 1734 */ 1735 if ( ! lang.sEmptyTable && zeroRecords && 1736 defaults.sEmptyTable === "No data available in table" ) 1737 { 1738 _fnMap( lang, lang, 'sZeroRecords', 'sEmptyTable' ); 1739 } 1740 1741 /* Likewise with loading records */ 1742 if ( ! lang.sLoadingRecords && zeroRecords && 1743 defaults.sLoadingRecords === "Loading..." ) 1744 { 1745 _fnMap( lang, lang, 'sZeroRecords', 'sLoadingRecords' ); 1746 } 1747 1748 // Old parameter name of the thousands separator mapped onto the new 1749 if ( lang.sInfoThousands ) { 1750 lang.sThousands = lang.sInfoThousands; 1751 } 1752 1753 var decimal = lang.sDecimal; 1754 if ( decimal ) { 1755 _addNumericSort( decimal ); 1756 } 1757 } 1758 1759 1760 /** 1761 * Map one parameter onto another 1762 * @param {object} o Object to map 1763 * @param {*} knew The new parameter name 1764 * @param {*} old The old parameter name 1765 */ 1766 var _fnCompatMap = function ( o, knew, old ) { 1767 if ( o[ knew ] !== undefined ) { 1768 o[ old ] = o[ knew ]; 1769 } 1770 }; 1771 1772 1773 /** 1774 * Provide backwards compatibility for the main DT options. Note that the new 1775 * options are mapped onto the old parameters, so this is an external interface 1776 * change only. 1777 * @param {object} init Object to map 1778 */ 1779 function _fnCompatOpts ( init ) 1780 { 1781 _fnCompatMap( init, 'ordering', 'bSort' ); 1782 _fnCompatMap( init, 'orderMulti', 'bSortMulti' ); 1783 _fnCompatMap( init, 'orderClasses', 'bSortClasses' ); 1784 _fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' ); 1785 _fnCompatMap( init, 'order', 'aaSorting' ); 1786 _fnCompatMap( init, 'orderFixed', 'aaSortingFixed' ); 1787 _fnCompatMap( init, 'paging', 'bPaginate' ); 1788 _fnCompatMap( init, 'pagingType', 'sPaginationType' ); 1789 _fnCompatMap( init, 'pageLength', 'iDisplayLength' ); 1790 _fnCompatMap( init, 'searching', 'bFilter' ); 1791 1792 // Boolean initialisation of x-scrolling 1793 if ( typeof init.sScrollX === 'boolean' ) { 1794 init.sScrollX = init.sScrollX ? '100%' : ''; 1795 } 1796 if ( typeof init.scrollX === 'boolean' ) { 1797 init.scrollX = init.scrollX ? '100%' : ''; 1798 } 1799 1800 // Column search objects are in an array, so it needs to be converted 1801 // element by element 1802 var searchCols = init.aoSearchCols; 1803 1804 if ( searchCols ) { 1805 for ( var i=0, ien=searchCols.length ; i<ien ; i++ ) { 1806 if ( searchCols[i] ) { 1807 _fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] ); 1808 } 1809 } 1810 } 1811 } 1812 1813 1814 /** 1815 * Provide backwards compatibility for column options. Note that the new options 1816 * are mapped onto the old parameters, so this is an external interface change 1817 * only. 1818 * @param {object} init Object to map 1819 */ 1820 function _fnCompatCols ( init ) 1821 { 1822 _fnCompatMap( init, 'orderable', 'bSortable' ); 1823 _fnCompatMap( init, 'orderData', 'aDataSort' ); 1824 _fnCompatMap( init, 'orderSequence', 'asSorting' ); 1825 _fnCompatMap( init, 'orderDataType', 'sortDataType' ); 1826 1827 // orderData can be given as an integer 1828 var dataSort = init.aDataSort; 1829 if ( dataSort && ! $.isArray( dataSort ) ) { 1830 init.aDataSort = [ dataSort ]; 1831 } 1832 } 1833 1834 1835 /** 1836 * Browser feature detection for capabilities, quirks 1837 * @param {object} settings dataTables settings object 1838 * @memberof DataTable#oApi 1839 */ 1840 function _fnBrowserDetect( settings ) 1841 { 1842 // We don't need to do this every time DataTables is constructed, the values 1843 // calculated are specific to the browser and OS configuration which we 1844 // don't expect to change between initialisations 1845 if ( ! DataTable.__browser ) { 1846 var browser = {}; 1847 DataTable.__browser = browser; 1848 1849 // Scrolling feature / quirks detection 1850 var n = $('<div/>') 1851 .css( { 1852 position: 'fixed', 1853 top: 0, 1854 left: 0, 1855 height: 1, 1856 width: 1, 1857 overflow: 'hidden' 1858 } ) 1859 .append( 1860 $('<div/>') 1861 .css( { 1862 position: 'absolute', 1863 top: 1, 1864 left: 1, 1865 width: 100, 1866 overflow: 'scroll' 1867 } ) 1868 .append( 1869 $('<div/>') 1870 .css( { 1871 width: '100%', 1872 height: 10 1873 } ) 1874 ) 1875 ) 1876 .appendTo( 'body' ); 1877 1878 var outer = n.children(); 1879 var inner = outer.children(); 1880 1881 // Numbers below, in order, are: 1882 // inner.offsetWidth, inner.clientWidth, outer.offsetWidth, outer.clientWidth 1883 // 1884 // IE6 XP: 100 100 100 83 1885 // IE7 Vista: 100 100 100 83 1886 // IE 8+ Windows: 83 83 100 83 1887 // Evergreen Windows: 83 83 100 83 1888 // Evergreen Mac with scrollbars: 85 85 100 85 1889 // Evergreen Mac without scrollbars: 100 100 100 100 1890 1891 // Get scrollbar width 1892 browser.barWidth = outer[0].offsetWidth - outer[0].clientWidth; 1893 1894 // IE6/7 will oversize a width 100% element inside a scrolling element, to 1895 // include the width of the scrollbar, while other browsers ensure the inner 1896 // element is contained without forcing scrolling 1897 browser.bScrollOversize = inner[0].offsetWidth === 100 && outer[0].clientWidth !== 100; 1898 1899 // In rtl text layout, some browsers (most, but not all) will place the 1900 // scrollbar on the left, rather than the right. 1901 browser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1; 1902 1903 // IE8- don't provide height and width for getBoundingClientRect 1904 browser.bBounding = n[0].getBoundingClientRect().width ? true : false; 1905 1906 n.remove(); 1907 } 1908 1909 $.extend( settings.oBrowser, DataTable.__browser ); 1910 settings.oScroll.iBarWidth = DataTable.__browser.barWidth; 1911 } 1912 1913 1914 /** 1915 * Array.prototype reduce[Right] method, used for browsers which don't support 1916 * JS 1.6. Done this way to reduce code size, since we iterate either way 1917 * @param {object} settings dataTables settings object 1918 * @memberof DataTable#oApi 1919 */ 1920 function _fnReduce ( that, fn, init, start, end, inc ) 1921 { 1922 var 1923 i = start, 1924 value, 1925 isSet = false; 1926 1927 if ( init !== undefined ) { 1928 value = init; 1929 isSet = true; 1930 } 1931 1932 while ( i !== end ) { 1933 if ( ! that.hasOwnProperty(i) ) { 1934 continue; 1935 } 1936 1937 value = isSet ? 1938 fn( value, that[i], i, that ) : 1939 that[i]; 1940 1941 isSet = true; 1942 i += inc; 1943 } 1944 1945 return value; 1946 } 1947 1948 /** 1949 * Add a column to the list used for the table with default values 1950 * @param {object} oSettings dataTables settings object 1951 * @param {node} nTh The th element for this column 1952 * @memberof DataTable#oApi 1953 */ 1954 function _fnAddColumn( oSettings, nTh ) 1955 { 1956 // Add column to aoColumns array 1957 var oDefaults = DataTable.defaults.column; 1958 var iCol = oSettings.aoColumns.length; 1959 var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, { 1960 "nTh": nTh ? nTh : document.createElement('th'), 1961 "sTitle": oDefaults.sTitle ? oDefaults.sTitle : nTh ? nTh.innerHTML : '', 1962 "aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol], 1963 "mData": oDefaults.mData ? oDefaults.mData : iCol, 1964 idx: iCol 1965 } ); 1966 oSettings.aoColumns.push( oCol ); 1967 1968 // Add search object for column specific search. Note that the `searchCols[ iCol ]` 1969 // passed into extend can be undefined. This allows the user to give a default 1970 // with only some of the parameters defined, and also not give a default 1971 var searchCols = oSettings.aoPreSearchCols; 1972 searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] ); 1973 1974 // Use the default column options function to initialise classes etc 1975 _fnColumnOptions( oSettings, iCol, $(nTh).data() ); 1976 } 1977 1978 1979 /** 1980 * Apply options for a column 1981 * @param {object} oSettings dataTables settings object 1982 * @param {int} iCol column index to consider 1983 * @param {object} oOptions object with sType, bVisible and bSearchable etc 1984 * @memberof DataTable#oApi 1985 */ 1986 function _fnColumnOptions( oSettings, iCol, oOptions ) 1987 { 1988 var oCol = oSettings.aoColumns[ iCol ]; 1989 var oClasses = oSettings.oClasses; 1990 var th = $(oCol.nTh); 1991 1992 // Try to get width information from the DOM. We can't get it from CSS 1993 // as we'd need to parse the CSS stylesheet. `width` option can override 1994 if ( ! oCol.sWidthOrig ) { 1995 // Width attribute 1996 oCol.sWidthOrig = th.attr('width') || null; 1997 1998 // Style attribute 1999 var t = (th.attr('style') || '').match(/width:\s*(\d+[pxem%]+)/); 2000 if ( t ) { 2001 oCol.sWidthOrig = t[1]; 2002 } 2003 } 2004 2005 /* User specified column options */ 2006 if ( oOptions !== undefined && oOptions !== null ) 2007 { 2008 // Backwards compatibility 2009 _fnCompatCols( oOptions ); 2010 2011 // Map camel case parameters to their Hungarian counterparts 2012 _fnCamelToHungarian( DataTable.defaults.column, oOptions ); 2013 2014 /* Backwards compatibility for mDataProp */ 2015 if ( oOptions.mDataProp !== undefined && !oOptions.mData ) 2016 { 2017 oOptions.mData = oOptions.mDataProp; 2018 } 2019 2020 if ( oOptions.sType ) 2021 { 2022 oCol._sManualType = oOptions.sType; 2023 } 2024 2025 // `class` is a reserved word in Javascript, so we need to provide 2026 // the ability to use a valid name for the camel case input 2027 if ( oOptions.className && ! oOptions.sClass ) 2028 { 2029 oOptions.sClass = oOptions.className; 2030 } 2031 2032 $.extend( oCol, oOptions ); 2033 _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" ); 2034 2035 /* iDataSort to be applied (backwards compatibility), but aDataSort will take 2036 * priority if defined 2037 */ 2038 if ( oOptions.iDataSort !== undefined ) 2039 { 2040 oCol.aDataSort = [ oOptions.iDataSort ]; 2041 } 2042 _fnMap( oCol, oOptions, "aDataSort" ); 2043 } 2044 2045 /* Cache the data get and set functions for speed */ 2046 var mDataSrc = oCol.mData; 2047 var mData = _fnGetObjectDataFn( mDataSrc ); 2048 var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null; 2049 2050 var attrTest = function( src ) { 2051 return typeof src === 'string' && src.indexOf('@') !== -1; 2052 }; 2053 oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && ( 2054 attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter) 2055 ); 2056 oCol._setter = null; 2057 2058 oCol.fnGetData = function (rowData, type, meta) { 2059 var innerData = mData( rowData, type, undefined, meta ); 2060 2061 return mRender && type ? 2062 mRender( innerData, type, rowData, meta ) : 2063 innerData; 2064 }; 2065 oCol.fnSetData = function ( rowData, val, meta ) { 2066 return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta ); 2067 }; 2068 2069 // Indicate if DataTables should read DOM data as an object or array 2070 // Used in _fnGetRowElements 2071 if ( typeof mDataSrc !== 'number' ) { 2072 oSettings._rowReadObject = true; 2073 } 2074 2075 /* Feature sorting overrides column specific when off */ 2076 if ( !oSettings.oFeatures.bSort ) 2077 { 2078 oCol.bSortable = false; 2079 th.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called 2080 } 2081 2082 /* Check that the class assignment is correct for sorting */ 2083 var bAsc = $.inArray('asc', oCol.asSorting) !== -1; 2084 var bDesc = $.inArray('desc', oCol.asSorting) !== -1; 2085 if ( !oCol.bSortable || (!bAsc && !bDesc) ) 2086 { 2087 oCol.sSortingClass = oClasses.sSortableNone; 2088 oCol.sSortingClassJUI = ""; 2089 } 2090 else if ( bAsc && !bDesc ) 2091 { 2092 oCol.sSortingClass = oClasses.sSortableAsc; 2093 oCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed; 2094 } 2095 else if ( !bAsc && bDesc ) 2096 { 2097 oCol.sSortingClass = oClasses.sSortableDesc; 2098 oCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed; 2099 } 2100 else 2101 { 2102 oCol.sSortingClass = oClasses.sSortable; 2103 oCol.sSortingClassJUI = oClasses.sSortJUI; 2104 } 2105 } 2106 2107 2108 /** 2109 * Adjust the table column widths for new data. Note: you would probably want to 2110 * do a redraw after calling this function! 2111 * @param {object} settings dataTables settings object 2112 * @memberof DataTable#oApi 2113 */ 2114 function _fnAdjustColumnSizing ( settings ) 2115 { 2116 /* Not interested in doing column width calculation if auto-width is disabled */ 2117 if ( settings.oFeatures.bAutoWidth !== false ) 2118 { 2119 var columns = settings.aoColumns; 2120 2121 _fnCalculateColumnWidths( settings ); 2122 for ( var i=0 , iLen=columns.length ; i<iLen ; i++ ) 2123 { 2124 columns[i].nTh.style.width = columns[i].sWidth; 2125 } 2126 } 2127 2128 var scroll = settings.oScroll; 2129 if ( scroll.sY !== '' || scroll.sX !== '') 2130 { 2131 _fnScrollDraw( settings ); 2132 } 2133 2134 _fnCallbackFire( settings, null, 'column-sizing', [settings] ); 2135 } 2136 2137 2138 /** 2139 * Covert the index of a visible column to the index in the data array (take account 2140 * of hidden columns) 2141 * @param {object} oSettings dataTables settings object 2142 * @param {int} iMatch Visible column index to lookup 2143 * @returns {int} i the data index 2144 * @memberof DataTable#oApi 2145 */ 2146 function _fnVisibleToColumnIndex( oSettings, iMatch ) 2147 { 2148 var aiVis = _fnGetColumns( oSettings, 'bVisible' ); 2149 2150 return typeof aiVis[iMatch] === 'number' ? 2151 aiVis[iMatch] : 2152 null; 2153 } 2154 2155 2156 /** 2157 * Covert the index of an index in the data array and convert it to the visible 2158 * column index (take account of hidden columns) 2159 * @param {int} iMatch Column index to lookup 2160 * @param {object} oSettings dataTables settings object 2161 * @returns {int} i the data index 2162 * @memberof DataTable#oApi 2163 */ 2164 function _fnColumnIndexToVisible( oSettings, iMatch ) 2165 { 2166 var aiVis = _fnGetColumns( oSettings, 'bVisible' ); 2167 var iPos = $.inArray( iMatch, aiVis ); 2168 2169 return iPos !== -1 ? iPos : null; 2170 } 2171 2172 2173 /** 2174 * Get the number of visible columns 2175 * @param {object} oSettings dataTables settings object 2176 * @returns {int} i the number of visible columns 2177 * @memberof DataTable#oApi 2178 */ 2179 function _fnVisbleColumns( oSettings ) 2180 { 2181 var vis = 0; 2182 2183 // No reduce in IE8, use a loop for now 2184 $.each( oSettings.aoColumns, function ( i, col ) { 2185 if ( col.bVisible && $(col.nTh).css('display') !== 'none' ) { 2186 vis++; 2187 } 2188 } ); 2189 2190 return vis; 2191 } 2192 2193 2194 /** 2195 * Get an array of column indexes that match a given property 2196 * @param {object} oSettings dataTables settings object 2197 * @param {string} sParam Parameter in aoColumns to look for - typically 2198 * bVisible or bSearchable 2199 * @returns {array} Array of indexes with matched properties 2200 * @memberof DataTable#oApi 2201 */ 2202 function _fnGetColumns( oSettings, sParam ) 2203 { 2204 var a = []; 2205 2206 $.map( oSettings.aoColumns, function(val, i) { 2207 if ( val[sParam] ) { 2208 a.push( i ); 2209 } 2210 } ); 2211 2212 return a; 2213 } 2214 2215 2216 /** 2217 * Calculate the 'type' of a column 2218 * @param {object} settings dataTables settings object 2219 * @memberof DataTable#oApi 2220 */ 2221 function _fnColumnTypes ( settings ) 2222 { 2223 var columns = settings.aoColumns; 2224 var data = settings.aoData; 2225 var types = DataTable.ext.type.detect; 2226 var i, ien, j, jen, k, ken; 2227 var col, cell, detectedType, cache; 2228 2229 // For each column, spin over the 2230 for ( i=0, ien=columns.length ; i<ien ; i++ ) { 2231 col = columns[i]; 2232 cache = []; 2233 2234 if ( ! col.sType && col._sManualType ) { 2235 col.sType = col._sManualType; 2236 } 2237 else if ( ! col.sType ) { 2238 for ( j=0, jen=types.length ; j<jen ; j++ ) { 2239 for ( k=0, ken=data.length ; k<ken ; k++ ) { 2240 // Use a cache array so we only need to get the type data 2241 // from the formatter once (when using multiple detectors) 2242 if ( cache[k] === undefined ) { 2243 cache[k] = _fnGetCellData( settings, k, i, 'type' ); 2244 } 2245 2246 detectedType = types[j]( cache[k], settings ); 2247 2248 // If null, then this type can't apply to this column, so 2249 // rather than testing all cells, break out. There is an 2250 // exception for the last type which is `html`. We need to 2251 // scan all rows since it is possible to mix string and HTML 2252 // types 2253 if ( ! detectedType && j !== types.length-1 ) { 2254 break; 2255 } 2256 2257 // Only a single match is needed for html type since it is 2258 // bottom of the pile and very similar to string 2259 if ( detectedType === 'html' ) { 2260 break; 2261 } 2262 } 2263 2264 // Type is valid for all data points in the column - use this 2265 // type 2266 if ( detectedType ) { 2267 col.sType = detectedType; 2268 break; 2269 } 2270 } 2271 2272 // Fall back - if no type was detected, always use string 2273 if ( ! col.sType ) { 2274 col.sType = 'string'; 2275 } 2276 } 2277 } 2278 } 2279 2280 2281 /** 2282 * Take the column definitions and static columns arrays and calculate how 2283 * they relate to column indexes. The callback function will then apply the 2284 * definition found for a column to a suitable configuration object. 2285 * @param {object} oSettings dataTables settings object 2286 * @param {array} aoColDefs The aoColumnDefs array that is to be applied 2287 * @param {array} aoCols The aoColumns array that defines columns individually 2288 * @param {function} fn Callback function - takes two parameters, the calculated 2289 * column index and the definition for that column. 2290 * @memberof DataTable#oApi 2291 */ 2292 function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn ) 2293 { 2294 var i, iLen, j, jLen, k, kLen, def; 2295 var columns = oSettings.aoColumns; 2296 2297 // Column definitions with aTargets 2298 if ( aoColDefs ) 2299 { 2300 /* Loop over the definitions array - loop in reverse so first instance has priority */ 2301 for ( i=aoColDefs.length-1 ; i>=0 ; i-- ) 2302 { 2303 def = aoColDefs[i]; 2304 2305 /* Each definition can target multiple columns, as it is an array */ 2306 var aTargets = def.targets !== undefined ? 2307 def.targets : 2308 def.aTargets; 2309 2310 if ( ! $.isArray( aTargets ) ) 2311 { 2312 aTargets = [ aTargets ]; 2313 } 2314 2315 for ( j=0, jLen=aTargets.length ; j<jLen ; j++ ) 2316 { 2317 if ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 ) 2318 { 2319 /* Add columns that we don't yet know about */ 2320 while( columns.length <= aTargets[j] ) 2321 { 2322 _fnAddColumn( oSettings ); 2323 } 2324 2325 /* Integer, basic index */ 2326 fn( aTargets[j], def ); 2327 } 2328 else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 ) 2329 { 2330 /* Negative integer, right to left column counting */ 2331 fn( columns.length+aTargets[j], def ); 2332 } 2333 else if ( typeof aTargets[j] === 'string' ) 2334 { 2335 /* Class name matching on TH element */ 2336 for ( k=0, kLen=columns.length ; k<kLen ; k++ ) 2337 { 2338 if ( aTargets[j] == "_all" || 2339 $(columns[k].nTh).hasClass( aTargets[j] ) ) 2340 { 2341 fn( k, def ); 2342 } 2343 } 2344 } 2345 } 2346 } 2347 } 2348 2349 // Statically defined columns array 2350 if ( aoCols ) 2351 { 2352 for ( i=0, iLen=aoCols.length ; i<iLen ; i++ ) 2353 { 2354 fn( i, aoCols[i] ); 2355 } 2356 } 2357 } 2358 2359 /** 2360 * Add a data array to the table, creating DOM node etc. This is the parallel to 2361 * _fnGatherData, but for adding rows from a Javascript source, rather than a 2362 * DOM source. 2363 * @param {object} oSettings dataTables settings object 2364 * @param {array} aData data array to be added 2365 * @param {node} [nTr] TR element to add to the table - optional. If not given, 2366 * DataTables will create a row automatically 2367 * @param {array} [anTds] Array of TD|TH elements for the row - must be given 2368 * if nTr is. 2369 * @returns {int} >=0 if successful (index of new aoData entry), -1 if failed 2370 * @memberof DataTable#oApi 2371 */ 2372 function _fnAddData ( oSettings, aDataIn, nTr, anTds ) 2373 { 2374 /* Create the object for storing information about this new row */ 2375 var iRow = oSettings.aoData.length; 2376 var oData = $.extend( true, {}, DataTable.models.oRow, { 2377 src: nTr ? 'dom' : 'data', 2378 idx: iRow 2379 } ); 2380 2381 oData._aData = aDataIn; 2382 oSettings.aoData.push( oData ); 2383 2384 /* Create the cells */ 2385 var nTd, sThisType; 2386 var columns = oSettings.aoColumns; 2387 2388 // Invalidate the column types as the new data needs to be revalidated 2389 for ( var i=0, iLen=columns.length ; i<iLen ; i++ ) 2390 { 2391 columns[i].sType = null; 2392 } 2393 2394 /* Add to the display array */ 2395 oSettings.aiDisplayMaster.push( iRow ); 2396 2397 var id = oSettings.rowIdFn( aDataIn ); 2398 if ( id !== undefined ) { 2399 oSettings.aIds[ id ] = oData; 2400 } 2401 2402 /* Create the DOM information, or register it if already present */ 2403 if ( nTr || ! oSettings.oFeatures.bDeferRender ) 2404 { 2405 _fnCreateTr( oSettings, iRow, nTr, anTds ); 2406 } 2407 2408 return iRow; 2409 } 2410 2411 2412 /** 2413 * Add one or more TR elements to the table. Generally we'd expect to 2414 * use this for reading data from a DOM sourced table, but it could be 2415 * used for an TR element. Note that if a TR is given, it is used (i.e. 2416 * it is not cloned). 2417 * @param {object} settings dataTables settings object 2418 * @param {array|node|jQuery} trs The TR element(s) to add to the table 2419 * @returns {array} Array of indexes for the added rows 2420 * @memberof DataTable#oApi 2421 */ 2422 function _fnAddTr( settings, trs ) 2423 { 2424 var row; 2425 2426 // Allow an individual node to be passed in 2427 if ( ! (trs instanceof $) ) { 2428 trs = $(trs); 2429 } 2430 2431 return trs.map( function (i, el) { 2432 row = _fnGetRowElements( settings, el ); 2433 return _fnAddData( settings, row.data, el, row.cells ); 2434 } ); 2435 } 2436 2437 2438 /** 2439 * Take a TR element and convert it to an index in aoData 2440 * @param {object} oSettings dataTables settings object 2441 * @param {node} n the TR element to find 2442 * @returns {int} index if the node is found, null if not 2443 * @memberof DataTable#oApi 2444 */ 2445 function _fnNodeToDataIndex( oSettings, n ) 2446 { 2447 return (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null; 2448 } 2449 2450 2451 /** 2452 * Take a TD element and convert it into a column data index (not the visible index) 2453 * @param {object} oSettings dataTables settings object 2454 * @param {int} iRow The row number the TD/TH can be found in 2455 * @param {node} n The TD/TH element to find 2456 * @returns {int} index if the node is found, -1 if not 2457 * @memberof DataTable#oApi 2458 */ 2459 function _fnNodeToColumnIndex( oSettings, iRow, n ) 2460 { 2461 return $.inArray( n, oSettings.aoData[ iRow ].anCells ); 2462 } 2463 2464 2465 /** 2466 * Get the data for a given cell from the internal cache, taking into account data mapping 2467 * @param {object} settings dataTables settings object 2468 * @param {int} rowIdx aoData row id 2469 * @param {int} colIdx Column index 2470 * @param {string} type data get type ('display', 'type' 'filter' 'sort') 2471 * @returns {*} Cell data 2472 * @memberof DataTable#oApi 2473 */ 2474 function _fnGetCellData( settings, rowIdx, colIdx, type ) 2475 { 2476 var draw = settings.iDraw; 2477 var col = settings.aoColumns[colIdx]; 2478 var rowData = settings.aoData[rowIdx]._aData; 2479 var defaultContent = col.sDefaultContent; 2480 var cellData = col.fnGetData( rowData, type, { 2481 settings: settings, 2482 row: rowIdx, 2483 col: colIdx 2484 } ); 2485 2486 if ( cellData === undefined ) { 2487 if ( settings.iDrawError != draw && defaultContent === null ) { 2488 _fnLog( settings, 0, "Requested unknown parameter "+ 2489 (typeof col.mData=='function' ? '{function}' : "'"+col.mData+"'")+ 2490 " for row "+rowIdx+", column "+colIdx, 4 ); 2491 settings.iDrawError = draw; 2492 } 2493 return defaultContent; 2494 } 2495 2496 // When the data source is null and a specific data type is requested (i.e. 2497 // not the original data), we can use default column data 2498 if ( (cellData === rowData || cellData === null) && defaultContent !== null && type !== undefined ) { 2499 cellData = defaultContent; 2500 } 2501 else if ( typeof cellData === 'function' ) { 2502 // If the data source is a function, then we run it and use the return, 2503 // executing in the scope of the data object (for instances) 2504 return cellData.call( rowData ); 2505 } 2506 2507 if ( cellData === null && type == 'display' ) { 2508 return ''; 2509 } 2510 return cellData; 2511 } 2512 2513 2514 /** 2515 * Set the value for a specific cell, into the internal data cache 2516 * @param {object} settings dataTables settings object 2517 * @param {int} rowIdx aoData row id 2518 * @param {int} colIdx Column index 2519 * @param {*} val Value to set 2520 * @memberof DataTable#oApi 2521 */ 2522 function _fnSetCellData( settings, rowIdx, colIdx, val ) 2523 { 2524 var col = settings.aoColumns[colIdx]; 2525 var rowData = settings.aoData[rowIdx]._aData; 2526 2527 col.fnSetData( rowData, val, { 2528 settings: settings, 2529 row: rowIdx, 2530 col: colIdx 2531 } ); 2532 } 2533 2534 2535 // Private variable that is used to match action syntax in the data property object 2536 var __reArray = /\[.*?\]$/; 2537 var __reFn = /\(\)$/; 2538 2539 /** 2540 * Split string on periods, taking into account escaped periods 2541 * @param {string} str String to split 2542 * @return {array} Split string 2543 */ 2544 function _fnSplitObjNotation( str ) 2545 { 2546 return $.map( str.match(/(\\.|[^\.])+/g) || [''], function ( s ) { 2547 return s.replace(/\\./g, '.'); 2548 } ); 2549 } 2550 2551 2552 /** 2553 * Return a function that can be used to get data from a source object, taking 2554 * into account the ability to use nested objects as a source 2555 * @param {string|int|function} mSource The data source for the object 2556 * @returns {function} Data get function 2557 * @memberof DataTable#oApi 2558 */ 2559 function _fnGetObjectDataFn( mSource ) 2560 { 2561 if ( $.isPlainObject( mSource ) ) 2562 { 2563 /* Build an object of get functions, and wrap them in a single call */ 2564 var o = {}; 2565 $.each( mSource, function (key, val) { 2566 if ( val ) { 2567 o[key] = _fnGetObjectDataFn( val ); 2568 } 2569 } ); 2570 2571 return function (data, type, row, meta) { 2572 var t = o[type] || o._; 2573 return t !== undefined ? 2574 t(data, type, row, meta) : 2575 data; 2576 }; 2577 } 2578 else if ( mSource === null ) 2579 { 2580 /* Give an empty string for rendering / sorting etc */ 2581 return function (data) { // type, row and meta also passed, but not used 2582 return data; 2583 }; 2584 } 2585 else if ( typeof mSource === 'function' ) 2586 { 2587 return function (data, type, row, meta) { 2588 return mSource( data, type, row, meta ); 2589 }; 2590 } 2591 else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 || 2592 mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) ) 2593 { 2594 /* If there is a . in the source string then the data source is in a 2595 * nested object so we loop over the data for each level to get the next 2596 * level down. On each loop we test for undefined, and if found immediately 2597 * return. This allows entire objects to be missing and sDefaultContent to 2598 * be used if defined, rather than throwing an error 2599 */ 2600 var fetchData = function (data, type, src) { 2601 var arrayNotation, funcNotation, out, innerSrc; 2602 2603 if ( src !== "" ) 2604 { 2605 var a = _fnSplitObjNotation( src ); 2606 2607 for ( var i=0, iLen=a.length ; i<iLen ; i++ ) 2608 { 2609 // Check if we are dealing with special notation 2610 arrayNotation = a[i].match(__reArray); 2611 funcNotation = a[i].match(__reFn); 2612 2613 if ( arrayNotation ) 2614 { 2615 // Array notation 2616 a[i] = a[i].replace(__reArray, ''); 2617 2618 // Condition allows simply [] to be passed in 2619 if ( a[i] !== "" ) { 2620 data = data[ a[i] ]; 2621 } 2622 out = []; 2623 2624 // Get the remainder of the nested object to get 2625 a.splice( 0, i+1 ); 2626 innerSrc = a.join('.'); 2627 2628 // Traverse each entry in the array getting the properties requested 2629 if ( $.isArray( data ) ) { 2630 for ( var j=0, jLen=data.length ; j<jLen ; j++ ) { 2631 out.push( fetchData( data[j], type, innerSrc ) ); 2632 } 2633 } 2634 2635 // If a string is given in between the array notation indicators, that 2636 // is used to join the strings together, otherwise an array is returned 2637 var join = arrayNotation[0].substring(1, arrayNotation[0].length-1); 2638 data = (join==="") ? out : out.join(join); 2639 2640 // The inner call to fetchData has already traversed through the remainder 2641 // of the source requested, so we exit from the loop 2642 break; 2643 } 2644 else if ( funcNotation ) 2645 { 2646 // Function call 2647 a[i] = a[i].replace(__reFn, ''); 2648 data = data[ a[i] ](); 2649 continue; 2650 } 2651 2652 if ( data === null || data[ a[i] ] === undefined ) 2653 { 2654 return undefined; 2655 } 2656 data = data[ a[i] ]; 2657 } 2658 } 2659 2660 return data; 2661 }; 2662 2663 return function (data, type) { // row and meta also passed, but not used 2664 return fetchData( data, type, mSource ); 2665 }; 2666 } 2667 else 2668 { 2669 /* Array or flat object mapping */ 2670 return function (data, type) { // row and meta also passed, but not used 2671 return data[mSource]; 2672 }; 2673 } 2674 } 2675 2676 2677 /** 2678 * Return a function that can be used to set data from a source object, taking 2679 * into account the ability to use nested objects as a source 2680 * @param {string|int|function} mSource The data source for the object 2681 * @returns {function} Data set function 2682 * @memberof DataTable#oApi 2683 */ 2684 function _fnSetObjectDataFn( mSource ) 2685 { 2686 if ( $.isPlainObject( mSource ) ) 2687 { 2688 /* Unlike get, only the underscore (global) option is used for for 2689 * setting data since we don't know the type here. This is why an object 2690 * option is not documented for `mData` (which is read/write), but it is 2691 * for `mRender` which is read only. 2692 */ 2693 return _fnSetObjectDataFn( mSource._ ); 2694 } 2695 else if ( mSource === null ) 2696 { 2697 /* Nothing to do when the data source is null */ 2698 return function () {}; 2699 } 2700 else if ( typeof mSource === 'function' ) 2701 { 2702 return function (data, val, meta) { 2703 mSource( data, 'set', val, meta ); 2704 }; 2705 } 2706 else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 || 2707 mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) ) 2708 { 2709 /* Like the get, we need to get data from a nested object */ 2710 var setData = function (data, val, src) { 2711 var a = _fnSplitObjNotation( src ), b; 2712 var aLast = a[a.length-1]; 2713 var arrayNotation, funcNotation, o, innerSrc; 2714 2715 for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ ) 2716 { 2717 // Check if we are dealing with an array notation request 2718 arrayNotation = a[i].match(__reArray); 2719 funcNotation = a[i].match(__reFn); 2720 2721 if ( arrayNotation ) 2722 { 2723 a[i] = a[i].replace(__reArray, ''); 2724 data[ a[i] ] = []; 2725 2726 // Get the remainder of the nested object to set so we can recurse 2727 b = a.slice(); 2728 b.splice( 0, i+1 ); 2729 innerSrc = b.join('.'); 2730 2731 // Traverse each entry in the array setting the properties requested 2732 if ( $.isArray( val ) ) 2733 { 2734 for ( var j=0, jLen=val.length ; j<jLen ; j++ ) 2735 { 2736 o = {}; 2737 setData( o, val[j], innerSrc ); 2738 data[ a[i] ].push( o ); 2739 } 2740 } 2741 else 2742 { 2743 // We've been asked to save data to an array, but it 2744 // isn't array data to be saved. Best that can be done 2745 // is to just save the value. 2746 data[ a[i] ] = val; 2747 } 2748 2749 // The inner call to setData has already traversed through the remainder 2750 // of the source and has set the data, thus we can exit here 2751 return; 2752 } 2753 else if ( funcNotation ) 2754 { 2755 // Function call 2756 a[i] = a[i].replace(__reFn, ''); 2757 data = data[ a[i] ]( val ); 2758 } 2759 2760 // If the nested object doesn't currently exist - since we are 2761 // trying to set the value - create it 2762 if ( data[ a[i] ] === null || data[ a[i] ] === undefined ) 2763 { 2764 data[ a[i] ] = {}; 2765 } 2766 data = data[ a[i] ]; 2767 } 2768 2769 // Last item in the input - i.e, the actual set 2770 if ( aLast.match(__reFn ) ) 2771 { 2772 // Function call 2773 data = data[ aLast.replace(__reFn, '') ]( val ); 2774 } 2775 else 2776 { 2777 // If array notation is used, we just want to strip it and use the property name 2778 // and assign the value. If it isn't used, then we get the result we want anyway 2779 data[ aLast.replace(__reArray, '') ] = val; 2780 } 2781 }; 2782 2783 return function (data, val) { // meta is also passed in, but not used 2784 return setData( data, val, mSource ); 2785 }; 2786 } 2787 else 2788 { 2789 /* Array or flat object mapping */ 2790 return function (data, val) { // meta is also passed in, but not used 2791 data[mSource] = val; 2792 }; 2793 } 2794 } 2795 2796 2797 /** 2798 * Return an array with the full table data 2799 * @param {object} oSettings dataTables settings object 2800 * @returns array {array} aData Master data array 2801 * @memberof DataTable#oApi 2802 */ 2803 function _fnGetDataMaster ( settings ) 2804 { 2805 return _pluck( settings.aoData, '_aData' ); 2806 } 2807 2808 2809 /** 2810 * Nuke the table 2811 * @param {object} oSettings dataTables settings object 2812 * @memberof DataTable#oApi 2813 */ 2814 function _fnClearTable( settings ) 2815 { 2816 settings.aoData.length = 0; 2817 settings.aiDisplayMaster.length = 0; 2818 settings.aiDisplay.length = 0; 2819 settings.aIds = {}; 2820 } 2821 2822 2823 /** 2824 * Take an array of integers (index array) and remove a target integer (value - not 2825 * the key!) 2826 * @param {array} a Index array to target 2827 * @param {int} iTarget value to find 2828 * @memberof DataTable#oApi 2829 */ 2830 function _fnDeleteIndex( a, iTarget, splice ) 2831 { 2832 var iTargetIndex = -1; 2833 2834 for ( var i=0, iLen=a.length ; i<iLen ; i++ ) 2835 { 2836 if ( a[i] == iTarget ) 2837 { 2838 iTargetIndex = i; 2839 } 2840 else if ( a[i] > iTarget ) 2841 { 2842 a[i]--; 2843 } 2844 } 2845 2846 if ( iTargetIndex != -1 && splice === undefined ) 2847 { 2848 a.splice( iTargetIndex, 1 ); 2849 } 2850 } 2851 2852 2853 /** 2854 * Mark cached data as invalid such that a re-read of the data will occur when 2855 * the cached data is next requested. Also update from the data source object. 2856 * 2857 * @param {object} settings DataTables settings object 2858 * @param {int} rowIdx Row index to invalidate 2859 * @param {string} [src] Source to invalidate from: undefined, 'auto', 'dom' 2860 * or 'data' 2861 * @param {int} [colIdx] Column index to invalidate. If undefined the whole 2862 * row will be invalidated 2863 * @memberof DataTable#oApi 2864 * 2865 * @todo For the modularisation of v1.11 this will need to become a callback, so 2866 * the sort and filter methods can subscribe to it. That will required 2867 * initialisation options for sorting, which is why it is not already baked in 2868 */ 2869 function _fnInvalidate( settings, rowIdx, src, colIdx ) 2870 { 2871 var row = settings.aoData[ rowIdx ]; 2872 var i, ien; 2873 var cellWrite = function ( cell, col ) { 2874 // This is very frustrating, but in IE if you just write directly 2875 // to innerHTML, and elements that are overwritten are GC'ed, 2876 // even if there is a reference to them elsewhere 2877 while ( cell.childNodes.length ) { 2878 cell.removeChild( cell.firstChild ); 2879 } 2880 2881 cell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' ); 2882 }; 2883 2884 // Are we reading last data from DOM or the data object? 2885 if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) { 2886 // Read the data from the DOM 2887 row._aData = _fnGetRowElements( 2888 settings, row, colIdx, colIdx === undefined ? undefined : row._aData 2889 ) 2890 .data; 2891 } 2892 else { 2893 // Reading from data object, update the DOM 2894 var cells = row.anCells; 2895 2896 if ( cells ) { 2897 if ( colIdx !== undefined ) { 2898 cellWrite( cells[colIdx], colIdx ); 2899 } 2900 else { 2901 for ( i=0, ien=cells.length ; i<ien ; i++ ) { 2902 cellWrite( cells[i], i ); 2903 } 2904 } 2905 } 2906 } 2907 2908 // For both row and cell invalidation, the cached data for sorting and 2909 // filtering is nulled out 2910 row._aSortData = null; 2911 row._aFilterData = null; 2912 2913 // Invalidate the type for a specific column (if given) or all columns since 2914 // the data might have changed 2915 var cols = settings.aoColumns; 2916 if ( colIdx !== undefined ) { 2917 cols[ colIdx ].sType = null; 2918 } 2919 else { 2920 for ( i=0, ien=cols.length ; i<ien ; i++ ) { 2921 cols[i].sType = null; 2922 } 2923 2924 // Update DataTables special `DT_*` attributes for the row 2925 _fnRowAttributes( settings, row ); 2926 } 2927 } 2928 2929 2930 /** 2931 * Build a data source object from an HTML row, reading the contents of the 2932 * cells that are in the row. 2933 * 2934 * @param {object} settings DataTables settings object 2935 * @param {node|object} TR element from which to read data or existing row 2936 * object from which to re-read the data from the cells 2937 * @param {int} [colIdx] Optional column index 2938 * @param {array|object} [d] Data source object. If `colIdx` is given then this 2939 * parameter should also be given and will be used to write the data into. 2940 * Only the column in question will be written 2941 * @returns {object} Object with two parameters: `data` the data read, in 2942 * document order, and `cells` and array of nodes (they can be useful to the 2943 * caller, so rather than needing a second traversal to get them, just return 2944 * them from here). 2945 * @memberof DataTable#oApi 2946 */ 2947 function _fnGetRowElements( settings, row, colIdx, d ) 2948 { 2949 var 2950 tds = [], 2951 td = row.firstChild, 2952 name, col, o, i=0, contents, 2953 columns = settings.aoColumns, 2954 objectRead = settings._rowReadObject; 2955 2956 // Allow the data object to be passed in, or construct 2957 d = d !== undefined ? 2958 d : 2959 objectRead ? 2960 {} : 2961 []; 2962 2963 var attr = function ( str, td ) { 2964 if ( typeof str === 'string' ) { 2965 var idx = str.indexOf('@'); 2966 2967 if ( idx !== -1 ) { 2968 var attr = str.substring( idx+1 ); 2969 var setter = _fnSetObjectDataFn( str ); 2970 setter( d, td.getAttribute( attr ) ); 2971 } 2972 } 2973 }; 2974 2975 // Read data from a cell and store into the data object 2976 var cellProcess = function ( cell ) { 2977 if ( colIdx === undefined || colIdx === i ) { 2978 col = columns[i]; 2979 contents = $.trim(cell.innerHTML); 2980 2981 if ( col && col._bAttrSrc ) { 2982 var setter = _fnSetObjectDataFn( col.mData._ ); 2983 setter( d, contents ); 2984 2985 attr( col.mData.sort, cell ); 2986 attr( col.mData.type, cell ); 2987 attr( col.mData.filter, cell ); 2988 } 2989 else { 2990 // Depending on the `data` option for the columns the data can 2991 // be read to either an object or an array. 2992 if ( objectRead ) { 2993 if ( ! col._setter ) { 2994 // Cache the setter function 2995 col._setter = _fnSetObjectDataFn( col.mData ); 2996 } 2997 col._setter( d, contents ); 2998 } 2999 else { 3000 d[i] = contents; 3001 } 3002 } 3003 } 3004 3005 i++; 3006 }; 3007 3008 if ( td ) { 3009 // `tr` element was passed in 3010 while ( td ) { 3011 name = td.nodeName.toUpperCase(); 3012 3013 if ( name == "TD" || name == "TH" ) { 3014 cellProcess( td ); 3015 tds.push( td ); 3016 } 3017 3018 td = td.nextSibling; 3019 } 3020 } 3021 else { 3022 // Existing row object passed in 3023 tds = row.anCells; 3024 3025 for ( var j=0, jen=tds.length ; j<jen ; j++ ) { 3026 cellProcess( tds[j] ); 3027 } 3028 } 3029 3030 // Read the ID from the DOM if present 3031 var rowNode = row.firstChild ? row : row.nTr; 3032 3033 if ( rowNode ) { 3034 var id = rowNode.getAttribute( 'id' ); 3035 3036 if ( id ) { 3037 _fnSetObjectDataFn( settings.rowId )( d, id ); 3038 } 3039 } 3040 3041 return { 3042 data: d, 3043 cells: tds 3044 }; 3045 } 3046 /** 3047 * Create a new TR element (and it's TD children) for a row 3048 * @param {object} oSettings dataTables settings object 3049 * @param {int} iRow Row to consider 3050 * @param {node} [nTrIn] TR element to add to the table - optional. If not given, 3051 * DataTables will create a row automatically 3052 * @param {array} [anTds] Array of TD|TH elements for the row - must be given 3053 * if nTr is. 3054 * @memberof DataTable#oApi 3055 */ 3056 function _fnCreateTr ( oSettings, iRow, nTrIn, anTds ) 3057 { 3058 var 3059 row = oSettings.aoData[iRow], 3060 rowData = row._aData, 3061 cells = [], 3062 nTr, nTd, oCol, 3063 i, iLen; 3064 3065 if ( row.nTr === null ) 3066 { 3067 nTr = nTrIn || document.createElement('tr'); 3068 3069 row.nTr = nTr; 3070 row.anCells = cells; 3071 3072 /* Use a private property on the node to allow reserve mapping from the node 3073 * to the aoData array for fast look up 3074 */ 3075 nTr._DT_RowIndex = iRow; 3076 3077 /* Special parameters can be given by the data source to be used on the row */ 3078 _fnRowAttributes( oSettings, row ); 3079 3080 /* Process each column */ 3081 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ ) 3082 { 3083 oCol = oSettings.aoColumns[i]; 3084 3085 nTd = nTrIn ? anTds[i] : document.createElement( oCol.sCellType ); 3086 nTd._DT_CellIndex = { 3087 row: iRow, 3088 column: i 3089 }; 3090 3091 cells.push( nTd ); 3092 3093 // Need to create the HTML if new, or if a rendering function is defined 3094 if ( (!nTrIn || oCol.mRender || oCol.mData !== i) && 3095 (!$.isPlainObject(oCol.mData) || oCol.mData._ !== i+'.display') 3096 ) { 3097 nTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' ); 3098 } 3099 3100 /* Add user defined class */ 3101 if ( oCol.sClass ) 3102 { 3103 nTd.className += ' '+oCol.sClass; 3104 } 3105 3106 // Visibility - add or remove as required 3107 if ( oCol.bVisible && ! nTrIn ) 3108 { 3109 nTr.appendChild( nTd ); 3110 } 3111 else if ( ! oCol.bVisible && nTrIn ) 3112 { 3113 nTd.parentNode.removeChild( nTd ); 3114 } 3115 3116 if ( oCol.fnCreatedCell ) 3117 { 3118 oCol.fnCreatedCell.call( oSettings.oInstance, 3119 nTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i 3120 ); 3121 } 3122 } 3123 3124 _fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [nTr, rowData, iRow] ); 3125 } 3126 3127 // Remove once webkit bug 131819 and Chromium bug 365619 have been resolved 3128 // and deployed 3129 row.nTr.setAttribute( 'role', 'row' ); 3130 } 3131 3132 3133 /** 3134 * Add attributes to a row based on the special `DT_*` parameters in a data 3135 * source object. 3136 * @param {object} settings DataTables settings object 3137 * @param {object} DataTables row object for the row to be modified 3138 * @memberof DataTable#oApi 3139 */ 3140 function _fnRowAttributes( settings, row ) 3141 { 3142 var tr = row.nTr; 3143 var data = row._aData; 3144 3145 if ( tr ) { 3146 var id = settings.rowIdFn( data ); 3147 3148 if ( id ) { 3149 tr.id = id; 3150 } 3151 3152 if ( data.DT_RowClass ) { 3153 // Remove any classes added by DT_RowClass before 3154 var a = data.DT_RowClass.split(' '); 3155 row.__rowc = row.__rowc ? 3156 _unique( row.__rowc.concat( a ) ) : 3157 a; 3158 3159 $(tr) 3160 .removeClass( row.__rowc.join(' ') ) 3161 .addClass( data.DT_RowClass ); 3162 } 3163 3164 if ( data.DT_RowAttr ) { 3165 $(tr).attr( data.DT_RowAttr ); 3166 } 3167 3168 if ( data.DT_RowData ) { 3169 $(tr).data( data.DT_RowData ); 3170 } 3171 } 3172 } 3173 3174 3175 /** 3176 * Create the HTML header for the table 3177 * @param {object} oSettings dataTables settings object 3178 * @memberof DataTable#oApi 3179 */ 3180 function _fnBuildHead( oSettings ) 3181 { 3182 var i, ien, cell, row, column; 3183 var thead = oSettings.nTHead; 3184 var tfoot = oSettings.nTFoot; 3185 var createHeader = $('th, td', thead).length === 0; 3186 var classes = oSettings.oClasses; 3187 var columns = oSettings.aoColumns; 3188 3189 if ( createHeader ) { 3190 row = $('<tr/>').appendTo( thead ); 3191 } 3192 3193 for ( i=0, ien=columns.length ; i<ien ; i++ ) { 3194 column = columns[i]; 3195 cell = $( column.nTh ).addClass( column.sClass ); 3196 3197 if ( createHeader ) { 3198 cell.appendTo( row ); 3199 } 3200 3201 // 1.11 move into sorting 3202 if ( oSettings.oFeatures.bSort ) { 3203 cell.addClass( column.sSortingClass ); 3204 3205 if ( column.bSortable !== false ) { 3206 cell 3207 .attr( 'tabindex', oSettings.iTabIndex ) 3208 .attr( 'aria-controls', oSettings.sTableId ); 3209 3210 _fnSortAttachListener( oSettings, column.nTh, i ); 3211 } 3212 } 3213 3214 if ( column.sTitle != cell[0].innerHTML ) { 3215 cell.html( column.sTitle ); 3216 } 3217 3218 _fnRenderer( oSettings, 'header' )( 3219 oSettings, cell, column, classes 3220 ); 3221 } 3222 3223 if ( createHeader ) { 3224 _fnDetectHeader( oSettings.aoHeader, thead ); 3225 } 3226 3227 /* ARIA role for the rows */ 3228 $(thead).find('>tr').attr('role', 'row'); 3229 3230 /* Deal with the footer - add classes if required */ 3231 $(thead).find('>tr>th, >tr>td').addClass( classes.sHeaderTH ); 3232 $(tfoot).find('>tr>th, >tr>td').addClass( classes.sFooterTH ); 3233 3234 // Cache the footer cells. Note that we only take the cells from the first 3235 // row in the footer. If there is more than one row the user wants to 3236 // interact with, they need to use the table().foot() method. Note also this 3237 // allows cells to be used for multiple columns using colspan 3238 if ( tfoot !== null ) { 3239 var cells = oSettings.aoFooter[0]; 3240 3241 for ( i=0, ien=cells.length ; i<ien ; i++ ) { 3242 column = columns[i]; 3243 column.nTf = cells[i].cell; 3244 3245 if ( column.sClass ) { 3246 $(column.nTf).addClass( column.sClass ); 3247 } 3248 } 3249 } 3250 } 3251 3252 3253 /** 3254 * Draw the header (or footer) element based on the column visibility states. The 3255 * methodology here is to use the layout array from _fnDetectHeader, modified for 3256 * the instantaneous column visibility, to construct the new layout. The grid is 3257 * traversed over cell at a time in a rows x columns grid fashion, although each 3258 * cell insert can cover multiple elements in the grid - which is tracks using the 3259 * aApplied array. Cell inserts in the grid will only occur where there isn't 3260 * already a cell in that position. 3261 * @param {object} oSettings dataTables settings object 3262 * @param array {objects} aoSource Layout array from _fnDetectHeader 3263 * @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc, 3264 * @memberof DataTable#oApi 3265 */ 3266 function _fnDrawHead( oSettings, aoSource, bIncludeHidden ) 3267 { 3268 var i, iLen, j, jLen, k, kLen, n, nLocalTr; 3269 var aoLocal = []; 3270 var aApplied = []; 3271 var iColumns = oSettings.aoColumns.length; 3272 var iRowspan, iColspan; 3273 3274 if ( ! aoSource ) 3275 { 3276 return; 3277 } 3278 3279 if ( bIncludeHidden === undefined ) 3280 { 3281 bIncludeHidden = false; 3282 } 3283 3284 /* Make a copy of the master layout array, but without the visible columns in it */ 3285 for ( i=0, iLen=aoSource.length ; i<iLen ; i++ ) 3286 { 3287 aoLocal[i] = aoSource[i].slice(); 3288 aoLocal[i].nTr = aoSource[i].nTr; 3289 3290 /* Remove any columns which are currently hidden */ 3291 for ( j=iColumns-1 ; j>=0 ; j-- ) 3292 { 3293 if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden ) 3294 { 3295 aoLocal[i].splice( j, 1 ); 3296 } 3297 } 3298 3299 /* Prep the applied array - it needs an element for each row */ 3300 aApplied.push( [] ); 3301 } 3302 3303 for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ ) 3304 { 3305 nLocalTr = aoLocal[i].nTr; 3306 3307 /* All cells are going to be replaced, so empty out the row */ 3308 if ( nLocalTr ) 3309 { 3310 while( (n = nLocalTr.firstChild) ) 3311 { 3312 nLocalTr.removeChild( n ); 3313 } 3314 } 3315 3316 for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ ) 3317 { 3318 iRowspan = 1; 3319 iColspan = 1; 3320 3321 /* Check to see if there is already a cell (row/colspan) covering our target 3322 * insert point. If there is, then there is nothing to do. 3323 */ 3324 if ( aApplied[i][j] === undefined ) 3325 { 3326 nLocalTr.appendChild( aoLocal[i][j].cell ); 3327 aApplied[i][j] = 1; 3328 3329 /* Expand the cell to cover as many rows as needed */ 3330 while ( aoLocal[i+iRowspan] !== undefined && 3331 aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell ) 3332 { 3333 aApplied[i+iRowspan][j] = 1; 3334 iRowspan++; 3335 } 3336 3337 /* Expand the cell to cover as many columns as needed */ 3338 while ( aoLocal[i][j+iColspan] !== undefined && 3339 aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell ) 3340 { 3341 /* Must update the applied array over the rows for the columns */ 3342 for ( k=0 ; k<iRowspan ; k++ ) 3343 { 3344 aApplied[i+k][j+iColspan] = 1; 3345 } 3346 iColspan++; 3347 } 3348 3349 /* Do the actual expansion in the DOM */ 3350 $(aoLocal[i][j].cell) 3351 .attr('rowspan', iRowspan) 3352 .attr('colspan', iColspan); 3353 } 3354 } 3355 } 3356 } 3357 3358 3359 /** 3360 * Insert the required TR nodes into the table for display 3361 * @param {object} oSettings dataTables settings object 3362 * @memberof DataTable#oApi 3363 */ 3364 function _fnDraw( oSettings ) 3365 { 3366 /* Provide a pre-callback function which can be used to cancel the draw is false is returned */ 3367 var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] ); 3368 if ( $.inArray( false, aPreDraw ) !== -1 ) 3369 { 3370 _fnProcessingDisplay( oSettings, false ); 3371 return; 3372 } 3373 3374 var i, iLen, n; 3375 var anRows = []; 3376 var iRowCount = 0; 3377 var asStripeClasses = oSettings.asStripeClasses; 3378 var iStripes = asStripeClasses.length; 3379 var iOpenRows = oSettings.aoOpenRows.length; 3380 var oLang = oSettings.oLanguage; 3381 var iInitDisplayStart = oSettings.iInitDisplayStart; 3382 var bServerSide = _fnDataSource( oSettings ) == 'ssp'; 3383 var aiDisplay = oSettings.aiDisplay; 3384 3385 oSettings.bDrawing = true; 3386 3387 /* Check and see if we have an initial draw position from state saving */ 3388 if ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 ) 3389 { 3390 oSettings._iDisplayStart = bServerSide ? 3391 iInitDisplayStart : 3392 iInitDisplayStart >= oSettings.fnRecordsDisplay() ? 3393 0 : 3394 iInitDisplayStart; 3395 3396 oSettings.iInitDisplayStart = -1; 3397 } 3398 3399 var iDisplayStart = oSettings._iDisplayStart; 3400 var iDisplayEnd = oSettings.fnDisplayEnd(); 3401 3402 /* Server-side processing draw intercept */ 3403 if ( oSettings.bDeferLoading ) 3404 { 3405 oSettings.bDeferLoading = false; 3406 oSettings.iDraw++; 3407 _fnProcessingDisplay( oSettings, false ); 3408 } 3409 else if ( !bServerSide ) 3410 { 3411 oSettings.iDraw++; 3412 } 3413 else if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) ) 3414 { 3415 return; 3416 } 3417 3418 if ( aiDisplay.length !== 0 ) 3419 { 3420 var iStart = bServerSide ? 0 : iDisplayStart; 3421 var iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd; 3422 3423 for ( var j=iStart ; j<iEnd ; j++ ) 3424 { 3425 var iDataIndex = aiDisplay[j]; 3426 var aoData = oSettings.aoData[ iDataIndex ]; 3427 if ( aoData.nTr === null ) 3428 { 3429 _fnCreateTr( oSettings, iDataIndex ); 3430 } 3431 3432 var nRow = aoData.nTr; 3433 3434 /* Remove the old striping classes and then add the new one */ 3435 if ( iStripes !== 0 ) 3436 { 3437 var sStripe = asStripeClasses[ iRowCount % iStripes ]; 3438 if ( aoData._sRowStripe != sStripe ) 3439 { 3440 $(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe ); 3441 aoData._sRowStripe = sStripe; 3442 } 3443 } 3444 3445 // Row callback functions - might want to manipulate the row 3446 // iRowCount and j are not currently documented. Are they at all 3447 // useful? 3448 _fnCallbackFire( oSettings, 'aoRowCallback', null, 3449 [nRow, aoData._aData, iRowCount, j] ); 3450 3451 anRows.push( nRow ); 3452 iRowCount++; 3453 } 3454 } 3455 else 3456 { 3457 /* Table is empty - create a row with an empty message in it */ 3458 var sZero = oLang.sZeroRecords; 3459 if ( oSettings.iDraw == 1 && _fnDataSource( oSettings ) == 'ajax' ) 3460 { 3461 sZero = oLang.sLoadingRecords; 3462 } 3463 else if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 ) 3464 { 3465 sZero = oLang.sEmptyTable; 3466 } 3467 3468 anRows[ 0 ] = $( '<tr/>', { 'class': iStripes ? asStripeClasses[0] : '' } ) 3469 .append( $('<td />', { 3470 'valign': 'top', 3471 'colSpan': _fnVisbleColumns( oSettings ), 3472 'class': oSettings.oClasses.sRowEmpty 3473 } ).html( sZero ) )[0]; 3474 } 3475 3476 /* Header and footer callbacks */ 3477 _fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0], 3478 _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] ); 3479 3480 _fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0], 3481 _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] ); 3482 3483 var body = $(oSettings.nTBody); 3484 3485 body.children().detach(); 3486 body.append( $(anRows) ); 3487 3488 /* Call all required callback functions for the end of a draw */ 3489 _fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] ); 3490 3491 /* Draw is complete, sorting and filtering must be as well */ 3492 oSettings.bSorted = false; 3493 oSettings.bFiltered = false; 3494 oSettings.bDrawing = false; 3495 } 3496 3497 3498 /** 3499 * Redraw the table - taking account of the various features which are enabled 3500 * @param {object} oSettings dataTables settings object 3501 * @param {boolean} [holdPosition] Keep the current paging position. By default 3502 * the paging is reset to the first page 3503 * @memberof DataTable#oApi 3504 */ 3505 function _fnReDraw( settings, holdPosition ) 3506 { 3507 var 3508 features = settings.oFeatures, 3509 sort = features.bSort, 3510 filter = features.bFilter; 3511 3512 if ( sort ) { 3513 _fnSort( settings ); 3514 } 3515 3516 if ( filter ) { 3517 _fnFilterComplete( settings, settings.oPreviousSearch ); 3518 } 3519 else { 3520 // No filtering, so we want to just use the display master 3521 settings.aiDisplay = settings.aiDisplayMaster.slice(); 3522 } 3523 3524 if ( holdPosition !== true ) { 3525 settings._iDisplayStart = 0; 3526 } 3527 3528 // Let any modules know about the draw hold position state (used by 3529 // scrolling internally) 3530 settings._drawHold = holdPosition; 3531 3532 _fnDraw( settings ); 3533 3534 settings._drawHold = false; 3535 } 3536 3537 3538 /** 3539 * Add the options to the page HTML for the table 3540 * @param {object} oSettings dataTables settings object 3541 * @memberof DataTable#oApi 3542 */ 3543 function _fnAddOptionsHtml ( oSettings ) 3544 { 3545 var classes = oSettings.oClasses; 3546 var table = $(oSettings.nTable); 3547 var holding = $('<div/>').insertBefore( table ); // Holding element for speed 3548 var features = oSettings.oFeatures; 3549 3550 // All DataTables are wrapped in a div 3551 var insert = $('<div/>', { 3552 id: oSettings.sTableId+'_wrapper', 3553 'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter) 3554 } ); 3555 3556 oSettings.nHolding = holding[0]; 3557 oSettings.nTableWrapper = insert[0]; 3558 oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling; 3559 3560 /* Loop over the user set positioning and place the elements as needed */ 3561 var aDom = oSettings.sDom.split(''); 3562 var featureNode, cOption, nNewNode, cNext, sAttr, j; 3563 for ( var i=0 ; i<aDom.length ; i++ ) 3564 { 3565 featureNode = null; 3566 cOption = aDom[i]; 3567 3568 if ( cOption == '<' ) 3569 { 3570 /* New container div */ 3571 nNewNode = $('<div/>')[0]; 3572 3573 /* Check to see if we should append an id and/or a class name to the container */ 3574 cNext = aDom[i+1]; 3575 if ( cNext == "'" || cNext == '"' ) 3576 { 3577 sAttr = ""; 3578 j = 2; 3579 while ( aDom[i+j] != cNext ) 3580 { 3581 sAttr += aDom[i+j]; 3582 j++; 3583 } 3584 3585 /* Replace jQuery UI constants @todo depreciated */ 3586 if ( sAttr == "H" ) 3587 { 3588 sAttr = classes.sJUIHeader; 3589 } 3590 else if ( sAttr == "F" ) 3591 { 3592 sAttr = classes.sJUIFooter; 3593 } 3594 3595 /* The attribute can be in the format of "#id.class", "#id" or "class" This logic 3596 * breaks the string into parts and applies them as needed 3597 */ 3598 if ( sAttr.indexOf('.') != -1 ) 3599 { 3600 var aSplit = sAttr.split('.'); 3601 nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1); 3602 nNewNode.className = aSplit[1]; 3603 } 3604 else if ( sAttr.charAt(0) == "#" ) 3605 { 3606 nNewNode.id = sAttr.substr(1, sAttr.length-1); 3607 } 3608 else 3609 { 3610 nNewNode.className = sAttr; 3611 } 3612 3613 i += j; /* Move along the position array */ 3614 } 3615 3616 insert.append( nNewNode ); 3617 insert = $(nNewNode); 3618 } 3619 else if ( cOption == '>' ) 3620 { 3621 /* End container div */ 3622 insert = insert.parent(); 3623 } 3624 // @todo Move options into their own plugins? 3625 else if ( cOption == 'l' && features.bPaginate && features.bLengthChange ) 3626 { 3627 /* Length */ 3628 featureNode = _fnFeatureHtmlLength( oSettings ); 3629 } 3630 else if ( cOption == 'f' && features.bFilter ) 3631 { 3632 /* Filter */ 3633 featureNode = _fnFeatureHtmlFilter( oSettings ); 3634 } 3635 else if ( cOption == 'r' && features.bProcessing ) 3636 { 3637 /* pRocessing */ 3638 featureNode = _fnFeatureHtmlProcessing( oSettings ); 3639 } 3640 else if ( cOption == 't' ) 3641 { 3642 /* Table */ 3643 featureNode = _fnFeatureHtmlTable( oSettings ); 3644 } 3645 else if ( cOption == 'i' && features.bInfo ) 3646 { 3647 /* Info */ 3648 featureNode = _fnFeatureHtmlInfo( oSettings ); 3649 } 3650 else if ( cOption == 'p' && features.bPaginate ) 3651 { 3652 /* Pagination */ 3653 featureNode = _fnFeatureHtmlPaginate( oSettings ); 3654 } 3655 else if ( DataTable.ext.feature.length !== 0 ) 3656 { 3657 /* Plug-in features */ 3658 var aoFeatures = DataTable.ext.feature; 3659 for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ ) 3660 { 3661 if ( cOption == aoFeatures[k].cFeature ) 3662 { 3663 featureNode = aoFeatures[k].fnInit( oSettings ); 3664 break; 3665 } 3666 } 3667 } 3668 3669 /* Add to the 2D features array */ 3670 if ( featureNode ) 3671 { 3672 var aanFeatures = oSettings.aanFeatures; 3673 3674 if ( ! aanFeatures[cOption] ) 3675 { 3676 aanFeatures[cOption] = []; 3677 } 3678 3679 aanFeatures[cOption].push( featureNode ); 3680 insert.append( featureNode ); 3681 } 3682 } 3683 3684 /* Built our DOM structure - replace the holding div with what we want */ 3685 holding.replaceWith( insert ); 3686 oSettings.nHolding = null; 3687 } 3688 3689 3690 /** 3691 * Use the DOM source to create up an array of header cells. The idea here is to 3692 * create a layout grid (array) of rows x columns, which contains a reference 3693 * to the cell that that point in the grid (regardless of col/rowspan), such that 3694 * any column / row could be removed and the new grid constructed 3695 * @param array {object} aLayout Array to store the calculated layout in 3696 * @param {node} nThead The header/footer element for the table 3697 * @memberof DataTable#oApi 3698 */ 3699 function _fnDetectHeader ( aLayout, nThead ) 3700 { 3701 var nTrs = $(nThead).children('tr'); 3702 var nTr, nCell; 3703 var i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan; 3704 var bUnique; 3705 var fnShiftCol = function ( a, i, j ) { 3706 var k = a[i]; 3707 while ( k[j] ) { 3708 j++; 3709 } 3710 return j; 3711 }; 3712 3713 aLayout.splice( 0, aLayout.length ); 3714 3715 /* We know how many rows there are in the layout - so prep it */ 3716 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ ) 3717 { 3718 aLayout.push( [] ); 3719 } 3720 3721 /* Calculate a layout array */ 3722 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ ) 3723 { 3724 nTr = nTrs[i]; 3725 iColumn = 0; 3726 3727 /* For every cell in the row... */ 3728 nCell = nTr.firstChild; 3729 while ( nCell ) { 3730 if ( nCell.nodeName.toUpperCase() == "TD" || 3731 nCell.nodeName.toUpperCase() == "TH" ) 3732 { 3733 /* Get the col and rowspan attributes from the DOM and sanitise them */ 3734 iColspan = nCell.getAttribute('colspan') * 1; 3735 iRowspan = nCell.getAttribute('rowspan') * 1; 3736 iColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan; 3737 iRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan; 3738 3739 /* There might be colspan cells already in this row, so shift our target 3740 * accordingly 3741 */ 3742 iColShifted = fnShiftCol( aLayout, i, iColumn ); 3743 3744 /* Cache calculation for unique columns */ 3745 bUnique = iColspan === 1 ? true : false; 3746 3747 /* If there is col / rowspan, copy the information into the layout grid */ 3748 for ( l=0 ; l<iColspan ; l++ ) 3749 { 3750 for ( k=0 ; k<iRowspan ; k++ ) 3751 { 3752 aLayout[i+k][iColShifted+l] = { 3753 "cell": nCell, 3754 "unique": bUnique 3755 }; 3756 aLayout[i+k].nTr = nTr; 3757 } 3758 } 3759 } 3760 nCell = nCell.nextSibling; 3761 } 3762 } 3763 } 3764 3765 3766 /** 3767 * Get an array of unique th elements, one for each column 3768 * @param {object} oSettings dataTables settings object 3769 * @param {node} nHeader automatically detect the layout from this node - optional 3770 * @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional 3771 * @returns array {node} aReturn list of unique th's 3772 * @memberof DataTable#oApi 3773 */ 3774 function _fnGetUniqueThs ( oSettings, nHeader, aLayout ) 3775 { 3776 var aReturn = []; 3777 if ( !aLayout ) 3778 { 3779 aLayout = oSettings.aoHeader; 3780 if ( nHeader ) 3781 { 3782 aLayout = []; 3783 _fnDetectHeader( aLayout, nHeader ); 3784 } 3785 } 3786 3787 for ( var i=0, iLen=aLayout.length ; i<iLen ; i++ ) 3788 { 3789 for ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ ) 3790 { 3791 if ( aLayout[i][j].unique && 3792 (!aReturn[j] || !oSettings.bSortCellsTop) ) 3793 { 3794 aReturn[j] = aLayout[i][j].cell; 3795 } 3796 } 3797 } 3798 3799 return aReturn; 3800 } 3801 3802 /** 3803 * Create an Ajax call based on the table's settings, taking into account that 3804 * parameters can have multiple forms, and backwards compatibility. 3805 * 3806 * @param {object} oSettings dataTables settings object 3807 * @param {array} data Data to send to the server, required by 3808 * DataTables - may be augmented by developer callbacks 3809 * @param {function} fn Callback function to run when data is obtained 3810 */ 3811 function _fnBuildAjax( oSettings, data, fn ) 3812 { 3813 // Compatibility with 1.9-, allow fnServerData and event to manipulate 3814 _fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] ); 3815 3816 // Convert to object based for 1.10+ if using the old array scheme which can 3817 // come from server-side processing or serverParams 3818 if ( data && $.isArray(data) ) { 3819 var tmp = {}; 3820 var rbracket = /(.*?)\[\]$/; 3821 3822 $.each( data, function (key, val) { 3823 var match = val.name.match(rbracket); 3824 3825 if ( match ) { 3826 // Support for arrays 3827 var name = match[0]; 3828 3829 if ( ! tmp[ name ] ) { 3830 tmp[ name ] = []; 3831 } 3832 tmp[ name ].push( val.value ); 3833 } 3834 else { 3835 tmp[val.name] = val.value; 3836 } 3837 } ); 3838 data = tmp; 3839 } 3840 3841 var ajaxData; 3842 var ajax = oSettings.ajax; 3843 var instance = oSettings.oInstance; 3844 var callback = function ( json ) { 3845 _fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR] ); 3846 fn( json ); 3847 }; 3848 3849 if ( $.isPlainObject( ajax ) && ajax.data ) 3850 { 3851 ajaxData = ajax.data; 3852 3853 var newData = $.isFunction( ajaxData ) ? 3854 ajaxData( data, oSettings ) : // fn can manipulate data or return 3855 ajaxData; // an object object or array to merge 3856 3857 // If the function returned something, use that alone 3858 data = $.isFunction( ajaxData ) && newData ? 3859 newData : 3860 $.extend( true, data, newData ); 3861 3862 // Remove the data property as we've resolved it already and don't want 3863 // jQuery to do it again (it is restored at the end of the function) 3864 delete ajax.data; 3865 } 3866 3867 var baseAjax = { 3868 "data": data, 3869 "success": function (json) { 3870 var error = json.error || json.sError; 3871 if ( error ) { 3872 _fnLog( oSettings, 0, error ); 3873 } 3874 3875 oSettings.json = json; 3876 callback( json ); 3877 }, 3878 "dataType": "json", 3879 "cache": false, 3880 "type": oSettings.sServerMethod, 3881 "error": function (xhr, error, thrown) { 3882 var ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR] ); 3883 3884 if ( $.inArray( true, ret ) === -1 ) { 3885 if ( error == "parsererror" ) { 3886 _fnLog( oSettings, 0, 'Invalid JSON response', 1 ); 3887 } 3888 else if ( xhr.readyState === 4 ) { 3889 _fnLog( oSettings, 0, 'Ajax error', 7 ); 3890 } 3891 } 3892 3893 _fnProcessingDisplay( oSettings, false ); 3894 } 3895 }; 3896 3897 // Store the data submitted for the API 3898 oSettings.oAjaxData = data; 3899 3900 // Allow plug-ins and external processes to modify the data 3901 _fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data] ); 3902 3903 if ( oSettings.fnServerData ) 3904 { 3905 // DataTables 1.9- compatibility 3906 oSettings.fnServerData.call( instance, 3907 oSettings.sAjaxSource, 3908 $.map( data, function (val, key) { // Need to convert back to 1.9 trad format 3909 return { name: key, value: val }; 3910 } ), 3911 callback, 3912 oSettings 3913 ); 3914 } 3915 else if ( oSettings.sAjaxSource || typeof ajax === 'string' ) 3916 { 3917 // DataTables 1.9- compatibility 3918 oSettings.jqXHR = $.ajax( $.extend( baseAjax, { 3919 url: ajax || oSettings.sAjaxSource 3920 } ) ); 3921 } 3922 else if ( $.isFunction( ajax ) ) 3923 { 3924 // Is a function - let the caller define what needs to be done 3925 oSettings.jqXHR = ajax.call( instance, data, callback, oSettings ); 3926 } 3927 else 3928 { 3929 // Object to extend the base settings 3930 oSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) ); 3931 3932 // Restore for next time around 3933 ajax.data = ajaxData; 3934 } 3935 } 3936 3937 3938 /** 3939 * Update the table using an Ajax call 3940 * @param {object} settings dataTables settings object 3941 * @returns {boolean} Block the table drawing or not 3942 * @memberof DataTable#oApi 3943 */ 3944 function _fnAjaxUpdate( settings ) 3945 { 3946 if ( settings.bAjaxDataGet ) { 3947 settings.iDraw++; 3948 _fnProcessingDisplay( settings, true ); 3949 3950 _fnBuildAjax( 3951 settings, 3952 _fnAjaxParameters( settings ), 3953 function(json) { 3954 _fnAjaxUpdateDraw( settings, json ); 3955 } 3956 ); 3957 3958 return false; 3959 } 3960 return true; 3961 } 3962 3963 3964 /** 3965 * Build up the parameters in an object needed for a server-side processing 3966 * request. Note that this is basically done twice, is different ways - a modern 3967 * method which is used by default in DataTables 1.10 which uses objects and 3968 * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if 3969 * the sAjaxSource option is used in the initialisation, or the legacyAjax 3970 * option is set. 3971 * @param {object} oSettings dataTables settings object 3972 * @returns {bool} block the table drawing or not 3973 * @memberof DataTable#oApi 3974 */ 3975 function _fnAjaxParameters( settings ) 3976 { 3977 var 3978 columns = settings.aoColumns, 3979 columnCount = columns.length, 3980 features = settings.oFeatures, 3981 preSearch = settings.oPreviousSearch, 3982 preColSearch = settings.aoPreSearchCols, 3983 i, data = [], dataProp, column, columnSearch, 3984 sort = _fnSortFlatten( settings ), 3985 displayStart = settings._iDisplayStart, 3986 displayLength = features.bPaginate !== false ? 3987 settings._iDisplayLength : 3988 -1; 3989 3990 var param = function ( name, value ) { 3991 data.push( { 'name': name, 'value': value } ); 3992 }; 3993 3994 // DataTables 1.9- compatible method 3995 param( 'sEcho', settings.iDraw ); 3996 param( 'iColumns', columnCount ); 3997 param( 'sColumns', _pluck( columns, 'sName' ).join(',') ); 3998 param( 'iDisplayStart', displayStart ); 3999 param( 'iDisplayLength', displayLength ); 4000 4001 // DataTables 1.10+ method 4002 var d = { 4003 draw: settings.iDraw, 4004 columns: [], 4005 order: [], 4006 start: displayStart, 4007 length: displayLength, 4008 search: { 4009 value: preSearch.sSearch, 4010 regex: preSearch.bRegex 4011 } 4012 }; 4013 4014 for ( i=0 ; i<columnCount ; i++ ) { 4015 column = columns[i]; 4016 columnSearch = preColSearch[i]; 4017 dataProp = typeof column.mData=="function" ? 'function' : column.mData ; 4018 4019 d.columns.push( { 4020 data: dataProp, 4021 name: column.sName, 4022 searchable: column.bSearchable, 4023 orderable: column.bSortable, 4024 search: { 4025 value: columnSearch.sSearch, 4026 regex: columnSearch.bRegex 4027 } 4028 } ); 4029 4030 param( "mDataProp_"+i, dataProp ); 4031 4032 if ( features.bFilter ) { 4033 param( 'sSearch_'+i, columnSearch.sSearch ); 4034 param( 'bRegex_'+i, columnSearch.bRegex ); 4035 param( 'bSearchable_'+i, column.bSearchable ); 4036 } 4037 4038 if ( features.bSort ) { 4039 param( 'bSortable_'+i, column.bSortable ); 4040 } 4041 } 4042 4043 if ( features.bFilter ) { 4044 param( 'sSearch', preSearch.sSearch ); 4045 param( 'bRegex', preSearch.bRegex ); 4046 } 4047 4048 if ( features.bSort ) { 4049 $.each( sort, function ( i, val ) { 4050 d.order.push( { column: val.col, dir: val.dir } ); 4051 4052 param( 'iSortCol_'+i, val.col ); 4053 param( 'sSortDir_'+i, val.dir ); 4054 } ); 4055 4056 param( 'iSortingCols', sort.length ); 4057 } 4058 4059 // If the legacy.ajax parameter is null, then we automatically decide which 4060 // form to use, based on sAjaxSource 4061 var legacy = DataTable.ext.legacy.ajax; 4062 if ( legacy === null ) { 4063 return settings.sAjaxSource ? data : d; 4064 } 4065 4066 // Otherwise, if legacy has been specified then we use that to decide on the 4067 // form 4068 return legacy ? data : d; 4069 } 4070 4071 4072 /** 4073 * Data the data from the server (nuking the old) and redraw the table 4074 * @param {object} oSettings dataTables settings object 4075 * @param {object} json json data return from the server. 4076 * @param {string} json.sEcho Tracking flag for DataTables to match requests 4077 * @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering 4078 * @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering 4079 * @param {array} json.aaData The data to display on this page 4080 * @param {string} [json.sColumns] Column ordering (sName, comma separated) 4081 * @memberof DataTable#oApi 4082 */ 4083 function _fnAjaxUpdateDraw ( settings, json ) 4084 { 4085 // v1.10 uses camelCase variables, while 1.9 uses Hungarian notation. 4086 // Support both 4087 var compat = function ( old, modern ) { 4088 return json[old] !== undefined ? json[old] : json[modern]; 4089 }; 4090 4091 var data = _fnAjaxDataSrc( settings, json ); 4092 var draw = compat( 'sEcho', 'draw' ); 4093 var recordsTotal = compat( 'iTotalRecords', 'recordsTotal' ); 4094 var recordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' ); 4095 4096 if ( draw ) { 4097 // Protect against out of sequence returns 4098 if ( draw*1 < settings.iDraw ) { 4099 return; 4100 } 4101 settings.iDraw = draw * 1; 4102 } 4103 4104 _fnClearTable( settings ); 4105 settings._iRecordsTotal = parseInt(recordsTotal, 10); 4106 settings._iRecordsDisplay = parseInt(recordsFiltered, 10); 4107 4108 for ( var i=0, ien=data.length ; i<ien ; i++ ) { 4109 _fnAddData( settings, data[i] ); 4110 } 4111 settings.aiDisplay = settings.aiDisplayMaster.slice(); 4112 4113 settings.bAjaxDataGet = false; 4114 _fnDraw( settings ); 4115 4116 if ( ! settings._bInitComplete ) { 4117 _fnInitComplete( settings, json ); 4118 } 4119 4120 settings.bAjaxDataGet = true; 4121 _fnProcessingDisplay( settings, false ); 4122 } 4123 4124 4125 /** 4126 * Get the data from the JSON data source to use for drawing a table. Using 4127 * `_fnGetObjectDataFn` allows the data to be sourced from a property of the 4128 * source object, or from a processing function. 4129 * @param {object} oSettings dataTables settings object 4130 * @param {object} json Data source object / array from the server 4131 * @return {array} Array of data to use 4132 */ 4133 function _fnAjaxDataSrc ( oSettings, json ) 4134 { 4135 var dataSrc = $.isPlainObject( oSettings.ajax ) && oSettings.ajax.dataSrc !== undefined ? 4136 oSettings.ajax.dataSrc : 4137 oSettings.sAjaxDataProp; // Compatibility with 1.9-. 4138 4139 // Compatibility with 1.9-. In order to read from aaData, check if the 4140 // default has been changed, if not, check for aaData 4141 if ( dataSrc === 'data' ) { 4142 return json.aaData || json[dataSrc]; 4143 } 4144 4145 return dataSrc !== "" ? 4146 _fnGetObjectDataFn( dataSrc )( json ) : 4147 json; 4148 } 4149 4150 /** 4151 * Generate the node required for filtering text 4152 * @returns {node} Filter control element 4153 * @param {object} oSettings dataTables settings object 4154 * @memberof DataTable#oApi 4155 */ 4156 function _fnFeatureHtmlFilter ( settings ) 4157 { 4158 var classes = settings.oClasses; 4159 var tableId = settings.sTableId; 4160 var language = settings.oLanguage; 4161 var previousSearch = settings.oPreviousSearch; 4162 var features = settings.aanFeatures; 4163 var input = '<input type="search" class="'+classes.sFilterInput+'"/>'; 4164 4165 var str = language.sSearch; 4166 str = str.match(/_INPUT_/) ? 4167 str.replace('_INPUT_', input) : 4168 str+input; 4169 4170 var filter = $('<div/>', { 4171 'id': ! features.f ? tableId+'_filter' : null, 4172 'class': classes.sFilter 4173 } ) 4174 .append( $('<label/>' ).append( str ) ); 4175 4176 var searchFn = function() { 4177 /* Update all other filter input elements for the new display */ 4178 var n = features.f; 4179 var val = !this.value ? "" : this.value; // mental IE8 fix :-( 4180 4181 /* Now do the filter */ 4182 if ( val != previousSearch.sSearch ) { 4183 _fnFilterComplete( settings, { 4184 "sSearch": val, 4185 "bRegex": previousSearch.bRegex, 4186 "bSmart": previousSearch.bSmart , 4187 "bCaseInsensitive": previousSearch.bCaseInsensitive 4188 } ); 4189 4190 // Need to redraw, without resorting 4191 settings._iDisplayStart = 0; 4192 _fnDraw( settings ); 4193 } 4194 }; 4195 4196 var searchDelay = settings.searchDelay !== null ? 4197 settings.searchDelay : 4198 _fnDataSource( settings ) === 'ssp' ? 4199 400 : 4200 0; 4201 4202 var jqFilter = $('input', filter) 4203 .val( previousSearch.sSearch ) 4204 .attr( 'placeholder', language.sSearchPlaceholder ) 4205 .bind( 4206 'keyup.DT search.DT input.DT paste.DT cut.DT', 4207 searchDelay ? 4208 _fnThrottle( searchFn, searchDelay ) : 4209 searchFn 4210 ) 4211 .bind( 'keypress.DT', function(e) { 4212 /* Prevent form submission */ 4213 if ( e.keyCode == 13 ) { 4214 return false; 4215 } 4216 } ) 4217 .attr('aria-controls', tableId); 4218 4219 // Update the input elements whenever the table is filtered 4220 $(settings.nTable).on( 'search.dt.DT', function ( ev, s ) { 4221 if ( settings === s ) { 4222 // IE9 throws an 'unknown error' if document.activeElement is used 4223 // inside an iframe or frame... 4224 try { 4225 if ( jqFilter[0] !== document.activeElement ) { 4226 jqFilter.val( previousSearch.sSearch ); 4227 } 4228 } 4229 catch ( e ) {} 4230 } 4231 } ); 4232 4233 return filter[0]; 4234 } 4235 4236 4237 /** 4238 * Filter the table using both the global filter and column based filtering 4239 * @param {object} oSettings dataTables settings object 4240 * @param {object} oSearch search information 4241 * @param {int} [iForce] force a research of the master array (1) or not (undefined or 0) 4242 * @memberof DataTable#oApi 4243 */ 4244 function _fnFilterComplete ( oSettings, oInput, iForce ) 4245 { 4246 var oPrevSearch = oSettings.oPreviousSearch; 4247 var aoPrevSearch = oSettings.aoPreSearchCols; 4248 var fnSaveFilter = function ( oFilter ) { 4249 /* Save the filtering values */ 4250 oPrevSearch.sSearch = oFilter.sSearch; 4251 oPrevSearch.bRegex = oFilter.bRegex; 4252 oPrevSearch.bSmart = oFilter.bSmart; 4253 oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive; 4254 }; 4255 var fnRegex = function ( o ) { 4256 // Backwards compatibility with the bEscapeRegex option 4257 return o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex; 4258 }; 4259 4260 // Resolve any column types that are unknown due to addition or invalidation 4261 // @todo As per sort - can this be moved into an event handler? 4262 _fnColumnTypes( oSettings ); 4263 4264 /* In server-side processing all filtering is done by the server, so no point hanging around here */ 4265 if ( _fnDataSource( oSettings ) != 'ssp' ) 4266 { 4267 /* Global filter */ 4268 _fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive ); 4269 fnSaveFilter( oInput ); 4270 4271 /* Now do the individual column filter */ 4272 for ( var i=0 ; i<aoPrevSearch.length ; i++ ) 4273 { 4274 _fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, fnRegex(aoPrevSearch[i]), 4275 aoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive ); 4276 } 4277 4278 /* Custom filtering */ 4279 _fnFilterCustom( oSettings ); 4280 } 4281 else 4282 { 4283 fnSaveFilter( oInput ); 4284 } 4285 4286 /* Tell the draw function we have been filtering */ 4287 oSettings.bFiltered = true; 4288 _fnCallbackFire( oSettings, null, 'search', [oSettings] ); 4289 } 4290 4291 4292 /** 4293 * Apply custom filtering functions 4294 * @param {object} oSettings dataTables settings object 4295 * @memberof DataTable#oApi 4296 */ 4297 function _fnFilterCustom( settings ) 4298 { 4299 var filters = DataTable.ext.search; 4300 var displayRows = settings.aiDisplay; 4301 var row, rowIdx; 4302 4303 for ( var i=0, ien=filters.length ; i<ien ; i++ ) { 4304 var rows = []; 4305 4306 // Loop over each row and see if it should be included 4307 for ( var j=0, jen=displayRows.length ; j<jen ; j++ ) { 4308 rowIdx = displayRows[ j ]; 4309 row = settings.aoData[ rowIdx ]; 4310 4311 if ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) { 4312 rows.push( rowIdx ); 4313 } 4314 } 4315 4316 // So the array reference doesn't break set the results into the 4317 // existing array 4318 displayRows.length = 0; 4319 $.merge( displayRows, rows ); 4320 } 4321 } 4322 4323 4324 /** 4325 * Filter the table on a per-column basis 4326 * @param {object} oSettings dataTables settings object 4327 * @param {string} sInput string to filter on 4328 * @param {int} iColumn column to filter 4329 * @param {bool} bRegex treat search string as a regular expression or not 4330 * @param {bool} bSmart use smart filtering or not 4331 * @param {bool} bCaseInsensitive Do case insenstive matching or not 4332 * @memberof DataTable#oApi 4333 */ 4334 function _fnFilterColumn ( settings, searchStr, colIdx, regex, smart, caseInsensitive ) 4335 { 4336 if ( searchStr === '' ) { 4337 return; 4338 } 4339 4340 var data; 4341 var display = settings.aiDisplay; 4342 var rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive ); 4343 4344 for ( var i=display.length-1 ; i>=0 ; i-- ) { 4345 data = settings.aoData[ display[i] ]._aFilterData[ colIdx ]; 4346 4347 if ( ! rpSearch.test( data ) ) { 4348 display.splice( i, 1 ); 4349 } 4350 } 4351 } 4352 4353 4354 /** 4355 * Filter the data table based on user input and draw the table 4356 * @param {object} settings dataTables settings object 4357 * @param {string} input string to filter on 4358 * @param {int} force optional - force a research of the master array (1) or not (undefined or 0) 4359 * @param {bool} regex treat as a regular expression or not 4360 * @param {bool} smart perform smart filtering or not 4361 * @param {bool} caseInsensitive Do case insenstive matching or not 4362 * @memberof DataTable#oApi 4363 */ 4364 function _fnFilter( settings, input, force, regex, smart, caseInsensitive ) 4365 { 4366 var rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive ); 4367 var prevSearch = settings.oPreviousSearch.sSearch; 4368 var displayMaster = settings.aiDisplayMaster; 4369 var display, invalidated, i; 4370 4371 // Need to take account of custom filtering functions - always filter 4372 if ( DataTable.ext.search.length !== 0 ) { 4373 force = true; 4374 } 4375 4376 // Check if any of the rows were invalidated 4377 invalidated = _fnFilterData( settings ); 4378 4379 // If the input is blank - we just want the full data set 4380 if ( input.length <= 0 ) { 4381 settings.aiDisplay = displayMaster.slice(); 4382 } 4383 else { 4384 // New search - start from the master array 4385 if ( invalidated || 4386 force || 4387 prevSearch.length > input.length || 4388 input.indexOf(prevSearch) !== 0 || 4389 settings.bSorted // On resort, the display master needs to be 4390 // re-filtered since indexes will have changed 4391 ) { 4392 settings.aiDisplay = displayMaster.slice(); 4393 } 4394 4395 // Search the display array 4396 display = settings.aiDisplay; 4397 4398 for ( i=display.length-1 ; i>=0 ; i-- ) { 4399 if ( ! rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) { 4400 display.splice( i, 1 ); 4401 } 4402 } 4403 } 4404 } 4405 4406 4407 /** 4408 * Build a regular expression object suitable for searching a table 4409 * @param {string} sSearch string to search for 4410 * @param {bool} bRegex treat as a regular expression or not 4411 * @param {bool} bSmart perform smart filtering or not 4412 * @param {bool} bCaseInsensitive Do case insensitive matching or not 4413 * @returns {RegExp} constructed object 4414 * @memberof DataTable#oApi 4415 */ 4416 function _fnFilterCreateSearch( search, regex, smart, caseInsensitive ) 4417 { 4418 search = regex ? 4419 search : 4420 _fnEscapeRegex( search ); 4421 4422 if ( smart ) { 4423 /* For smart filtering we want to allow the search to work regardless of 4424 * word order. We also want double quoted text to be preserved, so word 4425 * order is important - a la google. So this is what we want to 4426 * generate: 4427 * 4428 * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$ 4429 */ 4430 var a = $.map( search.match( /"[^"]+"|[^ ]+/g ) || [''], function ( word ) { 4431 if ( word.charAt(0) === '"' ) { 4432 var m = word.match( /^"(.*)"$/ ); 4433 word = m ? m[1] : word; 4434 } 4435 4436 return word.replace('"', ''); 4437 } ); 4438 4439 search = '^(?=.*?'+a.join( ')(?=.*?' )+').*$'; 4440 } 4441 4442 return new RegExp( search, caseInsensitive ? 'i' : '' ); 4443 } 4444 4445 4446 /** 4447 * Escape a string such that it can be used in a regular expression 4448 * @param {string} sVal string to escape 4449 * @returns {string} escaped string 4450 * @memberof DataTable#oApi 4451 */ 4452 var _fnEscapeRegex = DataTable.util.escapeRegex; 4453 4454 var __filter_div = $('<div>')[0]; 4455 var __filter_div_textContent = __filter_div.textContent !== undefined; 4456 4457 // Update the filtering data for each row if needed (by invalidation or first run) 4458 function _fnFilterData ( settings ) 4459 { 4460 var columns = settings.aoColumns; 4461 var column; 4462 var i, j, ien, jen, filterData, cellData, row; 4463 var fomatters = DataTable.ext.type.search; 4464 var wasInvalidated = false; 4465 4466 for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) { 4467 row = settings.aoData[i]; 4468 4469 if ( ! row._aFilterData ) { 4470 filterData = []; 4471 4472 for ( j=0, jen=columns.length ; j<jen ; j++ ) { 4473 column = columns[j]; 4474 4475 if ( column.bSearchable ) { 4476 cellData = _fnGetCellData( settings, i, j, 'filter' ); 4477 4478 if ( fomatters[ column.sType ] ) { 4479 cellData = fomatters[ column.sType ]( cellData ); 4480 } 4481 4482 // Search in DataTables 1.10 is string based. In 1.11 this 4483 // should be altered to also allow strict type checking. 4484 if ( cellData === null ) { 4485 cellData = ''; 4486 } 4487 4488 if ( typeof cellData !== 'string' && cellData.toString ) { 4489 cellData = cellData.toString(); 4490 } 4491 } 4492 else { 4493 cellData = ''; 4494 } 4495 4496 // If it looks like there is an HTML entity in the string, 4497 // attempt to decode it so sorting works as expected. Note that 4498 // we could use a single line of jQuery to do this, but the DOM 4499 // method used here is much faster http://jsperf.com/html-decode 4500 if ( cellData.indexOf && cellData.indexOf('&') !== -1 ) { 4501 __filter_div.innerHTML = cellData; 4502 cellData = __filter_div_textContent ? 4503 __filter_div.textContent : 4504 __filter_div.innerText; 4505 } 4506 4507 if ( cellData.replace ) { 4508 cellData = cellData.replace(/[\r\n]/g, ''); 4509 } 4510 4511 filterData.push( cellData ); 4512 } 4513 4514 row._aFilterData = filterData; 4515 row._sFilterRow = filterData.join(' '); 4516 wasInvalidated = true; 4517 } 4518 } 4519 4520 return wasInvalidated; 4521 } 4522 4523 4524 /** 4525 * Convert from the internal Hungarian notation to camelCase for external 4526 * interaction 4527 * @param {object} obj Object to convert 4528 * @returns {object} Inverted object 4529 * @memberof DataTable#oApi 4530 */ 4531 function _fnSearchToCamel ( obj ) 4532 { 4533 return { 4534 search: obj.sSearch, 4535 smart: obj.bSmart, 4536 regex: obj.bRegex, 4537 caseInsensitive: obj.bCaseInsensitive 4538 }; 4539 } 4540 4541 4542 4543 /** 4544 * Convert from camelCase notation to the internal Hungarian. We could use the 4545 * Hungarian convert function here, but this is cleaner 4546 * @param {object} obj Object to convert 4547 * @returns {object} Inverted object 4548 * @memberof DataTable#oApi 4549 */ 4550 function _fnSearchToHung ( obj ) 4551 { 4552 return { 4553 sSearch: obj.search, 4554 bSmart: obj.smart, 4555 bRegex: obj.regex, 4556 bCaseInsensitive: obj.caseInsensitive 4557 }; 4558 } 4559 4560 /** 4561 * Generate the node required for the info display 4562 * @param {object} oSettings dataTables settings object 4563 * @returns {node} Information element 4564 * @memberof DataTable#oApi 4565 */ 4566 function _fnFeatureHtmlInfo ( settings ) 4567 { 4568 var 4569 tid = settings.sTableId, 4570 nodes = settings.aanFeatures.i, 4571 n = $('<div/>', { 4572 'class': settings.oClasses.sInfo, 4573 'id': ! nodes ? tid+'_info' : null 4574 } ); 4575 4576 if ( ! nodes ) { 4577 // Update display on each draw 4578 settings.aoDrawCallback.push( { 4579 "fn": _fnUpdateInfo, 4580 "sName": "information" 4581 } ); 4582 4583 n 4584 .attr( 'role', 'status' ) 4585 .attr( 'aria-live', 'polite' ); 4586 4587 // Table is described by our info div 4588 $(settings.nTable).attr( 'aria-describedby', tid+'_info' ); 4589 } 4590 4591 return n[0]; 4592 } 4593 4594 4595 /** 4596 * Update the information elements in the display 4597 * @param {object} settings dataTables settings object 4598 * @memberof DataTable#oApi 4599 */ 4600 function _fnUpdateInfo ( settings ) 4601 { 4602 /* Show information about the table */ 4603 var nodes = settings.aanFeatures.i; 4604 if ( nodes.length === 0 ) { 4605 return; 4606 } 4607 4608 var 4609 lang = settings.oLanguage, 4610 start = settings._iDisplayStart+1, 4611 end = settings.fnDisplayEnd(), 4612 max = settings.fnRecordsTotal(), 4613 total = settings.fnRecordsDisplay(), 4614 out = total ? 4615 lang.sInfo : 4616 lang.sInfoEmpty; 4617 4618 if ( total !== max ) { 4619 /* Record set after filtering */ 4620 out += ' ' + lang.sInfoFiltered; 4621 } 4622 4623 // Convert the macros 4624 out += lang.sInfoPostFix; 4625 out = _fnInfoMacros( settings, out ); 4626 4627 var callback = lang.fnInfoCallback; 4628 if ( callback !== null ) { 4629 out = callback.call( settings.oInstance, 4630 settings, start, end, max, total, out 4631 ); 4632 } 4633 4634 $(nodes).html( out ); 4635 } 4636 4637 4638 function _fnInfoMacros ( settings, str ) 4639 { 4640 // When infinite scrolling, we are always starting at 1. _iDisplayStart is used only 4641 // internally 4642 var 4643 formatter = settings.fnFormatNumber, 4644 start = settings._iDisplayStart+1, 4645 len = settings._iDisplayLength, 4646 vis = settings.fnRecordsDisplay(), 4647 all = len === -1; 4648 4649 return str. 4650 replace(/_START_/g, formatter.call( settings, start ) ). 4651 replace(/_END_/g, formatter.call( settings, settings.fnDisplayEnd() ) ). 4652 replace(/_MAX_/g, formatter.call( settings, settings.fnRecordsTotal() ) ). 4653 replace(/_TOTAL_/g, formatter.call( settings, vis ) ). 4654 replace(/_PAGE_/g, formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ). 4655 replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) ); 4656 } 4657 4658 4659 4660 /** 4661 * Draw the table for the first time, adding all required features 4662 * @param {object} settings dataTables settings object 4663 * @memberof DataTable#oApi 4664 */ 4665 function _fnInitialise ( settings ) 4666 { 4667 var i, iLen, iAjaxStart=settings.iInitDisplayStart; 4668 var columns = settings.aoColumns, column; 4669 var features = settings.oFeatures; 4670 var deferLoading = settings.bDeferLoading; // value modified by the draw 4671 4672 /* Ensure that the table data is fully initialised */ 4673 if ( ! settings.bInitialised ) { 4674 setTimeout( function(){ _fnInitialise( settings ); }, 200 ); 4675 return; 4676 } 4677 4678 /* Show the display HTML options */ 4679 _fnAddOptionsHtml( settings ); 4680 4681 /* Build and draw the header / footer for the table */ 4682 _fnBuildHead( settings ); 4683 _fnDrawHead( settings, settings.aoHeader ); 4684 _fnDrawHead( settings, settings.aoFooter ); 4685 4686 /* Okay to show that something is going on now */ 4687 _fnProcessingDisplay( settings, true ); 4688 4689 /* Calculate sizes for columns */ 4690 if ( features.bAutoWidth ) { 4691 _fnCalculateColumnWidths( settings ); 4692 } 4693 4694 for ( i=0, iLen=columns.length ; i<iLen ; i++ ) { 4695 column = columns[i]; 4696 4697 if ( column.sWidth ) { 4698 column.nTh.style.width = _fnStringToCss( column.sWidth ); 4699 } 4700 } 4701 4702 _fnCallbackFire( settings, null, 'preInit', [settings] ); 4703 4704 // If there is default sorting required - let's do it. The sort function 4705 // will do the drawing for us. Otherwise we draw the table regardless of the 4706 // Ajax source - this allows the table to look initialised for Ajax sourcing 4707 // data (show 'loading' message possibly) 4708 _fnReDraw( settings ); 4709 4710 // Server-side processing init complete is done by _fnAjaxUpdateDraw 4711 var dataSrc = _fnDataSource( settings ); 4712 if ( dataSrc != 'ssp' || deferLoading ) { 4713 // if there is an ajax source load the data 4714 if ( dataSrc == 'ajax' ) { 4715 _fnBuildAjax( settings, [], function(json) { 4716 var aData = _fnAjaxDataSrc( settings, json ); 4717 4718 // Got the data - add it to the table 4719 for ( i=0 ; i<aData.length ; i++ ) { 4720 _fnAddData( settings, aData[i] ); 4721 } 4722 4723 // Reset the init display for cookie saving. We've already done 4724 // a filter, and therefore cleared it before. So we need to make 4725 // it appear 'fresh' 4726 settings.iInitDisplayStart = iAjaxStart; 4727 4728 _fnReDraw( settings ); 4729 4730 _fnProcessingDisplay( settings, false ); 4731 _fnInitComplete( settings, json ); 4732 }, settings ); 4733 } 4734 else { 4735 _fnProcessingDisplay( settings, false ); 4736 _fnInitComplete( settings ); 4737 } 4738 } 4739 } 4740 4741 4742 /** 4743 * Draw the table for the first time, adding all required features 4744 * @param {object} oSettings dataTables settings object 4745 * @param {object} [json] JSON from the server that completed the table, if using Ajax source 4746 * with client-side processing (optional) 4747 * @memberof DataTable#oApi 4748 */ 4749 function _fnInitComplete ( settings, json ) 4750 { 4751 settings._bInitComplete = true; 4752 4753 // When data was added after the initialisation (data or Ajax) we need to 4754 // calculate the column sizing 4755 if ( json || settings.oInit.aaData ) { 4756 _fnAdjustColumnSizing( settings ); 4757 } 4758 4759 _fnCallbackFire( settings, null, 'plugin-init', [settings, json] ); 4760 _fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] ); 4761 } 4762 4763 4764 function _fnLengthChange ( settings, val ) 4765 { 4766 var len = parseInt( val, 10 ); 4767 settings._iDisplayLength = len; 4768 4769 _fnLengthOverflow( settings ); 4770 4771 // Fire length change event 4772 _fnCallbackFire( settings, null, 'length', [settings, len] ); 4773 } 4774 4775 4776 /** 4777 * Generate the node required for user display length changing 4778 * @param {object} settings dataTables settings object 4779 * @returns {node} Display length feature node 4780 * @memberof DataTable#oApi 4781 */ 4782 function _fnFeatureHtmlLength ( settings ) 4783 { 4784 var 4785 classes = settings.oClasses, 4786 tableId = settings.sTableId, 4787 menu = settings.aLengthMenu, 4788 d2 = $.isArray( menu[0] ), 4789 lengths = d2 ? menu[0] : menu, 4790 language = d2 ? menu[1] : menu; 4791 4792 var select = $('<select/>', { 4793 'name': tableId+'_length', 4794 'aria-controls': tableId, 4795 'class': classes.sLengthSelect 4796 } ); 4797 4798 for ( var i=0, ien=lengths.length ; i<ien ; i++ ) { 4799 select[0][ i ] = new Option( language[i], lengths[i] ); 4800 } 4801 4802 var div = $('<div><label/></div>').addClass( classes.sLength ); 4803 if ( ! settings.aanFeatures.l ) { 4804 div[0].id = tableId+'_length'; 4805 } 4806 4807 div.children().append( 4808 settings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML ) 4809 ); 4810 4811 // Can't use `select` variable as user might provide their own and the 4812 // reference is broken by the use of outerHTML 4813 $('select', div) 4814 .val( settings._iDisplayLength ) 4815 .bind( 'change.DT', function(e) { 4816 _fnLengthChange( settings, $(this).val() ); 4817 _fnDraw( settings ); 4818 } ); 4819 4820 // Update node value whenever anything changes the table's length 4821 $(settings.nTable).bind( 'length.dt.DT', function (e, s, len) { 4822 if ( settings === s ) { 4823 $('select', div).val( len ); 4824 } 4825 } ); 4826 4827 return div[0]; 4828 } 4829 4830 4831 4832 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 4833 * Note that most of the paging logic is done in 4834 * DataTable.ext.pager 4835 */ 4836 4837 /** 4838 * Generate the node required for default pagination 4839 * @param {object} oSettings dataTables settings object 4840 * @returns {node} Pagination feature node 4841 * @memberof DataTable#oApi 4842 */ 4843 function _fnFeatureHtmlPaginate ( settings ) 4844 { 4845 var 4846 type = settings.sPaginationType, 4847 plugin = DataTable.ext.pager[ type ], 4848 modern = typeof plugin === 'function', 4849 redraw = function( settings ) { 4850 _fnDraw( settings ); 4851 }, 4852 node = $('<div/>').addClass( settings.oClasses.sPaging + type )[0], 4853 features = settings.aanFeatures; 4854 4855 if ( ! modern ) { 4856 plugin.fnInit( settings, node, redraw ); 4857 } 4858 4859 /* Add a draw callback for the pagination on first instance, to update the paging display */ 4860 if ( ! features.p ) 4861 { 4862 node.id = settings.sTableId+'_paginate'; 4863 4864 settings.aoDrawCallback.push( { 4865 "fn": function( settings ) { 4866 if ( modern ) { 4867 var 4868 start = settings._iDisplayStart, 4869 len = settings._iDisplayLength, 4870 visRecords = settings.fnRecordsDisplay(), 4871 all = len === -1, 4872 page = all ? 0 : Math.ceil( start / len ), 4873 pages = all ? 1 : Math.ceil( visRecords / len ), 4874 buttons = plugin(page, pages), 4875 i, ien; 4876 4877 for ( i=0, ien=features.p.length ; i<ien ; i++ ) { 4878 _fnRenderer( settings, 'pageButton' )( 4879 settings, features.p[i], i, buttons, page, pages 4880 ); 4881 } 4882 } 4883 else { 4884 plugin.fnUpdate( settings, redraw ); 4885 } 4886 }, 4887 "sName": "pagination" 4888 } ); 4889 } 4890 4891 return node; 4892 } 4893 4894 4895 /** 4896 * Alter the display settings to change the page 4897 * @param {object} settings DataTables settings object 4898 * @param {string|int} action Paging action to take: "first", "previous", 4899 * "next" or "last" or page number to jump to (integer) 4900 * @param [bool] redraw Automatically draw the update or not 4901 * @returns {bool} true page has changed, false - no change 4902 * @memberof DataTable#oApi 4903 */ 4904 function _fnPageChange ( settings, action, redraw ) 4905 { 4906 var 4907 start = settings._iDisplayStart, 4908 len = settings._iDisplayLength, 4909 records = settings.fnRecordsDisplay(); 4910 4911 if ( records === 0 || len === -1 ) 4912 { 4913 start = 0; 4914 } 4915 else if ( typeof action === "number" ) 4916 { 4917 start = action * len; 4918 4919 if ( start > records ) 4920 { 4921 start = 0; 4922 } 4923 } 4924 else if ( action == "first" ) 4925 { 4926 start = 0; 4927 } 4928 else if ( action == "previous" ) 4929 { 4930 start = len >= 0 ? 4931 start - len : 4932 0; 4933 4934 if ( start < 0 ) 4935 { 4936 start = 0; 4937 } 4938 } 4939 else if ( action == "next" ) 4940 { 4941 if ( start + len < records ) 4942 { 4943 start += len; 4944 } 4945 } 4946 else if ( action == "last" ) 4947 { 4948 start = Math.floor( (records-1) / len) * len; 4949 } 4950 else 4951 { 4952 _fnLog( settings, 0, "Unknown paging action: "+action, 5 ); 4953 } 4954 4955 var changed = settings._iDisplayStart !== start; 4956 settings._iDisplayStart = start; 4957 4958 if ( changed ) { 4959 _fnCallbackFire( settings, null, 'page', [settings] ); 4960 4961 if ( redraw ) { 4962 _fnDraw( settings ); 4963 } 4964 } 4965 4966 return changed; 4967 } 4968 4969 4970 4971 /** 4972 * Generate the node required for the processing node 4973 * @param {object} settings dataTables settings object 4974 * @returns {node} Processing element 4975 * @memberof DataTable#oApi 4976 */ 4977 function _fnFeatureHtmlProcessing ( settings ) 4978 { 4979 return $('<div/>', { 4980 'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null, 4981 'class': settings.oClasses.sProcessing 4982 } ) 4983 .html( settings.oLanguage.sProcessing ) 4984 .insertBefore( settings.nTable )[0]; 4985 } 4986 4987 4988 /** 4989 * Display or hide the processing indicator 4990 * @param {object} settings dataTables settings object 4991 * @param {bool} show Show the processing indicator (true) or not (false) 4992 * @memberof DataTable#oApi 4993 */ 4994 function _fnProcessingDisplay ( settings, show ) 4995 { 4996 if ( settings.oFeatures.bProcessing ) { 4997 $(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' ); 4998 } 4999 5000 _fnCallbackFire( settings, null, 'processing', [settings, show] ); 5001 } 5002 5003 /** 5004 * Add any control elements for the table - specifically scrolling 5005 * @param {object} settings dataTables settings object 5006 * @returns {node} Node to add to the DOM 5007 * @memberof DataTable#oApi 5008 */ 5009 function _fnFeatureHtmlTable ( settings ) 5010 { 5011 var table = $(settings.nTable); 5012 5013 // Add the ARIA grid role to the table 5014 table.attr( 'role', 'grid' ); 5015 5016 // Scrolling from here on in 5017 var scroll = settings.oScroll; 5018 5019 if ( scroll.sX === '' && scroll.sY === '' ) { 5020 return settings.nTable; 5021 } 5022 5023 var scrollX = scroll.sX; 5024 var scrollY = scroll.sY; 5025 var classes = settings.oClasses; 5026 var caption = table.children('caption'); 5027 var captionSide = caption.length ? caption[0]._captionSide : null; 5028 var headerClone = $( table[0].cloneNode(false) ); 5029 var footerClone = $( table[0].cloneNode(false) ); 5030 var footer = table.children('tfoot'); 5031 var _div = '<div/>'; 5032 var size = function ( s ) { 5033 return !s ? null : _fnStringToCss( s ); 5034 }; 5035 5036 if ( ! footer.length ) { 5037 footer = null; 5038 } 5039 5040 /* 5041 * The HTML structure that we want to generate in this function is: 5042 * div - scroller 5043 * div - scroll head 5044 * div - scroll head inner 5045 * table - scroll head table 5046 * thead - thead 5047 * div - scroll body 5048 * table - table (master table) 5049 * thead - thead clone for sizing 5050 * tbody - tbody 5051 * div - scroll foot 5052 * div - scroll foot inner 5053 * table - scroll foot table 5054 * tfoot - tfoot 5055 */ 5056 var scroller = $( _div, { 'class': classes.sScrollWrapper } ) 5057 .append( 5058 $(_div, { 'class': classes.sScrollHead } ) 5059 .css( { 5060 overflow: 'hidden', 5061 position: 'relative', 5062 border: 0, 5063 width: scrollX ? size(scrollX) : '100%' 5064 } ) 5065 .append( 5066 $(_div, { 'class': classes.sScrollHeadInner } ) 5067 .css( { 5068 'box-sizing': 'content-box', 5069 width: scroll.sXInner || '100%' 5070 } ) 5071 .append( 5072 headerClone 5073 .removeAttr('id') 5074 .css( 'margin-left', 0 ) 5075 .append( captionSide === 'top' ? caption : null ) 5076 .append( 5077 table.children('thead') 5078 ) 5079 ) 5080 ) 5081 ) 5082 .append( 5083 $(_div, { 'class': classes.sScrollBody } ) 5084 .css( { 5085 position: 'relative', 5086 overflow: 'auto', 5087 width: size( scrollX ) 5088 } ) 5089 .append( table ) 5090 ); 5091 5092 if ( footer ) { 5093 scroller.append( 5094 $(_div, { 'class': classes.sScrollFoot } ) 5095 .css( { 5096 overflow: 'hidden', 5097 border: 0, 5098 width: scrollX ? size(scrollX) : '100%' 5099 } ) 5100 .append( 5101 $(_div, { 'class': classes.sScrollFootInner } ) 5102 .append( 5103 footerClone 5104 .removeAttr('id') 5105 .css( 'margin-left', 0 ) 5106 .append( captionSide === 'bottom' ? caption : null ) 5107 .append( 5108 table.children('tfoot') 5109 ) 5110 ) 5111 ) 5112 ); 5113 } 5114 5115 var children = scroller.children(); 5116 var scrollHead = children[0]; 5117 var scrollBody = children[1]; 5118 var scrollFoot = footer ? children[2] : null; 5119 5120 // When the body is scrolled, then we also want to scroll the headers 5121 if ( scrollX ) { 5122 $(scrollBody).on( 'scroll.DT', function (e) { 5123 var scrollLeft = this.scrollLeft; 5124 5125 scrollHead.scrollLeft = scrollLeft; 5126 5127 if ( footer ) { 5128 scrollFoot.scrollLeft = scrollLeft; 5129 } 5130 } ); 5131 } 5132 5133 $(scrollBody).css( 5134 scrollY && scroll.bCollapse ? 'max-height' : 'height', 5135 scrollY 5136 ); 5137 5138 settings.nScrollHead = scrollHead; 5139 settings.nScrollBody = scrollBody; 5140 settings.nScrollFoot = scrollFoot; 5141 5142 // On redraw - align columns 5143 settings.aoDrawCallback.push( { 5144 "fn": _fnScrollDraw, 5145 "sName": "scrolling" 5146 } ); 5147 5148 return scroller[0]; 5149 } 5150 5151 5152 5153 /** 5154 * Update the header, footer and body tables for resizing - i.e. column 5155 * alignment. 5156 * 5157 * Welcome to the most horrible function DataTables. The process that this 5158 * function follows is basically: 5159 * 1. Re-create the table inside the scrolling div 5160 * 2. Take live measurements from the DOM 5161 * 3. Apply the measurements to align the columns 5162 * 4. Clean up 5163 * 5164 * @param {object} settings dataTables settings object 5165 * @memberof DataTable#oApi 5166 */ 5167 function _fnScrollDraw ( settings ) 5168 { 5169 // Given that this is such a monster function, a lot of variables are use 5170 // to try and keep the minimised size as small as possible 5171 var 5172 scroll = settings.oScroll, 5173 scrollX = scroll.sX, 5174 scrollXInner = scroll.sXInner, 5175 scrollY = scroll.sY, 5176 barWidth = scroll.iBarWidth, 5177 divHeader = $(settings.nScrollHead), 5178 divHeaderStyle = divHeader[0].style, 5179 divHeaderInner = divHeader.children('div'), 5180 divHeaderInnerStyle = divHeaderInner[0].style, 5181 divHeaderTable = divHeaderInner.children('table'), 5182 divBodyEl = settings.nScrollBody, 5183 divBody = $(divBodyEl), 5184 divBodyStyle = divBodyEl.style, 5185 divFooter = $(settings.nScrollFoot), 5186 divFooterInner = divFooter.children('div'), 5187 divFooterTable = divFooterInner.children('table'), 5188 header = $(settings.nTHead), 5189 table = $(settings.nTable), 5190 tableEl = table[0], 5191 tableStyle = tableEl.style, 5192 footer = settings.nTFoot ? $(settings.nTFoot) : null, 5193 browser = settings.oBrowser, 5194 ie67 = browser.bScrollOversize, 5195 dtHeaderCells = _pluck( settings.aoColumns, 'nTh' ), 5196 headerTrgEls, footerTrgEls, 5197 headerSrcEls, footerSrcEls, 5198 headerCopy, footerCopy, 5199 headerWidths=[], footerWidths=[], 5200 headerContent=[], footerContent=[], 5201 idx, correction, sanityWidth, 5202 zeroOut = function(nSizer) { 5203 var style = nSizer.style; 5204 style.paddingTop = "0"; 5205 style.paddingBottom = "0"; 5206 style.borderTopWidth = "0"; 5207 style.borderBottomWidth = "0"; 5208 style.height = 0; 5209 }; 5210 5211 // If the scrollbar visibility has changed from the last draw, we need to 5212 // adjust the column sizes as the table width will have changed to account 5213 // for the scrollbar 5214 var scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight; 5215 5216 if ( settings.scrollBarVis !== scrollBarVis && settings.scrollBarVis !== undefined ) { 5217 settings.scrollBarVis = scrollBarVis; 5218 _fnAdjustColumnSizing( settings ); 5219 return; // adjust column sizing will call this function again 5220 } 5221 else { 5222 settings.scrollBarVis = scrollBarVis; 5223 } 5224 5225 /* 5226 * 1. Re-create the table inside the scrolling div 5227 */ 5228 5229 // Remove the old minimised thead and tfoot elements in the inner table 5230 table.children('thead, tfoot').remove(); 5231 5232 if ( footer ) { 5233 footerCopy = footer.clone().prependTo( table ); 5234 footerTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized 5235 footerSrcEls = footerCopy.find('tr'); 5236 } 5237 5238 // Clone the current header and footer elements and then place it into the inner table 5239 headerCopy = header.clone().prependTo( table ); 5240 headerTrgEls = header.find('tr'); // original header is in its own table 5241 headerSrcEls = headerCopy.find('tr'); 5242 headerCopy.find('th, td').removeAttr('tabindex'); 5243 5244 5245 /* 5246 * 2. Take live measurements from the DOM - do not alter the DOM itself! 5247 */ 5248 5249 // Remove old sizing and apply the calculated column widths 5250 // Get the unique column headers in the newly created (cloned) header. We want to apply the 5251 // calculated sizes to this header 5252 if ( ! scrollX ) 5253 { 5254 divBodyStyle.width = '100%'; 5255 divHeader[0].style.width = '100%'; 5256 } 5257 5258 $.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) { 5259 idx = _fnVisibleToColumnIndex( settings, i ); 5260 el.style.width = settings.aoColumns[idx].sWidth; 5261 } ); 5262 5263 if ( footer ) { 5264 _fnApplyToChildren( function(n) { 5265 n.style.width = ""; 5266 }, footerSrcEls ); 5267 } 5268 5269 // Size the table as a whole 5270 sanityWidth = table.outerWidth(); 5271 if ( scrollX === "" ) { 5272 // No x scrolling 5273 tableStyle.width = "100%"; 5274 5275 // IE7 will make the width of the table when 100% include the scrollbar 5276 // - which is shouldn't. When there is a scrollbar we need to take this 5277 // into account. 5278 if ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight || 5279 divBody.css('overflow-y') == "scroll") 5280 ) { 5281 tableStyle.width = _fnStringToCss( table.outerWidth() - barWidth); 5282 } 5283 5284 // Recalculate the sanity width 5285 sanityWidth = table.outerWidth(); 5286 } 5287 else if ( scrollXInner !== "" ) { 5288 // legacy x scroll inner has been given - use it 5289 tableStyle.width = _fnStringToCss(scrollXInner); 5290 5291 // Recalculate the sanity width 5292 sanityWidth = table.outerWidth(); 5293 } 5294 5295 // Hidden header should have zero height, so remove padding and borders. Then 5296 // set the width based on the real headers 5297 5298 // Apply all styles in one pass 5299 _fnApplyToChildren( zeroOut, headerSrcEls ); 5300 5301 // Read all widths in next pass 5302 _fnApplyToChildren( function(nSizer) { 5303 headerContent.push( nSizer.innerHTML ); 5304 headerWidths.push( _fnStringToCss( $(nSizer).css('width') ) ); 5305 }, headerSrcEls ); 5306 5307 // Apply all widths in final pass 5308 _fnApplyToChildren( function(nToSize, i) { 5309 // Only apply widths to the DataTables detected header cells - this 5310 // prevents complex headers from having contradictory sizes applied 5311 if ( $.inArray( nToSize, dtHeaderCells ) !== -1 ) { 5312 nToSize.style.width = headerWidths[i]; 5313 } 5314 }, headerTrgEls ); 5315 5316 $(headerSrcEls).height(0); 5317 5318 /* Same again with the footer if we have one */ 5319 if ( footer ) 5320 { 5321 _fnApplyToChildren( zeroOut, footerSrcEls ); 5322 5323 _fnApplyToChildren( function(nSizer) { 5324 footerContent.push( nSizer.innerHTML ); 5325 footerWidths.push( _fnStringToCss( $(nSizer).css('width') ) ); 5326 }, footerSrcEls ); 5327 5328 _fnApplyToChildren( function(nToSize, i) { 5329 nToSize.style.width = footerWidths[i]; 5330 }, footerTrgEls ); 5331 5332 $(footerSrcEls).height(0); 5333 } 5334 5335 5336 /* 5337 * 3. Apply the measurements 5338 */ 5339 5340 // "Hide" the header and footer that we used for the sizing. We need to keep 5341 // the content of the cell so that the width applied to the header and body 5342 // both match, but we want to hide it completely. We want to also fix their 5343 // width to what they currently are 5344 _fnApplyToChildren( function(nSizer, i) { 5345 nSizer.innerHTML = '<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+headerContent[i]+'</div>'; 5346 nSizer.style.width = headerWidths[i]; 5347 }, headerSrcEls ); 5348 5349 if ( footer ) 5350 { 5351 _fnApplyToChildren( function(nSizer, i) { 5352 nSizer.innerHTML = '<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+footerContent[i]+'</div>'; 5353 nSizer.style.width = footerWidths[i]; 5354 }, footerSrcEls ); 5355 } 5356 5357 // Sanity check that the table is of a sensible width. If not then we are going to get 5358 // misalignment - try to prevent this by not allowing the table to shrink below its min width 5359 if ( table.outerWidth() < sanityWidth ) 5360 { 5361 // The min width depends upon if we have a vertical scrollbar visible or not */ 5362 correction = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight || 5363 divBody.css('overflow-y') == "scroll")) ? 5364 sanityWidth+barWidth : 5365 sanityWidth; 5366 5367 // IE6/7 are a law unto themselves... 5368 if ( ie67 && (divBodyEl.scrollHeight > 5369 divBodyEl.offsetHeight || divBody.css('overflow-y') == "scroll") 5370 ) { 5371 tableStyle.width = _fnStringToCss( correction-barWidth ); 5372 } 5373 5374 // And give the user a warning that we've stopped the table getting too small 5375 if ( scrollX === "" || scrollXInner !== "" ) { 5376 _fnLog( settings, 1, 'Possible column misalignment', 6 ); 5377 } 5378 } 5379 else 5380 { 5381 correction = '100%'; 5382 } 5383 5384 // Apply to the container elements 5385 divBodyStyle.width = _fnStringToCss( correction ); 5386 divHeaderStyle.width = _fnStringToCss( correction ); 5387 5388 if ( footer ) { 5389 settings.nScrollFoot.style.width = _fnStringToCss( correction ); 5390 } 5391 5392 5393 /* 5394 * 4. Clean up 5395 */ 5396 if ( ! scrollY ) { 5397 /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting 5398 * the scrollbar height from the visible display, rather than adding it on. We need to 5399 * set the height in order to sort this. Don't want to do it in any other browsers. 5400 */ 5401 if ( ie67 ) { 5402 divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth ); 5403 } 5404 } 5405 5406 /* Finally set the width's of the header and footer tables */ 5407 var iOuterWidth = table.outerWidth(); 5408 divHeaderTable[0].style.width = _fnStringToCss( iOuterWidth ); 5409 divHeaderInnerStyle.width = _fnStringToCss( iOuterWidth ); 5410 5411 // Figure out if there are scrollbar present - if so then we need a the header and footer to 5412 // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar) 5413 var bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll"; 5414 var padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' ); 5415 divHeaderInnerStyle[ padding ] = bScrolling ? barWidth+"px" : "0px"; 5416 5417 if ( footer ) { 5418 divFooterTable[0].style.width = _fnStringToCss( iOuterWidth ); 5419 divFooterInner[0].style.width = _fnStringToCss( iOuterWidth ); 5420 divFooterInner[0].style[padding] = bScrolling ? barWidth+"px" : "0px"; 5421 } 5422 5423 // Correct DOM ordering for colgroup - comes before the thead 5424 table.children('colgroup').insertBefore( table.children('thead') ); 5425 5426 /* Adjust the position of the header in case we loose the y-scrollbar */ 5427 divBody.scroll(); 5428 5429 // If sorting or filtering has occurred, jump the scrolling back to the top 5430 // only if we aren't holding the position 5431 if ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) { 5432 divBodyEl.scrollTop = 0; 5433 } 5434 } 5435 5436 5437 5438 /** 5439 * Apply a given function to the display child nodes of an element array (typically 5440 * TD children of TR rows 5441 * @param {function} fn Method to apply to the objects 5442 * @param array {nodes} an1 List of elements to look through for display children 5443 * @param array {nodes} an2 Another list (identical structure to the first) - optional 5444 * @memberof DataTable#oApi 5445 */ 5446 function _fnApplyToChildren( fn, an1, an2 ) 5447 { 5448 var index=0, i=0, iLen=an1.length; 5449 var nNode1, nNode2; 5450 5451 while ( i < iLen ) { 5452 nNode1 = an1[i].firstChild; 5453 nNode2 = an2 ? an2[i].firstChild : null; 5454 5455 while ( nNode1 ) { 5456 if ( nNode1.nodeType === 1 ) { 5457 if ( an2 ) { 5458 fn( nNode1, nNode2, index ); 5459 } 5460 else { 5461 fn( nNode1, index ); 5462 } 5463 5464 index++; 5465 } 5466 5467 nNode1 = nNode1.nextSibling; 5468 nNode2 = an2 ? nNode2.nextSibling : null; 5469 } 5470 5471 i++; 5472 } 5473 } 5474 5475 5476 5477 var __re_html_remove = /<.*?>/g; 5478 5479 5480 /** 5481 * Calculate the width of columns for the table 5482 * @param {object} oSettings dataTables settings object 5483 * @memberof DataTable#oApi 5484 */ 5485 function _fnCalculateColumnWidths ( oSettings ) 5486 { 5487 var 5488 table = oSettings.nTable, 5489 columns = oSettings.aoColumns, 5490 scroll = oSettings.oScroll, 5491 scrollY = scroll.sY, 5492 scrollX = scroll.sX, 5493 scrollXInner = scroll.sXInner, 5494 columnCount = columns.length, 5495 visibleColumns = _fnGetColumns( oSettings, 'bVisible' ), 5496 headerCells = $('th', oSettings.nTHead), 5497 tableWidthAttr = table.getAttribute('width'), // from DOM element 5498 tableContainer = table.parentNode, 5499 userInputs = false, 5500 i, column, columnIdx, width, outerWidth, 5501 browser = oSettings.oBrowser, 5502 ie67 = browser.bScrollOversize; 5503 5504 var styleWidth = table.style.width; 5505 if ( styleWidth && styleWidth.indexOf('%') !== -1 ) { 5506 tableWidthAttr = styleWidth; 5507 } 5508 5509 /* Convert any user input sizes into pixel sizes */ 5510 for ( i=0 ; i<visibleColumns.length ; i++ ) { 5511 column = columns[ visibleColumns[i] ]; 5512 5513 if ( column.sWidth !== null ) { 5514 column.sWidth = _fnConvertToWidth( column.sWidthOrig, tableContainer ); 5515 5516 userInputs = true; 5517 } 5518 } 5519 5520 /* If the number of columns in the DOM equals the number that we have to 5521 * process in DataTables, then we can use the offsets that are created by 5522 * the web- browser. No custom sizes can be set in order for this to happen, 5523 * nor scrolling used 5524 */ 5525 if ( ie67 || ! userInputs && ! scrollX && ! scrollY && 5526 columnCount == _fnVisbleColumns( oSettings ) && 5527 columnCount == headerCells.length 5528 ) { 5529 for ( i=0 ; i<columnCount ; i++ ) { 5530 var colIdx = _fnVisibleToColumnIndex( oSettings, i ); 5531 5532 if ( colIdx !== null ) { 5533 columns[ colIdx ].sWidth = _fnStringToCss( headerCells.eq(i).width() ); 5534 } 5535 } 5536 } 5537 else 5538 { 5539 // Otherwise construct a single row, worst case, table with the widest 5540 // node in the data, assign any user defined widths, then insert it into 5541 // the DOM and allow the browser to do all the hard work of calculating 5542 // table widths 5543 var tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table 5544 .css( 'visibility', 'hidden' ) 5545 .removeAttr( 'id' ); 5546 5547 // Clean up the table body 5548 tmpTable.find('tbody tr').remove(); 5549 var tr = $('<tr/>').appendTo( tmpTable.find('tbody') ); 5550 5551 // Clone the table header and footer - we can't use the header / footer 5552 // from the cloned table, since if scrolling is active, the table's 5553 // real header and footer are contained in different table tags 5554 tmpTable.find('thead, tfoot').remove(); 5555 tmpTable 5556 .append( $(oSettings.nTHead).clone() ) 5557 .append( $(oSettings.nTFoot).clone() ); 5558 5559 // Remove any assigned widths from the footer (from scrolling) 5560 tmpTable.find('tfoot th, tfoot td').css('width', ''); 5561 5562 // Apply custom sizing to the cloned header 5563 headerCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] ); 5564 5565 for ( i=0 ; i<visibleColumns.length ; i++ ) { 5566 column = columns[ visibleColumns[i] ]; 5567 5568 headerCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ? 5569 _fnStringToCss( column.sWidthOrig ) : 5570 ''; 5571 5572 // For scrollX we need to force the column width otherwise the 5573 // browser will collapse it. If this width is smaller than the 5574 // width the column requires, then it will have no effect 5575 if ( column.sWidthOrig && scrollX ) { 5576 $( headerCells[i] ).append( $('<div/>').css( { 5577 width: column.sWidthOrig, 5578 margin: 0, 5579 padding: 0, 5580 border: 0, 5581 height: 1 5582 } ) ); 5583 } 5584 } 5585 5586 // Find the widest cell for each column and put it into the table 5587 if ( oSettings.aoData.length ) { 5588 for ( i=0 ; i<visibleColumns.length ; i++ ) { 5589 columnIdx = visibleColumns[i]; 5590 column = columns[ columnIdx ]; 5591 5592 $( _fnGetWidestNode( oSettings, columnIdx ) ) 5593 .clone( false ) 5594 .append( column.sContentPadding ) 5595 .appendTo( tr ); 5596 } 5597 } 5598 5599 // Tidy the temporary table - remove name attributes so there aren't 5600 // duplicated in the dom (radio elements for example) 5601 $('[name]', tmpTable).removeAttr('name'); 5602 5603 // Table has been built, attach to the document so we can work with it. 5604 // A holding element is used, positioned at the top of the container 5605 // with minimal height, so it has no effect on if the container scrolls 5606 // or not. Otherwise it might trigger scrolling when it actually isn't 5607 // needed 5608 var holder = $('<div/>').css( scrollX || scrollY ? 5609 { 5610 position: 'absolute', 5611 top: 0, 5612 left: 0, 5613 height: 1, 5614 right: 0, 5615 overflow: 'hidden' 5616 } : 5617 {} 5618 ) 5619 .append( tmpTable ) 5620 .appendTo( tableContainer ); 5621 5622 // When scrolling (X or Y) we want to set the width of the table as 5623 // appropriate. However, when not scrolling leave the table width as it 5624 // is. This results in slightly different, but I think correct behaviour 5625 if ( scrollX && scrollXInner ) { 5626 tmpTable.width( scrollXInner ); 5627 } 5628 else if ( scrollX ) { 5629 tmpTable.css( 'width', 'auto' ); 5630 tmpTable.removeAttr('width'); 5631 5632 // If there is no width attribute or style, then allow the table to 5633 // collapse 5634 if ( tmpTable.width() < tableContainer.clientWidth && tableWidthAttr ) { 5635 tmpTable.width( tableContainer.clientWidth ); 5636 } 5637 } 5638 else if ( scrollY ) { 5639 tmpTable.width( tableContainer.clientWidth ); 5640 } 5641 else if ( tableWidthAttr ) { 5642 tmpTable.width( tableWidthAttr ); 5643 } 5644 5645 // Get the width of each column in the constructed table - we need to 5646 // know the inner width (so it can be assigned to the other table's 5647 // cells) and the outer width so we can calculate the full width of the 5648 // table. This is safe since DataTables requires a unique cell for each 5649 // column, but if ever a header can span multiple columns, this will 5650 // need to be modified. 5651 var total = 0; 5652 for ( i=0 ; i<visibleColumns.length ; i++ ) { 5653 var cell = $(headerCells[i]); 5654 var border = cell.outerWidth() - cell.width(); 5655 5656 // Use getBounding... where possible (not IE8-) because it can give 5657 // sub-pixel accuracy, which we then want to round up! 5658 var bounding = browser.bBounding ? 5659 Math.ceil( headerCells[i].getBoundingClientRect().width ) : 5660 cell.outerWidth(); 5661 5662 // Total is tracked to remove any sub-pixel errors as the outerWidth 5663 // of the table might not equal the total given here (IE!). 5664 total += bounding; 5665 5666 // Width for each column to use 5667 columns[ visibleColumns[i] ].sWidth = _fnStringToCss( bounding - border ); 5668 } 5669 5670 table.style.width = _fnStringToCss( total ); 5671 5672 // Finished with the table - ditch it 5673 holder.remove(); 5674 } 5675 5676 // If there is a width attr, we want to attach an event listener which 5677 // allows the table sizing to automatically adjust when the window is 5678 // resized. Use the width attr rather than CSS, since we can't know if the 5679 // CSS is a relative value or absolute - DOM read is always px. 5680 if ( tableWidthAttr ) { 5681 table.style.width = _fnStringToCss( tableWidthAttr ); 5682 } 5683 5684 if ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) { 5685 var bindResize = function () { 5686 $(window).bind('resize.DT-'+oSettings.sInstance, _fnThrottle( function () { 5687 _fnAdjustColumnSizing( oSettings ); 5688 } ) ); 5689 }; 5690 5691 // IE6/7 will crash if we bind a resize event handler on page load. 5692 // To be removed in 1.11 which drops IE6/7 support 5693 if ( ie67 ) { 5694 setTimeout( bindResize, 1000 ); 5695 } 5696 else { 5697 bindResize(); 5698 } 5699 5700 oSettings._reszEvt = true; 5701 } 5702 } 5703 5704 5705 /** 5706 * Throttle the calls to a function. Arguments and context are maintained for 5707 * the throttled function 5708 * @param {function} fn Function to be called 5709 * @param {int} [freq=200] call frequency in mS 5710 * @returns {function} wrapped function 5711 * @memberof DataTable#oApi 5712 */ 5713 var _fnThrottle = DataTable.util.throttle; 5714 5715 5716 /** 5717 * Convert a CSS unit width to pixels (e.g. 2em) 5718 * @param {string} width width to be converted 5719 * @param {node} parent parent to get the with for (required for relative widths) - optional 5720 * @returns {int} width in pixels 5721 * @memberof DataTable#oApi 5722 */ 5723 function _fnConvertToWidth ( width, parent ) 5724 { 5725 if ( ! width ) { 5726 return 0; 5727 } 5728 5729 var n = $('<div/>') 5730 .css( 'width', _fnStringToCss( width ) ) 5731 .appendTo( parent || document.body ); 5732 5733 var val = n[0].offsetWidth; 5734 n.remove(); 5735 5736 return val; 5737 } 5738 5739 5740 /** 5741 * Get the widest node 5742 * @param {object} settings dataTables settings object 5743 * @param {int} colIdx column of interest 5744 * @returns {node} widest table node 5745 * @memberof DataTable#oApi 5746 */ 5747 function _fnGetWidestNode( settings, colIdx ) 5748 { 5749 var idx = _fnGetMaxLenString( settings, colIdx ); 5750 if ( idx < 0 ) { 5751 return null; 5752 } 5753 5754 var data = settings.aoData[ idx ]; 5755 return ! data.nTr ? // Might not have been created when deferred rendering 5756 $('<td/>').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] : 5757 data.anCells[ colIdx ]; 5758 } 5759 5760 5761 /** 5762 * Get the maximum strlen for each data column 5763 * @param {object} settings dataTables settings object 5764 * @param {int} colIdx column of interest 5765 * @returns {string} max string length for each column 5766 * @memberof DataTable#oApi 5767 */ 5768 function _fnGetMaxLenString( settings, colIdx ) 5769 { 5770 var s, max=-1, maxIdx = -1; 5771 5772 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) { 5773 s = _fnGetCellData( settings, i, colIdx, 'display' )+''; 5774 s = s.replace( __re_html_remove, '' ); 5775 s = s.replace( / /g, ' ' ); 5776 5777 if ( s.length > max ) { 5778 max = s.length; 5779 maxIdx = i; 5780 } 5781 } 5782 5783 return maxIdx; 5784 } 5785 5786 5787 /** 5788 * Append a CSS unit (only if required) to a string 5789 * @param {string} value to css-ify 5790 * @returns {string} value with css unit 5791 * @memberof DataTable#oApi 5792 */ 5793 function _fnStringToCss( s ) 5794 { 5795 if ( s === null ) { 5796 return '0px'; 5797 } 5798 5799 if ( typeof s == 'number' ) { 5800 return s < 0 ? 5801 '0px' : 5802 s+'px'; 5803 } 5804 5805 // Check it has a unit character already 5806 return s.match(/\d$/) ? 5807 s+'px' : 5808 s; 5809 } 5810 5811 5812 5813 function _fnSortFlatten ( settings ) 5814 { 5815 var 5816 i, iLen, k, kLen, 5817 aSort = [], 5818 aiOrig = [], 5819 aoColumns = settings.aoColumns, 5820 aDataSort, iCol, sType, srcCol, 5821 fixed = settings.aaSortingFixed, 5822 fixedObj = $.isPlainObject( fixed ), 5823 nestedSort = [], 5824 add = function ( a ) { 5825 if ( a.length && ! $.isArray( a[0] ) ) { 5826 // 1D array 5827 nestedSort.push( a ); 5828 } 5829 else { 5830 // 2D array 5831 $.merge( nestedSort, a ); 5832 } 5833 }; 5834 5835 // Build the sort array, with pre-fix and post-fix options if they have been 5836 // specified 5837 if ( $.isArray( fixed ) ) { 5838 add( fixed ); 5839 } 5840 5841 if ( fixedObj && fixed.pre ) { 5842 add( fixed.pre ); 5843 } 5844 5845 add( settings.aaSorting ); 5846 5847 if (fixedObj && fixed.post ) { 5848 add( fixed.post ); 5849 } 5850 5851 for ( i=0 ; i<nestedSort.length ; i++ ) 5852 { 5853 srcCol = nestedSort[i][0]; 5854 aDataSort = aoColumns[ srcCol ].aDataSort; 5855 5856 for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ ) 5857 { 5858 iCol = aDataSort[k]; 5859 sType = aoColumns[ iCol ].sType || 'string'; 5860 5861 if ( nestedSort[i]._idx === undefined ) { 5862 nestedSort[i]._idx = $.inArray( nestedSort[i][1], aoColumns[iCol].asSorting ); 5863 } 5864 5865 aSort.push( { 5866 src: srcCol, 5867 col: iCol, 5868 dir: nestedSort[i][1], 5869 index: nestedSort[i]._idx, 5870 type: sType, 5871 formatter: DataTable.ext.type.order[ sType+"-pre" ] 5872 } ); 5873 } 5874 } 5875 5876 return aSort; 5877 } 5878 5879 /** 5880 * Change the order of the table 5881 * @param {object} oSettings dataTables settings object 5882 * @memberof DataTable#oApi 5883 * @todo This really needs split up! 5884 */ 5885 function _fnSort ( oSettings ) 5886 { 5887 var 5888 i, ien, iLen, j, jLen, k, kLen, 5889 sDataType, nTh, 5890 aiOrig = [], 5891 oExtSort = DataTable.ext.type.order, 5892 aoData = oSettings.aoData, 5893 aoColumns = oSettings.aoColumns, 5894 aDataSort, data, iCol, sType, oSort, 5895 formatters = 0, 5896 sortCol, 5897 displayMaster = oSettings.aiDisplayMaster, 5898 aSort; 5899 5900 // Resolve any column types that are unknown due to addition or invalidation 5901 // @todo Can this be moved into a 'data-ready' handler which is called when 5902 // data is going to be used in the table? 5903 _fnColumnTypes( oSettings ); 5904 5905 aSort = _fnSortFlatten( oSettings ); 5906 5907 for ( i=0, ien=aSort.length ; i<ien ; i++ ) { 5908 sortCol = aSort[i]; 5909 5910 // Track if we can use the fast sort algorithm 5911 if ( sortCol.formatter ) { 5912 formatters++; 5913 } 5914 5915 // Load the data needed for the sort, for each cell 5916 _fnSortData( oSettings, sortCol.col ); 5917 } 5918 5919 /* No sorting required if server-side or no sorting array */ 5920 if ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 ) 5921 { 5922 // Create a value - key array of the current row positions such that we can use their 5923 // current position during the sort, if values match, in order to perform stable sorting 5924 for ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) { 5925 aiOrig[ displayMaster[i] ] = i; 5926 } 5927 5928 /* Do the sort - here we want multi-column sorting based on a given data source (column) 5929 * and sorting function (from oSort) in a certain direction. It's reasonably complex to 5930 * follow on it's own, but this is what we want (example two column sorting): 5931 * fnLocalSorting = function(a,b){ 5932 * var iTest; 5933 * iTest = oSort['string-asc']('data11', 'data12'); 5934 * if (iTest !== 0) 5935 * return iTest; 5936 * iTest = oSort['numeric-desc']('data21', 'data22'); 5937 * if (iTest !== 0) 5938 * return iTest; 5939 * return oSort['numeric-asc']( aiOrig[a], aiOrig[b] ); 5940 * } 5941 * Basically we have a test for each sorting column, if the data in that column is equal, 5942 * test the next column. If all columns match, then we use a numeric sort on the row 5943 * positions in the original data array to provide a stable sort. 5944 * 5945 * Note - I know it seems excessive to have two sorting methods, but the first is around 5946 * 15% faster, so the second is only maintained for backwards compatibility with sorting 5947 * methods which do not have a pre-sort formatting function. 5948 */ 5949 if ( formatters === aSort.length ) { 5950 // All sort types have formatting functions 5951 displayMaster.sort( function ( a, b ) { 5952 var 5953 x, y, k, test, sort, 5954 len=aSort.length, 5955 dataA = aoData[a]._aSortData, 5956 dataB = aoData[b]._aSortData; 5957 5958 for ( k=0 ; k<len ; k++ ) { 5959 sort = aSort[k]; 5960 5961 x = dataA[ sort.col ]; 5962 y = dataB[ sort.col ]; 5963 5964 test = x<y ? -1 : x>y ? 1 : 0; 5965 if ( test !== 0 ) { 5966 return sort.dir === 'asc' ? test : -test; 5967 } 5968 } 5969 5970 x = aiOrig[a]; 5971 y = aiOrig[b]; 5972 return x<y ? -1 : x>y ? 1 : 0; 5973 } ); 5974 } 5975 else { 5976 // Depreciated - remove in 1.11 (providing a plug-in option) 5977 // Not all sort types have formatting methods, so we have to call their sorting 5978 // methods. 5979 displayMaster.sort( function ( a, b ) { 5980 var 5981 x, y, k, l, test, sort, fn, 5982 len=aSort.length, 5983 dataA = aoData[a]._aSortData, 5984 dataB = aoData[b]._aSortData; 5985 5986 for ( k=0 ; k<len ; k++ ) { 5987 sort = aSort[k]; 5988 5989 x = dataA[ sort.col ]; 5990 y = dataB[ sort.col ]; 5991 5992 fn = oExtSort[ sort.type+"-"+sort.dir ] || oExtSort[ "string-"+sort.dir ]; 5993 test = fn( x, y ); 5994 if ( test !== 0 ) { 5995 return test; 5996 } 5997 } 5998 5999 x = aiOrig[a]; 6000 y = aiOrig[b]; 6001 return x<y ? -1 : x>y ? 1 : 0; 6002 } ); 6003 } 6004 } 6005 6006 /* Tell the draw function that we have sorted the data */ 6007 oSettings.bSorted = true; 6008 } 6009 6010 6011 function _fnSortAria ( settings ) 6012 { 6013 var label; 6014 var nextSort; 6015 var columns = settings.aoColumns; 6016 var aSort = _fnSortFlatten( settings ); 6017 var oAria = settings.oLanguage.oAria; 6018 6019 // ARIA attributes - need to loop all columns, to update all (removing old 6020 // attributes as needed) 6021 for ( var i=0, iLen=columns.length ; i<iLen ; i++ ) 6022 { 6023 var col = columns[i]; 6024 var asSorting = col.asSorting; 6025 var sTitle = col.sTitle.replace( /<.*?>/g, "" ); 6026 var th = col.nTh; 6027 6028 // IE7 is throwing an error when setting these properties with jQuery's 6029 // attr() and removeAttr() methods... 6030 th.removeAttribute('aria-sort'); 6031 6032 /* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */ 6033 if ( col.bSortable ) { 6034 if ( aSort.length > 0 && aSort[0].col == i ) { 6035 th.setAttribute('aria-sort', aSort[0].dir=="asc" ? "ascending" : "descending" ); 6036 nextSort = asSorting[ aSort[0].index+1 ] || asSorting[0]; 6037 } 6038 else { 6039 nextSort = asSorting[0]; 6040 } 6041 6042 label = sTitle + ( nextSort === "asc" ? 6043 oAria.sSortAscending : 6044 oAria.sSortDescending 6045 ); 6046 } 6047 else { 6048 label = sTitle; 6049 } 6050 6051 th.setAttribute('aria-label', label); 6052 } 6053 } 6054 6055 6056 /** 6057 * Function to run on user sort request 6058 * @param {object} settings dataTables settings object 6059 * @param {node} attachTo node to attach the handler to 6060 * @param {int} colIdx column sorting index 6061 * @param {boolean} [append=false] Append the requested sort to the existing 6062 * sort if true (i.e. multi-column sort) 6063 * @param {function} [callback] callback function 6064 * @memberof DataTable#oApi 6065 */ 6066 function _fnSortListener ( settings, colIdx, append, callback ) 6067 { 6068 var col = settings.aoColumns[ colIdx ]; 6069 var sorting = settings.aaSorting; 6070 var asSorting = col.asSorting; 6071 var nextSortIdx; 6072 var next = function ( a, overflow ) { 6073 var idx = a._idx; 6074 if ( idx === undefined ) { 6075 idx = $.inArray( a[1], asSorting ); 6076 } 6077 6078 return idx+1 < asSorting.length ? 6079 idx+1 : 6080 overflow ? 6081 null : 6082 0; 6083 }; 6084 6085 // Convert to 2D array if needed 6086 if ( typeof sorting[0] === 'number' ) { 6087 sorting = settings.aaSorting = [ sorting ]; 6088 } 6089 6090 // If appending the sort then we are multi-column sorting 6091 if ( append && settings.oFeatures.bSortMulti ) { 6092 // Are we already doing some kind of sort on this column? 6093 var sortIdx = $.inArray( colIdx, _pluck(sorting, '0') ); 6094 6095 if ( sortIdx !== -1 ) { 6096 // Yes, modify the sort 6097 nextSortIdx = next( sorting[sortIdx], true ); 6098 6099 if ( nextSortIdx === null && sorting.length === 1 ) { 6100 nextSortIdx = 0; // can't remove sorting completely 6101 } 6102 6103 if ( nextSortIdx === null ) { 6104 sorting.splice( sortIdx, 1 ); 6105 } 6106 else { 6107 sorting[sortIdx][1] = asSorting[ nextSortIdx ]; 6108 sorting[sortIdx]._idx = nextSortIdx; 6109 } 6110 } 6111 else { 6112 // No sort on this column yet 6113 sorting.push( [ colIdx, asSorting[0], 0 ] ); 6114 sorting[sorting.length-1]._idx = 0; 6115 } 6116 } 6117 else if ( sorting.length && sorting[0][0] == colIdx ) { 6118 // Single column - already sorting on this column, modify the sort 6119 nextSortIdx = next( sorting[0] ); 6120 6121 sorting.length = 1; 6122 sorting[0][1] = asSorting[ nextSortIdx ]; 6123 sorting[0]._idx = nextSortIdx; 6124 } 6125 else { 6126 // Single column - sort only on this column 6127 sorting.length = 0; 6128 sorting.push( [ colIdx, asSorting[0] ] ); 6129 sorting[0]._idx = 0; 6130 } 6131 6132 // Run the sort by calling a full redraw 6133 _fnReDraw( settings ); 6134 6135 // callback used for async user interaction 6136 if ( typeof callback == 'function' ) { 6137 callback( settings ); 6138 } 6139 } 6140 6141 6142 /** 6143 * Attach a sort handler (click) to a node 6144 * @param {object} settings dataTables settings object 6145 * @param {node} attachTo node to attach the handler to 6146 * @param {int} colIdx column sorting index 6147 * @param {function} [callback] callback function 6148 * @memberof DataTable#oApi 6149 */ 6150 function _fnSortAttachListener ( settings, attachTo, colIdx, callback ) 6151 { 6152 var col = settings.aoColumns[ colIdx ]; 6153 6154 _fnBindAction( attachTo, {}, function (e) { 6155 /* If the column is not sortable - don't to anything */ 6156 if ( col.bSortable === false ) { 6157 return; 6158 } 6159 6160 // If processing is enabled use a timeout to allow the processing 6161 // display to be shown - otherwise to it synchronously 6162 if ( settings.oFeatures.bProcessing ) { 6163 _fnProcessingDisplay( settings, true ); 6164 6165 setTimeout( function() { 6166 _fnSortListener( settings, colIdx, e.shiftKey, callback ); 6167 6168 // In server-side processing, the draw callback will remove the 6169 // processing display 6170 if ( _fnDataSource( settings ) !== 'ssp' ) { 6171 _fnProcessingDisplay( settings, false ); 6172 } 6173 }, 0 ); 6174 } 6175 else { 6176 _fnSortListener( settings, colIdx, e.shiftKey, callback ); 6177 } 6178 } ); 6179 } 6180 6181 6182 /** 6183 * Set the sorting classes on table's body, Note: it is safe to call this function 6184 * when bSort and bSortClasses are false 6185 * @param {object} oSettings dataTables settings object 6186 * @memberof DataTable#oApi 6187 */ 6188 function _fnSortingClasses( settings ) 6189 { 6190 var oldSort = settings.aLastSort; 6191 var sortClass = settings.oClasses.sSortColumn; 6192 var sort = _fnSortFlatten( settings ); 6193 var features = settings.oFeatures; 6194 var i, ien, colIdx; 6195 6196 if ( features.bSort && features.bSortClasses ) { 6197 // Remove old sorting classes 6198 for ( i=0, ien=oldSort.length ; i<ien ; i++ ) { 6199 colIdx = oldSort[i].src; 6200 6201 // Remove column sorting 6202 $( _pluck( settings.aoData, 'anCells', colIdx ) ) 6203 .removeClass( sortClass + (i<2 ? i+1 : 3) ); 6204 } 6205 6206 // Add new column sorting 6207 for ( i=0, ien=sort.length ; i<ien ; i++ ) { 6208 colIdx = sort[i].src; 6209 6210 $( _pluck( settings.aoData, 'anCells', colIdx ) ) 6211 .addClass( sortClass + (i<2 ? i+1 : 3) ); 6212 } 6213 } 6214 6215 settings.aLastSort = sort; 6216 } 6217 6218 6219 // Get the data to sort a column, be it from cache, fresh (populating the 6220 // cache), or from a sort formatter 6221 function _fnSortData( settings, idx ) 6222 { 6223 // Custom sorting function - provided by the sort data type 6224 var column = settings.aoColumns[ idx ]; 6225 var customSort = DataTable.ext.order[ column.sSortDataType ]; 6226 var customData; 6227 6228 if ( customSort ) { 6229 customData = customSort.call( settings.oInstance, settings, idx, 6230 _fnColumnIndexToVisible( settings, idx ) 6231 ); 6232 } 6233 6234 // Use / populate cache 6235 var row, cellData; 6236 var formatter = DataTable.ext.type.order[ column.sType+"-pre" ]; 6237 6238 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) { 6239 row = settings.aoData[i]; 6240 6241 if ( ! row._aSortData ) { 6242 row._aSortData = []; 6243 } 6244 6245 if ( ! row._aSortData[idx] || customSort ) { 6246 cellData = customSort ? 6247 customData[i] : // If there was a custom sort function, use data from there 6248 _fnGetCellData( settings, i, idx, 'sort' ); 6249 6250 row._aSortData[ idx ] = formatter ? 6251 formatter( cellData ) : 6252 cellData; 6253 } 6254 } 6255 } 6256 6257 6258 6259 /** 6260 * Save the state of a table 6261 * @param {object} oSettings dataTables settings object 6262 * @memberof DataTable#oApi 6263 */ 6264 function _fnSaveState ( settings ) 6265 { 6266 if ( !settings.oFeatures.bStateSave || settings.bDestroying ) 6267 { 6268 return; 6269 } 6270 6271 /* Store the interesting variables */ 6272 var state = { 6273 time: +new Date(), 6274 start: settings._iDisplayStart, 6275 length: settings._iDisplayLength, 6276 order: $.extend( true, [], settings.aaSorting ), 6277 search: _fnSearchToCamel( settings.oPreviousSearch ), 6278 columns: $.map( settings.aoColumns, function ( col, i ) { 6279 return { 6280 visible: col.bVisible, 6281 search: _fnSearchToCamel( settings.aoPreSearchCols[i] ) 6282 }; 6283 } ) 6284 }; 6285 6286 _fnCallbackFire( settings, "aoStateSaveParams", 'stateSaveParams', [settings, state] ); 6287 6288 settings.oSavedState = state; 6289 settings.fnStateSaveCallback.call( settings.oInstance, settings, state ); 6290 } 6291 6292 6293 /** 6294 * Attempt to load a saved table state 6295 * @param {object} oSettings dataTables settings object 6296 * @param {object} oInit DataTables init object so we can override settings 6297 * @memberof DataTable#oApi 6298 */ 6299 function _fnLoadState ( settings, oInit ) 6300 { 6301 var i, ien; 6302 var columns = settings.aoColumns; 6303 6304 if ( ! settings.oFeatures.bStateSave ) { 6305 return; 6306 } 6307 6308 var state = settings.fnStateLoadCallback.call( settings.oInstance, settings ); 6309 if ( ! state || ! state.time ) { 6310 return; 6311 } 6312 6313 /* Allow custom and plug-in manipulation functions to alter the saved data set and 6314 * cancelling of loading by returning false 6315 */ 6316 var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, state] ); 6317 if ( $.inArray( false, abStateLoad ) !== -1 ) { 6318 return; 6319 } 6320 6321 /* Reject old data */ 6322 var duration = settings.iStateDuration; 6323 if ( duration > 0 && state.time < +new Date() - (duration*1000) ) { 6324 return; 6325 } 6326 6327 // Number of columns have changed - all bets are off, no restore of settings 6328 if ( columns.length !== state.columns.length ) { 6329 return; 6330 } 6331 6332 // Store the saved state so it might be accessed at any time 6333 settings.oLoadedState = $.extend( true, {}, state ); 6334 6335 // Restore key features - todo - for 1.11 this needs to be done by 6336 // subscribed events 6337 if ( state.start !== undefined ) { 6338 settings._iDisplayStart = state.start; 6339 settings.iInitDisplayStart = state.start; 6340 } 6341 if ( state.length !== undefined ) { 6342 settings._iDisplayLength = state.length; 6343 } 6344 6345 // Order 6346 if ( state.order !== undefined ) { 6347 settings.aaSorting = []; 6348 $.each( state.order, function ( i, col ) { 6349 settings.aaSorting.push( col[0] >= columns.length ? 6350 [ 0, col[1] ] : 6351 col 6352 ); 6353 } ); 6354 } 6355 6356 // Search 6357 if ( state.search !== undefined ) { 6358 $.extend( settings.oPreviousSearch, _fnSearchToHung( state.search ) ); 6359 } 6360 6361 // Columns 6362 for ( i=0, ien=state.columns.length ; i<ien ; i++ ) { 6363 var col = state.columns[i]; 6364 6365 // Visibility 6366 if ( col.visible !== undefined ) { 6367 columns[i].bVisible = col.visible; 6368 } 6369 6370 // Search 6371 if ( col.search !== undefined ) { 6372 $.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) ); 6373 } 6374 } 6375 6376 _fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, state] ); 6377 } 6378 6379 6380 /** 6381 * Return the settings object for a particular table 6382 * @param {node} table table we are using as a dataTable 6383 * @returns {object} Settings object - or null if not found 6384 * @memberof DataTable#oApi 6385 */ 6386 function _fnSettingsFromNode ( table ) 6387 { 6388 var settings = DataTable.settings; 6389 var idx = $.inArray( table, _pluck( settings, 'nTable' ) ); 6390 6391 return idx !== -1 ? 6392 settings[ idx ] : 6393 null; 6394 } 6395 6396 6397 /** 6398 * Log an error message 6399 * @param {object} settings dataTables settings object 6400 * @param {int} level log error messages, or display them to the user 6401 * @param {string} msg error message 6402 * @param {int} tn Technical note id to get more information about the error. 6403 * @memberof DataTable#oApi 6404 */ 6405 function _fnLog( settings, level, msg, tn ) 6406 { 6407 msg = 'DataTables warning: '+ 6408 (settings ? 'table id='+settings.sTableId+' - ' : '')+msg; 6409 6410 if ( tn ) { 6411 msg += '. For more information about this error, please see '+ 6412 'http://datatables.net/tn/'+tn; 6413 } 6414 6415 if ( ! level ) { 6416 // Backwards compatibility pre 1.10 6417 var ext = DataTable.ext; 6418 var type = ext.sErrMode || ext.errMode; 6419 6420 if ( settings ) { 6421 _fnCallbackFire( settings, null, 'error', [ settings, tn, msg ] ); 6422 } 6423 6424 if ( type == 'alert' ) { 6425 alert( msg ); 6426 } 6427 else if ( type == 'throw' ) { 6428 throw new Error(msg); 6429 } 6430 else if ( typeof type == 'function' ) { 6431 type( settings, tn, msg ); 6432 } 6433 } 6434 else if ( window.console && console.log ) { 6435 console.log( msg ); 6436 } 6437 } 6438 6439 6440 /** 6441 * See if a property is defined on one object, if so assign it to the other object 6442 * @param {object} ret target object 6443 * @param {object} src source object 6444 * @param {string} name property 6445 * @param {string} [mappedName] name to map too - optional, name used if not given 6446 * @memberof DataTable#oApi 6447 */ 6448 function _fnMap( ret, src, name, mappedName ) 6449 { 6450 if ( $.isArray( name ) ) { 6451 $.each( name, function (i, val) { 6452 if ( $.isArray( val ) ) { 6453 _fnMap( ret, src, val[0], val[1] ); 6454 } 6455 else { 6456 _fnMap( ret, src, val ); 6457 } 6458 } ); 6459 6460 return; 6461 } 6462 6463 if ( mappedName === undefined ) { 6464 mappedName = name; 6465 } 6466 6467 if ( src[name] !== undefined ) { 6468 ret[mappedName] = src[name]; 6469 } 6470 } 6471 6472 6473 /** 6474 * Extend objects - very similar to jQuery.extend, but deep copy objects, and 6475 * shallow copy arrays. The reason we need to do this, is that we don't want to 6476 * deep copy array init values (such as aaSorting) since the dev wouldn't be 6477 * able to override them, but we do want to deep copy arrays. 6478 * @param {object} out Object to extend 6479 * @param {object} extender Object from which the properties will be applied to 6480 * out 6481 * @param {boolean} breakRefs If true, then arrays will be sliced to take an 6482 * independent copy with the exception of the `data` or `aaData` parameters 6483 * if they are present. This is so you can pass in a collection to 6484 * DataTables and have that used as your data source without breaking the 6485 * references 6486 * @returns {object} out Reference, just for convenience - out === the return. 6487 * @memberof DataTable#oApi 6488 * @todo This doesn't take account of arrays inside the deep copied objects. 6489 */ 6490 function _fnExtend( out, extender, breakRefs ) 6491 { 6492 var val; 6493 6494 for ( var prop in extender ) { 6495 if ( extender.hasOwnProperty(prop) ) { 6496 val = extender[prop]; 6497 6498 if ( $.isPlainObject( val ) ) { 6499 if ( ! $.isPlainObject( out[prop] ) ) { 6500 out[prop] = {}; 6501 } 6502 $.extend( true, out[prop], val ); 6503 } 6504 else if ( breakRefs && prop !== 'data' && prop !== 'aaData' && $.isArray(val) ) { 6505 out[prop] = val.slice(); 6506 } 6507 else { 6508 out[prop] = val; 6509 } 6510 } 6511 } 6512 6513 return out; 6514 } 6515 6516 6517 /** 6518 * Bind an event handers to allow a click or return key to activate the callback. 6519 * This is good for accessibility since a return on the keyboard will have the 6520 * same effect as a click, if the element has focus. 6521 * @param {element} n Element to bind the action to 6522 * @param {object} oData Data object to pass to the triggered function 6523 * @param {function} fn Callback function for when the event is triggered 6524 * @memberof DataTable#oApi 6525 */ 6526 function _fnBindAction( n, oData, fn ) 6527 { 6528 $(n) 6529 .bind( 'click.DT', oData, function (e) { 6530 n.blur(); // Remove focus outline for mouse users 6531 fn(e); 6532 } ) 6533 .bind( 'keypress.DT', oData, function (e){ 6534 if ( e.which === 13 ) { 6535 e.preventDefault(); 6536 fn(e); 6537 } 6538 } ) 6539 .bind( 'selectstart.DT', function () { 6540 /* Take the brutal approach to cancelling text selection */ 6541 return false; 6542 } ); 6543 } 6544 6545 6546 /** 6547 * Register a callback function. Easily allows a callback function to be added to 6548 * an array store of callback functions that can then all be called together. 6549 * @param {object} oSettings dataTables settings object 6550 * @param {string} sStore Name of the array storage for the callbacks in oSettings 6551 * @param {function} fn Function to be called back 6552 * @param {string} sName Identifying name for the callback (i.e. a label) 6553 * @memberof DataTable#oApi 6554 */ 6555 function _fnCallbackReg( oSettings, sStore, fn, sName ) 6556 { 6557 if ( fn ) 6558 { 6559 oSettings[sStore].push( { 6560 "fn": fn, 6561 "sName": sName 6562 } ); 6563 } 6564 } 6565 6566 6567 /** 6568 * Fire callback functions and trigger events. Note that the loop over the 6569 * callback array store is done backwards! Further note that you do not want to 6570 * fire off triggers in time sensitive applications (for example cell creation) 6571 * as its slow. 6572 * @param {object} settings dataTables settings object 6573 * @param {string} callbackArr Name of the array storage for the callbacks in 6574 * oSettings 6575 * @param {string} eventName Name of the jQuery custom event to trigger. If 6576 * null no trigger is fired 6577 * @param {array} args Array of arguments to pass to the callback function / 6578 * trigger 6579 * @memberof DataTable#oApi 6580 */ 6581 function _fnCallbackFire( settings, callbackArr, eventName, args ) 6582 { 6583 var ret = []; 6584 6585 if ( callbackArr ) { 6586 ret = $.map( settings[callbackArr].slice().reverse(), function (val, i) { 6587 return val.fn.apply( settings.oInstance, args ); 6588 } ); 6589 } 6590 6591 if ( eventName !== null ) { 6592 var e = $.Event( eventName+'.dt' ); 6593 6594 $(settings.nTable).trigger( e, args ); 6595 6596 ret.push( e.result ); 6597 } 6598 6599 return ret; 6600 } 6601 6602 6603 function _fnLengthOverflow ( settings ) 6604 { 6605 var 6606 start = settings._iDisplayStart, 6607 end = settings.fnDisplayEnd(), 6608 len = settings._iDisplayLength; 6609 6610 /* If we have space to show extra rows (backing up from the end point - then do so */ 6611 if ( start >= end ) 6612 { 6613 start = end - len; 6614 } 6615 6616 // Keep the start record on the current page 6617 start -= (start % len); 6618 6619 if ( len === -1 || start < 0 ) 6620 { 6621 start = 0; 6622 } 6623 6624 settings._iDisplayStart = start; 6625 } 6626 6627 6628 function _fnRenderer( settings, type ) 6629 { 6630 var renderer = settings.renderer; 6631 var host = DataTable.ext.renderer[type]; 6632 6633 if ( $.isPlainObject( renderer ) && renderer[type] ) { 6634 // Specific renderer for this type. If available use it, otherwise use 6635 // the default. 6636 return host[renderer[type]] || host._; 6637 } 6638 else if ( typeof renderer === 'string' ) { 6639 // Common renderer - if there is one available for this type use it, 6640 // otherwise use the default 6641 return host[renderer] || host._; 6642 } 6643 6644 // Use the default 6645 return host._; 6646 } 6647 6648 6649 /** 6650 * Detect the data source being used for the table. Used to simplify the code 6651 * a little (ajax) and to make it compress a little smaller. 6652 * 6653 * @param {object} settings dataTables settings object 6654 * @returns {string} Data source 6655 * @memberof DataTable#oApi 6656 */ 6657 function _fnDataSource ( settings ) 6658 { 6659 if ( settings.oFeatures.bServerSide ) { 6660 return 'ssp'; 6661 } 6662 else if ( settings.ajax || settings.sAjaxSource ) { 6663 return 'ajax'; 6664 } 6665 return 'dom'; 6666 } 6667 6668 6669 6670 6671 /** 6672 * Computed structure of the DataTables API, defined by the options passed to 6673 * `DataTable.Api.register()` when building the API. 6674 * 6675 * The structure is built in order to speed creation and extension of the Api 6676 * objects since the extensions are effectively pre-parsed. 6677 * 6678 * The array is an array of objects with the following structure, where this 6679 * base array represents the Api prototype base: 6680 * 6681 * [ 6682 * { 6683 * name: 'data' -- string - Property name 6684 * val: function () {}, -- function - Api method (or undefined if just an object 6685 * methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result 6686 * propExt: [ ... ] -- array - Array of Api object definitions to extend the property 6687 * }, 6688 * { 6689 * name: 'row' 6690 * val: {}, 6691 * methodExt: [ ... ], 6692 * propExt: [ 6693 * { 6694 * name: 'data' 6695 * val: function () {}, 6696 * methodExt: [ ... ], 6697 * propExt: [ ... ] 6698 * }, 6699 * ... 6700 * ] 6701 * } 6702 * ] 6703 * 6704 * @type {Array} 6705 * @ignore 6706 */ 6707 var __apiStruct = []; 6708 6709 6710 /** 6711 * `Array.prototype` reference. 6712 * 6713 * @type object 6714 * @ignore 6715 */ 6716 var __arrayProto = Array.prototype; 6717 6718 6719 /** 6720 * Abstraction for `context` parameter of the `Api` constructor to allow it to 6721 * take several different forms for ease of use. 6722 * 6723 * Each of the input parameter types will be converted to a DataTables settings 6724 * object where possible. 6725 * 6726 * @param {string|node|jQuery|object} mixed DataTable identifier. Can be one 6727 * of: 6728 * 6729 * * `string` - jQuery selector. Any DataTables' matching the given selector 6730 * with be found and used. 6731 * * `node` - `TABLE` node which has already been formed into a DataTable. 6732 * * `jQuery` - A jQuery object of `TABLE` nodes. 6733 * * `object` - DataTables settings object 6734 * * `DataTables.Api` - API instance 6735 * @return {array|null} Matching DataTables settings objects. `null` or 6736 * `undefined` is returned if no matching DataTable is found. 6737 * @ignore 6738 */ 6739 var _toSettings = function ( mixed ) 6740 { 6741 var idx, jq; 6742 var settings = DataTable.settings; 6743 var tables = $.map( settings, function (el, i) { 6744 return el.nTable; 6745 } ); 6746 6747 if ( ! mixed ) { 6748 return []; 6749 } 6750 else if ( mixed.nTable && mixed.oApi ) { 6751 // DataTables settings object 6752 return [ mixed ]; 6753 } 6754 else if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) { 6755 // Table node 6756 idx = $.inArray( mixed, tables ); 6757 return idx !== -1 ? [ settings[idx] ] : null; 6758 } 6759 else if ( mixed && typeof mixed.settings === 'function' ) { 6760 return mixed.settings().toArray(); 6761 } 6762 else if ( typeof mixed === 'string' ) { 6763 // jQuery selector 6764 jq = $(mixed); 6765 } 6766 else if ( mixed instanceof $ ) { 6767 // jQuery object (also DataTables instance) 6768 jq = mixed; 6769 } 6770 6771 if ( jq ) { 6772 return jq.map( function(i) { 6773 idx = $.inArray( this, tables ); 6774 return idx !== -1 ? settings[idx] : null; 6775 } ).toArray(); 6776 } 6777 }; 6778 6779 6780 /** 6781 * DataTables API class - used to control and interface with one or more 6782 * DataTables enhanced tables. 6783 * 6784 * The API class is heavily based on jQuery, presenting a chainable interface 6785 * that you can use to interact with tables. Each instance of the API class has 6786 * a "context" - i.e. the tables that it will operate on. This could be a single 6787 * table, all tables on a page or a sub-set thereof. 6788 * 6789 * Additionally the API is designed to allow you to easily work with the data in 6790 * the tables, retrieving and manipulating it as required. This is done by 6791 * presenting the API class as an array like interface. The contents of the 6792 * array depend upon the actions requested by each method (for example 6793 * `rows().nodes()` will return an array of nodes, while `rows().data()` will 6794 * return an array of objects or arrays depending upon your table's 6795 * configuration). The API object has a number of array like methods (`push`, 6796 * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`, 6797 * `unique` etc) to assist your working with the data held in a table. 6798 * 6799 * Most methods (those which return an Api instance) are chainable, which means 6800 * the return from a method call also has all of the methods available that the 6801 * top level object had. For example, these two calls are equivalent: 6802 * 6803 * // Not chained 6804 * api.row.add( {...} ); 6805 * api.draw(); 6806 * 6807 * // Chained 6808 * api.row.add( {...} ).draw(); 6809 * 6810 * @class DataTable.Api 6811 * @param {array|object|string|jQuery} context DataTable identifier. This is 6812 * used to define which DataTables enhanced tables this API will operate on. 6813 * Can be one of: 6814 * 6815 * * `string` - jQuery selector. Any DataTables' matching the given selector 6816 * with be found and used. 6817 * * `node` - `TABLE` node which has already been formed into a DataTable. 6818 * * `jQuery` - A jQuery object of `TABLE` nodes. 6819 * * `object` - DataTables settings object 6820 * @param {array} [data] Data to initialise the Api instance with. 6821 * 6822 * @example 6823 * // Direct initialisation during DataTables construction 6824 * var api = $('#example').DataTable(); 6825 * 6826 * @example 6827 * // Initialisation using a DataTables jQuery object 6828 * var api = $('#example').dataTable().api(); 6829 * 6830 * @example 6831 * // Initialisation as a constructor 6832 * var api = new $.fn.DataTable.Api( 'table.dataTable' ); 6833 */ 6834 _Api = function ( context, data ) 6835 { 6836 if ( ! (this instanceof _Api) ) { 6837 return new _Api( context, data ); 6838 } 6839 6840 var settings = []; 6841 var ctxSettings = function ( o ) { 6842 var a = _toSettings( o ); 6843 if ( a ) { 6844 settings = settings.concat( a ); 6845 } 6846 }; 6847 6848 if ( $.isArray( context ) ) { 6849 for ( var i=0, ien=context.length ; i<ien ; i++ ) { 6850 ctxSettings( context[i] ); 6851 } 6852 } 6853 else { 6854 ctxSettings( context ); 6855 } 6856 6857 // Remove duplicates 6858 this.context = _unique( settings ); 6859 6860 // Initial data 6861 if ( data ) { 6862 $.merge( this, data ); 6863 } 6864 6865 // selector 6866 this.selector = { 6867 rows: null, 6868 cols: null, 6869 opts: null 6870 }; 6871 6872 _Api.extend( this, this, __apiStruct ); 6873 }; 6874 6875 DataTable.Api = _Api; 6876 6877 // Don't destroy the existing prototype, just extend it. Required for jQuery 2's 6878 // isPlainObject. 6879 $.extend( _Api.prototype, { 6880 any: function () 6881 { 6882 return this.count() !== 0; 6883 }, 6884 6885 6886 concat: __arrayProto.concat, 6887 6888 6889 context: [], // array of table settings objects 6890 6891 6892 count: function () 6893 { 6894 return this.flatten().length; 6895 }, 6896 6897 6898 each: function ( fn ) 6899 { 6900 for ( var i=0, ien=this.length ; i<ien; i++ ) { 6901 fn.call( this, this[i], i, this ); 6902 } 6903 6904 return this; 6905 }, 6906 6907 6908 eq: function ( idx ) 6909 { 6910 var ctx = this.context; 6911 6912 return ctx.length > idx ? 6913 new _Api( ctx[idx], this[idx] ) : 6914 null; 6915 }, 6916 6917 6918 filter: function ( fn ) 6919 { 6920 var a = []; 6921 6922 if ( __arrayProto.filter ) { 6923 a = __arrayProto.filter.call( this, fn, this ); 6924 } 6925 else { 6926 // Compatibility for browsers without EMCA-252-5 (JS 1.6) 6927 for ( var i=0, ien=this.length ; i<ien ; i++ ) { 6928 if ( fn.call( this, this[i], i, this ) ) { 6929 a.push( this[i] ); 6930 } 6931 } 6932 } 6933 6934 return new _Api( this.context, a ); 6935 }, 6936 6937 6938 flatten: function () 6939 { 6940 var a = []; 6941 return new _Api( this.context, a.concat.apply( a, this.toArray() ) ); 6942 }, 6943 6944 6945 join: __arrayProto.join, 6946 6947 6948 indexOf: __arrayProto.indexOf || function (obj, start) 6949 { 6950 for ( var i=(start || 0), ien=this.length ; i<ien ; i++ ) { 6951 if ( this[i] === obj ) { 6952 return i; 6953 } 6954 } 6955 return -1; 6956 }, 6957 6958 iterator: function ( flatten, type, fn, alwaysNew ) { 6959 var 6960 a = [], ret, 6961 i, ien, j, jen, 6962 context = this.context, 6963 rows, items, item, 6964 selector = this.selector; 6965 6966 // Argument shifting 6967 if ( typeof flatten === 'string' ) { 6968 alwaysNew = fn; 6969 fn = type; 6970 type = flatten; 6971 flatten = false; 6972 } 6973 6974 for ( i=0, ien=context.length ; i<ien ; i++ ) { 6975 var apiInst = new _Api( context[i] ); 6976 6977 if ( type === 'table' ) { 6978 ret = fn.call( apiInst, context[i], i ); 6979 6980 if ( ret !== undefined ) { 6981 a.push( ret ); 6982 } 6983 } 6984 else if ( type === 'columns' || type === 'rows' ) { 6985 // this has same length as context - one entry for each table 6986 ret = fn.call( apiInst, context[i], this[i], i ); 6987 6988 if ( ret !== undefined ) { 6989 a.push( ret ); 6990 } 6991 } 6992 else if ( type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) { 6993 // columns and rows share the same structure. 6994 // 'this' is an array of column indexes for each context 6995 items = this[i]; 6996 6997 if ( type === 'column-rows' ) { 6998 rows = _selector_row_indexes( context[i], selector.opts ); 6999 } 7000 7001 for ( j=0, jen=items.length ; j<jen ; j++ ) { 7002 item = items[j]; 7003 7004 if ( type === 'cell' ) { 7005 ret = fn.call( apiInst, context[i], item.row, item.column, i, j ); 7006 } 7007 else { 7008 ret = fn.call( apiInst, context[i], item, i, j, rows ); 7009 } 7010 7011 if ( ret !== undefined ) { 7012 a.push( ret ); 7013 } 7014 } 7015 } 7016 } 7017 7018 if ( a.length || alwaysNew ) { 7019 var api = new _Api( context, flatten ? a.concat.apply( [], a ) : a ); 7020 var apiSelector = api.selector; 7021 apiSelector.rows = selector.rows; 7022 apiSelector.cols = selector.cols; 7023 apiSelector.opts = selector.opts; 7024 return api; 7025 } 7026 return this; 7027 }, 7028 7029 7030 lastIndexOf: __arrayProto.lastIndexOf || function (obj, start) 7031 { 7032 // Bit cheeky... 7033 return this.indexOf.apply( this.toArray.reverse(), arguments ); 7034 }, 7035 7036 7037 length: 0, 7038 7039 7040 map: function ( fn ) 7041 { 7042 var a = []; 7043 7044 if ( __arrayProto.map ) { 7045 a = __arrayProto.map.call( this, fn, this ); 7046 } 7047 else { 7048 // Compatibility for browsers without EMCA-252-5 (JS 1.6) 7049 for ( var i=0, ien=this.length ; i<ien ; i++ ) { 7050 a.push( fn.call( this, this[i], i ) ); 7051 } 7052 } 7053 7054 return new _Api( this.context, a ); 7055 }, 7056 7057 7058 pluck: function ( prop ) 7059 { 7060 return this.map( function ( el ) { 7061 return el[ prop ]; 7062 } ); 7063 }, 7064 7065 pop: __arrayProto.pop, 7066 7067 7068 push: __arrayProto.push, 7069 7070 7071 // Does not return an API instance 7072 reduce: __arrayProto.reduce || function ( fn, init ) 7073 { 7074 return _fnReduce( this, fn, init, 0, this.length, 1 ); 7075 }, 7076 7077 7078 reduceRight: __arrayProto.reduceRight || function ( fn, init ) 7079 { 7080 return _fnReduce( this, fn, init, this.length-1, -1, -1 ); 7081 }, 7082 7083 7084 reverse: __arrayProto.reverse, 7085 7086 7087 // Object with rows, columns and opts 7088 selector: null, 7089 7090 7091 shift: __arrayProto.shift, 7092 7093 7094 sort: __arrayProto.sort, // ? name - order? 7095 7096 7097 splice: __arrayProto.splice, 7098 7099 7100 toArray: function () 7101 { 7102 return __arrayProto.slice.call( this ); 7103 }, 7104 7105 7106 to$: function () 7107 { 7108 return $( this ); 7109 }, 7110 7111 7112 toJQuery: function () 7113 { 7114 return $( this ); 7115 }, 7116 7117 7118 unique: function () 7119 { 7120 return new _Api( this.context, _unique(this) ); 7121 }, 7122 7123 7124 unshift: __arrayProto.unshift 7125 } ); 7126 7127 7128 _Api.extend = function ( scope, obj, ext ) 7129 { 7130 // Only extend API instances and static properties of the API 7131 if ( ! ext.length || ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) { 7132 return; 7133 } 7134 7135 var 7136 i, ien, 7137 j, jen, 7138 struct, inner, 7139 methodScoping = function ( scope, fn, struc ) { 7140 return function () { 7141 var ret = fn.apply( scope, arguments ); 7142 7143 // Method extension 7144 _Api.extend( ret, ret, struc.methodExt ); 7145 return ret; 7146 }; 7147 }; 7148 7149 for ( i=0, ien=ext.length ; i<ien ; i++ ) { 7150 struct = ext[i]; 7151 7152 // Value 7153 obj[ struct.name ] = typeof struct.val === 'function' ? 7154 methodScoping( scope, struct.val, struct ) : 7155 $.isPlainObject( struct.val ) ? 7156 {} : 7157 struct.val; 7158 7159 obj[ struct.name ].__dt_wrapper = true; 7160 7161 // Property extension 7162 _Api.extend( scope, obj[ struct.name ], struct.propExt ); 7163 } 7164 }; 7165 7166 7167 // @todo - Is there need for an augment function? 7168 // _Api.augment = function ( inst, name ) 7169 // { 7170 // // Find src object in the structure from the name 7171 // var parts = name.split('.'); 7172 7173 // _Api.extend( inst, obj ); 7174 // }; 7175 7176 7177 // [ 7178 // { 7179 // name: 'data' -- string - Property name 7180 // val: function () {}, -- function - Api method (or undefined if just an object 7181 // methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result 7182 // propExt: [ ... ] -- array - Array of Api object definitions to extend the property 7183 // }, 7184 // { 7185 // name: 'row' 7186 // val: {}, 7187 // methodExt: [ ... ], 7188 // propExt: [ 7189 // { 7190 // name: 'data' 7191 // val: function () {}, 7192 // methodExt: [ ... ], 7193 // propExt: [ ... ] 7194 // }, 7195 // ... 7196 // ] 7197 // } 7198 // ] 7199 7200 _Api.register = _api_register = function ( name, val ) 7201 { 7202 if ( $.isArray( name ) ) { 7203 for ( var j=0, jen=name.length ; j<jen ; j++ ) { 7204 _Api.register( name[j], val ); 7205 } 7206 return; 7207 } 7208 7209 var 7210 i, ien, 7211 heir = name.split('.'), 7212 struct = __apiStruct, 7213 key, method; 7214 7215 var find = function ( src, name ) { 7216 for ( var i=0, ien=src.length ; i<ien ; i++ ) { 7217 if ( src[i].name === name ) { 7218 return src[i]; 7219 } 7220 } 7221 return null; 7222 }; 7223 7224 for ( i=0, ien=heir.length ; i<ien ; i++ ) { 7225 method = heir[i].indexOf('()') !== -1; 7226 key = method ? 7227 heir[i].replace('()', '') : 7228 heir[i]; 7229 7230 var src = find( struct, key ); 7231 if ( ! src ) { 7232 src = { 7233 name: key, 7234 val: {}, 7235 methodExt: [], 7236 propExt: [] 7237 }; 7238 struct.push( src ); 7239 } 7240 7241 if ( i === ien-1 ) { 7242 src.val = val; 7243 } 7244 else { 7245 struct = method ? 7246 src.methodExt : 7247 src.propExt; 7248 } 7249 } 7250 }; 7251 7252 7253 _Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) { 7254 _Api.register( pluralName, val ); 7255 7256 _Api.register( singularName, function () { 7257 var ret = val.apply( this, arguments ); 7258 7259 if ( ret === this ) { 7260 // Returned item is the API instance that was passed in, return it 7261 return this; 7262 } 7263 else if ( ret instanceof _Api ) { 7264 // New API instance returned, want the value from the first item 7265 // in the returned array for the singular result. 7266 return ret.length ? 7267 $.isArray( ret[0] ) ? 7268 new _Api( ret.context, ret[0] ) : // Array results are 'enhanced' 7269 ret[0] : 7270 undefined; 7271 } 7272 7273 // Non-API return - just fire it back 7274 return ret; 7275 } ); 7276 }; 7277 7278 7279 /** 7280 * Selector for HTML tables. Apply the given selector to the give array of 7281 * DataTables settings objects. 7282 * 7283 * @param {string|integer} [selector] jQuery selector string or integer 7284 * @param {array} Array of DataTables settings objects to be filtered 7285 * @return {array} 7286 * @ignore 7287 */ 7288 var __table_selector = function ( selector, a ) 7289 { 7290 // Integer is used to pick out a table by index 7291 if ( typeof selector === 'number' ) { 7292 return [ a[ selector ] ]; 7293 } 7294 7295 // Perform a jQuery selector on the table nodes 7296 var nodes = $.map( a, function (el, i) { 7297 return el.nTable; 7298 } ); 7299 7300 return $(nodes) 7301 .filter( selector ) 7302 .map( function (i) { 7303 // Need to translate back from the table node to the settings 7304 var idx = $.inArray( this, nodes ); 7305 return a[ idx ]; 7306 } ) 7307 .toArray(); 7308 }; 7309 7310 7311 7312 /** 7313 * Context selector for the API's context (i.e. the tables the API instance 7314 * refers to. 7315 * 7316 * @name DataTable.Api#tables 7317 * @param {string|integer} [selector] Selector to pick which tables the iterator 7318 * should operate on. If not given, all tables in the current context are 7319 * used. This can be given as a jQuery selector (for example `':gt(0)'`) to 7320 * select multiple tables or as an integer to select a single table. 7321 * @returns {DataTable.Api} Returns a new API instance if a selector is given. 7322 */ 7323 _api_register( 'tables()', function ( selector ) { 7324 // A new instance is created if there was a selector specified 7325 return selector ? 7326 new _Api( __table_selector( selector, this.context ) ) : 7327 this; 7328 } ); 7329 7330 7331 _api_register( 'table()', function ( selector ) { 7332 var tables = this.tables( selector ); 7333 var ctx = tables.context; 7334 7335 // Truncate to the first matched table 7336 return ctx.length ? 7337 new _Api( ctx[0] ) : 7338 tables; 7339 } ); 7340 7341 7342 _api_registerPlural( 'tables().nodes()', 'table().node()' , function () { 7343 return this.iterator( 'table', function ( ctx ) { 7344 return ctx.nTable; 7345 }, 1 ); 7346 } ); 7347 7348 7349 _api_registerPlural( 'tables().body()', 'table().body()' , function () { 7350 return this.iterator( 'table', function ( ctx ) { 7351 return ctx.nTBody; 7352 }, 1 ); 7353 } ); 7354 7355 7356 _api_registerPlural( 'tables().header()', 'table().header()' , function () { 7357 return this.iterator( 'table', function ( ctx ) { 7358 return ctx.nTHead; 7359 }, 1 ); 7360 } ); 7361 7362 7363 _api_registerPlural( 'tables().footer()', 'table().footer()' , function () { 7364 return this.iterator( 'table', function ( ctx ) { 7365 return ctx.nTFoot; 7366 }, 1 ); 7367 } ); 7368 7369 7370 _api_registerPlural( 'tables().containers()', 'table().container()' , function () { 7371 return this.iterator( 'table', function ( ctx ) { 7372 return ctx.nTableWrapper; 7373 }, 1 ); 7374 } ); 7375 7376 7377 7378 /** 7379 * Redraw the tables in the current context. 7380 */ 7381 _api_register( 'draw()', function ( paging ) { 7382 return this.iterator( 'table', function ( settings ) { 7383 if ( paging === 'page' ) { 7384 _fnDraw( settings ); 7385 } 7386 else { 7387 if ( typeof paging === 'string' ) { 7388 paging = paging === 'full-hold' ? 7389 false : 7390 true; 7391 } 7392 7393 _fnReDraw( settings, paging===false ); 7394 } 7395 } ); 7396 } ); 7397 7398 7399 7400 /** 7401 * Get the current page index. 7402 * 7403 * @return {integer} Current page index (zero based) 7404 *//** 7405 * Set the current page. 7406 * 7407 * Note that if you attempt to show a page which does not exist, DataTables will 7408 * not throw an error, but rather reset the paging. 7409 * 7410 * @param {integer|string} action The paging action to take. This can be one of: 7411 * * `integer` - The page index to jump to 7412 * * `string` - An action to take: 7413 * * `first` - Jump to first page. 7414 * * `next` - Jump to the next page 7415 * * `previous` - Jump to previous page 7416 * * `last` - Jump to the last page. 7417 * @returns {DataTables.Api} this 7418 */ 7419 _api_register( 'page()', function ( action ) { 7420 if ( action === undefined ) { 7421 return this.page.info().page; // not an expensive call 7422 } 7423 7424 // else, have an action to take on all tables 7425 return this.iterator( 'table', function ( settings ) { 7426 _fnPageChange( settings, action ); 7427 } ); 7428 } ); 7429 7430 7431 /** 7432 * Paging information for the first table in the current context. 7433 * 7434 * If you require paging information for another table, use the `table()` method 7435 * with a suitable selector. 7436 * 7437 * @return {object} Object with the following properties set: 7438 * * `page` - Current page index (zero based - i.e. the first page is `0`) 7439 * * `pages` - Total number of pages 7440 * * `start` - Display index for the first record shown on the current page 7441 * * `end` - Display index for the last record shown on the current page 7442 * * `length` - Display length (number of records). Note that generally `start 7443 * + length = end`, but this is not always true, for example if there are 7444 * only 2 records to show on the final page, with a length of 10. 7445 * * `recordsTotal` - Full data set length 7446 * * `recordsDisplay` - Data set length once the current filtering criterion 7447 * are applied. 7448 */ 7449 _api_register( 'page.info()', function ( action ) { 7450 if ( this.context.length === 0 ) { 7451 return undefined; 7452 } 7453 7454 var 7455 settings = this.context[0], 7456 start = settings._iDisplayStart, 7457 len = settings.oFeatures.bPaginate ? settings._iDisplayLength : -1, 7458 visRecords = settings.fnRecordsDisplay(), 7459 all = len === -1; 7460 7461 return { 7462 "page": all ? 0 : Math.floor( start / len ), 7463 "pages": all ? 1 : Math.ceil( visRecords / len ), 7464 "start": start, 7465 "end": settings.fnDisplayEnd(), 7466 "length": len, 7467 "recordsTotal": settings.fnRecordsTotal(), 7468 "recordsDisplay": visRecords, 7469 "serverSide": _fnDataSource( settings ) === 'ssp' 7470 }; 7471 } ); 7472 7473 7474 /** 7475 * Get the current page length. 7476 * 7477 * @return {integer} Current page length. Note `-1` indicates that all records 7478 * are to be shown. 7479 *//** 7480 * Set the current page length. 7481 * 7482 * @param {integer} Page length to set. Use `-1` to show all records. 7483 * @returns {DataTables.Api} this 7484 */ 7485 _api_register( 'page.len()', function ( len ) { 7486 // Note that we can't call this function 'length()' because `length` 7487 // is a Javascript property of functions which defines how many arguments 7488 // the function expects. 7489 if ( len === undefined ) { 7490 return this.context.length !== 0 ? 7491 this.context[0]._iDisplayLength : 7492 undefined; 7493 } 7494 7495 // else, set the page length 7496 return this.iterator( 'table', function ( settings ) { 7497 _fnLengthChange( settings, len ); 7498 } ); 7499 } ); 7500 7501 7502 7503 var __reload = function ( settings, holdPosition, callback ) { 7504 // Use the draw event to trigger a callback 7505 if ( callback ) { 7506 var api = new _Api( settings ); 7507 7508 api.one( 'draw', function () { 7509 callback( api.ajax.json() ); 7510 } ); 7511 } 7512 7513 if ( _fnDataSource( settings ) == 'ssp' ) { 7514 _fnReDraw( settings, holdPosition ); 7515 } 7516 else { 7517 _fnProcessingDisplay( settings, true ); 7518 7519 // Cancel an existing request 7520 var xhr = settings.jqXHR; 7521 if ( xhr && xhr.readyState !== 4 ) { 7522 xhr.abort(); 7523 } 7524 7525 // Trigger xhr 7526 _fnBuildAjax( settings, [], function( json ) { 7527 _fnClearTable( settings ); 7528 7529 var data = _fnAjaxDataSrc( settings, json ); 7530 for ( var i=0, ien=data.length ; i<ien ; i++ ) { 7531 _fnAddData( settings, data[i] ); 7532 } 7533 7534 _fnReDraw( settings, holdPosition ); 7535 _fnProcessingDisplay( settings, false ); 7536 } ); 7537 } 7538 }; 7539 7540 7541 /** 7542 * Get the JSON response from the last Ajax request that DataTables made to the 7543 * server. Note that this returns the JSON from the first table in the current 7544 * context. 7545 * 7546 * @return {object} JSON received from the server. 7547 */ 7548 _api_register( 'ajax.json()', function () { 7549 var ctx = this.context; 7550 7551 if ( ctx.length > 0 ) { 7552 return ctx[0].json; 7553 } 7554 7555 // else return undefined; 7556 } ); 7557 7558 7559 /** 7560 * Get the data submitted in the last Ajax request 7561 */ 7562 _api_register( 'ajax.params()', function () { 7563 var ctx = this.context; 7564 7565 if ( ctx.length > 0 ) { 7566 return ctx[0].oAjaxData; 7567 } 7568 7569 // else return undefined; 7570 } ); 7571 7572 7573 /** 7574 * Reload tables from the Ajax data source. Note that this function will 7575 * automatically re-draw the table when the remote data has been loaded. 7576 * 7577 * @param {boolean} [reset=true] Reset (default) or hold the current paging 7578 * position. A full re-sort and re-filter is performed when this method is 7579 * called, which is why the pagination reset is the default action. 7580 * @returns {DataTables.Api} this 7581 */ 7582 _api_register( 'ajax.reload()', function ( callback, resetPaging ) { 7583 return this.iterator( 'table', function (settings) { 7584 __reload( settings, resetPaging===false, callback ); 7585 } ); 7586 } ); 7587 7588 7589 /** 7590 * Get the current Ajax URL. Note that this returns the URL from the first 7591 * table in the current context. 7592 * 7593 * @return {string} Current Ajax source URL 7594 *//** 7595 * Set the Ajax URL. Note that this will set the URL for all tables in the 7596 * current context. 7597 * 7598 * @param {string} url URL to set. 7599 * @returns {DataTables.Api} this 7600 */ 7601 _api_register( 'ajax.url()', function ( url ) { 7602 var ctx = this.context; 7603 7604 if ( url === undefined ) { 7605 // get 7606 if ( ctx.length === 0 ) { 7607 return undefined; 7608 } 7609 ctx = ctx[0]; 7610 7611 return ctx.ajax ? 7612 $.isPlainObject( ctx.ajax ) ? 7613 ctx.ajax.url : 7614 ctx.ajax : 7615 ctx.sAjaxSource; 7616 } 7617 7618 // set 7619 return this.iterator( 'table', function ( settings ) { 7620 if ( $.isPlainObject( settings.ajax ) ) { 7621 settings.ajax.url = url; 7622 } 7623 else { 7624 settings.ajax = url; 7625 } 7626 // No need to consider sAjaxSource here since DataTables gives priority 7627 // to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any 7628 // value of `sAjaxSource` redundant. 7629 } ); 7630 } ); 7631 7632 7633 /** 7634 * Load data from the newly set Ajax URL. Note that this method is only 7635 * available when `ajax.url()` is used to set a URL. Additionally, this method 7636 * has the same effect as calling `ajax.reload()` but is provided for 7637 * convenience when setting a new URL. Like `ajax.reload()` it will 7638 * automatically redraw the table once the remote data has been loaded. 7639 * 7640 * @returns {DataTables.Api} this 7641 */ 7642 _api_register( 'ajax.url().load()', function ( callback, resetPaging ) { 7643 // Same as a reload, but makes sense to present it for easy access after a 7644 // url change 7645 return this.iterator( 'table', function ( ctx ) { 7646 __reload( ctx, resetPaging===false, callback ); 7647 } ); 7648 } ); 7649 7650 7651 7652 7653 var _selector_run = function ( type, selector, selectFn, settings, opts ) 7654 { 7655 var 7656 out = [], res, 7657 a, i, ien, j, jen, 7658 selectorType = typeof selector; 7659 7660 // Can't just check for isArray here, as an API or jQuery instance might be 7661 // given with their array like look 7662 if ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) { 7663 selector = [ selector ]; 7664 } 7665 7666 for ( i=0, ien=selector.length ; i<ien ; i++ ) { 7667 a = selector[i] && selector[i].split ? 7668 selector[i].split(',') : 7669 [ selector[i] ]; 7670 7671 for ( j=0, jen=a.length ; j<jen ; j++ ) { 7672 res = selectFn( typeof a[j] === 'string' ? $.trim(a[j]) : a[j] ); 7673 7674 if ( res && res.length ) { 7675 out = out.concat( res ); 7676 } 7677 } 7678 } 7679 7680 // selector extensions 7681 var ext = _ext.selector[ type ]; 7682 if ( ext.length ) { 7683 for ( i=0, ien=ext.length ; i<ien ; i++ ) { 7684 out = ext[i]( settings, opts, out ); 7685 } 7686 } 7687 7688 return _unique( out ); 7689 }; 7690 7691 7692 var _selector_opts = function ( opts ) 7693 { 7694 if ( ! opts ) { 7695 opts = {}; 7696 } 7697 7698 // Backwards compatibility for 1.9- which used the terminology filter rather 7699 // than search 7700 if ( opts.filter && opts.search === undefined ) { 7701 opts.search = opts.filter; 7702 } 7703 7704 return $.extend( { 7705 search: 'none', 7706 order: 'current', 7707 page: 'all' 7708 }, opts ); 7709 }; 7710 7711 7712 var _selector_first = function ( inst ) 7713 { 7714 // Reduce the API instance to the first item found 7715 for ( var i=0, ien=inst.length ; i<ien ; i++ ) { 7716 if ( inst[i].length > 0 ) { 7717 // Assign the first element to the first item in the instance 7718 // and truncate the instance and context 7719 inst[0] = inst[i]; 7720 inst[0].length = 1; 7721 inst.length = 1; 7722 inst.context = [ inst.context[i] ]; 7723 7724 return inst; 7725 } 7726 } 7727 7728 // Not found - return an empty instance 7729 inst.length = 0; 7730 return inst; 7731 }; 7732 7733 7734 var _selector_row_indexes = function ( settings, opts ) 7735 { 7736 var 7737 i, ien, tmp, a=[], 7738 displayFiltered = settings.aiDisplay, 7739 displayMaster = settings.aiDisplayMaster; 7740 7741 var 7742 search = opts.search, // none, applied, removed 7743 order = opts.order, // applied, current, index (original - compatibility with 1.9) 7744 page = opts.page; // all, current 7745 7746 if ( _fnDataSource( settings ) == 'ssp' ) { 7747 // In server-side processing mode, most options are irrelevant since 7748 // rows not shown don't exist and the index order is the applied order 7749 // Removed is a special case - for consistency just return an empty 7750 // array 7751 return search === 'removed' ? 7752 [] : 7753 _range( 0, displayMaster.length ); 7754 } 7755 else if ( page == 'current' ) { 7756 // Current page implies that order=current and fitler=applied, since it is 7757 // fairly senseless otherwise, regardless of what order and search actually 7758 // are 7759 for ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) { 7760 a.push( displayFiltered[i] ); 7761 } 7762 } 7763 else if ( order == 'current' || order == 'applied' ) { 7764 a = search == 'none' ? 7765 displayMaster.slice() : // no search 7766 search == 'applied' ? 7767 displayFiltered.slice() : // applied search 7768 $.map( displayMaster, function (el, i) { // removed search 7769 return $.inArray( el, displayFiltered ) === -1 ? el : null; 7770 } ); 7771 } 7772 else if ( order == 'index' || order == 'original' ) { 7773 for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) { 7774 if ( search == 'none' ) { 7775 a.push( i ); 7776 } 7777 else { // applied | removed 7778 tmp = $.inArray( i, displayFiltered ); 7779 7780 if ((tmp === -1 && search == 'removed') || 7781 (tmp >= 0 && search == 'applied') ) 7782 { 7783 a.push( i ); 7784 } 7785 } 7786 } 7787 } 7788 7789 return a; 7790 }; 7791 7792 7793 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 7794 * Rows 7795 * 7796 * {} - no selector - use all available rows 7797 * {integer} - row aoData index 7798 * {node} - TR node 7799 * {string} - jQuery selector to apply to the TR elements 7800 * {array} - jQuery array of nodes, or simply an array of TR nodes 7801 * 7802 */ 7803 7804 7805 var __row_selector = function ( settings, selector, opts ) 7806 { 7807 var run = function ( sel ) { 7808 var selInt = _intVal( sel ); 7809 var i, ien; 7810 7811 // Short cut - selector is a number and no options provided (default is 7812 // all records, so no need to check if the index is in there, since it 7813 // must be - dev error if the index doesn't exist). 7814 if ( selInt !== null && ! opts ) { 7815 return [ selInt ]; 7816 } 7817 7818 var rows = _selector_row_indexes( settings, opts ); 7819 7820 if ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) { 7821 // Selector - integer 7822 return [ selInt ]; 7823 } 7824 else if ( ! sel ) { 7825 // Selector - none 7826 return rows; 7827 } 7828 7829 // Selector - function 7830 if ( typeof sel === 'function' ) { 7831 return $.map( rows, function (idx) { 7832 var row = settings.aoData[ idx ]; 7833 return sel( idx, row._aData, row.nTr ) ? idx : null; 7834 } ); 7835 } 7836 7837 // Get nodes in the order from the `rows` array with null values removed 7838 var nodes = _removeEmpty( 7839 _pluck_order( settings.aoData, rows, 'nTr' ) 7840 ); 7841 7842 // Selector - node 7843 if ( sel.nodeName ) { 7844 if ( sel._DT_RowIndex !== undefined ) { 7845 return [ sel._DT_RowIndex ]; // Property added by DT for fast lookup 7846 } 7847 else if ( sel._DT_CellIndex ) { 7848 return [ sel._DT_CellIndex.row ]; 7849 } 7850 else { 7851 var host = $(sel).closest('*[data-dt-row]'); 7852 return host.length ? 7853 [ host.data('dt-row') ] : 7854 []; 7855 } 7856 } 7857 7858 // ID selector. Want to always be able to select rows by id, regardless 7859 // of if the tr element has been created or not, so can't rely upon 7860 // jQuery here - hence a custom implementation. This does not match 7861 // Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything, 7862 // but to select it using a CSS selector engine (like Sizzle or 7863 // querySelect) it would need to need to be escaped for some characters. 7864 // DataTables simplifies this for row selectors since you can select 7865 // only a row. A # indicates an id any anything that follows is the id - 7866 // unescaped. 7867 if ( typeof sel === 'string' && sel.charAt(0) === '#' ) { 7868 // get row index from id 7869 var rowObj = settings.aIds[ sel.replace( /^#/, '' ) ]; 7870 if ( rowObj !== undefined ) { 7871 return [ rowObj.idx ]; 7872 } 7873 7874 // need to fall through to jQuery in case there is DOM id that 7875 // matches 7876 } 7877 7878 // Selector - jQuery selector string, array of nodes or jQuery object/ 7879 // As jQuery's .filter() allows jQuery objects to be passed in filter, 7880 // it also allows arrays, so this will cope with all three options 7881 return $(nodes) 7882 .filter( sel ) 7883 .map( function () { 7884 return this._DT_RowIndex; 7885 } ) 7886 .toArray(); 7887 }; 7888 7889 return _selector_run( 'row', selector, run, settings, opts ); 7890 }; 7891 7892 7893 _api_register( 'rows()', function ( selector, opts ) { 7894 // argument shifting 7895 if ( selector === undefined ) { 7896 selector = ''; 7897 } 7898 else if ( $.isPlainObject( selector ) ) { 7899 opts = selector; 7900 selector = ''; 7901 } 7902 7903 opts = _selector_opts( opts ); 7904 7905 var inst = this.iterator( 'table', function ( settings ) { 7906 return __row_selector( settings, selector, opts ); 7907 }, 1 ); 7908 7909 // Want argument shifting here and in __row_selector? 7910 inst.selector.rows = selector; 7911 inst.selector.opts = opts; 7912 7913 return inst; 7914 } ); 7915 7916 _api_register( 'rows().nodes()', function () { 7917 return this.iterator( 'row', function ( settings, row ) { 7918 return settings.aoData[ row ].nTr || undefined; 7919 }, 1 ); 7920 } ); 7921 7922 _api_register( 'rows().data()', function () { 7923 return this.iterator( true, 'rows', function ( settings, rows ) { 7924 return _pluck_order( settings.aoData, rows, '_aData' ); 7925 }, 1 ); 7926 } ); 7927 7928 _api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) { 7929 return this.iterator( 'row', function ( settings, row ) { 7930 var r = settings.aoData[ row ]; 7931 return type === 'search' ? r._aFilterData : r._aSortData; 7932 }, 1 ); 7933 } ); 7934 7935 _api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) { 7936 return this.iterator( 'row', function ( settings, row ) { 7937 _fnInvalidate( settings, row, src ); 7938 } ); 7939 } ); 7940 7941 _api_registerPlural( 'rows().indexes()', 'row().index()', function () { 7942 return this.iterator( 'row', function ( settings, row ) { 7943 return row; 7944 }, 1 ); 7945 } ); 7946 7947 _api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) { 7948 var a = []; 7949 var context = this.context; 7950 7951 // `iterator` will drop undefined values, but in this case we want them 7952 for ( var i=0, ien=context.length ; i<ien ; i++ ) { 7953 for ( var j=0, jen=this[i].length ; j<jen ; j++ ) { 7954 var id = context[i].rowIdFn( context[i].aoData[ this[i][j] ]._aData ); 7955 a.push( (hash === true ? '#' : '' )+ id ); 7956 } 7957 } 7958 7959 return new _Api( context, a ); 7960 } ); 7961 7962 _api_registerPlural( 'rows().remove()', 'row().remove()', function () { 7963 var that = this; 7964 7965 this.iterator( 'row', function ( settings, row, thatIdx ) { 7966 var data = settings.aoData; 7967 var rowData = data[ row ]; 7968 var i, ien, j, jen; 7969 var loopRow, loopCells; 7970 7971 data.splice( row, 1 ); 7972 7973 // Update the cached indexes 7974 for ( i=0, ien=data.length ; i<ien ; i++ ) { 7975 loopRow = data[i]; 7976 loopCells = loopRow.anCells; 7977 7978 // Rows 7979 if ( loopRow.nTr !== null ) { 7980 loopRow.nTr._DT_RowIndex = i; 7981 } 7982 7983 // Cells 7984 if ( loopCells !== null ) { 7985 for ( j=0, jen=loopCells.length ; j<jen ; j++ ) { 7986 loopCells[j]._DT_CellIndex.row = i; 7987 } 7988 } 7989 } 7990 7991 // Delete from the display arrays 7992 _fnDeleteIndex( settings.aiDisplayMaster, row ); 7993 _fnDeleteIndex( settings.aiDisplay, row ); 7994 _fnDeleteIndex( that[ thatIdx ], row, false ); // maintain local indexes 7995 7996 // Check for an 'overflow' they case for displaying the table 7997 _fnLengthOverflow( settings ); 7998 7999 // Remove the row's ID reference if there is one 8000 var id = settings.rowIdFn( rowData._aData ); 8001 if ( id !== undefined ) { 8002 delete settings.aIds[ id ]; 8003 } 8004 } ); 8005 8006 this.iterator( 'table', function ( settings ) { 8007 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) { 8008 settings.aoData[i].idx = i; 8009 } 8010 } ); 8011 8012 return this; 8013 } ); 8014 8015 8016 _api_register( 'rows.add()', function ( rows ) { 8017 var newRows = this.iterator( 'table', function ( settings ) { 8018 var row, i, ien; 8019 var out = []; 8020 8021 for ( i=0, ien=rows.length ; i<ien ; i++ ) { 8022 row = rows[i]; 8023 8024 if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) { 8025 out.push( _fnAddTr( settings, row )[0] ); 8026 } 8027 else { 8028 out.push( _fnAddData( settings, row ) ); 8029 } 8030 } 8031 8032 return out; 8033 }, 1 ); 8034 8035 // Return an Api.rows() extended instance, so rows().nodes() etc can be used 8036 var modRows = this.rows( -1 ); 8037 modRows.pop(); 8038 $.merge( modRows, newRows ); 8039 8040 return modRows; 8041 } ); 8042 8043 8044 8045 8046 8047 /** 8048 * 8049 */ 8050 _api_register( 'row()', function ( selector, opts ) { 8051 return _selector_first( this.rows( selector, opts ) ); 8052 } ); 8053 8054 8055 _api_register( 'row().data()', function ( data ) { 8056 var ctx = this.context; 8057 8058 if ( data === undefined ) { 8059 // Get 8060 return ctx.length && this.length ? 8061 ctx[0].aoData[ this[0] ]._aData : 8062 undefined; 8063 } 8064 8065 // Set 8066 ctx[0].aoData[ this[0] ]._aData = data; 8067 8068 // Automatically invalidate 8069 _fnInvalidate( ctx[0], this[0], 'data' ); 8070 8071 return this; 8072 } ); 8073 8074 8075 _api_register( 'row().node()', function () { 8076 var ctx = this.context; 8077 8078 return ctx.length && this.length ? 8079 ctx[0].aoData[ this[0] ].nTr || null : 8080 null; 8081 } ); 8082 8083 8084 _api_register( 'row.add()', function ( row ) { 8085 // Allow a jQuery object to be passed in - only a single row is added from 8086 // it though - the first element in the set 8087 if ( row instanceof $ && row.length ) { 8088 row = row[0]; 8089 } 8090 8091 var rows = this.iterator( 'table', function ( settings ) { 8092 if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) { 8093 return _fnAddTr( settings, row )[0]; 8094 } 8095 return _fnAddData( settings, row ); 8096 } ); 8097 8098 // Return an Api.rows() extended instance, with the newly added row selected 8099 return this.row( rows[0] ); 8100 } ); 8101 8102 8103 8104 var __details_add = function ( ctx, row, data, klass ) 8105 { 8106 // Convert to array of TR elements 8107 var rows = []; 8108 var addRow = function ( r, k ) { 8109 // Recursion to allow for arrays of jQuery objects 8110 if ( $.isArray( r ) || r instanceof $ ) { 8111 for ( var i=0, ien=r.length ; i<ien ; i++ ) { 8112 addRow( r[i], k ); 8113 } 8114 return; 8115 } 8116 8117 // If we get a TR element, then just add it directly - up to the dev 8118 // to add the correct number of columns etc 8119 if ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) { 8120 rows.push( r ); 8121 } 8122 else { 8123 // Otherwise create a row with a wrapper 8124 var created = $('<tr><td/></tr>').addClass( k ); 8125 $('td', created) 8126 .addClass( k ) 8127 .html( r ) 8128 [0].colSpan = _fnVisbleColumns( ctx ); 8129 8130 rows.push( created[0] ); 8131 } 8132 }; 8133 8134 addRow( data, klass ); 8135 8136 if ( row._details ) { 8137 row._details.remove(); 8138 } 8139 8140 row._details = $(rows); 8141 8142 // If the children were already shown, that state should be retained 8143 if ( row._detailsShow ) { 8144 row._details.insertAfter( row.nTr ); 8145 } 8146 }; 8147 8148 8149 var __details_remove = function ( api, idx ) 8150 { 8151 var ctx = api.context; 8152 8153 if ( ctx.length ) { 8154 var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ]; 8155 8156 if ( row && row._details ) { 8157 row._details.remove(); 8158 8159 row._detailsShow = undefined; 8160 row._details = undefined; 8161 } 8162 } 8163 }; 8164 8165 8166 var __details_display = function ( api, show ) { 8167 var ctx = api.context; 8168 8169 if ( ctx.length && api.length ) { 8170 var row = ctx[0].aoData[ api[0] ]; 8171 8172 if ( row._details ) { 8173 row._detailsShow = show; 8174 8175 if ( show ) { 8176 row._details.insertAfter( row.nTr ); 8177 } 8178 else { 8179 row._details.detach(); 8180 } 8181 8182 __details_events( ctx[0] ); 8183 } 8184 } 8185 }; 8186 8187 8188 var __details_events = function ( settings ) 8189 { 8190 var api = new _Api( settings ); 8191 var namespace = '.dt.DT_details'; 8192 var drawEvent = 'draw'+namespace; 8193 var colvisEvent = 'column-visibility'+namespace; 8194 var destroyEvent = 'destroy'+namespace; 8195 var data = settings.aoData; 8196 8197 api.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent ); 8198 8199 if ( _pluck( data, '_details' ).length > 0 ) { 8200 // On each draw, insert the required elements into the document 8201 api.on( drawEvent, function ( e, ctx ) { 8202 if ( settings !== ctx ) { 8203 return; 8204 } 8205 8206 api.rows( {page:'current'} ).eq(0).each( function (idx) { 8207 // Internal data grab 8208 var row = data[ idx ]; 8209 8210 if ( row._detailsShow ) { 8211 row._details.insertAfter( row.nTr ); 8212 } 8213 } ); 8214 } ); 8215 8216 // Column visibility change - update the colspan 8217 api.on( colvisEvent, function ( e, ctx, idx, vis ) { 8218 if ( settings !== ctx ) { 8219 return; 8220 } 8221 8222 // Update the colspan for the details rows (note, only if it already has 8223 // a colspan) 8224 var row, visible = _fnVisbleColumns( ctx ); 8225 8226 for ( var i=0, ien=data.length ; i<ien ; i++ ) { 8227 row = data[i]; 8228 8229 if ( row._details ) { 8230 row._details.children('td[colspan]').attr('colspan', visible ); 8231 } 8232 } 8233 } ); 8234 8235 // Table destroyed - nuke any child rows 8236 api.on( destroyEvent, function ( e, ctx ) { 8237 if ( settings !== ctx ) { 8238 return; 8239 } 8240 8241 for ( var i=0, ien=data.length ; i<ien ; i++ ) { 8242 if ( data[i]._details ) { 8243 __details_remove( api, i ); 8244 } 8245 } 8246 } ); 8247 } 8248 }; 8249 8250 // Strings for the method names to help minification 8251 var _emp = ''; 8252 var _child_obj = _emp+'row().child'; 8253 var _child_mth = _child_obj+'()'; 8254 8255 // data can be: 8256 // tr 8257 // string 8258 // jQuery or array of any of the above 8259 _api_register( _child_mth, function ( data, klass ) { 8260 var ctx = this.context; 8261 8262 if ( data === undefined ) { 8263 // get 8264 return ctx.length && this.length ? 8265 ctx[0].aoData[ this[0] ]._details : 8266 undefined; 8267 } 8268 else if ( data === true ) { 8269 // show 8270 this.child.show(); 8271 } 8272 else if ( data === false ) { 8273 // remove 8274 __details_remove( this ); 8275 } 8276 else if ( ctx.length && this.length ) { 8277 // set 8278 __details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass ); 8279 } 8280 8281 return this; 8282 } ); 8283 8284 8285 _api_register( [ 8286 _child_obj+'.show()', 8287 _child_mth+'.show()' // only when `child()` was called with parameters (without 8288 ], function ( show ) { // it returns an object and this method is not executed) 8289 __details_display( this, true ); 8290 return this; 8291 } ); 8292 8293 8294 _api_register( [ 8295 _child_obj+'.hide()', 8296 _child_mth+'.hide()' // only when `child()` was called with parameters (without 8297 ], function () { // it returns an object and this method is not executed) 8298 __details_display( this, false ); 8299 return this; 8300 } ); 8301 8302 8303 _api_register( [ 8304 _child_obj+'.remove()', 8305 _child_mth+'.remove()' // only when `child()` was called with parameters (without 8306 ], function () { // it returns an object and this method is not executed) 8307 __details_remove( this ); 8308 return this; 8309 } ); 8310 8311 8312 _api_register( _child_obj+'.isShown()', function () { 8313 var ctx = this.context; 8314 8315 if ( ctx.length && this.length ) { 8316 // _detailsShown as false or undefined will fall through to return false 8317 return ctx[0].aoData[ this[0] ]._detailsShow || false; 8318 } 8319 return false; 8320 } ); 8321 8322 8323 8324 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 8325 * Columns 8326 * 8327 * {integer} - column index (>=0 count from left, <0 count from right) 8328 * "{integer}:visIdx" - visible column index (i.e. translate to column index) (>=0 count from left, <0 count from right) 8329 * "{integer}:visible" - alias for {integer}:visIdx (>=0 count from left, <0 count from right) 8330 * "{string}:name" - column name 8331 * "{string}" - jQuery selector on column header nodes 8332 * 8333 */ 8334 8335 // can be an array of these items, comma separated list, or an array of comma 8336 // separated lists 8337 8338 var __re_column_selector = /^(.+):(name|visIdx|visible)$/; 8339 8340 8341 // r1 and r2 are redundant - but it means that the parameters match for the 8342 // iterator callback in columns().data() 8343 var __columnData = function ( settings, column, r1, r2, rows ) { 8344 var a = []; 8345 for ( var row=0, ien=rows.length ; row<ien ; row++ ) { 8346 a.push( _fnGetCellData( settings, rows[row], column ) ); 8347 } 8348 return a; 8349 }; 8350 8351 8352 var __column_selector = function ( settings, selector, opts ) 8353 { 8354 var 8355 columns = settings.aoColumns, 8356 names = _pluck( columns, 'sName' ), 8357 nodes = _pluck( columns, 'nTh' ); 8358 8359 var run = function ( s ) { 8360 var selInt = _intVal( s ); 8361 8362 // Selector - all 8363 if ( s === '' ) { 8364 return _range( columns.length ); 8365 } 8366 8367 // Selector - index 8368 if ( selInt !== null ) { 8369 return [ selInt >= 0 ? 8370 selInt : // Count from left 8371 columns.length + selInt // Count from right (+ because its a negative value) 8372 ]; 8373 } 8374 8375 // Selector = function 8376 if ( typeof s === 'function' ) { 8377 var rows = _selector_row_indexes( settings, opts ); 8378 8379 return $.map( columns, function (col, idx) { 8380 return s( 8381 idx, 8382 __columnData( settings, idx, 0, 0, rows ), 8383 nodes[ idx ] 8384 ) ? idx : null; 8385 } ); 8386 } 8387 8388 // jQuery or string selector 8389 var match = typeof s === 'string' ? 8390 s.match( __re_column_selector ) : 8391 ''; 8392 8393 if ( match ) { 8394 switch( match[2] ) { 8395 case 'visIdx': 8396 case 'visible': 8397 var idx = parseInt( match[1], 10 ); 8398 // Visible index given, convert to column index 8399 if ( idx < 0 ) { 8400 // Counting from the right 8401 var visColumns = $.map( columns, function (col,i) { 8402 return col.bVisible ? i : null; 8403 } ); 8404 return [ visColumns[ visColumns.length + idx ] ]; 8405 } 8406 // Counting from the left 8407 return [ _fnVisibleToColumnIndex( settings, idx ) ]; 8408 8409 case 'name': 8410 // match by name. `names` is column index complete and in order 8411 return $.map( names, function (name, i) { 8412 return name === match[1] ? i : null; 8413 } ); 8414 8415 default: 8416 return []; 8417 } 8418 } 8419 8420 // Cell in the table body 8421 if ( s.nodeName && s._DT_CellIndex ) { 8422 return [ s._DT_CellIndex.column ]; 8423 } 8424 8425 // jQuery selector on the TH elements for the columns 8426 var jqResult = $( nodes ) 8427 .filter( s ) 8428 .map( function () { 8429 return $.inArray( this, nodes ); // `nodes` is column index complete and in order 8430 } ) 8431 .toArray(); 8432 8433 if ( jqResult.length || ! s.nodeName ) { 8434 return jqResult; 8435 } 8436 8437 // Otherwise a node which might have a `dt-column` data attribute, or be 8438 // a child or such an element 8439 var host = $(s).closest('*[data-dt-column]'); 8440 return host.length ? 8441 [ host.data('dt-column') ] : 8442 []; 8443 }; 8444 8445 return _selector_run( 'column', selector, run, settings, opts ); 8446 }; 8447 8448 8449 var __setColumnVis = function ( settings, column, vis ) { 8450 var 8451 cols = settings.aoColumns, 8452 col = cols[ column ], 8453 data = settings.aoData, 8454 row, cells, i, ien, tr; 8455 8456 // Get 8457 if ( vis === undefined ) { 8458 return col.bVisible; 8459 } 8460 8461 // Set 8462 // No change 8463 if ( col.bVisible === vis ) { 8464 return; 8465 } 8466 8467 if ( vis ) { 8468 // Insert column 8469 // Need to decide if we should use appendChild or insertBefore 8470 var insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 ); 8471 8472 for ( i=0, ien=data.length ; i<ien ; i++ ) { 8473 tr = data[i].nTr; 8474 cells = data[i].anCells; 8475 8476 if ( tr ) { 8477 // insertBefore can act like appendChild if 2nd arg is null 8478 tr.insertBefore( cells[ column ], cells[ insertBefore ] || null ); 8479 } 8480 } 8481 } 8482 else { 8483 // Remove column 8484 $( _pluck( settings.aoData, 'anCells', column ) ).detach(); 8485 } 8486 8487 // Common actions 8488 col.bVisible = vis; 8489 _fnDrawHead( settings, settings.aoHeader ); 8490 _fnDrawHead( settings, settings.aoFooter ); 8491 8492 _fnSaveState( settings ); 8493 }; 8494 8495 8496 _api_register( 'columns()', function ( selector, opts ) { 8497 // argument shifting 8498 if ( selector === undefined ) { 8499 selector = ''; 8500 } 8501 else if ( $.isPlainObject( selector ) ) { 8502 opts = selector; 8503 selector = ''; 8504 } 8505 8506 opts = _selector_opts( opts ); 8507 8508 var inst = this.iterator( 'table', function ( settings ) { 8509 return __column_selector( settings, selector, opts ); 8510 }, 1 ); 8511 8512 // Want argument shifting here and in _row_selector? 8513 inst.selector.cols = selector; 8514 inst.selector.opts = opts; 8515 8516 return inst; 8517 } ); 8518 8519 _api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) { 8520 return this.iterator( 'column', function ( settings, column ) { 8521 return settings.aoColumns[column].nTh; 8522 }, 1 ); 8523 } ); 8524 8525 _api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) { 8526 return this.iterator( 'column', function ( settings, column ) { 8527 return settings.aoColumns[column].nTf; 8528 }, 1 ); 8529 } ); 8530 8531 _api_registerPlural( 'columns().data()', 'column().data()', function () { 8532 return this.iterator( 'column-rows', __columnData, 1 ); 8533 } ); 8534 8535 _api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () { 8536 return this.iterator( 'column', function ( settings, column ) { 8537 return settings.aoColumns[column].mData; 8538 }, 1 ); 8539 } ); 8540 8541 _api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) { 8542 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) { 8543 return _pluck_order( settings.aoData, rows, 8544 type === 'search' ? '_aFilterData' : '_aSortData', column 8545 ); 8546 }, 1 ); 8547 } ); 8548 8549 _api_registerPlural( 'columns().nodes()', 'column().nodes()', function () { 8550 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) { 8551 return _pluck_order( settings.aoData, rows, 'anCells', column ) ; 8552 }, 1 ); 8553 } ); 8554 8555 _api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) { 8556 var ret = this.iterator( 'column', function ( settings, column ) { 8557 if ( vis === undefined ) { 8558 return settings.aoColumns[ column ].bVisible; 8559 } // else 8560 __setColumnVis( settings, column, vis ); 8561 } ); 8562 8563 // Group the column visibility changes 8564 if ( vis !== undefined ) { 8565 // Second loop once the first is done for events 8566 this.iterator( 'column', function ( settings, column ) { 8567 _fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis, calc] ); 8568 } ); 8569 8570 if ( calc === undefined || calc ) { 8571 this.columns.adjust(); 8572 } 8573 } 8574 8575 return ret; 8576 } ); 8577 8578 _api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) { 8579 return this.iterator( 'column', function ( settings, column ) { 8580 return type === 'visible' ? 8581 _fnColumnIndexToVisible( settings, column ) : 8582 column; 8583 }, 1 ); 8584 } ); 8585 8586 _api_register( 'columns.adjust()', function () { 8587 return this.iterator( 'table', function ( settings ) { 8588 _fnAdjustColumnSizing( settings ); 8589 }, 1 ); 8590 } ); 8591 8592 _api_register( 'column.index()', function ( type, idx ) { 8593 if ( this.context.length !== 0 ) { 8594 var ctx = this.context[0]; 8595 8596 if ( type === 'fromVisible' || type === 'toData' ) { 8597 return _fnVisibleToColumnIndex( ctx, idx ); 8598 } 8599 else if ( type === 'fromData' || type === 'toVisible' ) { 8600 return _fnColumnIndexToVisible( ctx, idx ); 8601 } 8602 } 8603 } ); 8604 8605 _api_register( 'column()', function ( selector, opts ) { 8606 return _selector_first( this.columns( selector, opts ) ); 8607 } ); 8608 8609 8610 8611 var __cell_selector = function ( settings, selector, opts ) 8612 { 8613 var data = settings.aoData; 8614 var rows = _selector_row_indexes( settings, opts ); 8615 var cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) ); 8616 var allCells = $( [].concat.apply([], cells) ); 8617 var row; 8618 var columns = settings.aoColumns.length; 8619 var a, i, ien, j, o, host; 8620 8621 var run = function ( s ) { 8622 var fnSelector = typeof s === 'function'; 8623 8624 if ( s === null || s === undefined || fnSelector ) { 8625 // All cells and function selectors 8626 a = []; 8627 8628 for ( i=0, ien=rows.length ; i<ien ; i++ ) { 8629 row = rows[i]; 8630 8631 for ( j=0 ; j<columns ; j++ ) { 8632 o = { 8633 row: row, 8634 column: j 8635 }; 8636 8637 if ( fnSelector ) { 8638 // Selector - function 8639 host = data[ row ]; 8640 8641 if ( s( o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null ) ) { 8642 a.push( o ); 8643 } 8644 } 8645 else { 8646 // Selector - all 8647 a.push( o ); 8648 } 8649 } 8650 } 8651 8652 return a; 8653 } 8654 8655 // Selector - index 8656 if ( $.isPlainObject( s ) ) { 8657 return [s]; 8658 } 8659 8660 // Selector - jQuery filtered cells 8661 var jqResult = allCells 8662 .filter( s ) 8663 .map( function (i, el) { 8664 return { // use a new object, in case someone changes the values 8665 row: el._DT_CellIndex.row, 8666 column: el._DT_CellIndex.column 8667 }; 8668 } ) 8669 .toArray(); 8670 8671 if ( jqResult.length || ! s.nodeName ) { 8672 return jqResult; 8673 } 8674 8675 // Otherwise the selector is a node, and there is one last option - the 8676 // element might be a child of an element which has dt-row and dt-column 8677 // data attributes 8678 host = $(s).closest('*[data-dt-row]'); 8679 return host.length ? 8680 [ { 8681 row: host.data('dt-row'), 8682 column: host.data('dt-column') 8683 } ] : 8684 []; 8685 }; 8686 8687 return _selector_run( 'cell', selector, run, settings, opts ); 8688 }; 8689 8690 8691 8692 8693 _api_register( 'cells()', function ( rowSelector, columnSelector, opts ) { 8694 // Argument shifting 8695 if ( $.isPlainObject( rowSelector ) ) { 8696 // Indexes 8697 if ( rowSelector.row === undefined ) { 8698 // Selector options in first parameter 8699 opts = rowSelector; 8700 rowSelector = null; 8701 } 8702 else { 8703 // Cell index objects in first parameter 8704 opts = columnSelector; 8705 columnSelector = null; 8706 } 8707 } 8708 if ( $.isPlainObject( columnSelector ) ) { 8709 opts = columnSelector; 8710 columnSelector = null; 8711 } 8712 8713 // Cell selector 8714 if ( columnSelector === null || columnSelector === undefined ) { 8715 return this.iterator( 'table', function ( settings ) { 8716 return __cell_selector( settings, rowSelector, _selector_opts( opts ) ); 8717 } ); 8718 } 8719 8720 // Row + column selector 8721 var columns = this.columns( columnSelector, opts ); 8722 var rows = this.rows( rowSelector, opts ); 8723 var a, i, ien, j, jen; 8724 8725 var cells = this.iterator( 'table', function ( settings, idx ) { 8726 a = []; 8727 8728 for ( i=0, ien=rows[idx].length ; i<ien ; i++ ) { 8729 for ( j=0, jen=columns[idx].length ; j<jen ; j++ ) { 8730 a.push( { 8731 row: rows[idx][i], 8732 column: columns[idx][j] 8733 } ); 8734 } 8735 } 8736 8737 return a; 8738 }, 1 ); 8739 8740 $.extend( cells.selector, { 8741 cols: columnSelector, 8742 rows: rowSelector, 8743 opts: opts 8744 } ); 8745 8746 return cells; 8747 } ); 8748 8749 8750 _api_registerPlural( 'cells().nodes()', 'cell().node()', function () { 8751 return this.iterator( 'cell', function ( settings, row, column ) { 8752 var data = settings.aoData[ row ]; 8753 8754 return data && data.anCells ? 8755 data.anCells[ column ] : 8756 undefined; 8757 }, 1 ); 8758 } ); 8759 8760 8761 _api_register( 'cells().data()', function () { 8762 return this.iterator( 'cell', function ( settings, row, column ) { 8763 return _fnGetCellData( settings, row, column ); 8764 }, 1 ); 8765 } ); 8766 8767 8768 _api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) { 8769 type = type === 'search' ? '_aFilterData' : '_aSortData'; 8770 8771 return this.iterator( 'cell', function ( settings, row, column ) { 8772 return settings.aoData[ row ][ type ][ column ]; 8773 }, 1 ); 8774 } ); 8775 8776 8777 _api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) { 8778 return this.iterator( 'cell', function ( settings, row, column ) { 8779 return _fnGetCellData( settings, row, column, type ); 8780 }, 1 ); 8781 } ); 8782 8783 8784 _api_registerPlural( 'cells().indexes()', 'cell().index()', function () { 8785 return this.iterator( 'cell', function ( settings, row, column ) { 8786 return { 8787 row: row, 8788 column: column, 8789 columnVisible: _fnColumnIndexToVisible( settings, column ) 8790 }; 8791 }, 1 ); 8792 } ); 8793 8794 8795 _api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) { 8796 return this.iterator( 'cell', function ( settings, row, column ) { 8797 _fnInvalidate( settings, row, src, column ); 8798 } ); 8799 } ); 8800 8801 8802 8803 _api_register( 'cell()', function ( rowSelector, columnSelector, opts ) { 8804 return _selector_first( this.cells( rowSelector, columnSelector, opts ) ); 8805 } ); 8806 8807 8808 _api_register( 'cell().data()', function ( data ) { 8809 var ctx = this.context; 8810 var cell = this[0]; 8811 8812 if ( data === undefined ) { 8813 // Get 8814 return ctx.length && cell.length ? 8815 _fnGetCellData( ctx[0], cell[0].row, cell[0].column ) : 8816 undefined; 8817 } 8818 8819 // Set 8820 _fnSetCellData( ctx[0], cell[0].row, cell[0].column, data ); 8821 _fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column ); 8822 8823 return this; 8824 } ); 8825 8826 8827 8828 /** 8829 * Get current ordering (sorting) that has been applied to the table. 8830 * 8831 * @returns {array} 2D array containing the sorting information for the first 8832 * table in the current context. Each element in the parent array represents 8833 * a column being sorted upon (i.e. multi-sorting with two columns would have 8834 * 2 inner arrays). The inner arrays may have 2 or 3 elements. The first is 8835 * the column index that the sorting condition applies to, the second is the 8836 * direction of the sort (`desc` or `asc`) and, optionally, the third is the 8837 * index of the sorting order from the `column.sorting` initialisation array. 8838 *//** 8839 * Set the ordering for the table. 8840 * 8841 * @param {integer} order Column index to sort upon. 8842 * @param {string} direction Direction of the sort to be applied (`asc` or `desc`) 8843 * @returns {DataTables.Api} this 8844 *//** 8845 * Set the ordering for the table. 8846 * 8847 * @param {array} order 1D array of sorting information to be applied. 8848 * @param {array} [...] Optional additional sorting conditions 8849 * @returns {DataTables.Api} this 8850 *//** 8851 * Set the ordering for the table. 8852 * 8853 * @param {array} order 2D array of sorting information to be applied. 8854 * @returns {DataTables.Api} this 8855 */ 8856 _api_register( 'order()', function ( order, dir ) { 8857 var ctx = this.context; 8858 8859 if ( order === undefined ) { 8860 // get 8861 return ctx.length !== 0 ? 8862 ctx[0].aaSorting : 8863 undefined; 8864 } 8865 8866 // set 8867 if ( typeof order === 'number' ) { 8868 // Simple column / direction passed in 8869 order = [ [ order, dir ] ]; 8870 } 8871 else if ( order.length && ! $.isArray( order[0] ) ) { 8872 // Arguments passed in (list of 1D arrays) 8873 order = Array.prototype.slice.call( arguments ); 8874 } 8875 // otherwise a 2D array was passed in 8876 8877 return this.iterator( 'table', function ( settings ) { 8878 settings.aaSorting = order.slice(); 8879 } ); 8880 } ); 8881 8882 8883 /** 8884 * Attach a sort listener to an element for a given column 8885 * 8886 * @param {node|jQuery|string} node Identifier for the element(s) to attach the 8887 * listener to. This can take the form of a single DOM node, a jQuery 8888 * collection of nodes or a jQuery selector which will identify the node(s). 8889 * @param {integer} column the column that a click on this node will sort on 8890 * @param {function} [callback] callback function when sort is run 8891 * @returns {DataTables.Api} this 8892 */ 8893 _api_register( 'order.listener()', function ( node, column, callback ) { 8894 return this.iterator( 'table', function ( settings ) { 8895 _fnSortAttachListener( settings, node, column, callback ); 8896 } ); 8897 } ); 8898 8899 8900 _api_register( 'order.fixed()', function ( set ) { 8901 if ( ! set ) { 8902 var ctx = this.context; 8903 var fixed = ctx.length ? 8904 ctx[0].aaSortingFixed : 8905 undefined; 8906 8907 return $.isArray( fixed ) ? 8908 { pre: fixed } : 8909 fixed; 8910 } 8911 8912 return this.iterator( 'table', function ( settings ) { 8913 settings.aaSortingFixed = $.extend( true, {}, set ); 8914 } ); 8915 } ); 8916 8917 8918 // Order by the selected column(s) 8919 _api_register( [ 8920 'columns().order()', 8921 'column().order()' 8922 ], function ( dir ) { 8923 var that = this; 8924 8925 return this.iterator( 'table', function ( settings, i ) { 8926 var sort = []; 8927 8928 $.each( that[i], function (j, col) { 8929 sort.push( [ col, dir ] ); 8930 } ); 8931 8932 settings.aaSorting = sort; 8933 } ); 8934 } ); 8935 8936 8937 8938 _api_register( 'search()', function ( input, regex, smart, caseInsen ) { 8939 var ctx = this.context; 8940 8941 if ( input === undefined ) { 8942 // get 8943 return ctx.length !== 0 ? 8944 ctx[0].oPreviousSearch.sSearch : 8945 undefined; 8946 } 8947 8948 // set 8949 return this.iterator( 'table', function ( settings ) { 8950 if ( ! settings.oFeatures.bFilter ) { 8951 return; 8952 } 8953 8954 _fnFilterComplete( settings, $.extend( {}, settings.oPreviousSearch, { 8955 "sSearch": input+"", 8956 "bRegex": regex === null ? false : regex, 8957 "bSmart": smart === null ? true : smart, 8958 "bCaseInsensitive": caseInsen === null ? true : caseInsen 8959 } ), 1 ); 8960 } ); 8961 } ); 8962 8963 8964 _api_registerPlural( 8965 'columns().search()', 8966 'column().search()', 8967 function ( input, regex, smart, caseInsen ) { 8968 return this.iterator( 'column', function ( settings, column ) { 8969 var preSearch = settings.aoPreSearchCols; 8970 8971 if ( input === undefined ) { 8972 // get 8973 return preSearch[ column ].sSearch; 8974 } 8975 8976 // set 8977 if ( ! settings.oFeatures.bFilter ) { 8978 return; 8979 } 8980 8981 $.extend( preSearch[ column ], { 8982 "sSearch": input+"", 8983 "bRegex": regex === null ? false : regex, 8984 "bSmart": smart === null ? true : smart, 8985 "bCaseInsensitive": caseInsen === null ? true : caseInsen 8986 } ); 8987 8988 _fnFilterComplete( settings, settings.oPreviousSearch, 1 ); 8989 } ); 8990 } 8991 ); 8992 8993 /* 8994 * State API methods 8995 */ 8996 8997 _api_register( 'state()', function () { 8998 return this.context.length ? 8999 this.context[0].oSavedState : 9000 null; 9001 } ); 9002 9003 9004 _api_register( 'state.clear()', function () { 9005 return this.iterator( 'table', function ( settings ) { 9006 // Save an empty object 9007 settings.fnStateSaveCallback.call( settings.oInstance, settings, {} ); 9008 } ); 9009 } ); 9010 9011 9012 _api_register( 'state.loaded()', function () { 9013 return this.context.length ? 9014 this.context[0].oLoadedState : 9015 null; 9016 } ); 9017 9018 9019 _api_register( 'state.save()', function () { 9020 return this.iterator( 'table', function ( settings ) { 9021 _fnSaveState( settings ); 9022 } ); 9023 } ); 9024 9025 9026 9027 /** 9028 * Provide a common method for plug-ins to check the version of DataTables being 9029 * used, in order to ensure compatibility. 9030 * 9031 * @param {string} version Version string to check for, in the format "X.Y.Z". 9032 * Note that the formats "X" and "X.Y" are also acceptable. 9033 * @returns {boolean} true if this version of DataTables is greater or equal to 9034 * the required version, or false if this version of DataTales is not 9035 * suitable 9036 * @static 9037 * @dtopt API-Static 9038 * 9039 * @example 9040 * alert( $.fn.dataTable.versionCheck( '1.9.0' ) ); 9041 */ 9042 DataTable.versionCheck = DataTable.fnVersionCheck = function( version ) 9043 { 9044 var aThis = DataTable.version.split('.'); 9045 var aThat = version.split('.'); 9046 var iThis, iThat; 9047 9048 for ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) { 9049 iThis = parseInt( aThis[i], 10 ) || 0; 9050 iThat = parseInt( aThat[i], 10 ) || 0; 9051 9052 // Parts are the same, keep comparing 9053 if (iThis === iThat) { 9054 continue; 9055 } 9056 9057 // Parts are different, return immediately 9058 return iThis > iThat; 9059 } 9060 9061 return true; 9062 }; 9063 9064 9065 /** 9066 * Check if a `<table>` node is a DataTable table already or not. 9067 * 9068 * @param {node|jquery|string} table Table node, jQuery object or jQuery 9069 * selector for the table to test. Note that if more than more than one 9070 * table is passed on, only the first will be checked 9071 * @returns {boolean} true the table given is a DataTable, or false otherwise 9072 * @static 9073 * @dtopt API-Static 9074 * 9075 * @example 9076 * if ( ! $.fn.DataTable.isDataTable( '#example' ) ) { 9077 * $('#example').dataTable(); 9078 * } 9079 */ 9080 DataTable.isDataTable = DataTable.fnIsDataTable = function ( table ) 9081 { 9082 var t = $(table).get(0); 9083 var is = false; 9084 9085 $.each( DataTable.settings, function (i, o) { 9086 var head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null; 9087 var foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null; 9088 9089 if ( o.nTable === t || head === t || foot === t ) { 9090 is = true; 9091 } 9092 } ); 9093 9094 return is; 9095 }; 9096 9097 9098 /** 9099 * Get all DataTable tables that have been initialised - optionally you can 9100 * select to get only currently visible tables. 9101 * 9102 * @param {boolean} [visible=false] Flag to indicate if you want all (default) 9103 * or visible tables only. 9104 * @returns {array} Array of `table` nodes (not DataTable instances) which are 9105 * DataTables 9106 * @static 9107 * @dtopt API-Static 9108 * 9109 * @example 9110 * $.each( $.fn.dataTable.tables(true), function () { 9111 * $(table).DataTable().columns.adjust(); 9112 * } ); 9113 */ 9114 DataTable.tables = DataTable.fnTables = function ( visible ) 9115 { 9116 var api = false; 9117 9118 if ( $.isPlainObject( visible ) ) { 9119 api = visible.api; 9120 visible = visible.visible; 9121 } 9122 9123 var a = $.map( DataTable.settings, function (o) { 9124 if ( !visible || (visible && $(o.nTable).is(':visible')) ) { 9125 return o.nTable; 9126 } 9127 } ); 9128 9129 return api ? 9130 new _Api( a ) : 9131 a; 9132 }; 9133 9134 9135 /** 9136 * Convert from camel case parameters to Hungarian notation. This is made public 9137 * for the extensions to provide the same ability as DataTables core to accept 9138 * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase 9139 * parameters. 9140 * 9141 * @param {object} src The model object which holds all parameters that can be 9142 * mapped. 9143 * @param {object} user The object to convert from camel case to Hungarian. 9144 * @param {boolean} force When set to `true`, properties which already have a 9145 * Hungarian value in the `user` object will be overwritten. Otherwise they 9146 * won't be. 9147 */ 9148 DataTable.camelToHungarian = _fnCamelToHungarian; 9149 9150 9151 9152 /** 9153 * 9154 */ 9155 _api_register( '$()', function ( selector, opts ) { 9156 var 9157 rows = this.rows( opts ).nodes(), // Get all rows 9158 jqRows = $(rows); 9159 9160 return $( [].concat( 9161 jqRows.filter( selector ).toArray(), 9162 jqRows.find( selector ).toArray() 9163 ) ); 9164 } ); 9165 9166 9167 // jQuery functions to operate on the tables 9168 $.each( [ 'on', 'one', 'off' ], function (i, key) { 9169 _api_register( key+'()', function ( /* event, handler */ ) { 9170 var args = Array.prototype.slice.call(arguments); 9171 9172 // Add the `dt` namespace automatically if it isn't already present 9173 if ( ! args[0].match(/\.dt\b/) ) { 9174 args[0] += '.dt'; 9175 } 9176 9177 var inst = $( this.tables().nodes() ); 9178 inst[key].apply( inst, args ); 9179 return this; 9180 } ); 9181 } ); 9182 9183 9184 _api_register( 'clear()', function () { 9185 return this.iterator( 'table', function ( settings ) { 9186 _fnClearTable( settings ); 9187 } ); 9188 } ); 9189 9190 9191 _api_register( 'settings()', function () { 9192 return new _Api( this.context, this.context ); 9193 } ); 9194 9195 9196 _api_register( 'init()', function () { 9197 var ctx = this.context; 9198 return ctx.length ? ctx[0].oInit : null; 9199 } ); 9200 9201 9202 _api_register( 'data()', function () { 9203 return this.iterator( 'table', function ( settings ) { 9204 return _pluck( settings.aoData, '_aData' ); 9205 } ).flatten(); 9206 } ); 9207 9208 9209 _api_register( 'destroy()', function ( remove ) { 9210 remove = remove || false; 9211 9212 return this.iterator( 'table', function ( settings ) { 9213 var orig = settings.nTableWrapper.parentNode; 9214 var classes = settings.oClasses; 9215 var table = settings.nTable; 9216 var tbody = settings.nTBody; 9217 var thead = settings.nTHead; 9218 var tfoot = settings.nTFoot; 9219 var jqTable = $(table); 9220 var jqTbody = $(tbody); 9221 var jqWrapper = $(settings.nTableWrapper); 9222 var rows = $.map( settings.aoData, function (r) { return r.nTr; } ); 9223 var i, ien; 9224 9225 // Flag to note that the table is currently being destroyed - no action 9226 // should be taken 9227 settings.bDestroying = true; 9228 9229 // Fire off the destroy callbacks for plug-ins etc 9230 _fnCallbackFire( settings, "aoDestroyCallback", "destroy", [settings] ); 9231 9232 // If not being removed from the document, make all columns visible 9233 if ( ! remove ) { 9234 new _Api( settings ).columns().visible( true ); 9235 } 9236 9237 // Blitz all `DT` namespaced events (these are internal events, the 9238 // lowercase, `dt` events are user subscribed and they are responsible 9239 // for removing them 9240 jqWrapper.unbind('.DT').find(':not(tbody *)').unbind('.DT'); 9241 $(window).unbind('.DT-'+settings.sInstance); 9242 9243 // When scrolling we had to break the table up - restore it 9244 if ( table != thead.parentNode ) { 9245 jqTable.children('thead').detach(); 9246 jqTable.append( thead ); 9247 } 9248 9249 if ( tfoot && table != tfoot.parentNode ) { 9250 jqTable.children('tfoot').detach(); 9251 jqTable.append( tfoot ); 9252 } 9253 9254 settings.aaSorting = []; 9255 settings.aaSortingFixed = []; 9256 _fnSortingClasses( settings ); 9257 9258 $( rows ).removeClass( settings.asStripeClasses.join(' ') ); 9259 9260 $('th, td', thead).removeClass( classes.sSortable+' '+ 9261 classes.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone 9262 ); 9263 9264 if ( settings.bJUI ) { 9265 $('th span.'+classes.sSortIcon+ ', td span.'+classes.sSortIcon, thead).detach(); 9266 $('th, td', thead).each( function () { 9267 var wrapper = $('div.'+classes.sSortJUIWrapper, this); 9268 $(this).append( wrapper.contents() ); 9269 wrapper.detach(); 9270 } ); 9271 } 9272 9273 // Add the TR elements back into the table in their original order 9274 jqTbody.children().detach(); 9275 jqTbody.append( rows ); 9276 9277 // Remove the DataTables generated nodes, events and classes 9278 var removedMethod = remove ? 'remove' : 'detach'; 9279 jqTable[ removedMethod ](); 9280 jqWrapper[ removedMethod ](); 9281 9282 // If we need to reattach the table to the document 9283 if ( ! remove && orig ) { 9284 // insertBefore acts like appendChild if !arg[1] 9285 orig.insertBefore( table, settings.nTableReinsertBefore ); 9286 9287 // Restore the width of the original table - was read from the style property, 9288 // so we can restore directly to that 9289 jqTable 9290 .css( 'width', settings.sDestroyWidth ) 9291 .removeClass( classes.sTable ); 9292 9293 // If the were originally stripe classes - then we add them back here. 9294 // Note this is not fool proof (for example if not all rows had stripe 9295 // classes - but it's a good effort without getting carried away 9296 ien = settings.asDestroyStripes.length; 9297 9298 if ( ien ) { 9299 jqTbody.children().each( function (i) { 9300 $(this).addClass( settings.asDestroyStripes[i % ien] ); 9301 } ); 9302 } 9303 } 9304 9305 /* Remove the settings object from the settings array */ 9306 var idx = $.inArray( settings, DataTable.settings ); 9307 if ( idx !== -1 ) { 9308 DataTable.settings.splice( idx, 1 ); 9309 } 9310 } ); 9311 } ); 9312 9313 9314 // Add the `every()` method for rows, columns and cells in a compact form 9315 $.each( [ 'column', 'row', 'cell' ], function ( i, type ) { 9316 _api_register( type+'s().every()', function ( fn ) { 9317 var opts = this.selector.opts; 9318 var api = this; 9319 9320 return this.iterator( type, function ( settings, arg1, arg2, arg3, arg4 ) { 9321 // Rows and columns: 9322 // arg1 - index 9323 // arg2 - table counter 9324 // arg3 - loop counter 9325 // arg4 - undefined 9326 // Cells: 9327 // arg1 - row index 9328 // arg2 - column index 9329 // arg3 - table counter 9330 // arg4 - loop counter 9331 fn.call( 9332 api[ type ]( 9333 arg1, 9334 type==='cell' ? arg2 : opts, 9335 type==='cell' ? opts : undefined 9336 ), 9337 arg1, arg2, arg3, arg4 9338 ); 9339 } ); 9340 } ); 9341 } ); 9342 9343 9344 // i18n method for extensions to be able to use the language object from the 9345 // DataTable 9346 _api_register( 'i18n()', function ( token, def, plural ) { 9347 var ctx = this.context[0]; 9348 var resolved = _fnGetObjectDataFn( token )( ctx.oLanguage ); 9349 9350 if ( resolved === undefined ) { 9351 resolved = def; 9352 } 9353 9354 if ( plural !== undefined && $.isPlainObject( resolved ) ) { 9355 resolved = resolved[ plural ] !== undefined ? 9356 resolved[ plural ] : 9357 resolved._; 9358 } 9359 9360 return resolved.replace( '%d', plural ); // nb: plural might be undefined, 9361 } ); 9362 9363 /** 9364 * Version string for plug-ins to check compatibility. Allowed format is 9365 * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used 9366 * only for non-release builds. See http://semver.org/ for more information. 9367 * @member 9368 * @type string 9369 * @default Version number 9370 */ 9371 DataTable.version = "1.10.12"; 9372 9373 /** 9374 * Private data store, containing all of the settings objects that are 9375 * created for the tables on a given page. 9376 * 9377 * Note that the `DataTable.settings` object is aliased to 9378 * `jQuery.fn.dataTableExt` through which it may be accessed and 9379 * manipulated, or `jQuery.fn.dataTable.settings`. 9380 * @member 9381 * @type array 9382 * @default [] 9383 * @private 9384 */ 9385 DataTable.settings = []; 9386 9387 /** 9388 * Object models container, for the various models that DataTables has 9389 * available to it. These models define the objects that are used to hold 9390 * the active state and configuration of the table. 9391 * @namespace 9392 */ 9393 DataTable.models = {}; 9394 9395 9396 9397 /** 9398 * Template object for the way in which DataTables holds information about 9399 * search information for the global filter and individual column filters. 9400 * @namespace 9401 */ 9402 DataTable.models.oSearch = { 9403 /** 9404 * Flag to indicate if the filtering should be case insensitive or not 9405 * @type boolean 9406 * @default true 9407 */ 9408 "bCaseInsensitive": true, 9409 9410 /** 9411 * Applied search term 9412 * @type string 9413 * @default <i>Empty string</i> 9414 */ 9415 "sSearch": "", 9416 9417 /** 9418 * Flag to indicate if the search term should be interpreted as a 9419 * regular expression (true) or not (false) and therefore and special 9420 * regex characters escaped. 9421 * @type boolean 9422 * @default false 9423 */ 9424 "bRegex": false, 9425 9426 /** 9427 * Flag to indicate if DataTables is to use its smart filtering or not. 9428 * @type boolean 9429 * @default true 9430 */ 9431 "bSmart": true 9432 }; 9433 9434 9435 9436 9437 /** 9438 * Template object for the way in which DataTables holds information about 9439 * each individual row. This is the object format used for the settings 9440 * aoData array. 9441 * @namespace 9442 */ 9443 DataTable.models.oRow = { 9444 /** 9445 * TR element for the row 9446 * @type node 9447 * @default null 9448 */ 9449 "nTr": null, 9450 9451 /** 9452 * Array of TD elements for each row. This is null until the row has been 9453 * created. 9454 * @type array nodes 9455 * @default [] 9456 */ 9457 "anCells": null, 9458 9459 /** 9460 * Data object from the original data source for the row. This is either 9461 * an array if using the traditional form of DataTables, or an object if 9462 * using mData options. The exact type will depend on the passed in 9463 * data from the data source, or will be an array if using DOM a data 9464 * source. 9465 * @type array|object 9466 * @default [] 9467 */ 9468 "_aData": [], 9469 9470 /** 9471 * Sorting data cache - this array is ostensibly the same length as the 9472 * number of columns (although each index is generated only as it is 9473 * needed), and holds the data that is used for sorting each column in the 9474 * row. We do this cache generation at the start of the sort in order that 9475 * the formatting of the sort data need be done only once for each cell 9476 * per sort. This array should not be read from or written to by anything 9477 * other than the master sorting methods. 9478 * @type array 9479 * @default null 9480 * @private 9481 */ 9482 "_aSortData": null, 9483 9484 /** 9485 * Per cell filtering data cache. As per the sort data cache, used to 9486 * increase the performance of the filtering in DataTables 9487 * @type array 9488 * @default null 9489 * @private 9490 */ 9491 "_aFilterData": null, 9492 9493 /** 9494 * Filtering data cache. This is the same as the cell filtering cache, but 9495 * in this case a string rather than an array. This is easily computed with 9496 * a join on `_aFilterData`, but is provided as a cache so the join isn't 9497 * needed on every search (memory traded for performance) 9498 * @type array 9499 * @default null 9500 * @private 9501 */ 9502 "_sFilterRow": null, 9503 9504 /** 9505 * Cache of the class name that DataTables has applied to the row, so we 9506 * can quickly look at this variable rather than needing to do a DOM check 9507 * on className for the nTr property. 9508 * @type string 9509 * @default <i>Empty string</i> 9510 * @private 9511 */ 9512 "_sRowStripe": "", 9513 9514 /** 9515 * Denote if the original data source was from the DOM, or the data source 9516 * object. This is used for invalidating data, so DataTables can 9517 * automatically read data from the original source, unless uninstructed 9518 * otherwise. 9519 * @type string 9520 * @default null 9521 * @private 9522 */ 9523 "src": null, 9524 9525 /** 9526 * Index in the aoData array. This saves an indexOf lookup when we have the 9527 * object, but want to know the index 9528 * @type integer 9529 * @default -1 9530 * @private 9531 */ 9532 "idx": -1 9533 }; 9534 9535 9536 /** 9537 * Template object for the column information object in DataTables. This object 9538 * is held in the settings aoColumns array and contains all the information that 9539 * DataTables needs about each individual column. 9540 * 9541 * Note that this object is related to {@link DataTable.defaults.column} 9542 * but this one is the internal data store for DataTables's cache of columns. 9543 * It should NOT be manipulated outside of DataTables. Any configuration should 9544 * be done through the initialisation options. 9545 * @namespace 9546 */ 9547 DataTable.models.oColumn = { 9548 /** 9549 * Column index. This could be worked out on-the-fly with $.inArray, but it 9550 * is faster to just hold it as a variable 9551 * @type integer 9552 * @default null 9553 */ 9554 "idx": null, 9555 9556 /** 9557 * A list of the columns that sorting should occur on when this column 9558 * is sorted. That this property is an array allows multi-column sorting 9559 * to be defined for a column (for example first name / last name columns 9560 * would benefit from this). The values are integers pointing to the 9561 * columns to be sorted on (typically it will be a single integer pointing 9562 * at itself, but that doesn't need to be the case). 9563 * @type array 9564 */ 9565 "aDataSort": null, 9566 9567 /** 9568 * Define the sorting directions that are applied to the column, in sequence 9569 * as the column is repeatedly sorted upon - i.e. the first value is used 9570 * as the sorting direction when the column if first sorted (clicked on). 9571 * Sort it again (click again) and it will move on to the next index. 9572 * Repeat until loop. 9573 * @type array 9574 */ 9575 "asSorting": null, 9576 9577 /** 9578 * Flag to indicate if the column is searchable, and thus should be included 9579 * in the filtering or not. 9580 * @type boolean 9581 */ 9582 "bSearchable": null, 9583 9584 /** 9585 * Flag to indicate if the column is sortable or not. 9586 * @type boolean 9587 */ 9588 "bSortable": null, 9589 9590 /** 9591 * Flag to indicate if the column is currently visible in the table or not 9592 * @type boolean 9593 */ 9594 "bVisible": null, 9595 9596 /** 9597 * Store for manual type assignment using the `column.type` option. This 9598 * is held in store so we can manipulate the column's `sType` property. 9599 * @type string 9600 * @default null 9601 * @private 9602 */ 9603 "_sManualType": null, 9604 9605 /** 9606 * Flag to indicate if HTML5 data attributes should be used as the data 9607 * source for filtering or sorting. True is either are. 9608 * @type boolean 9609 * @default false 9610 * @private 9611 */ 9612 "_bAttrSrc": false, 9613 9614 /** 9615 * Developer definable function that is called whenever a cell is created (Ajax source, 9616 * etc) or processed for input (DOM source). This can be used as a compliment to mRender 9617 * allowing you to modify the DOM element (add background colour for example) when the 9618 * element is available. 9619 * @type function 9620 * @param {element} nTd The TD node that has been created 9621 * @param {*} sData The Data for the cell 9622 * @param {array|object} oData The data for the whole row 9623 * @param {int} iRow The row index for the aoData data store 9624 * @default null 9625 */ 9626 "fnCreatedCell": null, 9627 9628 /** 9629 * Function to get data from a cell in a column. You should <b>never</b> 9630 * access data directly through _aData internally in DataTables - always use 9631 * the method attached to this property. It allows mData to function as 9632 * required. This function is automatically assigned by the column 9633 * initialisation method 9634 * @type function 9635 * @param {array|object} oData The data array/object for the array 9636 * (i.e. aoData[]._aData) 9637 * @param {string} sSpecific The specific data type you want to get - 9638 * 'display', 'type' 'filter' 'sort' 9639 * @returns {*} The data for the cell from the given row's data 9640 * @default null 9641 */ 9642 "fnGetData": null, 9643 9644 /** 9645 * Function to set data for a cell in the column. You should <b>never</b> 9646 * set the data directly to _aData internally in DataTables - always use 9647 * this method. It allows mData to function as required. This function 9648 * is automatically assigned by the column initialisation method 9649 * @type function 9650 * @param {array|object} oData The data array/object for the array 9651 * (i.e. aoData[]._aData) 9652 * @param {*} sValue Value to set 9653 * @default null 9654 */ 9655 "fnSetData": null, 9656 9657 /** 9658 * Property to read the value for the cells in the column from the data 9659 * source array / object. If null, then the default content is used, if a 9660 * function is given then the return from the function is used. 9661 * @type function|int|string|null 9662 * @default null 9663 */ 9664 "mData": null, 9665 9666 /** 9667 * Partner property to mData which is used (only when defined) to get 9668 * the data - i.e. it is basically the same as mData, but without the 9669 * 'set' option, and also the data fed to it is the result from mData. 9670 * This is the rendering method to match the data method of mData. 9671 * @type function|int|string|null 9672 * @default null 9673 */ 9674 "mRender": null, 9675 9676 /** 9677 * Unique header TH/TD element for this column - this is what the sorting 9678 * listener is attached to (if sorting is enabled.) 9679 * @type node 9680 * @default null 9681 */ 9682 "nTh": null, 9683 9684 /** 9685 * Unique footer TH/TD element for this column (if there is one). Not used 9686 * in DataTables as such, but can be used for plug-ins to reference the 9687 * footer for each column. 9688 * @type node 9689 * @default null 9690 */ 9691 "nTf": null, 9692 9693 /** 9694 * The class to apply to all TD elements in the table's TBODY for the column 9695 * @type string 9696 * @default null 9697 */ 9698 "sClass": null, 9699 9700 /** 9701 * When DataTables calculates the column widths to assign to each column, 9702 * it finds the longest string in each column and then constructs a 9703 * temporary table and reads the widths from that. The problem with this 9704 * is that "mmm" is much wider then "iiii", but the latter is a longer 9705 * string - thus the calculation can go wrong (doing it properly and putting 9706 * it into an DOM object and measuring that is horribly(!) slow). Thus as 9707 * a "work around" we provide this option. It will append its value to the 9708 * text that is found to be the longest string for the column - i.e. padding. 9709 * @type string 9710 */ 9711 "sContentPadding": null, 9712 9713 /** 9714 * Allows a default value to be given for a column's data, and will be used 9715 * whenever a null data source is encountered (this can be because mData 9716 * is set to null, or because the data source itself is null). 9717 * @type string 9718 * @default null 9719 */ 9720 "sDefaultContent": null, 9721 9722 /** 9723 * Name for the column, allowing reference to the column by name as well as 9724 * by index (needs a lookup to work by name). 9725 * @type string 9726 */ 9727 "sName": null, 9728 9729 /** 9730 * Custom sorting data type - defines which of the available plug-ins in 9731 * afnSortData the custom sorting will use - if any is defined. 9732 * @type string 9733 * @default std 9734 */ 9735 "sSortDataType": 'std', 9736 9737 /** 9738 * Class to be applied to the header element when sorting on this column 9739 * @type string 9740 * @default null 9741 */ 9742 "sSortingClass": null, 9743 9744 /** 9745 * Class to be applied to the header element when sorting on this column - 9746 * when jQuery UI theming is used. 9747 * @type string 9748 * @default null 9749 */ 9750 "sSortingClassJUI": null, 9751 9752 /** 9753 * Title of the column - what is seen in the TH element (nTh). 9754 * @type string 9755 */ 9756 "sTitle": null, 9757 9758 /** 9759 * Column sorting and filtering type 9760 * @type string 9761 * @default null 9762 */ 9763 "sType": null, 9764 9765 /** 9766 * Width of the column 9767 * @type string 9768 * @default null 9769 */ 9770 "sWidth": null, 9771 9772 /** 9773 * Width of the column when it was first "encountered" 9774 * @type string 9775 * @default null 9776 */ 9777 "sWidthOrig": null 9778 }; 9779 9780 9781 /* 9782 * Developer note: The properties of the object below are given in Hungarian 9783 * notation, that was used as the interface for DataTables prior to v1.10, however 9784 * from v1.10 onwards the primary interface is camel case. In order to avoid 9785 * breaking backwards compatibility utterly with this change, the Hungarian 9786 * version is still, internally the primary interface, but is is not documented 9787 * - hence the @name tags in each doc comment. This allows a Javascript function 9788 * to create a map from Hungarian notation to camel case (going the other direction 9789 * would require each property to be listed, which would at around 3K to the size 9790 * of DataTables, while this method is about a 0.5K hit. 9791 * 9792 * Ultimately this does pave the way for Hungarian notation to be dropped 9793 * completely, but that is a massive amount of work and will break current 9794 * installs (therefore is on-hold until v2). 9795 */ 9796 9797 /** 9798 * Initialisation options that can be given to DataTables at initialisation 9799 * time. 9800 * @namespace 9801 */ 9802 DataTable.defaults = { 9803 /** 9804 * An array of data to use for the table, passed in at initialisation which 9805 * will be used in preference to any data which is already in the DOM. This is 9806 * particularly useful for constructing tables purely in Javascript, for 9807 * example with a custom Ajax call. 9808 * @type array 9809 * @default null 9810 * 9811 * @dtopt Option 9812 * @name DataTable.defaults.data 9813 * 9814 * @example 9815 * // Using a 2D array data source 9816 * $(document).ready( function () { 9817 * $('#example').dataTable( { 9818 * "data": [ 9819 * ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'], 9820 * ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'], 9821 * ], 9822 * "columns": [ 9823 * { "title": "Engine" }, 9824 * { "title": "Browser" }, 9825 * { "title": "Platform" }, 9826 * { "title": "Version" }, 9827 * { "title": "Grade" } 9828 * ] 9829 * } ); 9830 * } ); 9831 * 9832 * @example 9833 * // Using an array of objects as a data source (`data`) 9834 * $(document).ready( function () { 9835 * $('#example').dataTable( { 9836 * "data": [ 9837 * { 9838 * "engine": "Trident", 9839 * "browser": "Internet Explorer 4.0", 9840 * "platform": "Win 95+", 9841 * "version": 4, 9842 * "grade": "X" 9843 * }, 9844 * { 9845 * "engine": "Trident", 9846 * "browser": "Internet Explorer 5.0", 9847 * "platform": "Win 95+", 9848 * "version": 5, 9849 * "grade": "C" 9850 * } 9851 * ], 9852 * "columns": [ 9853 * { "title": "Engine", "data": "engine" }, 9854 * { "title": "Browser", "data": "browser" }, 9855 * { "title": "Platform", "data": "platform" }, 9856 * { "title": "Version", "data": "version" }, 9857 * { "title": "Grade", "data": "grade" } 9858 * ] 9859 * } ); 9860 * } ); 9861 */ 9862 "aaData": null, 9863 9864 9865 /** 9866 * If ordering is enabled, then DataTables will perform a first pass sort on 9867 * initialisation. You can define which column(s) the sort is performed 9868 * upon, and the sorting direction, with this variable. The `sorting` array 9869 * should contain an array for each column to be sorted initially containing 9870 * the column's index and a direction string ('asc' or 'desc'). 9871 * @type array 9872 * @default [[0,'asc']] 9873 * 9874 * @dtopt Option 9875 * @name DataTable.defaults.order 9876 * 9877 * @example 9878 * // Sort by 3rd column first, and then 4th column 9879 * $(document).ready( function() { 9880 * $('#example').dataTable( { 9881 * "order": [[2,'asc'], [3,'desc']] 9882 * } ); 9883 * } ); 9884 * 9885 * // No initial sorting 9886 * $(document).ready( function() { 9887 * $('#example').dataTable( { 9888 * "order": [] 9889 * } ); 9890 * } ); 9891 */ 9892 "aaSorting": [[0,'asc']], 9893 9894 9895 /** 9896 * This parameter is basically identical to the `sorting` parameter, but 9897 * cannot be overridden by user interaction with the table. What this means 9898 * is that you could have a column (visible or hidden) which the sorting 9899 * will always be forced on first - any sorting after that (from the user) 9900 * will then be performed as required. This can be useful for grouping rows 9901 * together. 9902 * @type array 9903 * @default null 9904 * 9905 * @dtopt Option 9906 * @name DataTable.defaults.orderFixed 9907 * 9908 * @example 9909 * $(document).ready( function() { 9910 * $('#example').dataTable( { 9911 * "orderFixed": [[0,'asc']] 9912 * } ); 9913 * } ) 9914 */ 9915 "aaSortingFixed": [], 9916 9917 9918 /** 9919 * DataTables can be instructed to load data to display in the table from a 9920 * Ajax source. This option defines how that Ajax call is made and where to. 9921 * 9922 * The `ajax` property has three different modes of operation, depending on 9923 * how it is defined. These are: 9924 * 9925 * * `string` - Set the URL from where the data should be loaded from. 9926 * * `object` - Define properties for `jQuery.ajax`. 9927 * * `function` - Custom data get function 9928 * 9929 * `string` 9930 * -------- 9931 * 9932 * As a string, the `ajax` property simply defines the URL from which 9933 * DataTables will load data. 9934 * 9935 * `object` 9936 * -------- 9937 * 9938 * As an object, the parameters in the object are passed to 9939 * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control 9940 * of the Ajax request. DataTables has a number of default parameters which 9941 * you can override using this option. Please refer to the jQuery 9942 * documentation for a full description of the options available, although 9943 * the following parameters provide additional options in DataTables or 9944 * require special consideration: 9945 * 9946 * * `data` - As with jQuery, `data` can be provided as an object, but it 9947 * can also be used as a function to manipulate the data DataTables sends 9948 * to the server. The function takes a single parameter, an object of 9949 * parameters with the values that DataTables has readied for sending. An 9950 * object may be returned which will be merged into the DataTables 9951 * defaults, or you can add the items to the object that was passed in and 9952 * not return anything from the function. This supersedes `fnServerParams` 9953 * from DataTables 1.9-. 9954 * 9955 * * `dataSrc` - By default DataTables will look for the property `data` (or 9956 * `aaData` for compatibility with DataTables 1.9-) when obtaining data 9957 * from an Ajax source or for server-side processing - this parameter 9958 * allows that property to be changed. You can use Javascript dotted 9959 * object notation to get a data source for multiple levels of nesting, or 9960 * it my be used as a function. As a function it takes a single parameter, 9961 * the JSON returned from the server, which can be manipulated as 9962 * required, with the returned value being that used by DataTables as the 9963 * data source for the table. This supersedes `sAjaxDataProp` from 9964 * DataTables 1.9-. 9965 * 9966 * * `success` - Should not be overridden it is used internally in 9967 * DataTables. To manipulate / transform the data returned by the server 9968 * use `ajax.dataSrc`, or use `ajax` as a function (see below). 9969 * 9970 * `function` 9971 * ---------- 9972 * 9973 * As a function, making the Ajax call is left up to yourself allowing 9974 * complete control of the Ajax request. Indeed, if desired, a method other 9975 * than Ajax could be used to obtain the required data, such as Web storage 9976 * or an AIR database. 9977 * 9978 * The function is given four parameters and no return is required. The 9979 * parameters are: 9980 * 9981 * 1. _object_ - Data to send to the server 9982 * 2. _function_ - Callback function that must be executed when the required 9983 * data has been obtained. That data should be passed into the callback 9984 * as the only parameter 9985 * 3. _object_ - DataTables settings object for the table 9986 * 9987 * Note that this supersedes `fnServerData` from DataTables 1.9-. 9988 * 9989 * @type string|object|function 9990 * @default null 9991 * 9992 * @dtopt Option 9993 * @name DataTable.defaults.ajax 9994 * @since 1.10.0 9995 * 9996 * @example 9997 * // Get JSON data from a file via Ajax. 9998 * // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default). 9999 * $('#example').dataTable( { 10000 * "ajax": "data.json" 10001 * } ); 10002 * 10003 * @example 10004 * // Get JSON data from a file via Ajax, using `dataSrc` to change 10005 * // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`) 10006 * $('#example').dataTable( { 10007 * "ajax": { 10008 * "url": "data.json", 10009 * "dataSrc": "tableData" 10010 * } 10011 * } ); 10012 * 10013 * @example 10014 * // Get JSON data from a file via Ajax, using `dataSrc` to read data 10015 * // from a plain array rather than an array in an object 10016 * $('#example').dataTable( { 10017 * "ajax": { 10018 * "url": "data.json", 10019 * "dataSrc": "" 10020 * } 10021 * } ); 10022 * 10023 * @example 10024 * // Manipulate the data returned from the server - add a link to data 10025 * // (note this can, should, be done using `render` for the column - this 10026 * // is just a simple example of how the data can be manipulated). 10027 * $('#example').dataTable( { 10028 * "ajax": { 10029 * "url": "data.json", 10030 * "dataSrc": function ( json ) { 10031 * for ( var i=0, ien=json.length ; i<ien ; i++ ) { 10032 * json[i][0] = '<a href="/message/'+json[i][0]+'>View message</a>'; 10033 * } 10034 * return json; 10035 * } 10036 * } 10037 * } ); 10038 * 10039 * @example 10040 * // Add data to the request 10041 * $('#example').dataTable( { 10042 * "ajax": { 10043 * "url": "data.json", 10044 * "data": function ( d ) { 10045 * return { 10046 * "extra_search": $('#extra').val() 10047 * }; 10048 * } 10049 * } 10050 * } ); 10051 * 10052 * @example 10053 * // Send request as POST 10054 * $('#example').dataTable( { 10055 * "ajax": { 10056 * "url": "data.json", 10057 * "type": "POST" 10058 * } 10059 * } ); 10060 * 10061 * @example 10062 * // Get the data from localStorage (could interface with a form for 10063 * // adding, editing and removing rows). 10064 * $('#example').dataTable( { 10065 * "ajax": function (data, callback, settings) { 10066 * callback( 10067 * JSON.parse( localStorage.getItem('dataTablesData') ) 10068 * ); 10069 * } 10070 * } ); 10071 */ 10072 "ajax": null, 10073 10074 10075 /** 10076 * This parameter allows you to readily specify the entries in the length drop 10077 * down menu that DataTables shows when pagination is enabled. It can be 10078 * either a 1D array of options which will be used for both the displayed 10079 * option and the value, or a 2D array which will use the array in the first 10080 * position as the value, and the array in the second position as the 10081 * displayed options (useful for language strings such as 'All'). 10082 * 10083 * Note that the `pageLength` property will be automatically set to the 10084 * first value given in this array, unless `pageLength` is also provided. 10085 * @type array 10086 * @default [ 10, 25, 50, 100 ] 10087 * 10088 * @dtopt Option 10089 * @name DataTable.defaults.lengthMenu 10090 * 10091 * @example 10092 * $(document).ready( function() { 10093 * $('#example').dataTable( { 10094 * "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]] 10095 * } ); 10096 * } ); 10097 */ 10098 "aLengthMenu": [ 10, 25, 50, 100 ], 10099 10100 10101 /** 10102 * The `columns` option in the initialisation parameter allows you to define 10103 * details about the way individual columns behave. For a full list of 10104 * column options that can be set, please see 10105 * {@link DataTable.defaults.column}. Note that if you use `columns` to 10106 * define your columns, you must have an entry in the array for every single 10107 * column that you have in your table (these can be null if you don't which 10108 * to specify any options). 10109 * @member 10110 * 10111 * @name DataTable.defaults.column 10112 */ 10113 "aoColumns": null, 10114 10115 /** 10116 * Very similar to `columns`, `columnDefs` allows you to target a specific 10117 * column, multiple columns, or all columns, using the `targets` property of 10118 * each object in the array. This allows great flexibility when creating 10119 * tables, as the `columnDefs` arrays can be of any length, targeting the 10120 * columns you specifically want. `columnDefs` may use any of the column 10121 * options available: {@link DataTable.defaults.column}, but it _must_ 10122 * have `targets` defined in each object in the array. Values in the `targets` 10123 * array may be: 10124 * <ul> 10125 * <li>a string - class name will be matched on the TH for the column</li> 10126 * <li>0 or a positive integer - column index counting from the left</li> 10127 * <li>a negative integer - column index counting from the right</li> 10128 * <li>the string "_all" - all columns (i.e. assign a default)</li> 10129 * </ul> 10130 * @member 10131 * 10132 * @name DataTable.defaults.columnDefs 10133 */ 10134 "aoColumnDefs": null, 10135 10136 10137 /** 10138 * Basically the same as `search`, this parameter defines the individual column 10139 * filtering state at initialisation time. The array must be of the same size 10140 * as the number of columns, and each element be an object with the parameters 10141 * `search` and `escapeRegex` (the latter is optional). 'null' is also 10142 * accepted and the default will be used. 10143 * @type array 10144 * @default [] 10145 * 10146 * @dtopt Option 10147 * @name DataTable.defaults.searchCols 10148 * 10149 * @example 10150 * $(document).ready( function() { 10151 * $('#example').dataTable( { 10152 * "searchCols": [ 10153 * null, 10154 * { "search": "My filter" }, 10155 * null, 10156 * { "search": "^[0-9]", "escapeRegex": false } 10157 * ] 10158 * } ); 10159 * } ) 10160 */ 10161 "aoSearchCols": [], 10162 10163 10164 /** 10165 * An array of CSS classes that should be applied to displayed rows. This 10166 * array may be of any length, and DataTables will apply each class 10167 * sequentially, looping when required. 10168 * @type array 10169 * @default null <i>Will take the values determined by the `oClasses.stripe*` 10170 * options</i> 10171 * 10172 * @dtopt Option 10173 * @name DataTable.defaults.stripeClasses 10174 * 10175 * @example 10176 * $(document).ready( function() { 10177 * $('#example').dataTable( { 10178 * "stripeClasses": [ 'strip1', 'strip2', 'strip3' ] 10179 * } ); 10180 * } ) 10181 */ 10182 "asStripeClasses": null, 10183 10184 10185 /** 10186 * Enable or disable automatic column width calculation. This can be disabled 10187 * as an optimisation (it takes some time to calculate the widths) if the 10188 * tables widths are passed in using `columns`. 10189 * @type boolean 10190 * @default true 10191 * 10192 * @dtopt Features 10193 * @name DataTable.defaults.autoWidth 10194 * 10195 * @example 10196 * $(document).ready( function () { 10197 * $('#example').dataTable( { 10198 * "autoWidth": false 10199 * } ); 10200 * } ); 10201 */ 10202 "bAutoWidth": true, 10203 10204 10205 /** 10206 * Deferred rendering can provide DataTables with a huge speed boost when you 10207 * are using an Ajax or JS data source for the table. This option, when set to 10208 * true, will cause DataTables to defer the creation of the table elements for 10209 * each row until they are needed for a draw - saving a significant amount of 10210 * time. 10211 * @type boolean 10212 * @default false 10213 * 10214 * @dtopt Features 10215 * @name DataTable.defaults.deferRender 10216 * 10217 * @example 10218 * $(document).ready( function() { 10219 * $('#example').dataTable( { 10220 * "ajax": "sources/arrays.txt", 10221 * "deferRender": true 10222 * } ); 10223 * } ); 10224 */ 10225 "bDeferRender": false, 10226 10227 10228 /** 10229 * Replace a DataTable which matches the given selector and replace it with 10230 * one which has the properties of the new initialisation object passed. If no 10231 * table matches the selector, then the new DataTable will be constructed as 10232 * per normal. 10233 * @type boolean 10234 * @default false 10235 * 10236 * @dtopt Options 10237 * @name DataTable.defaults.destroy 10238 * 10239 * @example 10240 * $(document).ready( function() { 10241 * $('#example').dataTable( { 10242 * "srollY": "200px", 10243 * "paginate": false 10244 * } ); 10245 * 10246 * // Some time later.... 10247 * $('#example').dataTable( { 10248 * "filter": false, 10249 * "destroy": true 10250 * } ); 10251 * } ); 10252 */ 10253 "bDestroy": false, 10254 10255 10256 /** 10257 * Enable or disable filtering of data. Filtering in DataTables is "smart" in 10258 * that it allows the end user to input multiple words (space separated) and 10259 * will match a row containing those words, even if not in the order that was 10260 * specified (this allow matching across multiple columns). Note that if you 10261 * wish to use filtering in DataTables this must remain 'true' - to remove the 10262 * default filtering input box and retain filtering abilities, please use 10263 * {@link DataTable.defaults.dom}. 10264 * @type boolean 10265 * @default true 10266 * 10267 * @dtopt Features 10268 * @name DataTable.defaults.searching 10269 * 10270 * @example 10271 * $(document).ready( function () { 10272 * $('#example').dataTable( { 10273 * "searching": false 10274 * } ); 10275 * } ); 10276 */ 10277 "bFilter": true, 10278 10279 10280 /** 10281 * Enable or disable the table information display. This shows information 10282 * about the data that is currently visible on the page, including information 10283 * about filtered data if that action is being performed. 10284 * @type boolean 10285 * @default true 10286 * 10287 * @dtopt Features 10288 * @name DataTable.defaults.info 10289 * 10290 * @example 10291 * $(document).ready( function () { 10292 * $('#example').dataTable( { 10293 * "info": false 10294 * } ); 10295 * } ); 10296 */ 10297 "bInfo": true, 10298 10299 10300 /** 10301 * Enable jQuery UI ThemeRoller support (required as ThemeRoller requires some 10302 * slightly different and additional mark-up from what DataTables has 10303 * traditionally used). 10304 * @type boolean 10305 * @default false 10306 * 10307 * @dtopt Features 10308 * @name DataTable.defaults.jQueryUI 10309 * 10310 * @example 10311 * $(document).ready( function() { 10312 * $('#example').dataTable( { 10313 * "jQueryUI": true 10314 * } ); 10315 * } ); 10316 */ 10317 "bJQueryUI": false, 10318 10319 10320 /** 10321 * Allows the end user to select the size of a formatted page from a select 10322 * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`). 10323 * @type boolean 10324 * @default true 10325 * 10326 * @dtopt Features 10327 * @name DataTable.defaults.lengthChange 10328 * 10329 * @example 10330 * $(document).ready( function () { 10331 * $('#example').dataTable( { 10332 * "lengthChange": false 10333 * } ); 10334 * } ); 10335 */ 10336 "bLengthChange": true, 10337 10338 10339 /** 10340 * Enable or disable pagination. 10341 * @type boolean 10342 * @default true 10343 * 10344 * @dtopt Features 10345 * @name DataTable.defaults.paging 10346 * 10347 * @example 10348 * $(document).ready( function () { 10349 * $('#example').dataTable( { 10350 * "paging": false 10351 * } ); 10352 * } ); 10353 */ 10354 "bPaginate": true, 10355 10356 10357 /** 10358 * Enable or disable the display of a 'processing' indicator when the table is 10359 * being processed (e.g. a sort). This is particularly useful for tables with 10360 * large amounts of data where it can take a noticeable amount of time to sort 10361 * the entries. 10362 * @type boolean 10363 * @default false 10364 * 10365 * @dtopt Features 10366 * @name DataTable.defaults.processing 10367 * 10368 * @example 10369 * $(document).ready( function () { 10370 * $('#example').dataTable( { 10371 * "processing": true 10372 * } ); 10373 * } ); 10374 */ 10375 "bProcessing": false, 10376 10377 10378 /** 10379 * Retrieve the DataTables object for the given selector. Note that if the 10380 * table has already been initialised, this parameter will cause DataTables 10381 * to simply return the object that has already been set up - it will not take 10382 * account of any changes you might have made to the initialisation object 10383 * passed to DataTables (setting this parameter to true is an acknowledgement 10384 * that you understand this). `destroy` can be used to reinitialise a table if 10385 * you need. 10386 * @type boolean 10387 * @default false 10388 * 10389 * @dtopt Options 10390 * @name DataTable.defaults.retrieve 10391 * 10392 * @example 10393 * $(document).ready( function() { 10394 * initTable(); 10395 * tableActions(); 10396 * } ); 10397 * 10398 * function initTable () 10399 * { 10400 * return $('#example').dataTable( { 10401 * "scrollY": "200px", 10402 * "paginate": false, 10403 * "retrieve": true 10404 * } ); 10405 * } 10406 * 10407 * function tableActions () 10408 * { 10409 * var table = initTable(); 10410 * // perform API operations with oTable 10411 * } 10412 */ 10413 "bRetrieve": false, 10414 10415 10416 /** 10417 * When vertical (y) scrolling is enabled, DataTables will force the height of 10418 * the table's viewport to the given height at all times (useful for layout). 10419 * However, this can look odd when filtering data down to a small data set, 10420 * and the footer is left "floating" further down. This parameter (when 10421 * enabled) will cause DataTables to collapse the table's viewport down when 10422 * the result set will fit within the given Y height. 10423 * @type boolean 10424 * @default false 10425 * 10426 * @dtopt Options 10427 * @name DataTable.defaults.scrollCollapse 10428 * 10429 * @example 10430 * $(document).ready( function() { 10431 * $('#example').dataTable( { 10432 * "scrollY": "200", 10433 * "scrollCollapse": true 10434 * } ); 10435 * } ); 10436 */ 10437 "bScrollCollapse": false, 10438 10439 10440 /** 10441 * Configure DataTables to use server-side processing. Note that the 10442 * `ajax` parameter must also be given in order to give DataTables a 10443 * source to obtain the required data for each draw. 10444 * @type boolean 10445 * @default false 10446 * 10447 * @dtopt Features 10448 * @dtopt Server-side 10449 * @name DataTable.defaults.serverSide 10450 * 10451 * @example 10452 * $(document).ready( function () { 10453 * $('#example').dataTable( { 10454 * "serverSide": true, 10455 * "ajax": "xhr.php" 10456 * } ); 10457 * } ); 10458 */ 10459 "bServerSide": false, 10460 10461 10462 /** 10463 * Enable or disable sorting of columns. Sorting of individual columns can be 10464 * disabled by the `sortable` option for each column. 10465 * @type boolean 10466 * @default true 10467 * 10468 * @dtopt Features 10469 * @name DataTable.defaults.ordering 10470 * 10471 * @example 10472 * $(document).ready( function () { 10473 * $('#example').dataTable( { 10474 * "ordering": false 10475 * } ); 10476 * } ); 10477 */ 10478 "bSort": true, 10479 10480 10481 /** 10482 * Enable or display DataTables' ability to sort multiple columns at the 10483 * same time (activated by shift-click by the user). 10484 * @type boolean 10485 * @default true 10486 * 10487 * @dtopt Options 10488 * @name DataTable.defaults.orderMulti 10489 * 10490 * @example 10491 * // Disable multiple column sorting ability 10492 * $(document).ready( function () { 10493 * $('#example').dataTable( { 10494 * "orderMulti": false 10495 * } ); 10496 * } ); 10497 */ 10498 "bSortMulti": true, 10499 10500 10501 /** 10502 * Allows control over whether DataTables should use the top (true) unique 10503 * cell that is found for a single column, or the bottom (false - default). 10504 * This is useful when using complex headers. 10505 * @type boolean 10506 * @default false 10507 * 10508 * @dtopt Options 10509 * @name DataTable.defaults.orderCellsTop 10510 * 10511 * @example 10512 * $(document).ready( function() { 10513 * $('#example').dataTable( { 10514 * "orderCellsTop": true 10515 * } ); 10516 * } ); 10517 */ 10518 "bSortCellsTop": false, 10519 10520 10521 /** 10522 * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and 10523 * `sorting\_3` to the columns which are currently being sorted on. This is 10524 * presented as a feature switch as it can increase processing time (while 10525 * classes are removed and added) so for large data sets you might want to 10526 * turn this off. 10527 * @type boolean 10528 * @default true 10529 * 10530 * @dtopt Features 10531 * @name DataTable.defaults.orderClasses 10532 * 10533 * @example 10534 * $(document).ready( function () { 10535 * $('#example').dataTable( { 10536 * "orderClasses": false 10537 * } ); 10538 * } ); 10539 */ 10540 "bSortClasses": true, 10541 10542 10543 /** 10544 * Enable or disable state saving. When enabled HTML5 `localStorage` will be 10545 * used to save table display information such as pagination information, 10546 * display length, filtering and sorting. As such when the end user reloads 10547 * the page the display display will match what thy had previously set up. 10548 * 10549 * Due to the use of `localStorage` the default state saving is not supported 10550 * in IE6 or 7. If state saving is required in those browsers, use 10551 * `stateSaveCallback` to provide a storage solution such as cookies. 10552 * @type boolean 10553 * @default false 10554 * 10555 * @dtopt Features 10556 * @name DataTable.defaults.stateSave 10557 * 10558 * @example 10559 * $(document).ready( function () { 10560 * $('#example').dataTable( { 10561 * "stateSave": true 10562 * } ); 10563 * } ); 10564 */ 10565 "bStateSave": false, 10566 10567 10568 /** 10569 * This function is called when a TR element is created (and all TD child 10570 * elements have been inserted), or registered if using a DOM source, allowing 10571 * manipulation of the TR element (adding classes etc). 10572 * @type function 10573 * @param {node} row "TR" element for the current row 10574 * @param {array} data Raw data array for this row 10575 * @param {int} dataIndex The index of this row in the internal aoData array 10576 * 10577 * @dtopt Callbacks 10578 * @name DataTable.defaults.createdRow 10579 * 10580 * @example 10581 * $(document).ready( function() { 10582 * $('#example').dataTable( { 10583 * "createdRow": function( row, data, dataIndex ) { 10584 * // Bold the grade for all 'A' grade browsers 10585 * if ( data[4] == "A" ) 10586 * { 10587 * $('td:eq(4)', row).html( '<b>A</b>' ); 10588 * } 10589 * } 10590 * } ); 10591 * } ); 10592 */ 10593 "fnCreatedRow": null, 10594 10595 10596 /** 10597 * This function is called on every 'draw' event, and allows you to 10598 * dynamically modify any aspect you want about the created DOM. 10599 * @type function 10600 * @param {object} settings DataTables settings object 10601 * 10602 * @dtopt Callbacks 10603 * @name DataTable.defaults.drawCallback 10604 * 10605 * @example 10606 * $(document).ready( function() { 10607 * $('#example').dataTable( { 10608 * "drawCallback": function( settings ) { 10609 * alert( 'DataTables has redrawn the table' ); 10610 * } 10611 * } ); 10612 * } ); 10613 */ 10614 "fnDrawCallback": null, 10615 10616 10617 /** 10618 * Identical to fnHeaderCallback() but for the table footer this function 10619 * allows you to modify the table footer on every 'draw' event. 10620 * @type function 10621 * @param {node} foot "TR" element for the footer 10622 * @param {array} data Full table data (as derived from the original HTML) 10623 * @param {int} start Index for the current display starting point in the 10624 * display array 10625 * @param {int} end Index for the current display ending point in the 10626 * display array 10627 * @param {array int} display Index array to translate the visual position 10628 * to the full data array 10629 * 10630 * @dtopt Callbacks 10631 * @name DataTable.defaults.footerCallback 10632 * 10633 * @example 10634 * $(document).ready( function() { 10635 * $('#example').dataTable( { 10636 * "footerCallback": function( tfoot, data, start, end, display ) { 10637 * tfoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+start; 10638 * } 10639 * } ); 10640 * } ) 10641 */ 10642 "fnFooterCallback": null, 10643 10644 10645 /** 10646 * When rendering large numbers in the information element for the table 10647 * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers 10648 * to have a comma separator for the 'thousands' units (e.g. 1 million is 10649 * rendered as "1,000,000") to help readability for the end user. This 10650 * function will override the default method DataTables uses. 10651 * @type function 10652 * @member 10653 * @param {int} toFormat number to be formatted 10654 * @returns {string} formatted string for DataTables to show the number 10655 * 10656 * @dtopt Callbacks 10657 * @name DataTable.defaults.formatNumber 10658 * 10659 * @example 10660 * // Format a number using a single quote for the separator (note that 10661 * // this can also be done with the language.thousands option) 10662 * $(document).ready( function() { 10663 * $('#example').dataTable( { 10664 * "formatNumber": function ( toFormat ) { 10665 * return toFormat.toString().replace( 10666 * /\B(?=(\d{3})+(?!\d))/g, "'" 10667 * ); 10668 * }; 10669 * } ); 10670 * } ); 10671 */ 10672 "fnFormatNumber": function ( toFormat ) { 10673 return toFormat.toString().replace( 10674 /\B(?=(\d{3})+(?!\d))/g, 10675 this.oLanguage.sThousands 10676 ); 10677 }, 10678 10679 10680 /** 10681 * This function is called on every 'draw' event, and allows you to 10682 * dynamically modify the header row. This can be used to calculate and 10683 * display useful information about the table. 10684 * @type function 10685 * @param {node} head "TR" element for the header 10686 * @param {array} data Full table data (as derived from the original HTML) 10687 * @param {int} start Index for the current display starting point in the 10688 * display array 10689 * @param {int} end Index for the current display ending point in the 10690 * display array 10691 * @param {array int} display Index array to translate the visual position 10692 * to the full data array 10693 * 10694 * @dtopt Callbacks 10695 * @name DataTable.defaults.headerCallback 10696 * 10697 * @example 10698 * $(document).ready( function() { 10699 * $('#example').dataTable( { 10700 * "fheaderCallback": function( head, data, start, end, display ) { 10701 * head.getElementsByTagName('th')[0].innerHTML = "Displaying "+(end-start)+" records"; 10702 * } 10703 * } ); 10704 * } ) 10705 */ 10706 "fnHeaderCallback": null, 10707 10708 10709 /** 10710 * The information element can be used to convey information about the current 10711 * state of the table. Although the internationalisation options presented by 10712 * DataTables are quite capable of dealing with most customisations, there may 10713 * be times where you wish to customise the string further. This callback 10714 * allows you to do exactly that. 10715 * @type function 10716 * @param {object} oSettings DataTables settings object 10717 * @param {int} start Starting position in data for the draw 10718 * @param {int} end End position in data for the draw 10719 * @param {int} max Total number of rows in the table (regardless of 10720 * filtering) 10721 * @param {int} total Total number of rows in the data set, after filtering 10722 * @param {string} pre The string that DataTables has formatted using it's 10723 * own rules 10724 * @returns {string} The string to be displayed in the information element. 10725 * 10726 * @dtopt Callbacks 10727 * @name DataTable.defaults.infoCallback 10728 * 10729 * @example 10730 * $('#example').dataTable( { 10731 * "infoCallback": function( settings, start, end, max, total, pre ) { 10732 * return start +" to "+ end; 10733 * } 10734 * } ); 10735 */ 10736 "fnInfoCallback": null, 10737 10738 10739 /** 10740 * Called when the table has been initialised. Normally DataTables will 10741 * initialise sequentially and there will be no need for this function, 10742 * however, this does not hold true when using external language information 10743 * since that is obtained using an async XHR call. 10744 * @type function 10745 * @param {object} settings DataTables settings object 10746 * @param {object} json The JSON object request from the server - only 10747 * present if client-side Ajax sourced data is used 10748 * 10749 * @dtopt Callbacks 10750 * @name DataTable.defaults.initComplete 10751 * 10752 * @example 10753 * $(document).ready( function() { 10754 * $('#example').dataTable( { 10755 * "initComplete": function(settings, json) { 10756 * alert( 'DataTables has finished its initialisation.' ); 10757 * } 10758 * } ); 10759 * } ) 10760 */ 10761 "fnInitComplete": null, 10762 10763 10764 /** 10765 * Called at the very start of each table draw and can be used to cancel the 10766 * draw by returning false, any other return (including undefined) results in 10767 * the full draw occurring). 10768 * @type function 10769 * @param {object} settings DataTables settings object 10770 * @returns {boolean} False will cancel the draw, anything else (including no 10771 * return) will allow it to complete. 10772 * 10773 * @dtopt Callbacks 10774 * @name DataTable.defaults.preDrawCallback 10775 * 10776 * @example 10777 * $(document).ready( function() { 10778 * $('#example').dataTable( { 10779 * "preDrawCallback": function( settings ) { 10780 * if ( $('#test').val() == 1 ) { 10781 * return false; 10782 * } 10783 * } 10784 * } ); 10785 * } ); 10786 */ 10787 "fnPreDrawCallback": null, 10788 10789 10790 /** 10791 * This function allows you to 'post process' each row after it have been 10792 * generated for each table draw, but before it is rendered on screen. This 10793 * function might be used for setting the row class name etc. 10794 * @type function 10795 * @param {node} row "TR" element for the current row 10796 * @param {array} data Raw data array for this row 10797 * @param {int} displayIndex The display index for the current table draw 10798 * @param {int} displayIndexFull The index of the data in the full list of 10799 * rows (after filtering) 10800 * 10801 * @dtopt Callbacks 10802 * @name DataTable.defaults.rowCallback 10803 * 10804 * @example 10805 * $(document).ready( function() { 10806 * $('#example').dataTable( { 10807 * "rowCallback": function( row, data, displayIndex, displayIndexFull ) { 10808 * // Bold the grade for all 'A' grade browsers 10809 * if ( data[4] == "A" ) { 10810 * $('td:eq(4)', row).html( '<b>A</b>' ); 10811 * } 10812 * } 10813 * } ); 10814 * } ); 10815 */ 10816 "fnRowCallback": null, 10817 10818 10819 /** 10820 * __Deprecated__ The functionality provided by this parameter has now been 10821 * superseded by that provided through `ajax`, which should be used instead. 10822 * 10823 * This parameter allows you to override the default function which obtains 10824 * the data from the server so something more suitable for your application. 10825 * For example you could use POST data, or pull information from a Gears or 10826 * AIR database. 10827 * @type function 10828 * @member 10829 * @param {string} source HTTP source to obtain the data from (`ajax`) 10830 * @param {array} data A key/value pair object containing the data to send 10831 * to the server 10832 * @param {function} callback to be called on completion of the data get 10833 * process that will draw the data on the page. 10834 * @param {object} settings DataTables settings object 10835 * 10836 * @dtopt Callbacks 10837 * @dtopt Server-side 10838 * @name DataTable.defaults.serverData 10839 * 10840 * @deprecated 1.10. Please use `ajax` for this functionality now. 10841 */ 10842 "fnServerData": null, 10843 10844 10845 /** 10846 * __Deprecated__ The functionality provided by this parameter has now been 10847 * superseded by that provided through `ajax`, which should be used instead. 10848 * 10849 * It is often useful to send extra data to the server when making an Ajax 10850 * request - for example custom filtering information, and this callback 10851 * function makes it trivial to send extra information to the server. The 10852 * passed in parameter is the data set that has been constructed by 10853 * DataTables, and you can add to this or modify it as you require. 10854 * @type function 10855 * @param {array} data Data array (array of objects which are name/value 10856 * pairs) that has been constructed by DataTables and will be sent to the 10857 * server. In the case of Ajax sourced data with server-side processing 10858 * this will be an empty array, for server-side processing there will be a 10859 * significant number of parameters! 10860 * @returns {undefined} Ensure that you modify the data array passed in, 10861 * as this is passed by reference. 10862 * 10863 * @dtopt Callbacks 10864 * @dtopt Server-side 10865 * @name DataTable.defaults.serverParams 10866 * 10867 * @deprecated 1.10. Please use `ajax` for this functionality now. 10868 */ 10869 "fnServerParams": null, 10870 10871 10872 /** 10873 * Load the table state. With this function you can define from where, and how, the 10874 * state of a table is loaded. By default DataTables will load from `localStorage` 10875 * but you might wish to use a server-side database or cookies. 10876 * @type function 10877 * @member 10878 * @param {object} settings DataTables settings object 10879 * @return {object} The DataTables state object to be loaded 10880 * 10881 * @dtopt Callbacks 10882 * @name DataTable.defaults.stateLoadCallback 10883 * 10884 * @example 10885 * $(document).ready( function() { 10886 * $('#example').dataTable( { 10887 * "stateSave": true, 10888 * "stateLoadCallback": function (settings) { 10889 * var o; 10890 * 10891 * // Send an Ajax request to the server to get the data. Note that 10892 * // this is a synchronous request. 10893 * $.ajax( { 10894 * "url": "/state_load", 10895 * "async": false, 10896 * "dataType": "json", 10897 * "success": function (json) { 10898 * o = json; 10899 * } 10900 * } ); 10901 * 10902 * return o; 10903 * } 10904 * } ); 10905 * } ); 10906 */ 10907 "fnStateLoadCallback": function ( settings ) { 10908 try { 10909 return JSON.parse( 10910 (settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem( 10911 'DataTables_'+settings.sInstance+'_'+location.pathname 10912 ) 10913 ); 10914 } catch (e) {} 10915 }, 10916 10917 10918 /** 10919 * Callback which allows modification of the saved state prior to loading that state. 10920 * This callback is called when the table is loading state from the stored data, but 10921 * prior to the settings object being modified by the saved state. Note that for 10922 * plug-in authors, you should use the `stateLoadParams` event to load parameters for 10923 * a plug-in. 10924 * @type function 10925 * @param {object} settings DataTables settings object 10926 * @param {object} data The state object that is to be loaded 10927 * 10928 * @dtopt Callbacks 10929 * @name DataTable.defaults.stateLoadParams 10930 * 10931 * @example 10932 * // Remove a saved filter, so filtering is never loaded 10933 * $(document).ready( function() { 10934 * $('#example').dataTable( { 10935 * "stateSave": true, 10936 * "stateLoadParams": function (settings, data) { 10937 * data.oSearch.sSearch = ""; 10938 * } 10939 * } ); 10940 * } ); 10941 * 10942 * @example 10943 * // Disallow state loading by returning false 10944 * $(document).ready( function() { 10945 * $('#example').dataTable( { 10946 * "stateSave": true, 10947 * "stateLoadParams": function (settings, data) { 10948 * return false; 10949 * } 10950 * } ); 10951 * } ); 10952 */ 10953 "fnStateLoadParams": null, 10954 10955 10956 /** 10957 * Callback that is called when the state has been loaded from the state saving method 10958 * and the DataTables settings object has been modified as a result of the loaded state. 10959 * @type function 10960 * @param {object} settings DataTables settings object 10961 * @param {object} data The state object that was loaded 10962 * 10963 * @dtopt Callbacks 10964 * @name DataTable.defaults.stateLoaded 10965 * 10966 * @example 10967 * // Show an alert with the filtering value that was saved 10968 * $(document).ready( function() { 10969 * $('#example').dataTable( { 10970 * "stateSave": true, 10971 * "stateLoaded": function (settings, data) { 10972 * alert( 'Saved filter was: '+data.oSearch.sSearch ); 10973 * } 10974 * } ); 10975 * } ); 10976 */ 10977 "fnStateLoaded": null, 10978 10979 10980 /** 10981 * Save the table state. This function allows you to define where and how the state 10982 * information for the table is stored By default DataTables will use `localStorage` 10983 * but you might wish to use a server-side database or cookies. 10984 * @type function 10985 * @member 10986 * @param {object} settings DataTables settings object 10987 * @param {object} data The state object to be saved 10988 * 10989 * @dtopt Callbacks 10990 * @name DataTable.defaults.stateSaveCallback 10991 * 10992 * @example 10993 * $(document).ready( function() { 10994 * $('#example').dataTable( { 10995 * "stateSave": true, 10996 * "stateSaveCallback": function (settings, data) { 10997 * // Send an Ajax request to the server with the state object 10998 * $.ajax( { 10999 * "url": "/state_save", 11000 * "data": data, 11001 * "dataType": "json", 11002 * "method": "POST" 11003 * "success": function () {} 11004 * } ); 11005 * } 11006 * } ); 11007 * } ); 11008 */ 11009 "fnStateSaveCallback": function ( settings, data ) { 11010 try { 11011 (settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem( 11012 'DataTables_'+settings.sInstance+'_'+location.pathname, 11013 JSON.stringify( data ) 11014 ); 11015 } catch (e) {} 11016 }, 11017 11018 11019 /** 11020 * Callback which allows modification of the state to be saved. Called when the table 11021 * has changed state a new state save is required. This method allows modification of 11022 * the state saving object prior to actually doing the save, including addition or 11023 * other state properties or modification. Note that for plug-in authors, you should 11024 * use the `stateSaveParams` event to save parameters for a plug-in. 11025 * @type function 11026 * @param {object} settings DataTables settings object 11027 * @param {object} data The state object to be saved 11028 * 11029 * @dtopt Callbacks 11030 * @name DataTable.defaults.stateSaveParams 11031 * 11032 * @example 11033 * // Remove a saved filter, so filtering is never saved 11034 * $(document).ready( function() { 11035 * $('#example').dataTable( { 11036 * "stateSave": true, 11037 * "stateSaveParams": function (settings, data) { 11038 * data.oSearch.sSearch = ""; 11039 * } 11040 * } ); 11041 * } ); 11042 */ 11043 "fnStateSaveParams": null, 11044 11045 11046 /** 11047 * Duration for which the saved state information is considered valid. After this period 11048 * has elapsed the state will be returned to the default. 11049 * Value is given in seconds. 11050 * @type int 11051 * @default 7200 <i>(2 hours)</i> 11052 * 11053 * @dtopt Options 11054 * @name DataTable.defaults.stateDuration 11055 * 11056 * @example 11057 * $(document).ready( function() { 11058 * $('#example').dataTable( { 11059 * "stateDuration": 60*60*24; // 1 day 11060 * } ); 11061 * } ) 11062 */ 11063 "iStateDuration": 7200, 11064 11065 11066 /** 11067 * When enabled DataTables will not make a request to the server for the first 11068 * page draw - rather it will use the data already on the page (no sorting etc 11069 * will be applied to it), thus saving on an XHR at load time. `deferLoading` 11070 * is used to indicate that deferred loading is required, but it is also used 11071 * to tell DataTables how many records there are in the full table (allowing 11072 * the information element and pagination to be displayed correctly). In the case 11073 * where a filtering is applied to the table on initial load, this can be 11074 * indicated by giving the parameter as an array, where the first element is 11075 * the number of records available after filtering and the second element is the 11076 * number of records without filtering (allowing the table information element 11077 * to be shown correctly). 11078 * @type int | array 11079 * @default null 11080 * 11081 * @dtopt Options 11082 * @name DataTable.defaults.deferLoading 11083 * 11084 * @example 11085 * // 57 records available in the table, no filtering applied 11086 * $(document).ready( function() { 11087 * $('#example').dataTable( { 11088 * "serverSide": true, 11089 * "ajax": "scripts/server_processing.php", 11090 * "deferLoading": 57 11091 * } ); 11092 * } ); 11093 * 11094 * @example 11095 * // 57 records after filtering, 100 without filtering (an initial filter applied) 11096 * $(document).ready( function() { 11097 * $('#example').dataTable( { 11098 * "serverSide": true, 11099 * "ajax": "scripts/server_processing.php", 11100 * "deferLoading": [ 57, 100 ], 11101 * "search": { 11102 * "search": "my_filter" 11103 * } 11104 * } ); 11105 * } ); 11106 */ 11107 "iDeferLoading": null, 11108 11109 11110 /** 11111 * Number of rows to display on a single page when using pagination. If 11112 * feature enabled (`lengthChange`) then the end user will be able to override 11113 * this to a custom setting using a pop-up menu. 11114 * @type int 11115 * @default 10 11116 * 11117 * @dtopt Options 11118 * @name DataTable.defaults.pageLength 11119 * 11120 * @example 11121 * $(document).ready( function() { 11122 * $('#example').dataTable( { 11123 * "pageLength": 50 11124 * } ); 11125 * } ) 11126 */ 11127 "iDisplayLength": 10, 11128 11129 11130 /** 11131 * Define the starting point for data display when using DataTables with 11132 * pagination. Note that this parameter is the number of records, rather than 11133 * the page number, so if you have 10 records per page and want to start on 11134 * the third page, it should be "20". 11135 * @type int 11136 * @default 0 11137 * 11138 * @dtopt Options 11139 * @name DataTable.defaults.displayStart 11140 * 11141 * @example 11142 * $(document).ready( function() { 11143 * $('#example').dataTable( { 11144 * "displayStart": 20 11145 * } ); 11146 * } ) 11147 */ 11148 "iDisplayStart": 0, 11149 11150 11151 /** 11152 * By default DataTables allows keyboard navigation of the table (sorting, paging, 11153 * and filtering) by adding a `tabindex` attribute to the required elements. This 11154 * allows you to tab through the controls and press the enter key to activate them. 11155 * The tabindex is default 0, meaning that the tab follows the flow of the document. 11156 * You can overrule this using this parameter if you wish. Use a value of -1 to 11157 * disable built-in keyboard navigation. 11158 * @type int 11159 * @default 0 11160 * 11161 * @dtopt Options 11162 * @name DataTable.defaults.tabIndex 11163 * 11164 * @example 11165 * $(document).ready( function() { 11166 * $('#example').dataTable( { 11167 * "tabIndex": 1 11168 * } ); 11169 * } ); 11170 */ 11171 "iTabIndex": 0, 11172 11173 11174 /** 11175 * Classes that DataTables assigns to the various components and features 11176 * that it adds to the HTML table. This allows classes to be configured 11177 * during initialisation in addition to through the static 11178 * {@link DataTable.ext.oStdClasses} object). 11179 * @namespace 11180 * @name DataTable.defaults.classes 11181 */ 11182 "oClasses": {}, 11183 11184 11185 /** 11186 * All strings that DataTables uses in the user interface that it creates 11187 * are defined in this object, allowing you to modified them individually or 11188 * completely replace them all as required. 11189 * @namespace 11190 * @name DataTable.defaults.language 11191 */ 11192 "oLanguage": { 11193 /** 11194 * Strings that are used for WAI-ARIA labels and controls only (these are not 11195 * actually visible on the page, but will be read by screenreaders, and thus 11196 * must be internationalised as well). 11197 * @namespace 11198 * @name DataTable.defaults.language.aria 11199 */ 11200 "oAria": { 11201 /** 11202 * ARIA label that is added to the table headers when the column may be 11203 * sorted ascending by activing the column (click or return when focused). 11204 * Note that the column header is prefixed to this string. 11205 * @type string 11206 * @default : activate to sort column ascending 11207 * 11208 * @dtopt Language 11209 * @name DataTable.defaults.language.aria.sortAscending 11210 * 11211 * @example 11212 * $(document).ready( function() { 11213 * $('#example').dataTable( { 11214 * "language": { 11215 * "aria": { 11216 * "sortAscending": " - click/return to sort ascending" 11217 * } 11218 * } 11219 * } ); 11220 * } ); 11221 */ 11222 "sSortAscending": ": activate to sort column ascending", 11223 11224 /** 11225 * ARIA label that is added to the table headers when the column may be 11226 * sorted descending by activing the column (click or return when focused). 11227 * Note that the column header is prefixed to this string. 11228 * @type string 11229 * @default : activate to sort column ascending 11230 * 11231 * @dtopt Language 11232 * @name DataTable.defaults.language.aria.sortDescending 11233 * 11234 * @example 11235 * $(document).ready( function() { 11236 * $('#example').dataTable( { 11237 * "language": { 11238 * "aria": { 11239 * "sortDescending": " - click/return to sort descending" 11240 * } 11241 * } 11242 * } ); 11243 * } ); 11244 */ 11245 "sSortDescending": ": activate to sort column descending" 11246 }, 11247 11248 /** 11249 * Pagination string used by DataTables for the built-in pagination 11250 * control types. 11251 * @namespace 11252 * @name DataTable.defaults.language.paginate 11253 */ 11254 "oPaginate": { 11255 /** 11256 * Text to use when using the 'full_numbers' type of pagination for the 11257 * button to take the user to the first page. 11258 * @type string 11259 * @default First 11260 * 11261 * @dtopt Language 11262 * @name DataTable.defaults.language.paginate.first 11263 * 11264 * @example 11265 * $(document).ready( function() { 11266 * $('#example').dataTable( { 11267 * "language": { 11268 * "paginate": { 11269 * "first": "First page" 11270 * } 11271 * } 11272 * } ); 11273 * } ); 11274 */ 11275 "sFirst": "First", 11276 11277 11278 /** 11279 * Text to use when using the 'full_numbers' type of pagination for the 11280 * button to take the user to the last page. 11281 * @type string 11282 * @default Last 11283 * 11284 * @dtopt Language 11285 * @name DataTable.defaults.language.paginate.last 11286 * 11287 * @example 11288 * $(document).ready( function() { 11289 * $('#example').dataTable( { 11290 * "language": { 11291 * "paginate": { 11292 * "last": "Last page" 11293 * } 11294 * } 11295 * } ); 11296 * } ); 11297 */ 11298 "sLast": "Last", 11299 11300 11301 /** 11302 * Text to use for the 'next' pagination button (to take the user to the 11303 * next page). 11304 * @type string 11305 * @default Next 11306 * 11307 * @dtopt Language 11308 * @name DataTable.defaults.language.paginate.next 11309 * 11310 * @example 11311 * $(document).ready( function() { 11312 * $('#example').dataTable( { 11313 * "language": { 11314 * "paginate": { 11315 * "next": "Next page" 11316 * } 11317 * } 11318 * } ); 11319 * } ); 11320 */ 11321 "sNext": "Next", 11322 11323 11324 /** 11325 * Text to use for the 'previous' pagination button (to take the user to 11326 * the previous page). 11327 * @type string 11328 * @default Previous 11329 * 11330 * @dtopt Language 11331 * @name DataTable.defaults.language.paginate.previous 11332 * 11333 * @example 11334 * $(document).ready( function() { 11335 * $('#example').dataTable( { 11336 * "language": { 11337 * "paginate": { 11338 * "previous": "Previous page" 11339 * } 11340 * } 11341 * } ); 11342 * } ); 11343 */ 11344 "sPrevious": "Previous" 11345 }, 11346 11347 /** 11348 * This string is shown in preference to `zeroRecords` when the table is 11349 * empty of data (regardless of filtering). Note that this is an optional 11350 * parameter - if it is not given, the value of `zeroRecords` will be used 11351 * instead (either the default or given value). 11352 * @type string 11353 * @default No data available in table 11354 * 11355 * @dtopt Language 11356 * @name DataTable.defaults.language.emptyTable 11357 * 11358 * @example 11359 * $(document).ready( function() { 11360 * $('#example').dataTable( { 11361 * "language": { 11362 * "emptyTable": "No data available in table" 11363 * } 11364 * } ); 11365 * } ); 11366 */ 11367 "sEmptyTable": "No data available in table", 11368 11369 11370 /** 11371 * This string gives information to the end user about the information 11372 * that is current on display on the page. The following tokens can be 11373 * used in the string and will be dynamically replaced as the table 11374 * display updates. This tokens can be placed anywhere in the string, or 11375 * removed as needed by the language requires: 11376 * 11377 * * `\_START\_` - Display index of the first record on the current page 11378 * * `\_END\_` - Display index of the last record on the current page 11379 * * `\_TOTAL\_` - Number of records in the table after filtering 11380 * * `\_MAX\_` - Number of records in the table without filtering 11381 * * `\_PAGE\_` - Current page number 11382 * * `\_PAGES\_` - Total number of pages of data in the table 11383 * 11384 * @type string 11385 * @default Showing _START_ to _END_ of _TOTAL_ entries 11386 * 11387 * @dtopt Language 11388 * @name DataTable.defaults.language.info 11389 * 11390 * @example 11391 * $(document).ready( function() { 11392 * $('#example').dataTable( { 11393 * "language": { 11394 * "info": "Showing page _PAGE_ of _PAGES_" 11395 * } 11396 * } ); 11397 * } ); 11398 */ 11399 "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries", 11400 11401 11402 /** 11403 * Display information string for when the table is empty. Typically the 11404 * format of this string should match `info`. 11405 * @type string 11406 * @default Showing 0 to 0 of 0 entries 11407 * 11408 * @dtopt Language 11409 * @name DataTable.defaults.language.infoEmpty 11410 * 11411 * @example 11412 * $(document).ready( function() { 11413 * $('#example').dataTable( { 11414 * "language": { 11415 * "infoEmpty": "No entries to show" 11416 * } 11417 * } ); 11418 * } ); 11419 */ 11420 "sInfoEmpty": "Showing 0 to 0 of 0 entries", 11421 11422 11423 /** 11424 * When a user filters the information in a table, this string is appended 11425 * to the information (`info`) to give an idea of how strong the filtering 11426 * is. The variable _MAX_ is dynamically updated. 11427 * @type string 11428 * @default (filtered from _MAX_ total entries) 11429 * 11430 * @dtopt Language 11431 * @name DataTable.defaults.language.infoFiltered 11432 * 11433 * @example 11434 * $(document).ready( function() { 11435 * $('#example').dataTable( { 11436 * "language": { 11437 * "infoFiltered": " - filtering from _MAX_ records" 11438 * } 11439 * } ); 11440 * } ); 11441 */ 11442 "sInfoFiltered": "(filtered from _MAX_ total entries)", 11443 11444 11445 /** 11446 * If can be useful to append extra information to the info string at times, 11447 * and this variable does exactly that. This information will be appended to 11448 * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are 11449 * being used) at all times. 11450 * @type string 11451 * @default <i>Empty string</i> 11452 * 11453 * @dtopt Language 11454 * @name DataTable.defaults.language.infoPostFix 11455 * 11456 * @example 11457 * $(document).ready( function() { 11458 * $('#example').dataTable( { 11459 * "language": { 11460 * "infoPostFix": "All records shown are derived from real information." 11461 * } 11462 * } ); 11463 * } ); 11464 */ 11465 "sInfoPostFix": "", 11466 11467 11468 /** 11469 * This decimal place operator is a little different from the other 11470 * language options since DataTables doesn't output floating point 11471 * numbers, so it won't ever use this for display of a number. Rather, 11472 * what this parameter does is modify the sort methods of the table so 11473 * that numbers which are in a format which has a character other than 11474 * a period (`.`) as a decimal place will be sorted numerically. 11475 * 11476 * Note that numbers with different decimal places cannot be shown in 11477 * the same table and still be sortable, the table must be consistent. 11478 * However, multiple different tables on the page can use different 11479 * decimal place characters. 11480 * @type string 11481 * @default 11482 * 11483 * @dtopt Language 11484 * @name DataTable.defaults.language.decimal 11485 * 11486 * @example 11487 * $(document).ready( function() { 11488 * $('#example').dataTable( { 11489 * "language": { 11490 * "decimal": "," 11491 * "thousands": "." 11492 * } 11493 * } ); 11494 * } ); 11495 */ 11496 "sDecimal": "", 11497 11498 11499 /** 11500 * DataTables has a build in number formatter (`formatNumber`) which is 11501 * used to format large numbers that are used in the table information. 11502 * By default a comma is used, but this can be trivially changed to any 11503 * character you wish with this parameter. 11504 * @type string 11505 * @default , 11506 * 11507 * @dtopt Language 11508 * @name DataTable.defaults.language.thousands 11509 * 11510 * @example 11511 * $(document).ready( function() { 11512 * $('#example').dataTable( { 11513 * "language": { 11514 * "thousands": "'" 11515 * } 11516 * } ); 11517 * } ); 11518 */ 11519 "sThousands": ",", 11520 11521 11522 /** 11523 * Detail the action that will be taken when the drop down menu for the 11524 * pagination length option is changed. The '_MENU_' variable is replaced 11525 * with a default select list of 10, 25, 50 and 100, and can be replaced 11526 * with a custom select box if required. 11527 * @type string 11528 * @default Show _MENU_ entries 11529 * 11530 * @dtopt Language 11531 * @name DataTable.defaults.language.lengthMenu 11532 * 11533 * @example 11534 * // Language change only 11535 * $(document).ready( function() { 11536 * $('#example').dataTable( { 11537 * "language": { 11538 * "lengthMenu": "Display _MENU_ records" 11539 * } 11540 * } ); 11541 * } ); 11542 * 11543 * @example 11544 * // Language and options change 11545 * $(document).ready( function() { 11546 * $('#example').dataTable( { 11547 * "language": { 11548 * "lengthMenu": 'Display <select>'+ 11549 * '<option value="10">10</option>'+ 11550 * '<option value="20">20</option>'+ 11551 * '<option value="30">30</option>'+ 11552 * '<option value="40">40</option>'+ 11553 * '<option value="50">50</option>'+ 11554 * '<option value="-1">All</option>'+ 11555 * '</select> records' 11556 * } 11557 * } ); 11558 * } ); 11559 */ 11560 "sLengthMenu": "Show _MENU_ entries", 11561 11562 11563 /** 11564 * When using Ajax sourced data and during the first draw when DataTables is 11565 * gathering the data, this message is shown in an empty row in the table to 11566 * indicate to the end user the the data is being loaded. Note that this 11567 * parameter is not used when loading data by server-side processing, just 11568 * Ajax sourced data with client-side processing. 11569 * @type string 11570 * @default Loading... 11571 * 11572 * @dtopt Language 11573 * @name DataTable.defaults.language.loadingRecords 11574 * 11575 * @example 11576 * $(document).ready( function() { 11577 * $('#example').dataTable( { 11578 * "language": { 11579 * "loadingRecords": "Please wait - loading..." 11580 * } 11581 * } ); 11582 * } ); 11583 */ 11584 "sLoadingRecords": "Loading...", 11585 11586 11587 /** 11588 * Text which is displayed when the table is processing a user action 11589 * (usually a sort command or similar). 11590 * @type string 11591 * @default Processing... 11592 * 11593 * @dtopt Language 11594 * @name DataTable.defaults.language.processing 11595 * 11596 * @example 11597 * $(document).ready( function() { 11598 * $('#example').dataTable( { 11599 * "language": { 11600 * "processing": "DataTables is currently busy" 11601 * } 11602 * } ); 11603 * } ); 11604 */ 11605 "sProcessing": "Processing...", 11606 11607 11608 /** 11609 * Details the actions that will be taken when the user types into the 11610 * filtering input text box. The variable "_INPUT_", if used in the string, 11611 * is replaced with the HTML text box for the filtering input allowing 11612 * control over where it appears in the string. If "_INPUT_" is not given 11613 * then the input box is appended to the string automatically. 11614 * @type string 11615 * @default Search: 11616 * 11617 * @dtopt Language 11618 * @name DataTable.defaults.language.search 11619 * 11620 * @example 11621 * // Input text box will be appended at the end automatically 11622 * $(document).ready( function() { 11623 * $('#example').dataTable( { 11624 * "language": { 11625 * "search": "Filter records:" 11626 * } 11627 * } ); 11628 * } ); 11629 * 11630 * @example 11631 * // Specify where the filter should appear 11632 * $(document).ready( function() { 11633 * $('#example').dataTable( { 11634 * "language": { 11635 * "search": "Apply filter _INPUT_ to table" 11636 * } 11637 * } ); 11638 * } ); 11639 */ 11640 "sSearch": "Search:", 11641 11642 11643 /** 11644 * Assign a `placeholder` attribute to the search `input` element 11645 * @type string 11646 * @default 11647 * 11648 * @dtopt Language 11649 * @name DataTable.defaults.language.searchPlaceholder 11650 */ 11651 "sSearchPlaceholder": "", 11652 11653 11654 /** 11655 * All of the language information can be stored in a file on the 11656 * server-side, which DataTables will look up if this parameter is passed. 11657 * It must store the URL of the language file, which is in a JSON format, 11658 * and the object has the same properties as the oLanguage object in the 11659 * initialiser object (i.e. the above parameters). Please refer to one of 11660 * the example language files to see how this works in action. 11661 * @type string 11662 * @default <i>Empty string - i.e. disabled</i> 11663 * 11664 * @dtopt Language 11665 * @name DataTable.defaults.language.url 11666 * 11667 * @example 11668 * $(document).ready( function() { 11669 * $('#example').dataTable( { 11670 * "language": { 11671 * "url": "http://www.sprymedia.co.uk/dataTables/lang.txt" 11672 * } 11673 * } ); 11674 * } ); 11675 */ 11676 "sUrl": "", 11677 11678 11679 /** 11680 * Text shown inside the table records when the is no information to be 11681 * displayed after filtering. `emptyTable` is shown when there is simply no 11682 * information in the table at all (regardless of filtering). 11683 * @type string 11684 * @default No matching records found 11685 * 11686 * @dtopt Language 11687 * @name DataTable.defaults.language.zeroRecords 11688 * 11689 * @example 11690 * $(document).ready( function() { 11691 * $('#example').dataTable( { 11692 * "language": { 11693 * "zeroRecords": "No records to display" 11694 * } 11695 * } ); 11696 * } ); 11697 */ 11698 "sZeroRecords": "No matching records found" 11699 }, 11700 11701 11702 /** 11703 * This parameter allows you to have define the global filtering state at 11704 * initialisation time. As an object the `search` parameter must be 11705 * defined, but all other parameters are optional. When `regex` is true, 11706 * the search string will be treated as a regular expression, when false 11707 * (default) it will be treated as a straight string. When `smart` 11708 * DataTables will use it's smart filtering methods (to word match at 11709 * any point in the data), when false this will not be done. 11710 * @namespace 11711 * @extends DataTable.models.oSearch 11712 * 11713 * @dtopt Options 11714 * @name DataTable.defaults.search 11715 * 11716 * @example 11717 * $(document).ready( function() { 11718 * $('#example').dataTable( { 11719 * "search": {"search": "Initial search"} 11720 * } ); 11721 * } ) 11722 */ 11723 "oSearch": $.extend( {}, DataTable.models.oSearch ), 11724 11725 11726 /** 11727 * __Deprecated__ The functionality provided by this parameter has now been 11728 * superseded by that provided through `ajax`, which should be used instead. 11729 * 11730 * By default DataTables will look for the property `data` (or `aaData` for 11731 * compatibility with DataTables 1.9-) when obtaining data from an Ajax 11732 * source or for server-side processing - this parameter allows that 11733 * property to be changed. You can use Javascript dotted object notation to 11734 * get a data source for multiple levels of nesting. 11735 * @type string 11736 * @default data 11737 * 11738 * @dtopt Options 11739 * @dtopt Server-side 11740 * @name DataTable.defaults.ajaxDataProp 11741 * 11742 * @deprecated 1.10. Please use `ajax` for this functionality now. 11743 */ 11744 "sAjaxDataProp": "data", 11745 11746 11747 /** 11748 * __Deprecated__ The functionality provided by this parameter has now been 11749 * superseded by that provided through `ajax`, which should be used instead. 11750 * 11751 * You can instruct DataTables to load data from an external 11752 * source using this parameter (use aData if you want to pass data in you 11753 * already have). Simply provide a url a JSON object can be obtained from. 11754 * @type string 11755 * @default null 11756 * 11757 * @dtopt Options 11758 * @dtopt Server-side 11759 * @name DataTable.defaults.ajaxSource 11760 * 11761 * @deprecated 1.10. Please use `ajax` for this functionality now. 11762 */ 11763 "sAjaxSource": null, 11764 11765 11766 /** 11767 * This initialisation variable allows you to specify exactly where in the 11768 * DOM you want DataTables to inject the various controls it adds to the page 11769 * (for example you might want the pagination controls at the top of the 11770 * table). DIV elements (with or without a custom class) can also be added to 11771 * aid styling. The follow syntax is used: 11772 * <ul> 11773 * <li>The following options are allowed: 11774 * <ul> 11775 * <li>'l' - Length changing</li> 11776 * <li>'f' - Filtering input</li> 11777 * <li>'t' - The table!</li> 11778 * <li>'i' - Information</li> 11779 * <li>'p' - Pagination</li> 11780 * <li>'r' - pRocessing</li> 11781 * </ul> 11782 * </li> 11783 * <li>The following constants are allowed: 11784 * <ul> 11785 * <li>'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li> 11786 * <li>'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li> 11787 * </ul> 11788 * </li> 11789 * <li>The following syntax is expected: 11790 * <ul> 11791 * <li>'<' and '>' - div elements</li> 11792 * <li>'<"class" and '>' - div with a class</li> 11793 * <li>'<"#id" and '>' - div with an ID</li> 11794 * </ul> 11795 * </li> 11796 * <li>Examples: 11797 * <ul> 11798 * <li>'<"wrapper"flipt>'</li> 11799 * <li>'<lf<t>ip>'</li> 11800 * </ul> 11801 * </li> 11802 * </ul> 11803 * @type string 11804 * @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b> 11805 * <"H"lfr>t<"F"ip> <i>(when `jQueryUI` is true)</i> 11806 * 11807 * @dtopt Options 11808 * @name DataTable.defaults.dom 11809 * 11810 * @example 11811 * $(document).ready( function() { 11812 * $('#example').dataTable( { 11813 * "dom": '<"top"i>rt<"bottom"flp><"clear">' 11814 * } ); 11815 * } ); 11816 */ 11817 "sDom": "lfrtip", 11818 11819 11820 /** 11821 * Search delay option. This will throttle full table searches that use the 11822 * DataTables provided search input element (it does not effect calls to 11823 * `dt-api search()`, providing a delay before the search is made. 11824 * @type integer 11825 * @default 0 11826 * 11827 * @dtopt Options 11828 * @name DataTable.defaults.searchDelay 11829 * 11830 * @example 11831 * $(document).ready( function() { 11832 * $('#example').dataTable( { 11833 * "searchDelay": 200 11834 * } ); 11835 * } ) 11836 */ 11837 "searchDelay": null, 11838 11839 11840 /** 11841 * DataTables features four different built-in options for the buttons to 11842 * display for pagination control: 11843 * 11844 * * `simple` - 'Previous' and 'Next' buttons only 11845 * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers 11846 * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons 11847 * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus 11848 * page numbers 11849 * 11850 * Further methods can be added using {@link DataTable.ext.oPagination}. 11851 * @type string 11852 * @default simple_numbers 11853 * 11854 * @dtopt Options 11855 * @name DataTable.defaults.pagingType 11856 * 11857 * @example 11858 * $(document).ready( function() { 11859 * $('#example').dataTable( { 11860 * "pagingType": "full_numbers" 11861 * } ); 11862 * } ) 11863 */ 11864 "sPaginationType": "simple_numbers", 11865 11866 11867 /** 11868 * Enable horizontal scrolling. When a table is too wide to fit into a 11869 * certain layout, or you have a large number of columns in the table, you 11870 * can enable x-scrolling to show the table in a viewport, which can be 11871 * scrolled. This property can be `true` which will allow the table to 11872 * scroll horizontally when needed, or any CSS unit, or a number (in which 11873 * case it will be treated as a pixel measurement). Setting as simply `true` 11874 * is recommended. 11875 * @type boolean|string 11876 * @default <i>blank string - i.e. disabled</i> 11877 * 11878 * @dtopt Features 11879 * @name DataTable.defaults.scrollX 11880 * 11881 * @example 11882 * $(document).ready( function() { 11883 * $('#example').dataTable( { 11884 * "scrollX": true, 11885 * "scrollCollapse": true 11886 * } ); 11887 * } ); 11888 */ 11889 "sScrollX": "", 11890 11891 11892 /** 11893 * This property can be used to force a DataTable to use more width than it 11894 * might otherwise do when x-scrolling is enabled. For example if you have a 11895 * table which requires to be well spaced, this parameter is useful for 11896 * "over-sizing" the table, and thus forcing scrolling. This property can by 11897 * any CSS unit, or a number (in which case it will be treated as a pixel 11898 * measurement). 11899 * @type string 11900 * @default <i>blank string - i.e. disabled</i> 11901 * 11902 * @dtopt Options 11903 * @name DataTable.defaults.scrollXInner 11904 * 11905 * @example 11906 * $(document).ready( function() { 11907 * $('#example').dataTable( { 11908 * "scrollX": "100%", 11909 * "scrollXInner": "110%" 11910 * } ); 11911 * } ); 11912 */ 11913 "sScrollXInner": "", 11914 11915 11916 /** 11917 * Enable vertical scrolling. Vertical scrolling will constrain the DataTable 11918 * to the given height, and enable scrolling for any data which overflows the 11919 * current viewport. This can be used as an alternative to paging to display 11920 * a lot of data in a small area (although paging and scrolling can both be 11921 * enabled at the same time). This property can be any CSS unit, or a number 11922 * (in which case it will be treated as a pixel measurement). 11923 * @type string 11924 * @default <i>blank string - i.e. disabled</i> 11925 * 11926 * @dtopt Features 11927 * @name DataTable.defaults.scrollY 11928 * 11929 * @example 11930 * $(document).ready( function() { 11931 * $('#example').dataTable( { 11932 * "scrollY": "200px", 11933 * "paginate": false 11934 * } ); 11935 * } ); 11936 */ 11937 "sScrollY": "", 11938 11939 11940 /** 11941 * __Deprecated__ The functionality provided by this parameter has now been 11942 * superseded by that provided through `ajax`, which should be used instead. 11943 * 11944 * Set the HTTP method that is used to make the Ajax call for server-side 11945 * processing or Ajax sourced data. 11946 * @type string 11947 * @default GET 11948 * 11949 * @dtopt Options 11950 * @dtopt Server-side 11951 * @name DataTable.defaults.serverMethod 11952 * 11953 * @deprecated 1.10. Please use `ajax` for this functionality now. 11954 */ 11955 "sServerMethod": "GET", 11956 11957 11958 /** 11959 * DataTables makes use of renderers when displaying HTML elements for 11960 * a table. These renderers can be added or modified by plug-ins to 11961 * generate suitable mark-up for a site. For example the Bootstrap 11962 * integration plug-in for DataTables uses a paging button renderer to 11963 * display pagination buttons in the mark-up required by Bootstrap. 11964 * 11965 * For further information about the renderers available see 11966 * DataTable.ext.renderer 11967 * @type string|object 11968 * @default null 11969 * 11970 * @name DataTable.defaults.renderer 11971 * 11972 */ 11973 "renderer": null, 11974 11975 11976 /** 11977 * Set the data property name that DataTables should use to get a row's id 11978 * to set as the `id` property in the node. 11979 * @type string 11980 * @default DT_RowId 11981 * 11982 * @name DataTable.defaults.rowId 11983 */ 11984 "rowId": "DT_RowId" 11985 }; 11986 11987 _fnHungarianMap( DataTable.defaults ); 11988 11989 11990 11991 /* 11992 * Developer note - See note in model.defaults.js about the use of Hungarian 11993 * notation and camel case. 11994 */ 11995 11996 /** 11997 * Column options that can be given to DataTables at initialisation time. 11998 * @namespace 11999 */ 12000 DataTable.defaults.column = { 12001 /** 12002 * Define which column(s) an order will occur on for this column. This 12003 * allows a column's ordering to take multiple columns into account when 12004 * doing a sort or use the data from a different column. For example first 12005 * name / last name columns make sense to do a multi-column sort over the 12006 * two columns. 12007 * @type array|int 12008 * @default null <i>Takes the value of the column index automatically</i> 12009 * 12010 * @name DataTable.defaults.column.orderData 12011 * @dtopt Columns 12012 * 12013 * @example 12014 * // Using `columnDefs` 12015 * $(document).ready( function() { 12016 * $('#example').dataTable( { 12017 * "columnDefs": [ 12018 * { "orderData": [ 0, 1 ], "targets": [ 0 ] }, 12019 * { "orderData": [ 1, 0 ], "targets": [ 1 ] }, 12020 * { "orderData": 2, "targets": [ 2 ] } 12021 * ] 12022 * } ); 12023 * } ); 12024 * 12025 * @example 12026 * // Using `columns` 12027 * $(document).ready( function() { 12028 * $('#example').dataTable( { 12029 * "columns": [ 12030 * { "orderData": [ 0, 1 ] }, 12031 * { "orderData": [ 1, 0 ] }, 12032 * { "orderData": 2 }, 12033 * null, 12034 * null 12035 * ] 12036 * } ); 12037 * } ); 12038 */ 12039 "aDataSort": null, 12040 "iDataSort": -1, 12041 12042 12043 /** 12044 * You can control the default ordering direction, and even alter the 12045 * behaviour of the sort handler (i.e. only allow ascending ordering etc) 12046 * using this parameter. 12047 * @type array 12048 * @default [ 'asc', 'desc' ] 12049 * 12050 * @name DataTable.defaults.column.orderSequence 12051 * @dtopt Columns 12052 * 12053 * @example 12054 * // Using `columnDefs` 12055 * $(document).ready( function() { 12056 * $('#example').dataTable( { 12057 * "columnDefs": [ 12058 * { "orderSequence": [ "asc" ], "targets": [ 1 ] }, 12059 * { "orderSequence": [ "desc", "asc", "asc" ], "targets": [ 2 ] }, 12060 * { "orderSequence": [ "desc" ], "targets": [ 3 ] } 12061 * ] 12062 * } ); 12063 * } ); 12064 * 12065 * @example 12066 * // Using `columns` 12067 * $(document).ready( function() { 12068 * $('#example').dataTable( { 12069 * "columns": [ 12070 * null, 12071 * { "orderSequence": [ "asc" ] }, 12072 * { "orderSequence": [ "desc", "asc", "asc" ] }, 12073 * { "orderSequence": [ "desc" ] }, 12074 * null 12075 * ] 12076 * } ); 12077 * } ); 12078 */ 12079 "asSorting": [ 'asc', 'desc' ], 12080 12081 12082 /** 12083 * Enable or disable filtering on the data in this column. 12084 * @type boolean 12085 * @default true 12086 * 12087 * @name DataTable.defaults.column.searchable 12088 * @dtopt Columns 12089 * 12090 * @example 12091 * // Using `columnDefs` 12092 * $(document).ready( function() { 12093 * $('#example').dataTable( { 12094 * "columnDefs": [ 12095 * { "searchable": false, "targets": [ 0 ] } 12096 * ] } ); 12097 * } ); 12098 * 12099 * @example 12100 * // Using `columns` 12101 * $(document).ready( function() { 12102 * $('#example').dataTable( { 12103 * "columns": [ 12104 * { "searchable": false }, 12105 * null, 12106 * null, 12107 * null, 12108 * null 12109 * ] } ); 12110 * } ); 12111 */ 12112 "bSearchable": true, 12113 12114 12115 /** 12116 * Enable or disable ordering on this column. 12117 * @type boolean 12118 * @default true 12119 * 12120 * @name DataTable.defaults.column.orderable 12121 * @dtopt Columns 12122 * 12123 * @example 12124 * // Using `columnDefs` 12125 * $(document).ready( function() { 12126 * $('#example').dataTable( { 12127 * "columnDefs": [ 12128 * { "orderable": false, "targets": [ 0 ] } 12129 * ] } ); 12130 * } ); 12131 * 12132 * @example 12133 * // Using `columns` 12134 * $(document).ready( function() { 12135 * $('#example').dataTable( { 12136 * "columns": [ 12137 * { "orderable": false }, 12138 * null, 12139 * null, 12140 * null, 12141 * null 12142 * ] } ); 12143 * } ); 12144 */ 12145 "bSortable": true, 12146 12147 12148 /** 12149 * Enable or disable the display of this column. 12150 * @type boolean 12151 * @default true 12152 * 12153 * @name DataTable.defaults.column.visible 12154 * @dtopt Columns 12155 * 12156 * @example 12157 * // Using `columnDefs` 12158 * $(document).ready( function() { 12159 * $('#example').dataTable( { 12160 * "columnDefs": [ 12161 * { "visible": false, "targets": [ 0 ] } 12162 * ] } ); 12163 * } ); 12164 * 12165 * @example 12166 * // Using `columns` 12167 * $(document).ready( function() { 12168 * $('#example').dataTable( { 12169 * "columns": [ 12170 * { "visible": false }, 12171 * null, 12172 * null, 12173 * null, 12174 * null 12175 * ] } ); 12176 * } ); 12177 */ 12178 "bVisible": true, 12179 12180 12181 /** 12182 * Developer definable function that is called whenever a cell is created (Ajax source, 12183 * etc) or processed for input (DOM source). This can be used as a compliment to mRender 12184 * allowing you to modify the DOM element (add background colour for example) when the 12185 * element is available. 12186 * @type function 12187 * @param {element} td The TD node that has been created 12188 * @param {*} cellData The Data for the cell 12189 * @param {array|object} rowData The data for the whole row 12190 * @param {int} row The row index for the aoData data store 12191 * @param {int} col The column index for aoColumns 12192 * 12193 * @name DataTable.defaults.column.createdCell 12194 * @dtopt Columns 12195 * 12196 * @example 12197 * $(document).ready( function() { 12198 * $('#example').dataTable( { 12199 * "columnDefs": [ { 12200 * "targets": [3], 12201 * "createdCell": function (td, cellData, rowData, row, col) { 12202 * if ( cellData == "1.7" ) { 12203 * $(td).css('color', 'blue') 12204 * } 12205 * } 12206 * } ] 12207 * }); 12208 * } ); 12209 */ 12210 "fnCreatedCell": null, 12211 12212 12213 /** 12214 * This parameter has been replaced by `data` in DataTables to ensure naming 12215 * consistency. `dataProp` can still be used, as there is backwards 12216 * compatibility in DataTables for this option, but it is strongly 12217 * recommended that you use `data` in preference to `dataProp`. 12218 * @name DataTable.defaults.column.dataProp 12219 */ 12220 12221 12222 /** 12223 * This property can be used to read data from any data source property, 12224 * including deeply nested objects / properties. `data` can be given in a 12225 * number of different ways which effect its behaviour: 12226 * 12227 * * `integer` - treated as an array index for the data source. This is the 12228 * default that DataTables uses (incrementally increased for each column). 12229 * * `string` - read an object property from the data source. There are 12230 * three 'special' options that can be used in the string to alter how 12231 * DataTables reads the data from the source object: 12232 * * `.` - Dotted Javascript notation. Just as you use a `.` in 12233 * Javascript to read from nested objects, so to can the options 12234 * specified in `data`. For example: `browser.version` or 12235 * `browser.name`. If your object parameter name contains a period, use 12236 * `\\` to escape it - i.e. `first\\.name`. 12237 * * `[]` - Array notation. DataTables can automatically combine data 12238 * from and array source, joining the data with the characters provided 12239 * between the two brackets. For example: `name[, ]` would provide a 12240 * comma-space separated list from the source array. If no characters 12241 * are provided between the brackets, the original array source is 12242 * returned. 12243 * * `()` - Function notation. Adding `()` to the end of a parameter will 12244 * execute a function of the name given. For example: `browser()` for a 12245 * simple function on the data source, `browser.version()` for a 12246 * function in a nested property or even `browser().version` to get an 12247 * object property if the function called returns an object. Note that 12248 * function notation is recommended for use in `render` rather than 12249 * `data` as it is much simpler to use as a renderer. 12250 * * `null` - use the original data source for the row rather than plucking 12251 * data directly from it. This action has effects on two other 12252 * initialisation options: 12253 * * `defaultContent` - When null is given as the `data` option and 12254 * `defaultContent` is specified for the column, the value defined by 12255 * `defaultContent` will be used for the cell. 12256 * * `render` - When null is used for the `data` option and the `render` 12257 * option is specified for the column, the whole data source for the 12258 * row is used for the renderer. 12259 * * `function` - the function given will be executed whenever DataTables 12260 * needs to set or get the data for a cell in the column. The function 12261 * takes three parameters: 12262 * * Parameters: 12263 * * `{array|object}` The data source for the row 12264 * * `{string}` The type call data requested - this will be 'set' when 12265 * setting data or 'filter', 'display', 'type', 'sort' or undefined 12266 * when gathering data. Note that when `undefined` is given for the 12267 * type DataTables expects to get the raw data for the object back< 12268 * * `{*}` Data to set when the second parameter is 'set'. 12269 * * Return: 12270 * * The return value from the function is not required when 'set' is 12271 * the type of call, but otherwise the return is what will be used 12272 * for the data requested. 12273 * 12274 * Note that `data` is a getter and setter option. If you just require 12275 * formatting of data for output, you will likely want to use `render` which 12276 * is simply a getter and thus simpler to use. 12277 * 12278 * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The 12279 * name change reflects the flexibility of this property and is consistent 12280 * with the naming of mRender. If 'mDataProp' is given, then it will still 12281 * be used by DataTables, as it automatically maps the old name to the new 12282 * if required. 12283 * 12284 * @type string|int|function|null 12285 * @default null <i>Use automatically calculated column index</i> 12286 * 12287 * @name DataTable.defaults.column.data 12288 * @dtopt Columns 12289 * 12290 * @example 12291 * // Read table data from objects 12292 * // JSON structure for each row: 12293 * // { 12294 * // "engine": {value}, 12295 * // "browser": {value}, 12296 * // "platform": {value}, 12297 * // "version": {value}, 12298 * // "grade": {value} 12299 * // } 12300 * $(document).ready( function() { 12301 * $('#example').dataTable( { 12302 * "ajaxSource": "sources/objects.txt", 12303 * "columns": [ 12304 * { "data": "engine" }, 12305 * { "data": "browser" }, 12306 * { "data": "platform" }, 12307 * { "data": "version" }, 12308 * { "data": "grade" } 12309 * ] 12310 * } ); 12311 * } ); 12312 * 12313 * @example 12314 * // Read information from deeply nested objects 12315 * // JSON structure for each row: 12316 * // { 12317 * // "engine": {value}, 12318 * // "browser": {value}, 12319 * // "platform": { 12320 * // "inner": {value} 12321 * // }, 12322 * // "details": [ 12323 * // {value}, {value} 12324 * // ] 12325 * // } 12326 * $(document).ready( function() { 12327 * $('#example').dataTable( { 12328 * "ajaxSource": "sources/deep.txt", 12329 * "columns": [ 12330 * { "data": "engine" }, 12331 * { "data": "browser" }, 12332 * { "data": "platform.inner" }, 12333 * { "data": "platform.details.0" }, 12334 * { "data": "platform.details.1" } 12335 * ] 12336 * } ); 12337 * } ); 12338 * 12339 * @example 12340 * // Using `data` as a function to provide different information for 12341 * // sorting, filtering and display. In this case, currency (price) 12342 * $(document).ready( function() { 12343 * $('#example').dataTable( { 12344 * "columnDefs": [ { 12345 * "targets": [ 0 ], 12346 * "data": function ( source, type, val ) { 12347 * if (type === 'set') { 12348 * source.price = val; 12349 * // Store the computed dislay and filter values for efficiency 12350 * source.price_display = val=="" ? "" : "$"+numberFormat(val); 12351 * source.price_filter = val=="" ? "" : "$"+numberFormat(val)+" "+val; 12352 * return; 12353 * } 12354 * else if (type === 'display') { 12355 * return source.price_display; 12356 * } 12357 * else if (type === 'filter') { 12358 * return source.price_filter; 12359 * } 12360 * // 'sort', 'type' and undefined all just use the integer 12361 * return source.price; 12362 * } 12363 * } ] 12364 * } ); 12365 * } ); 12366 * 12367 * @example 12368 * // Using default content 12369 * $(document).ready( function() { 12370 * $('#example').dataTable( { 12371 * "columnDefs": [ { 12372 * "targets": [ 0 ], 12373 * "data": null, 12374 * "defaultContent": "Click to edit" 12375 * } ] 12376 * } ); 12377 * } ); 12378 * 12379 * @example 12380 * // Using array notation - outputting a list from an array 12381 * $(document).ready( function() { 12382 * $('#example').dataTable( { 12383 * "columnDefs": [ { 12384 * "targets": [ 0 ], 12385 * "data": "name[, ]" 12386 * } ] 12387 * } ); 12388 * } ); 12389 * 12390 */ 12391 "mData": null, 12392 12393 12394 /** 12395 * This property is the rendering partner to `data` and it is suggested that 12396 * when you want to manipulate data for display (including filtering, 12397 * sorting etc) without altering the underlying data for the table, use this 12398 * property. `render` can be considered to be the the read only companion to 12399 * `data` which is read / write (then as such more complex). Like `data` 12400 * this option can be given in a number of different ways to effect its 12401 * behaviour: 12402 * 12403 * * `integer` - treated as an array index for the data source. This is the 12404 * default that DataTables uses (incrementally increased for each column). 12405 * * `string` - read an object property from the data source. There are 12406 * three 'special' options that can be used in the string to alter how 12407 * DataTables reads the data from the source object: 12408 * * `.` - Dotted Javascript notation. Just as you use a `.` in 12409 * Javascript to read from nested objects, so to can the options 12410 * specified in `data`. For example: `browser.version` or 12411 * `browser.name`. If your object parameter name contains a period, use 12412 * `\\` to escape it - i.e. `first\\.name`. 12413 * * `[]` - Array notation. DataTables can automatically combine data 12414 * from and array source, joining the data with the characters provided 12415 * between the two brackets. For example: `name[, ]` would provide a 12416 * comma-space separated list from the source array. If no characters 12417 * are provided between the brackets, the original array source is 12418 * returned. 12419 * * `()` - Function notation. Adding `()` to the end of a parameter will 12420 * execute a function of the name given. For example: `browser()` for a 12421 * simple function on the data source, `browser.version()` for a 12422 * function in a nested property or even `browser().version` to get an 12423 * object property if the function called returns an object. 12424 * * `object` - use different data for the different data types requested by 12425 * DataTables ('filter', 'display', 'type' or 'sort'). The property names 12426 * of the object is the data type the property refers to and the value can 12427 * defined using an integer, string or function using the same rules as 12428 * `render` normally does. Note that an `_` option _must_ be specified. 12429 * This is the default value to use if you haven't specified a value for 12430 * the data type requested by DataTables. 12431 * * `function` - the function given will be executed whenever DataTables 12432 * needs to set or get the data for a cell in the column. The function 12433 * takes three parameters: 12434 * * Parameters: 12435 * * {array|object} The data source for the row (based on `data`) 12436 * * {string} The type call data requested - this will be 'filter', 12437 * 'display', 'type' or 'sort'. 12438 * * {array|object} The full data source for the row (not based on 12439 * `data`) 12440 * * Return: 12441 * * The return value from the function is what will be used for the 12442 * data requested. 12443 * 12444 * @type string|int|function|object|null 12445 * @default null Use the data source value. 12446 * 12447 * @name DataTable.defaults.column.render 12448 * @dtopt Columns 12449 * 12450 * @example 12451 * // Create a comma separated list from an array of objects 12452 * $(document).ready( function() { 12453 * $('#example').dataTable( { 12454 * "ajaxSource": "sources/deep.txt", 12455 * "columns": [ 12456 * { "data": "engine" }, 12457 * { "data": "browser" }, 12458 * { 12459 * "data": "platform", 12460 * "render": "[, ].name" 12461 * } 12462 * ] 12463 * } ); 12464 * } ); 12465 * 12466 * @example 12467 * // Execute a function to obtain data 12468 * $(document).ready( function() { 12469 * $('#example').dataTable( { 12470 * "columnDefs": [ { 12471 * "targets": [ 0 ], 12472 * "data": null, // Use the full data source object for the renderer's source 12473 * "render": "browserName()" 12474 * } ] 12475 * } ); 12476 * } ); 12477 * 12478 * @example 12479 * // As an object, extracting different data for the different types 12480 * // This would be used with a data source such as: 12481 * // { "phone": 5552368, "phone_filter": "5552368 555-2368", "phone_display": "555-2368" } 12482 * // Here the `phone` integer is used for sorting and type detection, while `phone_filter` 12483 * // (which has both forms) is used for filtering for if a user inputs either format, while 12484 * // the formatted phone number is the one that is shown in the table. 12485 * $(document).ready( function() { 12486 * $('#example').dataTable( { 12487 * "columnDefs": [ { 12488 * "targets": [ 0 ], 12489 * "data": null, // Use the full data source object for the renderer's source 12490 * "render": { 12491 * "_": "phone", 12492 * "filter": "phone_filter", 12493 * "display": "phone_display" 12494 * } 12495 * } ] 12496 * } ); 12497 * } ); 12498 * 12499 * @example 12500 * // Use as a function to create a link from the data source 12501 * $(document).ready( function() { 12502 * $('#example').dataTable( { 12503 * "columnDefs": [ { 12504 * "targets": [ 0 ], 12505 * "data": "download_link", 12506 * "render": function ( data, type, full ) { 12507 * return '<a href="'+data+'">Download</a>'; 12508 * } 12509 * } ] 12510 * } ); 12511 * } ); 12512 */ 12513 "mRender": null, 12514 12515 12516 /** 12517 * Change the cell type created for the column - either TD cells or TH cells. This 12518 * can be useful as TH cells have semantic meaning in the table body, allowing them 12519 * to act as a header for a row (you may wish to add scope='row' to the TH elements). 12520 * @type string 12521 * @default td 12522 * 12523 * @name DataTable.defaults.column.cellType 12524 * @dtopt Columns 12525 * 12526 * @example 12527 * // Make the first column use TH cells 12528 * $(document).ready( function() { 12529 * $('#example').dataTable( { 12530 * "columnDefs": [ { 12531 * "targets": [ 0 ], 12532 * "cellType": "th" 12533 * } ] 12534 * } ); 12535 * } ); 12536 */ 12537 "sCellType": "td", 12538 12539 12540 /** 12541 * Class to give to each cell in this column. 12542 * @type string 12543 * @default <i>Empty string</i> 12544 * 12545 * @name DataTable.defaults.column.class 12546 * @dtopt Columns 12547 * 12548 * @example 12549 * // Using `columnDefs` 12550 * $(document).ready( function() { 12551 * $('#example').dataTable( { 12552 * "columnDefs": [ 12553 * { "class": "my_class", "targets": [ 0 ] } 12554 * ] 12555 * } ); 12556 * } ); 12557 * 12558 * @example 12559 * // Using `columns` 12560 * $(document).ready( function() { 12561 * $('#example').dataTable( { 12562 * "columns": [ 12563 * { "class": "my_class" }, 12564 * null, 12565 * null, 12566 * null, 12567 * null 12568 * ] 12569 * } ); 12570 * } ); 12571 */ 12572 "sClass": "", 12573 12574 /** 12575 * When DataTables calculates the column widths to assign to each column, 12576 * it finds the longest string in each column and then constructs a 12577 * temporary table and reads the widths from that. The problem with this 12578 * is that "mmm" is much wider then "iiii", but the latter is a longer 12579 * string - thus the calculation can go wrong (doing it properly and putting 12580 * it into an DOM object and measuring that is horribly(!) slow). Thus as 12581 * a "work around" we provide this option. It will append its value to the 12582 * text that is found to be the longest string for the column - i.e. padding. 12583 * Generally you shouldn't need this! 12584 * @type string 12585 * @default <i>Empty string<i> 12586 * 12587 * @name DataTable.defaults.column.contentPadding 12588 * @dtopt Columns 12589 * 12590 * @example 12591 * // Using `columns` 12592 * $(document).ready( function() { 12593 * $('#example').dataTable( { 12594 * "columns": [ 12595 * null, 12596 * null, 12597 * null, 12598 * { 12599 * "contentPadding": "mmm" 12600 * } 12601 * ] 12602 * } ); 12603 * } ); 12604 */ 12605 "sContentPadding": "", 12606 12607 12608 /** 12609 * Allows a default value to be given for a column's data, and will be used 12610 * whenever a null data source is encountered (this can be because `data` 12611 * is set to null, or because the data source itself is null). 12612 * @type string 12613 * @default null 12614 * 12615 * @name DataTable.defaults.column.defaultContent 12616 * @dtopt Columns 12617 * 12618 * @example 12619 * // Using `columnDefs` 12620 * $(document).ready( function() { 12621 * $('#example').dataTable( { 12622 * "columnDefs": [ 12623 * { 12624 * "data": null, 12625 * "defaultContent": "Edit", 12626 * "targets": [ -1 ] 12627 * } 12628 * ] 12629 * } ); 12630 * } ); 12631 * 12632 * @example 12633 * // Using `columns` 12634 * $(document).ready( function() { 12635 * $('#example').dataTable( { 12636 * "columns": [ 12637 * null, 12638 * null, 12639 * null, 12640 * { 12641 * "data": null, 12642 * "defaultContent": "Edit" 12643 * } 12644 * ] 12645 * } ); 12646 * } ); 12647 */ 12648 "sDefaultContent": null, 12649 12650 12651 /** 12652 * This parameter is only used in DataTables' server-side processing. It can 12653 * be exceptionally useful to know what columns are being displayed on the 12654 * client side, and to map these to database fields. When defined, the names 12655 * also allow DataTables to reorder information from the server if it comes 12656 * back in an unexpected order (i.e. if you switch your columns around on the 12657 * client-side, your server-side code does not also need updating). 12658 * @type string 12659 * @default <i>Empty string</i> 12660 * 12661 * @name DataTable.defaults.column.name 12662 * @dtopt Columns 12663 * 12664 * @example 12665 * // Using `columnDefs` 12666 * $(document).ready( function() { 12667 * $('#example').dataTable( { 12668 * "columnDefs": [ 12669 * { "name": "engine", "targets": [ 0 ] }, 12670 * { "name": "browser", "targets": [ 1 ] }, 12671 * { "name": "platform", "targets": [ 2 ] }, 12672 * { "name": "version", "targets": [ 3 ] }, 12673 * { "name": "grade", "targets": [ 4 ] } 12674 * ] 12675 * } ); 12676 * } ); 12677 * 12678 * @example 12679 * // Using `columns` 12680 * $(document).ready( function() { 12681 * $('#example').dataTable( { 12682 * "columns": [ 12683 * { "name": "engine" }, 12684 * { "name": "browser" }, 12685 * { "name": "platform" }, 12686 * { "name": "version" }, 12687 * { "name": "grade" } 12688 * ] 12689 * } ); 12690 * } ); 12691 */ 12692 "sName": "", 12693 12694 12695 /** 12696 * Defines a data source type for the ordering which can be used to read 12697 * real-time information from the table (updating the internally cached 12698 * version) prior to ordering. This allows ordering to occur on user 12699 * editable elements such as form inputs. 12700 * @type string 12701 * @default std 12702 * 12703 * @name DataTable.defaults.column.orderDataType 12704 * @dtopt Columns 12705 * 12706 * @example 12707 * // Using `columnDefs` 12708 * $(document).ready( function() { 12709 * $('#example').dataTable( { 12710 * "columnDefs": [ 12711 * { "orderDataType": "dom-text", "targets": [ 2, 3 ] }, 12712 * { "type": "numeric", "targets": [ 3 ] }, 12713 * { "orderDataType": "dom-select", "targets": [ 4 ] }, 12714 * { "orderDataType": "dom-checkbox", "targets": [ 5 ] } 12715 * ] 12716 * } ); 12717 * } ); 12718 * 12719 * @example 12720 * // Using `columns` 12721 * $(document).ready( function() { 12722 * $('#example').dataTable( { 12723 * "columns": [ 12724 * null, 12725 * null, 12726 * { "orderDataType": "dom-text" }, 12727 * { "orderDataType": "dom-text", "type": "numeric" }, 12728 * { "orderDataType": "dom-select" }, 12729 * { "orderDataType": "dom-checkbox" } 12730 * ] 12731 * } ); 12732 * } ); 12733 */ 12734 "sSortDataType": "std", 12735 12736 12737 /** 12738 * The title of this column. 12739 * @type string 12740 * @default null <i>Derived from the 'TH' value for this column in the 12741 * original HTML table.</i> 12742 * 12743 * @name DataTable.defaults.column.title 12744 * @dtopt Columns 12745 * 12746 * @example 12747 * // Using `columnDefs` 12748 * $(document).ready( function() { 12749 * $('#example').dataTable( { 12750 * "columnDefs": [ 12751 * { "title": "My column title", "targets": [ 0 ] } 12752 * ] 12753 * } ); 12754 * } ); 12755 * 12756 * @example 12757 * // Using `columns` 12758 * $(document).ready( function() { 12759 * $('#example').dataTable( { 12760 * "columns": [ 12761 * { "title": "My column title" }, 12762 * null, 12763 * null, 12764 * null, 12765 * null 12766 * ] 12767 * } ); 12768 * } ); 12769 */ 12770 "sTitle": null, 12771 12772 12773 /** 12774 * The type allows you to specify how the data for this column will be 12775 * ordered. Four types (string, numeric, date and html (which will strip 12776 * HTML tags before ordering)) are currently available. Note that only date 12777 * formats understood by Javascript's Date() object will be accepted as type 12778 * date. For example: "Mar 26, 2008 5:03 PM". May take the values: 'string', 12779 * 'numeric', 'date' or 'html' (by default). Further types can be adding 12780 * through plug-ins. 12781 * @type string 12782 * @default null <i>Auto-detected from raw data</i> 12783 * 12784 * @name DataTable.defaults.column.type 12785 * @dtopt Columns 12786 * 12787 * @example 12788 * // Using `columnDefs` 12789 * $(document).ready( function() { 12790 * $('#example').dataTable( { 12791 * "columnDefs": [ 12792 * { "type": "html", "targets": [ 0 ] } 12793 * ] 12794 * } ); 12795 * } ); 12796 * 12797 * @example 12798 * // Using `columns` 12799 * $(document).ready( function() { 12800 * $('#example').dataTable( { 12801 * "columns": [ 12802 * { "type": "html" }, 12803 * null, 12804 * null, 12805 * null, 12806 * null 12807 * ] 12808 * } ); 12809 * } ); 12810 */ 12811 "sType": null, 12812 12813 12814 /** 12815 * Defining the width of the column, this parameter may take any CSS value 12816 * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not 12817 * been given a specific width through this interface ensuring that the table 12818 * remains readable. 12819 * @type string 12820 * @default null <i>Automatic</i> 12821 * 12822 * @name DataTable.defaults.column.width 12823 * @dtopt Columns 12824 * 12825 * @example 12826 * // Using `columnDefs` 12827 * $(document).ready( function() { 12828 * $('#example').dataTable( { 12829 * "columnDefs": [ 12830 * { "width": "20%", "targets": [ 0 ] } 12831 * ] 12832 * } ); 12833 * } ); 12834 * 12835 * @example 12836 * // Using `columns` 12837 * $(document).ready( function() { 12838 * $('#example').dataTable( { 12839 * "columns": [ 12840 * { "width": "20%" }, 12841 * null, 12842 * null, 12843 * null, 12844 * null 12845 * ] 12846 * } ); 12847 * } ); 12848 */ 12849 "sWidth": null 12850 }; 12851 12852 _fnHungarianMap( DataTable.defaults.column ); 12853 12854 12855 12856 /** 12857 * DataTables settings object - this holds all the information needed for a 12858 * given table, including configuration, data and current application of the 12859 * table options. DataTables does not have a single instance for each DataTable 12860 * with the settings attached to that instance, but rather instances of the 12861 * DataTable "class" are created on-the-fly as needed (typically by a 12862 * $().dataTable() call) and the settings object is then applied to that 12863 * instance. 12864 * 12865 * Note that this object is related to {@link DataTable.defaults} but this 12866 * one is the internal data store for DataTables's cache of columns. It should 12867 * NOT be manipulated outside of DataTables. Any configuration should be done 12868 * through the initialisation options. 12869 * @namespace 12870 * @todo Really should attach the settings object to individual instances so we 12871 * don't need to create new instances on each $().dataTable() call (if the 12872 * table already exists). It would also save passing oSettings around and 12873 * into every single function. However, this is a very significant 12874 * architecture change for DataTables and will almost certainly break 12875 * backwards compatibility with older installations. This is something that 12876 * will be done in 2.0. 12877 */ 12878 DataTable.models.oSettings = { 12879 /** 12880 * Primary features of DataTables and their enablement state. 12881 * @namespace 12882 */ 12883 "oFeatures": { 12884 12885 /** 12886 * Flag to say if DataTables should automatically try to calculate the 12887 * optimum table and columns widths (true) or not (false). 12888 * Note that this parameter will be set by the initialisation routine. To 12889 * set a default use {@link DataTable.defaults}. 12890 * @type boolean 12891 */ 12892 "bAutoWidth": null, 12893 12894 /** 12895 * Delay the creation of TR and TD elements until they are actually 12896 * needed by a driven page draw. This can give a significant speed 12897 * increase for Ajax source and Javascript source data, but makes no 12898 * difference at all fro DOM and server-side processing tables. 12899 * Note that this parameter will be set by the initialisation routine. To 12900 * set a default use {@link DataTable.defaults}. 12901 * @type boolean 12902 */ 12903 "bDeferRender": null, 12904 12905 /** 12906 * Enable filtering on the table or not. Note that if this is disabled 12907 * then there is no filtering at all on the table, including fnFilter. 12908 * To just remove the filtering input use sDom and remove the 'f' option. 12909 * Note that this parameter will be set by the initialisation routine. To 12910 * set a default use {@link DataTable.defaults}. 12911 * @type boolean 12912 */ 12913 "bFilter": null, 12914 12915 /** 12916 * Table information element (the 'Showing x of y records' div) enable 12917 * flag. 12918 * Note that this parameter will be set by the initialisation routine. To 12919 * set a default use {@link DataTable.defaults}. 12920 * @type boolean 12921 */ 12922 "bInfo": null, 12923 12924 /** 12925 * Present a user control allowing the end user to change the page size 12926 * when pagination is enabled. 12927 * Note that this parameter will be set by the initialisation routine. To 12928 * set a default use {@link DataTable.defaults}. 12929 * @type boolean 12930 */ 12931 "bLengthChange": null, 12932 12933 /** 12934 * Pagination enabled or not. Note that if this is disabled then length 12935 * changing must also be disabled. 12936 * Note that this parameter will be set by the initialisation routine. To 12937 * set a default use {@link DataTable.defaults}. 12938 * @type boolean 12939 */ 12940 "bPaginate": null, 12941 12942 /** 12943 * Processing indicator enable flag whenever DataTables is enacting a 12944 * user request - typically an Ajax request for server-side processing. 12945 * Note that this parameter will be set by the initialisation routine. To 12946 * set a default use {@link DataTable.defaults}. 12947 * @type boolean 12948 */ 12949 "bProcessing": null, 12950 12951 /** 12952 * Server-side processing enabled flag - when enabled DataTables will 12953 * get all data from the server for every draw - there is no filtering, 12954 * sorting or paging done on the client-side. 12955 * Note that this parameter will be set by the initialisation routine. To 12956 * set a default use {@link DataTable.defaults}. 12957 * @type boolean 12958 */ 12959 "bServerSide": null, 12960 12961 /** 12962 * Sorting enablement flag. 12963 * Note that this parameter will be set by the initialisation routine. To 12964 * set a default use {@link DataTable.defaults}. 12965 * @type boolean 12966 */ 12967 "bSort": null, 12968 12969 /** 12970 * Multi-column sorting 12971 * Note that this parameter will be set by the initialisation routine. To 12972 * set a default use {@link DataTable.defaults}. 12973 * @type boolean 12974 */ 12975 "bSortMulti": null, 12976 12977 /** 12978 * Apply a class to the columns which are being sorted to provide a 12979 * visual highlight or not. This can slow things down when enabled since 12980 * there is a lot of DOM interaction. 12981 * Note that this parameter will be set by the initialisation routine. To 12982 * set a default use {@link DataTable.defaults}. 12983 * @type boolean 12984 */ 12985 "bSortClasses": null, 12986 12987 /** 12988 * State saving enablement flag. 12989 * Note that this parameter will be set by the initialisation routine. To 12990 * set a default use {@link DataTable.defaults}. 12991 * @type boolean 12992 */ 12993 "bStateSave": null 12994 }, 12995 12996 12997 /** 12998 * Scrolling settings for a table. 12999 * @namespace 13000 */ 13001 "oScroll": { 13002 /** 13003 * When the table is shorter in height than sScrollY, collapse the 13004 * table container down to the height of the table (when true). 13005 * Note that this parameter will be set by the initialisation routine. To 13006 * set a default use {@link DataTable.defaults}. 13007 * @type boolean 13008 */ 13009 "bCollapse": null, 13010 13011 /** 13012 * Width of the scrollbar for the web-browser's platform. Calculated 13013 * during table initialisation. 13014 * @type int 13015 * @default 0 13016 */ 13017 "iBarWidth": 0, 13018 13019 /** 13020 * Viewport width for horizontal scrolling. Horizontal scrolling is 13021 * disabled if an empty string. 13022 * Note that this parameter will be set by the initialisation routine. To 13023 * set a default use {@link DataTable.defaults}. 13024 * @type string 13025 */ 13026 "sX": null, 13027 13028 /** 13029 * Width to expand the table to when using x-scrolling. Typically you 13030 * should not need to use this. 13031 * Note that this parameter will be set by the initialisation routine. To 13032 * set a default use {@link DataTable.defaults}. 13033 * @type string 13034 * @deprecated 13035 */ 13036 "sXInner": null, 13037 13038 /** 13039 * Viewport height for vertical scrolling. Vertical scrolling is disabled 13040 * if an empty string. 13041 * Note that this parameter will be set by the initialisation routine. To 13042 * set a default use {@link DataTable.defaults}. 13043 * @type string 13044 */ 13045 "sY": null 13046 }, 13047 13048 /** 13049 * Language information for the table. 13050 * @namespace 13051 * @extends DataTable.defaults.oLanguage 13052 */ 13053 "oLanguage": { 13054 /** 13055 * Information callback function. See 13056 * {@link DataTable.defaults.fnInfoCallback} 13057 * @type function 13058 * @default null 13059 */ 13060 "fnInfoCallback": null 13061 }, 13062 13063 /** 13064 * Browser support parameters 13065 * @namespace 13066 */ 13067 "oBrowser": { 13068 /** 13069 * Indicate if the browser incorrectly calculates width:100% inside a 13070 * scrolling element (IE6/7) 13071 * @type boolean 13072 * @default false 13073 */ 13074 "bScrollOversize": false, 13075 13076 /** 13077 * Determine if the vertical scrollbar is on the right or left of the 13078 * scrolling container - needed for rtl language layout, although not 13079 * all browsers move the scrollbar (Safari). 13080 * @type boolean 13081 * @default false 13082 */ 13083 "bScrollbarLeft": false, 13084 13085 /** 13086 * Flag for if `getBoundingClientRect` is fully supported or not 13087 * @type boolean 13088 * @default false 13089 */ 13090 "bBounding": false, 13091 13092 /** 13093 * Browser scrollbar width 13094 * @type integer 13095 * @default 0 13096 */ 13097 "barWidth": 0 13098 }, 13099 13100 13101 "ajax": null, 13102 13103 13104 /** 13105 * Array referencing the nodes which are used for the features. The 13106 * parameters of this object match what is allowed by sDom - i.e. 13107 * <ul> 13108 * <li>'l' - Length changing</li> 13109 * <li>'f' - Filtering input</li> 13110 * <li>'t' - The table!</li> 13111 * <li>'i' - Information</li> 13112 * <li>'p' - Pagination</li> 13113 * <li>'r' - pRocessing</li> 13114 * </ul> 13115 * @type array 13116 * @default [] 13117 */ 13118 "aanFeatures": [], 13119 13120 /** 13121 * Store data information - see {@link DataTable.models.oRow} for detailed 13122 * information. 13123 * @type array 13124 * @default [] 13125 */ 13126 "aoData": [], 13127 13128 /** 13129 * Array of indexes which are in the current display (after filtering etc) 13130 * @type array 13131 * @default [] 13132 */ 13133 "aiDisplay": [], 13134 13135 /** 13136 * Array of indexes for display - no filtering 13137 * @type array 13138 * @default [] 13139 */ 13140 "aiDisplayMaster": [], 13141 13142 /** 13143 * Map of row ids to data indexes 13144 * @type object 13145 * @default {} 13146 */ 13147 "aIds": {}, 13148 13149 /** 13150 * Store information about each column that is in use 13151 * @type array 13152 * @default [] 13153 */ 13154 "aoColumns": [], 13155 13156 /** 13157 * Store information about the table's header 13158 * @type array 13159 * @default [] 13160 */ 13161 "aoHeader": [], 13162 13163 /** 13164 * Store information about the table's footer 13165 * @type array 13166 * @default [] 13167 */ 13168 "aoFooter": [], 13169 13170 /** 13171 * Store the applied global search information in case we want to force a 13172 * research or compare the old search to a new one. 13173 * Note that this parameter will be set by the initialisation routine. To 13174 * set a default use {@link DataTable.defaults}. 13175 * @namespace 13176 * @extends DataTable.models.oSearch 13177 */ 13178 "oPreviousSearch": {}, 13179 13180 /** 13181 * Store the applied search for each column - see 13182 * {@link DataTable.models.oSearch} for the format that is used for the 13183 * filtering information for each column. 13184 * @type array 13185 * @default [] 13186 */ 13187 "aoPreSearchCols": [], 13188 13189 /** 13190 * Sorting that is applied to the table. Note that the inner arrays are 13191 * used in the following manner: 13192 * <ul> 13193 * <li>Index 0 - column number</li> 13194 * <li>Index 1 - current sorting direction</li> 13195 * </ul> 13196 * Note that this parameter will be set by the initialisation routine. To 13197 * set a default use {@link DataTable.defaults}. 13198 * @type array 13199 * @todo These inner arrays should really be objects 13200 */ 13201 "aaSorting": null, 13202 13203 /** 13204 * Sorting that is always applied to the table (i.e. prefixed in front of 13205 * aaSorting). 13206 * Note that this parameter will be set by the initialisation routine. To 13207 * set a default use {@link DataTable.defaults}. 13208 * @type array 13209 * @default [] 13210 */ 13211 "aaSortingFixed": [], 13212 13213 /** 13214 * Classes to use for the striping of a table. 13215 * Note that this parameter will be set by the initialisation routine. To 13216 * set a default use {@link DataTable.defaults}. 13217 * @type array 13218 * @default [] 13219 */ 13220 "asStripeClasses": null, 13221 13222 /** 13223 * If restoring a table - we should restore its striping classes as well 13224 * @type array 13225 * @default [] 13226 */ 13227 "asDestroyStripes": [], 13228 13229 /** 13230 * If restoring a table - we should restore its width 13231 * @type int 13232 * @default 0 13233 */ 13234 "sDestroyWidth": 0, 13235 13236 /** 13237 * Callback functions array for every time a row is inserted (i.e. on a draw). 13238 * @type array 13239 * @default [] 13240 */ 13241 "aoRowCallback": [], 13242 13243 /** 13244 * Callback functions for the header on each draw. 13245 * @type array 13246 * @default [] 13247 */ 13248 "aoHeaderCallback": [], 13249 13250 /** 13251 * Callback function for the footer on each draw. 13252 * @type array 13253 * @default [] 13254 */ 13255 "aoFooterCallback": [], 13256 13257 /** 13258 * Array of callback functions for draw callback functions 13259 * @type array 13260 * @default [] 13261 */ 13262 "aoDrawCallback": [], 13263 13264 /** 13265 * Array of callback functions for row created function 13266 * @type array 13267 * @default [] 13268 */ 13269 "aoRowCreatedCallback": [], 13270 13271 /** 13272 * Callback functions for just before the table is redrawn. A return of 13273 * false will be used to cancel the draw. 13274 * @type array 13275 * @default [] 13276 */ 13277 "aoPreDrawCallback": [], 13278 13279 /** 13280 * Callback functions for when the table has been initialised. 13281 * @type array 13282 * @default [] 13283 */ 13284 "aoInitComplete": [], 13285 13286 13287 /** 13288 * Callbacks for modifying the settings to be stored for state saving, prior to 13289 * saving state. 13290 * @type array 13291 * @default [] 13292 */ 13293 "aoStateSaveParams": [], 13294 13295 /** 13296 * Callbacks for modifying the settings that have been stored for state saving 13297 * prior to using the stored values to restore the state. 13298 * @type array 13299 * @default [] 13300 */ 13301 "aoStateLoadParams": [], 13302 13303 /** 13304 * Callbacks for operating on the settings object once the saved state has been 13305 * loaded 13306 * @type array 13307 * @default [] 13308 */ 13309 "aoStateLoaded": [], 13310 13311 /** 13312 * Cache the table ID for quick access 13313 * @type string 13314 * @default <i>Empty string</i> 13315 */ 13316 "sTableId": "", 13317 13318 /** 13319 * The TABLE node for the main table 13320 * @type node 13321 * @default null 13322 */ 13323 "nTable": null, 13324 13325 /** 13326 * Permanent ref to the thead element 13327 * @type node 13328 * @default null 13329 */ 13330 "nTHead": null, 13331 13332 /** 13333 * Permanent ref to the tfoot element - if it exists 13334 * @type node 13335 * @default null 13336 */ 13337 "nTFoot": null, 13338 13339 /** 13340 * Permanent ref to the tbody element 13341 * @type node 13342 * @default null 13343 */ 13344 "nTBody": null, 13345 13346 /** 13347 * Cache the wrapper node (contains all DataTables controlled elements) 13348 * @type node 13349 * @default null 13350 */ 13351 "nTableWrapper": null, 13352 13353 /** 13354 * Indicate if when using server-side processing the loading of data 13355 * should be deferred until the second draw. 13356 * Note that this parameter will be set by the initialisation routine. To 13357 * set a default use {@link DataTable.defaults}. 13358 * @type boolean 13359 * @default false 13360 */ 13361 "bDeferLoading": false, 13362 13363 /** 13364 * Indicate if all required information has been read in 13365 * @type boolean 13366 * @default false 13367 */ 13368 "bInitialised": false, 13369 13370 /** 13371 * Information about open rows. Each object in the array has the parameters 13372 * 'nTr' and 'nParent' 13373 * @type array 13374 * @default [] 13375 */ 13376 "aoOpenRows": [], 13377 13378 /** 13379 * Dictate the positioning of DataTables' control elements - see 13380 * {@link DataTable.model.oInit.sDom}. 13381 * Note that this parameter will be set by the initialisation routine. To 13382 * set a default use {@link DataTable.defaults}. 13383 * @type string 13384 * @default null 13385 */ 13386 "sDom": null, 13387 13388 /** 13389 * Search delay (in mS) 13390 * @type integer 13391 * @default null 13392 */ 13393 "searchDelay": null, 13394 13395 /** 13396 * Which type of pagination should be used. 13397 * Note that this parameter will be set by the initialisation routine. To 13398 * set a default use {@link DataTable.defaults}. 13399 * @type string 13400 * @default two_button 13401 */ 13402 "sPaginationType": "two_button", 13403 13404 /** 13405 * The state duration (for `stateSave`) in seconds. 13406 * Note that this parameter will be set by the initialisation routine. To 13407 * set a default use {@link DataTable.defaults}. 13408 * @type int 13409 * @default 0 13410 */ 13411 "iStateDuration": 0, 13412 13413 /** 13414 * Array of callback functions for state saving. Each array element is an 13415 * object with the following parameters: 13416 * <ul> 13417 * <li>function:fn - function to call. Takes two parameters, oSettings 13418 * and the JSON string to save that has been thus far created. Returns 13419 * a JSON string to be inserted into a json object 13420 * (i.e. '"param": [ 0, 1, 2]')</li> 13421 * <li>string:sName - name of callback</li> 13422 * </ul> 13423 * @type array 13424 * @default [] 13425 */ 13426 "aoStateSave": [], 13427 13428 /** 13429 * Array of callback functions for state loading. Each array element is an 13430 * object with the following parameters: 13431 * <ul> 13432 * <li>function:fn - function to call. Takes two parameters, oSettings 13433 * and the object stored. May return false to cancel state loading</li> 13434 * <li>string:sName - name of callback</li> 13435 * </ul> 13436 * @type array 13437 * @default [] 13438 */ 13439 "aoStateLoad": [], 13440 13441 /** 13442 * State that was saved. Useful for back reference 13443 * @type object 13444 * @default null 13445 */ 13446 "oSavedState": null, 13447 13448 /** 13449 * State that was loaded. Useful for back reference 13450 * @type object 13451 * @default null 13452 */ 13453 "oLoadedState": null, 13454 13455 /** 13456 * Source url for AJAX data for the table. 13457 * Note that this parameter will be set by the initialisation routine. To 13458 * set a default use {@link DataTable.defaults}. 13459 * @type string 13460 * @default null 13461 */ 13462 "sAjaxSource": null, 13463 13464 /** 13465 * Property from a given object from which to read the table data from. This 13466 * can be an empty string (when not server-side processing), in which case 13467 * it is assumed an an array is given directly. 13468 * Note that this parameter will be set by the initialisation routine. To 13469 * set a default use {@link DataTable.defaults}. 13470 * @type string 13471 */ 13472 "sAjaxDataProp": null, 13473 13474 /** 13475 * Note if draw should be blocked while getting data 13476 * @type boolean 13477 * @default true 13478 */ 13479 "bAjaxDataGet": true, 13480 13481 /** 13482 * The last jQuery XHR object that was used for server-side data gathering. 13483 * This can be used for working with the XHR information in one of the 13484 * callbacks 13485 * @type object 13486 * @default null 13487 */ 13488 "jqXHR": null, 13489 13490 /** 13491 * JSON returned from the server in the last Ajax request 13492 * @type object 13493 * @default undefined 13494 */ 13495 "json": undefined, 13496 13497 /** 13498 * Data submitted as part of the last Ajax request 13499 * @type object 13500 * @default undefined 13501 */ 13502 "oAjaxData": undefined, 13503 13504 /** 13505 * Function to get the server-side data. 13506 * Note that this parameter will be set by the initialisation routine. To 13507 * set a default use {@link DataTable.defaults}. 13508 * @type function 13509 */ 13510 "fnServerData": null, 13511 13512 /** 13513 * Functions which are called prior to sending an Ajax request so extra 13514 * parameters can easily be sent to the server 13515 * @type array 13516 * @default [] 13517 */ 13518 "aoServerParams": [], 13519 13520 /** 13521 * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if 13522 * required). 13523 * Note that this parameter will be set by the initialisation routine. To 13524 * set a default use {@link DataTable.defaults}. 13525 * @type string 13526 */ 13527 "sServerMethod": null, 13528 13529 /** 13530 * Format numbers for display. 13531 * Note that this parameter will be set by the initialisation routine. To 13532 * set a default use {@link DataTable.defaults}. 13533 * @type function 13534 */ 13535 "fnFormatNumber": null, 13536 13537 /** 13538 * List of options that can be used for the user selectable length menu. 13539 * Note that this parameter will be set by the initialisation routine. To 13540 * set a default use {@link DataTable.defaults}. 13541 * @type array 13542 * @default [] 13543 */ 13544 "aLengthMenu": null, 13545 13546 /** 13547 * Counter for the draws that the table does. Also used as a tracker for 13548 * server-side processing 13549 * @type int 13550 * @default 0 13551 */ 13552 "iDraw": 0, 13553 13554 /** 13555 * Indicate if a redraw is being done - useful for Ajax 13556 * @type boolean 13557 * @default false 13558 */ 13559 "bDrawing": false, 13560 13561 /** 13562 * Draw index (iDraw) of the last error when parsing the returned data 13563 * @type int 13564 * @default -1 13565 */ 13566 "iDrawError": -1, 13567 13568 /** 13569 * Paging display length 13570 * @type int 13571 * @default 10 13572 */ 13573 "_iDisplayLength": 10, 13574 13575 /** 13576 * Paging start point - aiDisplay index 13577 * @type int 13578 * @default 0 13579 */ 13580 "_iDisplayStart": 0, 13581 13582 /** 13583 * Server-side processing - number of records in the result set 13584 * (i.e. before filtering), Use fnRecordsTotal rather than 13585 * this property to get the value of the number of records, regardless of 13586 * the server-side processing setting. 13587 * @type int 13588 * @default 0 13589 * @private 13590 */ 13591 "_iRecordsTotal": 0, 13592 13593 /** 13594 * Server-side processing - number of records in the current display set 13595 * (i.e. after filtering). Use fnRecordsDisplay rather than 13596 * this property to get the value of the number of records, regardless of 13597 * the server-side processing setting. 13598 * @type boolean 13599 * @default 0 13600 * @private 13601 */ 13602 "_iRecordsDisplay": 0, 13603 13604 /** 13605 * Flag to indicate if jQuery UI marking and classes should be used. 13606 * Note that this parameter will be set by the initialisation routine. To 13607 * set a default use {@link DataTable.defaults}. 13608 * @type boolean 13609 */ 13610 "bJUI": null, 13611 13612 /** 13613 * The classes to use for the table 13614 * @type object 13615 * @default {} 13616 */ 13617 "oClasses": {}, 13618 13619 /** 13620 * Flag attached to the settings object so you can check in the draw 13621 * callback if filtering has been done in the draw. Deprecated in favour of 13622 * events. 13623 * @type boolean 13624 * @default false 13625 * @deprecated 13626 */ 13627 "bFiltered": false, 13628 13629 /** 13630 * Flag attached to the settings object so you can check in the draw 13631 * callback if sorting has been done in the draw. Deprecated in favour of 13632 * events. 13633 * @type boolean 13634 * @default false 13635 * @deprecated 13636 */ 13637 "bSorted": false, 13638 13639 /** 13640 * Indicate that if multiple rows are in the header and there is more than 13641 * one unique cell per column, if the top one (true) or bottom one (false) 13642 * should be used for sorting / title by DataTables. 13643 * Note that this parameter will be set by the initialisation routine. To 13644 * set a default use {@link DataTable.defaults}. 13645 * @type boolean 13646 */ 13647 "bSortCellsTop": null, 13648 13649 /** 13650 * Initialisation object that is used for the table 13651 * @type object 13652 * @default null 13653 */ 13654 "oInit": null, 13655 13656 /** 13657 * Destroy callback functions - for plug-ins to attach themselves to the 13658 * destroy so they can clean up markup and events. 13659 * @type array 13660 * @default [] 13661 */ 13662 "aoDestroyCallback": [], 13663 13664 13665 /** 13666 * Get the number of records in the current record set, before filtering 13667 * @type function 13668 */ 13669 "fnRecordsTotal": function () 13670 { 13671 return _fnDataSource( this ) == 'ssp' ? 13672 this._iRecordsTotal * 1 : 13673 this.aiDisplayMaster.length; 13674 }, 13675 13676 /** 13677 * Get the number of records in the current record set, after filtering 13678 * @type function 13679 */ 13680 "fnRecordsDisplay": function () 13681 { 13682 return _fnDataSource( this ) == 'ssp' ? 13683 this._iRecordsDisplay * 1 : 13684 this.aiDisplay.length; 13685 }, 13686 13687 /** 13688 * Get the display end point - aiDisplay index 13689 * @type function 13690 */ 13691 "fnDisplayEnd": function () 13692 { 13693 var 13694 len = this._iDisplayLength, 13695 start = this._iDisplayStart, 13696 calc = start + len, 13697 records = this.aiDisplay.length, 13698 features = this.oFeatures, 13699 paginate = features.bPaginate; 13700 13701 if ( features.bServerSide ) { 13702 return paginate === false || len === -1 ? 13703 start + records : 13704 Math.min( start+len, this._iRecordsDisplay ); 13705 } 13706 else { 13707 return ! paginate || calc>records || len===-1 ? 13708 records : 13709 calc; 13710 } 13711 }, 13712 13713 /** 13714 * The DataTables object for this table 13715 * @type object 13716 * @default null 13717 */ 13718 "oInstance": null, 13719 13720 /** 13721 * Unique identifier for each instance of the DataTables object. If there 13722 * is an ID on the table node, then it takes that value, otherwise an 13723 * incrementing internal counter is used. 13724 * @type string 13725 * @default null 13726 */ 13727 "sInstance": null, 13728 13729 /** 13730 * tabindex attribute value that is added to DataTables control elements, allowing 13731 * keyboard navigation of the table and its controls. 13732 */ 13733 "iTabIndex": 0, 13734 13735 /** 13736 * DIV container for the footer scrolling table if scrolling 13737 */ 13738 "nScrollHead": null, 13739 13740 /** 13741 * DIV container for the footer scrolling table if scrolling 13742 */ 13743 "nScrollFoot": null, 13744 13745 /** 13746 * Last applied sort 13747 * @type array 13748 * @default [] 13749 */ 13750 "aLastSort": [], 13751 13752 /** 13753 * Stored plug-in instances 13754 * @type object 13755 * @default {} 13756 */ 13757 "oPlugins": {}, 13758 13759 /** 13760 * Function used to get a row's id from the row's data 13761 * @type function 13762 * @default null 13763 */ 13764 "rowIdFn": null, 13765 13766 /** 13767 * Data location where to store a row's id 13768 * @type string 13769 * @default null 13770 */ 13771 "rowId": null 13772 }; 13773 13774 /** 13775 * Extension object for DataTables that is used to provide all extension 13776 * options. 13777 * 13778 * Note that the `DataTable.ext` object is available through 13779 * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is 13780 * also aliased to `jQuery.fn.dataTableExt` for historic reasons. 13781 * @namespace 13782 * @extends DataTable.models.ext 13783 */ 13784 13785 13786 /** 13787 * DataTables extensions 13788 * 13789 * This namespace acts as a collection area for plug-ins that can be used to 13790 * extend DataTables capabilities. Indeed many of the build in methods 13791 * use this method to provide their own capabilities (sorting methods for 13792 * example). 13793 * 13794 * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy 13795 * reasons 13796 * 13797 * @namespace 13798 */ 13799 DataTable.ext = _ext = { 13800 /** 13801 * Buttons. For use with the Buttons extension for DataTables. This is 13802 * defined here so other extensions can define buttons regardless of load 13803 * order. It is _not_ used by DataTables core. 13804 * 13805 * @type object 13806 * @default {} 13807 */ 13808 buttons: {}, 13809 13810 13811 /** 13812 * Element class names 13813 * 13814 * @type object 13815 * @default {} 13816 */ 13817 classes: {}, 13818 13819 13820 /** 13821 * DataTables build type (expanded by the download builder) 13822 * 13823 * @type string 13824 */ 13825 builder: "-source-", 13826 13827 13828 /** 13829 * Error reporting. 13830 * 13831 * How should DataTables report an error. Can take the value 'alert', 13832 * 'throw', 'none' or a function. 13833 * 13834 * @type string|function 13835 * @default alert 13836 */ 13837 errMode: "alert", 13838 13839 13840 /** 13841 * Feature plug-ins. 13842 * 13843 * This is an array of objects which describe the feature plug-ins that are 13844 * available to DataTables. These feature plug-ins are then available for 13845 * use through the `dom` initialisation option. 13846 * 13847 * Each feature plug-in is described by an object which must have the 13848 * following properties: 13849 * 13850 * * `fnInit` - function that is used to initialise the plug-in, 13851 * * `cFeature` - a character so the feature can be enabled by the `dom` 13852 * instillation option. This is case sensitive. 13853 * 13854 * The `fnInit` function has the following input parameters: 13855 * 13856 * 1. `{object}` DataTables settings object: see 13857 * {@link DataTable.models.oSettings} 13858 * 13859 * And the following return is expected: 13860 * 13861 * * {node|null} The element which contains your feature. Note that the 13862 * return may also be void if your plug-in does not require to inject any 13863 * DOM elements into DataTables control (`dom`) - for example this might 13864 * be useful when developing a plug-in which allows table control via 13865 * keyboard entry 13866 * 13867 * @type array 13868 * 13869 * @example 13870 * $.fn.dataTable.ext.features.push( { 13871 * "fnInit": function( oSettings ) { 13872 * return new TableTools( { "oDTSettings": oSettings } ); 13873 * }, 13874 * "cFeature": "T" 13875 * } ); 13876 */ 13877 feature: [], 13878 13879 13880 /** 13881 * Row searching. 13882 * 13883 * This method of searching is complimentary to the default type based 13884 * searching, and a lot more comprehensive as it allows you complete control 13885 * over the searching logic. Each element in this array is a function 13886 * (parameters described below) that is called for every row in the table, 13887 * and your logic decides if it should be included in the searching data set 13888 * or not. 13889 * 13890 * Searching functions have the following input parameters: 13891 * 13892 * 1. `{object}` DataTables settings object: see 13893 * {@link DataTable.models.oSettings} 13894 * 2. `{array|object}` Data for the row to be processed (same as the 13895 * original format that was passed in as the data source, or an array 13896 * from a DOM data source 13897 * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which 13898 * can be useful to retrieve the `TR` element if you need DOM interaction. 13899 * 13900 * And the following return is expected: 13901 * 13902 * * {boolean} Include the row in the searched result set (true) or not 13903 * (false) 13904 * 13905 * Note that as with the main search ability in DataTables, technically this 13906 * is "filtering", since it is subtractive. However, for consistency in 13907 * naming we call it searching here. 13908 * 13909 * @type array 13910 * @default [] 13911 * 13912 * @example 13913 * // The following example shows custom search being applied to the 13914 * // fourth column (i.e. the data[3] index) based on two input values 13915 * // from the end-user, matching the data in a certain range. 13916 * $.fn.dataTable.ext.search.push( 13917 * function( settings, data, dataIndex ) { 13918 * var min = document.getElementById('min').value * 1; 13919 * var max = document.getElementById('max').value * 1; 13920 * var version = data[3] == "-" ? 0 : data[3]*1; 13921 * 13922 * if ( min == "" && max == "" ) { 13923 * return true; 13924 * } 13925 * else if ( min == "" && version < max ) { 13926 * return true; 13927 * } 13928 * else if ( min < version && "" == max ) { 13929 * return true; 13930 * } 13931 * else if ( min < version && version < max ) { 13932 * return true; 13933 * } 13934 * return false; 13935 * } 13936 * ); 13937 */ 13938 search: [], 13939 13940 13941 /** 13942 * Selector extensions 13943 * 13944 * The `selector` option can be used to extend the options available for the 13945 * selector modifier options (`selector-modifier` object data type) that 13946 * each of the three built in selector types offer (row, column and cell + 13947 * their plural counterparts). For example the Select extension uses this 13948 * mechanism to provide an option to select only rows, columns and cells 13949 * that have been marked as selected by the end user (`{selected: true}`), 13950 * which can be used in conjunction with the existing built in selector 13951 * options. 13952 * 13953 * Each property is an array to which functions can be pushed. The functions 13954 * take three attributes: 13955 * 13956 * * Settings object for the host table 13957 * * Options object (`selector-modifier` object type) 13958 * * Array of selected item indexes 13959 * 13960 * The return is an array of the resulting item indexes after the custom 13961 * selector has been applied. 13962 * 13963 * @type object 13964 */ 13965 selector: { 13966 cell: [], 13967 column: [], 13968 row: [] 13969 }, 13970 13971 13972 /** 13973 * Internal functions, exposed for used in plug-ins. 13974 * 13975 * Please note that you should not need to use the internal methods for 13976 * anything other than a plug-in (and even then, try to avoid if possible). 13977 * The internal function may change between releases. 13978 * 13979 * @type object 13980 * @default {} 13981 */ 13982 internal: {}, 13983 13984 13985 /** 13986 * Legacy configuration options. Enable and disable legacy options that 13987 * are available in DataTables. 13988 * 13989 * @type object 13990 */ 13991 legacy: { 13992 /** 13993 * Enable / disable DataTables 1.9 compatible server-side processing 13994 * requests 13995 * 13996 * @type boolean 13997 * @default null 13998 */ 13999 ajax: null 14000 }, 14001 14002 14003 /** 14004 * Pagination plug-in methods. 14005 * 14006 * Each entry in this object is a function and defines which buttons should 14007 * be shown by the pagination rendering method that is used for the table: 14008 * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the 14009 * buttons are displayed in the document, while the functions here tell it 14010 * what buttons to display. This is done by returning an array of button 14011 * descriptions (what each button will do). 14012 * 14013 * Pagination types (the four built in options and any additional plug-in 14014 * options defined here) can be used through the `paginationType` 14015 * initialisation parameter. 14016 * 14017 * The functions defined take two parameters: 14018 * 14019 * 1. `{int} page` The current page index 14020 * 2. `{int} pages` The number of pages in the table 14021 * 14022 * Each function is expected to return an array where each element of the 14023 * array can be one of: 14024 * 14025 * * `first` - Jump to first page when activated 14026 * * `last` - Jump to last page when activated 14027 * * `previous` - Show previous page when activated 14028 * * `next` - Show next page when activated 14029 * * `{int}` - Show page of the index given 14030 * * `{array}` - A nested array containing the above elements to add a 14031 * containing 'DIV' element (might be useful for styling). 14032 * 14033 * Note that DataTables v1.9- used this object slightly differently whereby 14034 * an object with two functions would be defined for each plug-in. That 14035 * ability is still supported by DataTables 1.10+ to provide backwards 14036 * compatibility, but this option of use is now decremented and no longer 14037 * documented in DataTables 1.10+. 14038 * 14039 * @type object 14040 * @default {} 14041 * 14042 * @example 14043 * // Show previous, next and current page buttons only 14044 * $.fn.dataTableExt.oPagination.current = function ( page, pages ) { 14045 * return [ 'previous', page, 'next' ]; 14046 * }; 14047 */ 14048 pager: {}, 14049 14050 14051 renderer: { 14052 pageButton: {}, 14053 header: {} 14054 }, 14055 14056 14057 /** 14058 * Ordering plug-ins - custom data source 14059 * 14060 * The extension options for ordering of data available here is complimentary 14061 * to the default type based ordering that DataTables typically uses. It 14062 * allows much greater control over the the data that is being used to 14063 * order a column, but is necessarily therefore more complex. 14064 * 14065 * This type of ordering is useful if you want to do ordering based on data 14066 * live from the DOM (for example the contents of an 'input' element) rather 14067 * than just the static string that DataTables knows of. 14068 * 14069 * The way these plug-ins work is that you create an array of the values you 14070 * wish to be ordering for the column in question and then return that 14071 * array. The data in the array much be in the index order of the rows in 14072 * the table (not the currently ordering order!). Which order data gathering 14073 * function is run here depends on the `dt-init columns.orderDataType` 14074 * parameter that is used for the column (if any). 14075 * 14076 * The functions defined take two parameters: 14077 * 14078 * 1. `{object}` DataTables settings object: see 14079 * {@link DataTable.models.oSettings} 14080 * 2. `{int}` Target column index 14081 * 14082 * Each function is expected to return an array: 14083 * 14084 * * `{array}` Data for the column to be ordering upon 14085 * 14086 * @type array 14087 * 14088 * @example 14089 * // Ordering using `input` node values 14090 * $.fn.dataTable.ext.order['dom-text'] = function ( settings, col ) 14091 * { 14092 * return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) { 14093 * return $('input', td).val(); 14094 * } ); 14095 * } 14096 */ 14097 order: {}, 14098 14099 14100 /** 14101 * Type based plug-ins. 14102 * 14103 * Each column in DataTables has a type assigned to it, either by automatic 14104 * detection or by direct assignment using the `type` option for the column. 14105 * The type of a column will effect how it is ordering and search (plug-ins 14106 * can also make use of the column type if required). 14107 * 14108 * @namespace 14109 */ 14110 type: { 14111 /** 14112 * Type detection functions. 14113 * 14114 * The functions defined in this object are used to automatically detect 14115 * a column's type, making initialisation of DataTables super easy, even 14116 * when complex data is in the table. 14117 * 14118 * The functions defined take two parameters: 14119 * 14120 * 1. `{*}` Data from the column cell to be analysed 14121 * 2. `{settings}` DataTables settings object. This can be used to 14122 * perform context specific type detection - for example detection 14123 * based on language settings such as using a comma for a decimal 14124 * place. Generally speaking the options from the settings will not 14125 * be required 14126 * 14127 * Each function is expected to return: 14128 * 14129 * * `{string|null}` Data type detected, or null if unknown (and thus 14130 * pass it on to the other type detection functions. 14131 * 14132 * @type array 14133 * 14134 * @example 14135 * // Currency type detection plug-in: 14136 * $.fn.dataTable.ext.type.detect.push( 14137 * function ( data, settings ) { 14138 * // Check the numeric part 14139 * if ( ! $.isNumeric( data.substring(1) ) ) { 14140 * return null; 14141 * } 14142 * 14143 * // Check prefixed by currency 14144 * if ( data.charAt(0) == '$' || data.charAt(0) == '£' ) { 14145 * return 'currency'; 14146 * } 14147 * return null; 14148 * } 14149 * ); 14150 */ 14151 detect: [], 14152 14153 14154 /** 14155 * Type based search formatting. 14156 * 14157 * The type based searching functions can be used to pre-format the 14158 * data to be search on. For example, it can be used to strip HTML 14159 * tags or to de-format telephone numbers for numeric only searching. 14160 * 14161 * Note that is a search is not defined for a column of a given type, 14162 * no search formatting will be performed. 14163 * 14164 * Pre-processing of searching data plug-ins - When you assign the sType 14165 * for a column (or have it automatically detected for you by DataTables 14166 * or a type detection plug-in), you will typically be using this for 14167 * custom sorting, but it can also be used to provide custom searching 14168 * by allowing you to pre-processing the data and returning the data in 14169 * the format that should be searched upon. This is done by adding 14170 * functions this object with a parameter name which matches the sType 14171 * for that target column. This is the corollary of <i>afnSortData</i> 14172 * for searching data. 14173 * 14174 * The functions defined take a single parameter: 14175 * 14176 * 1. `{*}` Data from the column cell to be prepared for searching 14177 * 14178 * Each function is expected to return: 14179 * 14180 * * `{string|null}` Formatted string that will be used for the searching. 14181 * 14182 * @type object 14183 * @default {} 14184 * 14185 * @example 14186 * $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) { 14187 * return d.replace(/\n/g," ").replace( /<.*?>/g, "" ); 14188 * } 14189 */ 14190 search: {}, 14191 14192 14193 /** 14194 * Type based ordering. 14195 * 14196 * The column type tells DataTables what ordering to apply to the table 14197 * when a column is sorted upon. The order for each type that is defined, 14198 * is defined by the functions available in this object. 14199 * 14200 * Each ordering option can be described by three properties added to 14201 * this object: 14202 * 14203 * * `{type}-pre` - Pre-formatting function 14204 * * `{type}-asc` - Ascending order function 14205 * * `{type}-desc` - Descending order function 14206 * 14207 * All three can be used together, only `{type}-pre` or only 14208 * `{type}-asc` and `{type}-desc` together. It is generally recommended 14209 * that only `{type}-pre` is used, as this provides the optimal 14210 * implementation in terms of speed, although the others are provided 14211 * for compatibility with existing Javascript sort functions. 14212 * 14213 * `{type}-pre`: Functions defined take a single parameter: 14214 * 14215 * 1. `{*}` Data from the column cell to be prepared for ordering 14216 * 14217 * And return: 14218 * 14219 * * `{*}` Data to be sorted upon 14220 * 14221 * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort 14222 * functions, taking two parameters: 14223 * 14224 * 1. `{*}` Data to compare to the second parameter 14225 * 2. `{*}` Data to compare to the first parameter 14226 * 14227 * And returning: 14228 * 14229 * * `{*}` Ordering match: <0 if first parameter should be sorted lower 14230 * than the second parameter, ===0 if the two parameters are equal and 14231 * >0 if the first parameter should be sorted height than the second 14232 * parameter. 14233 * 14234 * @type object 14235 * @default {} 14236 * 14237 * @example 14238 * // Numeric ordering of formatted numbers with a pre-formatter 14239 * $.extend( $.fn.dataTable.ext.type.order, { 14240 * "string-pre": function(x) { 14241 * a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" ); 14242 * return parseFloat( a ); 14243 * } 14244 * } ); 14245 * 14246 * @example 14247 * // Case-sensitive string ordering, with no pre-formatting method 14248 * $.extend( $.fn.dataTable.ext.order, { 14249 * "string-case-asc": function(x,y) { 14250 * return ((x < y) ? -1 : ((x > y) ? 1 : 0)); 14251 * }, 14252 * "string-case-desc": function(x,y) { 14253 * return ((x < y) ? 1 : ((x > y) ? -1 : 0)); 14254 * } 14255 * } ); 14256 */ 14257 order: {} 14258 }, 14259 14260 /** 14261 * Unique DataTables instance counter 14262 * 14263 * @type int 14264 * @private 14265 */ 14266 _unique: 0, 14267 14268 14269 // 14270 // Depreciated 14271 // The following properties are retained for backwards compatiblity only. 14272 // The should not be used in new projects and will be removed in a future 14273 // version 14274 // 14275 14276 /** 14277 * Version check function. 14278 * @type function 14279 * @depreciated Since 1.10 14280 */ 14281 fnVersionCheck: DataTable.fnVersionCheck, 14282 14283 14284 /** 14285 * Index for what 'this' index API functions should use 14286 * @type int 14287 * @deprecated Since v1.10 14288 */ 14289 iApiIndex: 0, 14290 14291 14292 /** 14293 * jQuery UI class container 14294 * @type object 14295 * @deprecated Since v1.10 14296 */ 14297 oJUIClasses: {}, 14298 14299 14300 /** 14301 * Software version 14302 * @type string 14303 * @deprecated Since v1.10 14304 */ 14305 sVersion: DataTable.version 14306 }; 14307 14308 14309 // 14310 // Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts 14311 // 14312 $.extend( _ext, { 14313 afnFiltering: _ext.search, 14314 aTypes: _ext.type.detect, 14315 ofnSearch: _ext.type.search, 14316 oSort: _ext.type.order, 14317 afnSortData: _ext.order, 14318 aoFeatures: _ext.feature, 14319 oApi: _ext.internal, 14320 oStdClasses: _ext.classes, 14321 oPagination: _ext.pager 14322 } ); 14323 14324 14325 $.extend( DataTable.ext.classes, { 14326 "sTable": "dataTable", 14327 "sNoFooter": "no-footer", 14328 14329 /* Paging buttons */ 14330 "sPageButton": "paginate_button", 14331 "sPageButtonActive": "current", 14332 "sPageButtonDisabled": "disabled", 14333 14334 /* Striping classes */ 14335 "sStripeOdd": "odd", 14336 "sStripeEven": "even", 14337 14338 /* Empty row */ 14339 "sRowEmpty": "dataTables_empty", 14340 14341 /* Features */ 14342 "sWrapper": "dataTables_wrapper", 14343 "sFilter": "dataTables_filter", 14344 "sInfo": "dataTables_info", 14345 "sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */ 14346 "sLength": "dataTables_length", 14347 "sProcessing": "dataTables_processing", 14348 14349 /* Sorting */ 14350 "sSortAsc": "sorting_asc", 14351 "sSortDesc": "sorting_desc", 14352 "sSortable": "sorting", /* Sortable in both directions */ 14353 "sSortableAsc": "sorting_asc_disabled", 14354 "sSortableDesc": "sorting_desc_disabled", 14355 "sSortableNone": "sorting_disabled", 14356 "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */ 14357 14358 /* Filtering */ 14359 "sFilterInput": "", 14360 14361 /* Page length */ 14362 "sLengthSelect": "", 14363 14364 /* Scrolling */ 14365 "sScrollWrapper": "dataTables_scroll", 14366 "sScrollHead": "dataTables_scrollHead", 14367 "sScrollHeadInner": "dataTables_scrollHeadInner", 14368 "sScrollBody": "dataTables_scrollBody", 14369 "sScrollFoot": "dataTables_scrollFoot", 14370 "sScrollFootInner": "dataTables_scrollFootInner", 14371 14372 /* Misc */ 14373 "sHeaderTH": "", 14374 "sFooterTH": "", 14375 14376 // Deprecated 14377 "sSortJUIAsc": "", 14378 "sSortJUIDesc": "", 14379 "sSortJUI": "", 14380 "sSortJUIAscAllowed": "", 14381 "sSortJUIDescAllowed": "", 14382 "sSortJUIWrapper": "", 14383 "sSortIcon": "", 14384 "sJUIHeader": "", 14385 "sJUIFooter": "" 14386 } ); 14387 14388 14389 (function() { 14390 14391 // Reused strings for better compression. Closure compiler appears to have a 14392 // weird edge case where it is trying to expand strings rather than use the 14393 // variable version. This results in about 200 bytes being added, for very 14394 // little preference benefit since it this run on script load only. 14395 var _empty = ''; 14396 _empty = ''; 14397 14398 var _stateDefault = _empty + 'ui-state-default'; 14399 var _sortIcon = _empty + 'css_right ui-icon ui-icon-'; 14400 var _headerFooter = _empty + 'fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix'; 14401 14402 $.extend( DataTable.ext.oJUIClasses, DataTable.ext.classes, { 14403 /* Full numbers paging buttons */ 14404 "sPageButton": "fg-button ui-button "+_stateDefault, 14405 "sPageButtonActive": "ui-state-disabled", 14406 "sPageButtonDisabled": "ui-state-disabled", 14407 14408 /* Features */ 14409 "sPaging": "dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi "+ 14410 "ui-buttonset-multi paging_", /* Note that the type is postfixed */ 14411 14412 /* Sorting */ 14413 "sSortAsc": _stateDefault+" sorting_asc", 14414 "sSortDesc": _stateDefault+" sorting_desc", 14415 "sSortable": _stateDefault+" sorting", 14416 "sSortableAsc": _stateDefault+" sorting_asc_disabled", 14417 "sSortableDesc": _stateDefault+" sorting_desc_disabled", 14418 "sSortableNone": _stateDefault+" sorting_disabled", 14419 "sSortJUIAsc": _sortIcon+"triangle-1-n", 14420 "sSortJUIDesc": _sortIcon+"triangle-1-s", 14421 "sSortJUI": _sortIcon+"carat-2-n-s", 14422 "sSortJUIAscAllowed": _sortIcon+"carat-1-n", 14423 "sSortJUIDescAllowed": _sortIcon+"carat-1-s", 14424 "sSortJUIWrapper": "DataTables_sort_wrapper", 14425 "sSortIcon": "DataTables_sort_icon", 14426 14427 /* Scrolling */ 14428 "sScrollHead": "dataTables_scrollHead "+_stateDefault, 14429 "sScrollFoot": "dataTables_scrollFoot "+_stateDefault, 14430 14431 /* Misc */ 14432 "sHeaderTH": _stateDefault, 14433 "sFooterTH": _stateDefault, 14434 "sJUIHeader": _headerFooter+" ui-corner-tl ui-corner-tr", 14435 "sJUIFooter": _headerFooter+" ui-corner-bl ui-corner-br" 14436 } ); 14437 14438 }()); 14439 14440 14441 14442 var extPagination = DataTable.ext.pager; 14443 14444 function _numbers ( page, pages ) { 14445 var 14446 numbers = [], 14447 buttons = extPagination.numbers_length, 14448 half = Math.floor( buttons / 2 ), 14449 i = 1; 14450 14451 if ( pages <= buttons ) { 14452 numbers = _range( 0, pages ); 14453 } 14454 else if ( page <= half ) { 14455 numbers = _range( 0, buttons-2 ); 14456 numbers.push( 'ellipsis' ); 14457 numbers.push( pages-1 ); 14458 } 14459 else if ( page >= pages - 1 - half ) { 14460 numbers = _range( pages-(buttons-2), pages ); 14461 numbers.splice( 0, 0, 'ellipsis' ); // no unshift in ie6 14462 numbers.splice( 0, 0, 0 ); 14463 } 14464 else { 14465 numbers = _range( page-half+2, page+half-1 ); 14466 numbers.push( 'ellipsis' ); 14467 numbers.push( pages-1 ); 14468 numbers.splice( 0, 0, 'ellipsis' ); 14469 numbers.splice( 0, 0, 0 ); 14470 } 14471 14472 numbers.DT_el = 'span'; 14473 return numbers; 14474 } 14475 14476 14477 $.extend( extPagination, { 14478 simple: function ( page, pages ) { 14479 return [ 'previous', 'next' ]; 14480 }, 14481 14482 full: function ( page, pages ) { 14483 return [ 'first', 'previous', 'next', 'last' ]; 14484 }, 14485 14486 numbers: function ( page, pages ) { 14487 return [ _numbers(page, pages) ]; 14488 }, 14489 14490 simple_numbers: function ( page, pages ) { 14491 return [ 'previous', _numbers(page, pages), 'next' ]; 14492 }, 14493 14494 full_numbers: function ( page, pages ) { 14495 return [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ]; 14496 }, 14497 14498 // For testing and plug-ins to use 14499 _numbers: _numbers, 14500 14501 // Number of number buttons (including ellipsis) to show. _Must be odd!_ 14502 numbers_length: 7 14503 } ); 14504 14505 14506 $.extend( true, DataTable.ext.renderer, { 14507 pageButton: { 14508 _: function ( settings, host, idx, buttons, page, pages ) { 14509 var classes = settings.oClasses; 14510 var lang = settings.oLanguage.oPaginate; 14511 var aria = settings.oLanguage.oAria.paginate || {}; 14512 var btnDisplay, btnClass, counter=0; 14513 14514 var attach = function( container, buttons ) { 14515 var i, ien, node, button; 14516 var clickHandler = function ( e ) { 14517 _fnPageChange( settings, e.data.action, true ); 14518 }; 14519 14520 for ( i=0, ien=buttons.length ; i<ien ; i++ ) { 14521 button = buttons[i]; 14522 14523 if ( $.isArray( button ) ) { 14524 var inner = $( '<'+(button.DT_el || 'div')+'/>' ) 14525 .appendTo( container ); 14526 attach( inner, button ); 14527 } 14528 else { 14529 btnDisplay = null; 14530 btnClass = ''; 14531 14532 switch ( button ) { 14533 case 'ellipsis': 14534 container.append('<span class="ellipsis">…</span>'); 14535 break; 14536 14537 case 'first': 14538 btnDisplay = lang.sFirst; 14539 btnClass = button + (page > 0 ? 14540 '' : ' '+classes.sPageButtonDisabled); 14541 break; 14542 14543 case 'previous': 14544 btnDisplay = lang.sPrevious; 14545 btnClass = button + (page > 0 ? 14546 '' : ' '+classes.sPageButtonDisabled); 14547 break; 14548 14549 case 'next': 14550 btnDisplay = lang.sNext; 14551 btnClass = button + (page < pages-1 ? 14552 '' : ' '+classes.sPageButtonDisabled); 14553 break; 14554 14555 case 'last': 14556 btnDisplay = lang.sLast; 14557 btnClass = button + (page < pages-1 ? 14558 '' : ' '+classes.sPageButtonDisabled); 14559 break; 14560 14561 default: 14562 btnDisplay = button + 1; 14563 btnClass = page === button ? 14564 classes.sPageButtonActive : ''; 14565 break; 14566 } 14567 14568 if ( btnDisplay !== null ) { 14569 node = $('<a>', { 14570 'class': classes.sPageButton+' '+btnClass, 14571 'aria-controls': settings.sTableId, 14572 'aria-label': aria[ button ], 14573 'data-dt-idx': counter, 14574 'tabindex': settings.iTabIndex, 14575 'id': idx === 0 && typeof button === 'string' ? 14576 settings.sTableId +'_'+ button : 14577 null 14578 } ) 14579 .html( btnDisplay ) 14580 .appendTo( container ); 14581 14582 _fnBindAction( 14583 node, {action: button}, clickHandler 14584 ); 14585 14586 counter++; 14587 } 14588 } 14589 } 14590 }; 14591 14592 // IE9 throws an 'unknown error' if document.activeElement is used 14593 // inside an iframe or frame. Try / catch the error. Not good for 14594 // accessibility, but neither are frames. 14595 var activeEl; 14596 14597 try { 14598 // Because this approach is destroying and recreating the paging 14599 // elements, focus is lost on the select button which is bad for 14600 // accessibility. So we want to restore focus once the draw has 14601 // completed 14602 activeEl = $(host).find(document.activeElement).data('dt-idx'); 14603 } 14604 catch (e) {} 14605 14606 attach( $(host).empty(), buttons ); 14607 14608 if ( activeEl ) { 14609 $(host).find( '[data-dt-idx='+activeEl+']' ).focus(); 14610 } 14611 } 14612 } 14613 } ); 14614 14615 14616 14617 // Built in type detection. See model.ext.aTypes for information about 14618 // what is required from this methods. 14619 $.extend( DataTable.ext.type.detect, [ 14620 // Plain numbers - first since V8 detects some plain numbers as dates 14621 // e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...). 14622 function ( d, settings ) 14623 { 14624 var decimal = settings.oLanguage.sDecimal; 14625 return _isNumber( d, decimal ) ? 'num'+decimal : null; 14626 }, 14627 14628 // Dates (only those recognised by the browser's Date.parse) 14629 function ( d, settings ) 14630 { 14631 // V8 will remove any unknown characters at the start and end of the 14632 // expression, leading to false matches such as `$245.12` or `10%` being 14633 // a valid date. See forum thread 18941 for detail. 14634 if ( d && !(d instanceof Date) && ( ! _re_date_start.test(d) || ! _re_date_end.test(d) ) ) { 14635 return null; 14636 } 14637 var parsed = Date.parse(d); 14638 return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null; 14639 }, 14640 14641 // Formatted numbers 14642 function ( d, settings ) 14643 { 14644 var decimal = settings.oLanguage.sDecimal; 14645 return _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null; 14646 }, 14647 14648 // HTML numeric 14649 function ( d, settings ) 14650 { 14651 var decimal = settings.oLanguage.sDecimal; 14652 return _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null; 14653 }, 14654 14655 // HTML numeric, formatted 14656 function ( d, settings ) 14657 { 14658 var decimal = settings.oLanguage.sDecimal; 14659 return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null; 14660 }, 14661 14662 // HTML (this is strict checking - there must be html) 14663 function ( d, settings ) 14664 { 14665 return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ? 14666 'html' : null; 14667 } 14668 ] ); 14669 14670 14671 14672 // Filter formatting functions. See model.ext.ofnSearch for information about 14673 // what is required from these methods. 14674 // 14675 // Note that additional search methods are added for the html numbers and 14676 // html formatted numbers by `_addNumericSort()` when we know what the decimal 14677 // place is 14678 14679 14680 $.extend( DataTable.ext.type.search, { 14681 html: function ( data ) { 14682 return _empty(data) ? 14683 data : 14684 typeof data === 'string' ? 14685 data 14686 .replace( _re_new_lines, " " ) 14687 .replace( _re_html, "" ) : 14688 ''; 14689 }, 14690 14691 string: function ( data ) { 14692 return _empty(data) ? 14693 data : 14694 typeof data === 'string' ? 14695 data.replace( _re_new_lines, " " ) : 14696 data; 14697 } 14698 } ); 14699 14700 14701 14702 var __numericReplace = function ( d, decimalPlace, re1, re2 ) { 14703 if ( d !== 0 && (!d || d === '-') ) { 14704 return -Infinity; 14705 } 14706 14707 // If a decimal place other than `.` is used, it needs to be given to the 14708 // function so we can detect it and replace with a `.` which is the only 14709 // decimal place Javascript recognises - it is not locale aware. 14710 if ( decimalPlace ) { 14711 d = _numToDecimal( d, decimalPlace ); 14712 } 14713 14714 if ( d.replace ) { 14715 if ( re1 ) { 14716 d = d.replace( re1, '' ); 14717 } 14718 14719 if ( re2 ) { 14720 d = d.replace( re2, '' ); 14721 } 14722 } 14723 14724 return d * 1; 14725 }; 14726 14727 14728 // Add the numeric 'deformatting' functions for sorting and search. This is done 14729 // in a function to provide an easy ability for the language options to add 14730 // additional methods if a non-period decimal place is used. 14731 function _addNumericSort ( decimalPlace ) { 14732 $.each( 14733 { 14734 // Plain numbers 14735 "num": function ( d ) { 14736 return __numericReplace( d, decimalPlace ); 14737 }, 14738 14739 // Formatted numbers 14740 "num-fmt": function ( d ) { 14741 return __numericReplace( d, decimalPlace, _re_formatted_numeric ); 14742 }, 14743 14744 // HTML numeric 14745 "html-num": function ( d ) { 14746 return __numericReplace( d, decimalPlace, _re_html ); 14747 }, 14748 14749 // HTML numeric, formatted 14750 "html-num-fmt": function ( d ) { 14751 return __numericReplace( d, decimalPlace, _re_html, _re_formatted_numeric ); 14752 } 14753 }, 14754 function ( key, fn ) { 14755 // Add the ordering method 14756 _ext.type.order[ key+decimalPlace+'-pre' ] = fn; 14757 14758 // For HTML types add a search formatter that will strip the HTML 14759 if ( key.match(/^html\-/) ) { 14760 _ext.type.search[ key+decimalPlace ] = _ext.type.search.html; 14761 } 14762 } 14763 ); 14764 } 14765 14766 14767 // Default sort methods 14768 $.extend( _ext.type.order, { 14769 // Dates 14770 "date-pre": function ( d ) { 14771 return Date.parse( d ) || 0; 14772 }, 14773 14774 // html 14775 "html-pre": function ( a ) { 14776 return _empty(a) ? 14777 '' : 14778 a.replace ? 14779 a.replace( /<.*?>/g, "" ).toLowerCase() : 14780 a+''; 14781 }, 14782 14783 // string 14784 "string-pre": function ( a ) { 14785 // This is a little complex, but faster than always calling toString, 14786 // http://jsperf.com/tostring-v-check 14787 return _empty(a) ? 14788 '' : 14789 typeof a === 'string' ? 14790 a.toLowerCase() : 14791 ! a.toString ? 14792 '' : 14793 a.toString(); 14794 }, 14795 14796 // string-asc and -desc are retained only for compatibility with the old 14797 // sort methods 14798 "string-asc": function ( x, y ) { 14799 return ((x < y) ? -1 : ((x > y) ? 1 : 0)); 14800 }, 14801 14802 "string-desc": function ( x, y ) { 14803 return ((x < y) ? 1 : ((x > y) ? -1 : 0)); 14804 } 14805 } ); 14806 14807 14808 // Numeric sorting types - order doesn't matter here 14809 _addNumericSort( '' ); 14810 14811 14812 $.extend( true, DataTable.ext.renderer, { 14813 header: { 14814 _: function ( settings, cell, column, classes ) { 14815 // No additional mark-up required 14816 // Attach a sort listener to update on sort - note that using the 14817 // `DT` namespace will allow the event to be removed automatically 14818 // on destroy, while the `dt` namespaced event is the one we are 14819 // listening for 14820 $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) { 14821 if ( settings !== ctx ) { // need to check this this is the host 14822 return; // table, not a nested one 14823 } 14824 14825 var colIdx = column.idx; 14826 14827 cell 14828 .removeClass( 14829 column.sSortingClass +' '+ 14830 classes.sSortAsc +' '+ 14831 classes.sSortDesc 14832 ) 14833 .addClass( columns[ colIdx ] == 'asc' ? 14834 classes.sSortAsc : columns[ colIdx ] == 'desc' ? 14835 classes.sSortDesc : 14836 column.sSortingClass 14837 ); 14838 } ); 14839 }, 14840 14841 jqueryui: function ( settings, cell, column, classes ) { 14842 $('<div/>') 14843 .addClass( classes.sSortJUIWrapper ) 14844 .append( cell.contents() ) 14845 .append( $('<span/>') 14846 .addClass( classes.sSortIcon+' '+column.sSortingClassJUI ) 14847 ) 14848 .appendTo( cell ); 14849 14850 // Attach a sort listener to update on sort 14851 $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) { 14852 if ( settings !== ctx ) { 14853 return; 14854 } 14855 14856 var colIdx = column.idx; 14857 14858 cell 14859 .removeClass( classes.sSortAsc +" "+classes.sSortDesc ) 14860 .addClass( columns[ colIdx ] == 'asc' ? 14861 classes.sSortAsc : columns[ colIdx ] == 'desc' ? 14862 classes.sSortDesc : 14863 column.sSortingClass 14864 ); 14865 14866 cell 14867 .find( 'span.'+classes.sSortIcon ) 14868 .removeClass( 14869 classes.sSortJUIAsc +" "+ 14870 classes.sSortJUIDesc +" "+ 14871 classes.sSortJUI +" "+ 14872 classes.sSortJUIAscAllowed +" "+ 14873 classes.sSortJUIDescAllowed 14874 ) 14875 .addClass( columns[ colIdx ] == 'asc' ? 14876 classes.sSortJUIAsc : columns[ colIdx ] == 'desc' ? 14877 classes.sSortJUIDesc : 14878 column.sSortingClassJUI 14879 ); 14880 } ); 14881 } 14882 } 14883 } ); 14884 14885 /* 14886 * Public helper functions. These aren't used internally by DataTables, or 14887 * called by any of the options passed into DataTables, but they can be used 14888 * externally by developers working with DataTables. They are helper functions 14889 * to make working with DataTables a little bit easier. 14890 */ 14891 14892 var __htmlEscapeEntities = function ( d ) { 14893 return typeof d === 'string' ? 14894 d.replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"') : 14895 d; 14896 }; 14897 14898 /** 14899 * Helpers for `columns.render`. 14900 * 14901 * The options defined here can be used with the `columns.render` initialisation 14902 * option to provide a display renderer. The following functions are defined: 14903 * 14904 * * `number` - Will format numeric data (defined by `columns.data`) for 14905 * display, retaining the original unformatted data for sorting and filtering. 14906 * It takes 5 parameters: 14907 * * `string` - Thousands grouping separator 14908 * * `string` - Decimal point indicator 14909 * * `integer` - Number of decimal points to show 14910 * * `string` (optional) - Prefix. 14911 * * `string` (optional) - Postfix (/suffix). 14912 * * `text` - Escape HTML to help prevent XSS attacks. It has no optional 14913 * parameters. 14914 * 14915 * @example 14916 * // Column definition using the number renderer 14917 * { 14918 * data: "salary", 14919 * render: $.fn.dataTable.render.number( '\'', '.', 0, '$' ) 14920 * } 14921 * 14922 * @namespace 14923 */ 14924 DataTable.render = { 14925 number: function ( thousands, decimal, precision, prefix, postfix ) { 14926 return { 14927 display: function ( d ) { 14928 if ( typeof d !== 'number' && typeof d !== 'string' ) { 14929 return d; 14930 } 14931 14932 var negative = d < 0 ? '-' : ''; 14933 var flo = parseFloat( d ); 14934 14935 // If NaN then there isn't much formatting that we can do - just 14936 // return immediately, escaping any HTML (this was supposed to 14937 // be a number after all) 14938 if ( isNaN( flo ) ) { 14939 return __htmlEscapeEntities( d ); 14940 } 14941 14942 d = Math.abs( flo ); 14943 14944 var intPart = parseInt( d, 10 ); 14945 var floatPart = precision ? 14946 decimal+(d - intPart).toFixed( precision ).substring( 2 ): 14947 ''; 14948 14949 return negative + (prefix||'') + 14950 intPart.toString().replace( 14951 /\B(?=(\d{3})+(?!\d))/g, thousands 14952 ) + 14953 floatPart + 14954 (postfix||''); 14955 } 14956 }; 14957 }, 14958 14959 text: function () { 14960 return { 14961 display: __htmlEscapeEntities 14962 }; 14963 } 14964 }; 14965 14966 14967 /* 14968 * This is really a good bit rubbish this method of exposing the internal methods 14969 * publicly... - To be fixed in 2.0 using methods on the prototype 14970 */ 14971 14972 14973 /** 14974 * Create a wrapper function for exporting an internal functions to an external API. 14975 * @param {string} fn API function name 14976 * @returns {function} wrapped function 14977 * @memberof DataTable#internal 14978 */ 14979 function _fnExternApiFunc (fn) 14980 { 14981 return function() { 14982 var args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat( 14983 Array.prototype.slice.call(arguments) 14984 ); 14985 return DataTable.ext.internal[fn].apply( this, args ); 14986 }; 14987 } 14988 14989 14990 /** 14991 * Reference to internal functions for use by plug-in developers. Note that 14992 * these methods are references to internal functions and are considered to be 14993 * private. If you use these methods, be aware that they are liable to change 14994 * between versions. 14995 * @namespace 14996 */ 14997 $.extend( DataTable.ext.internal, { 14998 _fnExternApiFunc: _fnExternApiFunc, 14999 _fnBuildAjax: _fnBuildAjax, 15000 _fnAjaxUpdate: _fnAjaxUpdate, 15001 _fnAjaxParameters: _fnAjaxParameters, 15002 _fnAjaxUpdateDraw: _fnAjaxUpdateDraw, 15003 _fnAjaxDataSrc: _fnAjaxDataSrc, 15004 _fnAddColumn: _fnAddColumn, 15005 _fnColumnOptions: _fnColumnOptions, 15006 _fnAdjustColumnSizing: _fnAdjustColumnSizing, 15007 _fnVisibleToColumnIndex: _fnVisibleToColumnIndex, 15008 _fnColumnIndexToVisible: _fnColumnIndexToVisible, 15009 _fnVisbleColumns: _fnVisbleColumns, 15010 _fnGetColumns: _fnGetColumns, 15011 _fnColumnTypes: _fnColumnTypes, 15012 _fnApplyColumnDefs: _fnApplyColumnDefs, 15013 _fnHungarianMap: _fnHungarianMap, 15014 _fnCamelToHungarian: _fnCamelToHungarian, 15015 _fnLanguageCompat: _fnLanguageCompat, 15016 _fnBrowserDetect: _fnBrowserDetect, 15017 _fnAddData: _fnAddData, 15018 _fnAddTr: _fnAddTr, 15019 _fnNodeToDataIndex: _fnNodeToDataIndex, 15020 _fnNodeToColumnIndex: _fnNodeToColumnIndex, 15021 _fnGetCellData: _fnGetCellData, 15022 _fnSetCellData: _fnSetCellData, 15023 _fnSplitObjNotation: _fnSplitObjNotation, 15024 _fnGetObjectDataFn: _fnGetObjectDataFn, 15025 _fnSetObjectDataFn: _fnSetObjectDataFn, 15026 _fnGetDataMaster: _fnGetDataMaster, 15027 _fnClearTable: _fnClearTable, 15028 _fnDeleteIndex: _fnDeleteIndex, 15029 _fnInvalidate: _fnInvalidate, 15030 _fnGetRowElements: _fnGetRowElements, 15031 _fnCreateTr: _fnCreateTr, 15032 _fnBuildHead: _fnBuildHead, 15033 _fnDrawHead: _fnDrawHead, 15034 _fnDraw: _fnDraw, 15035 _fnReDraw: _fnReDraw, 15036 _fnAddOptionsHtml: _fnAddOptionsHtml, 15037 _fnDetectHeader: _fnDetectHeader, 15038 _fnGetUniqueThs: _fnGetUniqueThs, 15039 _fnFeatureHtmlFilter: _fnFeatureHtmlFilter, 15040 _fnFilterComplete: _fnFilterComplete, 15041 _fnFilterCustom: _fnFilterCustom, 15042 _fnFilterColumn: _fnFilterColumn, 15043 _fnFilter: _fnFilter, 15044 _fnFilterCreateSearch: _fnFilterCreateSearch, 15045 _fnEscapeRegex: _fnEscapeRegex, 15046 _fnFilterData: _fnFilterData, 15047 _fnFeatureHtmlInfo: _fnFeatureHtmlInfo, 15048 _fnUpdateInfo: _fnUpdateInfo, 15049 _fnInfoMacros: _fnInfoMacros, 15050 _fnInitialise: _fnInitialise, 15051 _fnInitComplete: _fnInitComplete, 15052 _fnLengthChange: _fnLengthChange, 15053 _fnFeatureHtmlLength: _fnFeatureHtmlLength, 15054 _fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate, 15055 _fnPageChange: _fnPageChange, 15056 _fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing, 15057 _fnProcessingDisplay: _fnProcessingDisplay, 15058 _fnFeatureHtmlTable: _fnFeatureHtmlTable, 15059 _fnScrollDraw: _fnScrollDraw, 15060 _fnApplyToChildren: _fnApplyToChildren, 15061 _fnCalculateColumnWidths: _fnCalculateColumnWidths, 15062 _fnThrottle: _fnThrottle, 15063 _fnConvertToWidth: _fnConvertToWidth, 15064 _fnGetWidestNode: _fnGetWidestNode, 15065 _fnGetMaxLenString: _fnGetMaxLenString, 15066 _fnStringToCss: _fnStringToCss, 15067 _fnSortFlatten: _fnSortFlatten, 15068 _fnSort: _fnSort, 15069 _fnSortAria: _fnSortAria, 15070 _fnSortListener: _fnSortListener, 15071 _fnSortAttachListener: _fnSortAttachListener, 15072 _fnSortingClasses: _fnSortingClasses, 15073 _fnSortData: _fnSortData, 15074 _fnSaveState: _fnSaveState, 15075 _fnLoadState: _fnLoadState, 15076 _fnSettingsFromNode: _fnSettingsFromNode, 15077 _fnLog: _fnLog, 15078 _fnMap: _fnMap, 15079 _fnBindAction: _fnBindAction, 15080 _fnCallbackReg: _fnCallbackReg, 15081 _fnCallbackFire: _fnCallbackFire, 15082 _fnLengthOverflow: _fnLengthOverflow, 15083 _fnRenderer: _fnRenderer, 15084 _fnDataSource: _fnDataSource, 15085 _fnRowAttributes: _fnRowAttributes, 15086 _fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant 15087 // in 1.10, so this dead-end function is 15088 // added to prevent errors 15089 } ); 15090 15091 15092 // jQuery access 15093 $.fn.dataTable = DataTable; 15094 15095 // Provide access to the host jQuery object (circular reference) 15096 DataTable.$ = $; 15097 15098 // Legacy aliases 15099 $.fn.dataTableSettings = DataTable.settings; 15100 $.fn.dataTableExt = DataTable.ext; 15101 15102 // With a capital `D` we return a DataTables API instance rather than a 15103 // jQuery object 15104 $.fn.DataTable = function ( opts ) { 15105 return $(this).dataTable( opts ).api(); 15106 }; 15107 15108 // All properties that are available to $.fn.dataTable should also be 15109 // available on $.fn.DataTable 15110 $.each( DataTable, function ( prop, val ) { 15111 $.fn.DataTable[ prop ] = val; 15112 } ); 15113 15114 15115 // Information about events fired by DataTables - for documentation. 15116 /** 15117 * Draw event, fired whenever the table is redrawn on the page, at the same 15118 * point as fnDrawCallback. This may be useful for binding events or 15119 * performing calculations when the table is altered at all. 15120 * @name DataTable#draw.dt 15121 * @event 15122 * @param {event} e jQuery event object 15123 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 15124 */ 15125 15126 /** 15127 * Search event, fired when the searching applied to the table (using the 15128 * built-in global search, or column filters) is altered. 15129 * @name DataTable#search.dt 15130 * @event 15131 * @param {event} e jQuery event object 15132 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 15133 */ 15134 15135 /** 15136 * Page change event, fired when the paging of the table is altered. 15137 * @name DataTable#page.dt 15138 * @event 15139 * @param {event} e jQuery event object 15140 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 15141 */ 15142 15143 /** 15144 * Order event, fired when the ordering applied to the table is altered. 15145 * @name DataTable#order.dt 15146 * @event 15147 * @param {event} e jQuery event object 15148 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 15149 */ 15150 15151 /** 15152 * DataTables initialisation complete event, fired when the table is fully 15153 * drawn, including Ajax data loaded, if Ajax data is required. 15154 * @name DataTable#init.dt 15155 * @event 15156 * @param {event} e jQuery event object 15157 * @param {object} oSettings DataTables settings object 15158 * @param {object} json The JSON object request from the server - only 15159 * present if client-side Ajax sourced data is used</li></ol> 15160 */ 15161 15162 /** 15163 * State save event, fired when the table has changed state a new state save 15164 * is required. This event allows modification of the state saving object 15165 * prior to actually doing the save, including addition or other state 15166 * properties (for plug-ins) or modification of a DataTables core property. 15167 * @name DataTable#stateSaveParams.dt 15168 * @event 15169 * @param {event} e jQuery event object 15170 * @param {object} oSettings DataTables settings object 15171 * @param {object} json The state information to be saved 15172 */ 15173 15174 /** 15175 * State load event, fired when the table is loading state from the stored 15176 * data, but prior to the settings object being modified by the saved state 15177 * - allowing modification of the saved state is required or loading of 15178 * state for a plug-in. 15179 * @name DataTable#stateLoadParams.dt 15180 * @event 15181 * @param {event} e jQuery event object 15182 * @param {object} oSettings DataTables settings object 15183 * @param {object} json The saved state information 15184 */ 15185 15186 /** 15187 * State loaded event, fired when state has been loaded from stored data and 15188 * the settings object has been modified by the loaded data. 15189 * @name DataTable#stateLoaded.dt 15190 * @event 15191 * @param {event} e jQuery event object 15192 * @param {object} oSettings DataTables settings object 15193 * @param {object} json The saved state information 15194 */ 15195 15196 /** 15197 * Processing event, fired when DataTables is doing some kind of processing 15198 * (be it, order, searcg or anything else). It can be used to indicate to 15199 * the end user that there is something happening, or that something has 15200 * finished. 15201 * @name DataTable#processing.dt 15202 * @event 15203 * @param {event} e jQuery event object 15204 * @param {object} oSettings DataTables settings object 15205 * @param {boolean} bShow Flag for if DataTables is doing processing or not 15206 */ 15207 15208 /** 15209 * Ajax (XHR) event, fired whenever an Ajax request is completed from a 15210 * request to made to the server for new data. This event is called before 15211 * DataTables processed the returned data, so it can also be used to pre- 15212 * process the data returned from the server, if needed. 15213 * 15214 * Note that this trigger is called in `fnServerData`, if you override 15215 * `fnServerData` and which to use this event, you need to trigger it in you 15216 * success function. 15217 * @name DataTable#xhr.dt 15218 * @event 15219 * @param {event} e jQuery event object 15220 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 15221 * @param {object} json JSON returned from the server 15222 * 15223 * @example 15224 * // Use a custom property returned from the server in another DOM element 15225 * $('#table').dataTable().on('xhr.dt', function (e, settings, json) { 15226 * $('#status').html( json.status ); 15227 * } ); 15228 * 15229 * @example 15230 * // Pre-process the data returned from the server 15231 * $('#table').dataTable().on('xhr.dt', function (e, settings, json) { 15232 * for ( var i=0, ien=json.aaData.length ; i<ien ; i++ ) { 15233 * json.aaData[i].sum = json.aaData[i].one + json.aaData[i].two; 15234 * } 15235 * // Note no return - manipulate the data directly in the JSON object. 15236 * } ); 15237 */ 15238 15239 /** 15240 * Destroy event, fired when the DataTable is destroyed by calling fnDestroy 15241 * or passing the bDestroy:true parameter in the initialisation object. This 15242 * can be used to remove bound events, added DOM nodes, etc. 15243 * @name DataTable#destroy.dt 15244 * @event 15245 * @param {event} e jQuery event object 15246 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 15247 */ 15248 15249 /** 15250 * Page length change event, fired when number of records to show on each 15251 * page (the length) is changed. 15252 * @name DataTable#length.dt 15253 * @event 15254 * @param {event} e jQuery event object 15255 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 15256 * @param {integer} len New length 15257 */ 15258 15259 /** 15260 * Column sizing has changed. 15261 * @name DataTable#column-sizing.dt 15262 * @event 15263 * @param {event} e jQuery event object 15264 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 15265 */ 15266 15267 /** 15268 * Column visibility has changed. 15269 * @name DataTable#column-visibility.dt 15270 * @event 15271 * @param {event} e jQuery event object 15272 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 15273 * @param {int} column Column index 15274 * @param {bool} vis `false` if column now hidden, or `true` if visible 15275 */ 15276 15277 return $.fn.dataTable; 15278}));
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.