1/* 2 * This combined file was created by the DataTables downloader builder: 3 * https://datatables.net/download 4 * 5 * To rebuild or modify this file with the latest versions of the included 6 * software please visit: 7 * https://datatables.net/download/#bs/dt-1.10.16/r-2.2.1 8 * 9 * Included libraries: 10 * DataTables 1.10.16, Responsive 2.2.1 11 */ 12 13/*! DataTables 1.10.16 14 * ©2008-2017 SpryMedia Ltd - datatables.net/license 15 */ 16 17/** 18 * @summary DataTables 19 * @description Paginate, search and order HTML tables 20 * @version 1.10.16 21 * @file jquery.dataTables.js 22 * @author SpryMedia Ltd 23 * @contact www.datatables.net 24 * @copyright Copyright 2008-2017 SpryMedia Ltd. 25 * 26 * This source file is free software, available under the following license: 27 * MIT license - http://datatables.net/license 28 * 29 * This source file is distributed in the hope that it will be useful, but 30 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 31 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. 32 * 33 * For details please refer to: http://www.datatables.net 34 */ 35 36/*jslint evil: true, undef: true, browser: true */ 37/*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*/ 38 39(function( factory ) { 40 "use strict"; 41 42 if ( typeof define === 'function' && define.amd ) { 43 // AMD 44 define( ['jquery'], function ( $ ) { 45 return factory( $, window, document ); 46 } ); 47 } 48 else if ( typeof exports === 'object' ) { 49 // CommonJS 50 module.exports = function (root, $) { 51 if ( ! root ) { 52 // CommonJS environments without a window global must pass a 53 // root. This will give an error otherwise 54 root = window; 55 } 56 57 if ( ! $ ) { 58 $ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window 59 require('jquery') : 60 require('jquery')( root ); 61 } 62 63 return factory( $, root, root.document ); 64 }; 65 } 66 else { 67 // Browser 68 factory( jQuery, window, document ); 69 } 70} 71(function( $, window, document, undefined ) { 72 "use strict"; 73 74 /** 75 * DataTables is a plug-in for the jQuery Javascript library. It is a highly 76 * flexible tool, based upon the foundations of progressive enhancement, 77 * which will add advanced interaction controls to any HTML table. For a 78 * full list of features please refer to 79 * [DataTables.net](href="http://datatables.net). 80 * 81 * Note that the `DataTable` object is not a global variable but is aliased 82 * to `jQuery.fn.DataTable` and `jQuery.fn.dataTable` through which it may 83 * be accessed. 84 * 85 * @class 86 * @param {object} [init={}] Configuration object for DataTables. Options 87 * are defined by {@link DataTable.defaults} 88 * @requires jQuery 1.7+ 89 * 90 * @example 91 * // Basic initialisation 92 * $(document).ready( function { 93 * $('#example').dataTable(); 94 * } ); 95 * 96 * @example 97 * // Initialisation with configuration options - in this case, disable 98 * // pagination and sorting. 99 * $(document).ready( function { 100 * $('#example').dataTable( { 101 * "paginate": false, 102 * "sort": false 103 * } ); 104 * } ); 105 */ 106 var DataTable = function ( options ) 107 {
vendor: 6,636 bytes, lines 107-266
107 108 /** 109 * Perform a jQuery selector action on the table's TR elements (from the tbody) and 110 * return the resulting jQuery object. 111 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on 112 * @param {object} [oOpts] Optional parameters for modifying the rows to be included 113 * @param {string} [oOpts.filter=none] Select TR elements that meet the current filter 114 * criterion ("applied") or all TR elements (i.e. no filter). 115 * @param {string} [oOpts.order=current] Order of the TR elements in the processed array. 116 * Can be either 'current', whereby the current sorting of the table is used, or 117 * 'original' whereby the original order the data was read into the table is used. 118 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page 119 * ("current") or not ("all"). If 'current' is given, then order is assumed to be 120 * 'current' and filter is 'applied', regardless of what they might be given as. 121 * @returns {object} jQuery object, filtered by the given selector. 122 * @dtopt API 123 * @deprecated Since v1.10 124 * 125 * @example 126 * $(document).ready(function() { 127 * var oTable = $('#example').dataTable(); 128 * 129 * // Highlight every second row 130 * oTable.$('tr:odd').css('backgroundColor', 'blue'); 131 * } ); 132 * 133 * @example 134 * $(document).ready(function() { 135 * var oTable = $('#example').dataTable(); 136 * 137 * // Filter to rows with 'Webkit' in them, add a background colour and then 138 * // remove the filter, thus highlighting the 'Webkit' rows only. 139 * oTable.fnFilter('Webkit'); 140 * oTable.$('tr', {"search": "applied"}).css('backgroundColor', 'blue'); 141 * oTable.fnFilter(''); 142 * } ); 143 */ 144 this.$ = function ( sSelector, oOpts ) 145 { 146 return this.api(true).$( sSelector, oOpts ); 147 }; 148 149 150 /** 151 * Almost identical to $ in operation, but in this case returns the data for the matched 152 * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes 153 * rather than any descendants, so the data can be obtained for the row/cell. If matching 154 * rows are found, the data returned is the original data array/object that was used to 155 * create the row (or a generated array if from a DOM source). 156 * 157 * This method is often useful in-combination with $ where both functions are given the 158 * same parameters and the array indexes will match identically. 159 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on 160 * @param {object} [oOpts] Optional parameters for modifying the rows to be included 161 * @param {string} [oOpts.filter=none] Select elements that meet the current filter 162 * criterion ("applied") or all elements (i.e. no filter). 163 * @param {string} [oOpts.order=current] Order of the data in the processed array. 164 * Can be either 'current', whereby the current sorting of the table is used, or 165 * 'original' whereby the original order the data was read into the table is used. 166 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page 167 * ("current") or not ("all"). If 'current' is given, then order is assumed to be 168 * 'current' and filter is 'applied', regardless of what they might be given as. 169 * @returns {array} Data for the matched elements. If any elements, as a result of the 170 * selector, were not TR, TD or TH elements in the DataTable, they will have a null 171 * entry in the array. 172 * @dtopt API 173 * @deprecated Since v1.10 174 * 175 * @example 176 * $(document).ready(function() { 177 * var oTable = $('#example').dataTable(); 178 * 179 * // Get the data from the first row in the table 180 * var data = oTable._('tr:first'); 181 * 182 * // Do something useful with the data 183 * alert( "First cell is: "+data[0] ); 184 * } ); 185 * 186 * @example 187 * $(document).ready(function() { 188 * var oTable = $('#example').dataTable(); 189 * 190 * // Filter to 'Webkit' and get all data for 191 * oTable.fnFilter('Webkit'); 192 * var data = oTable._('tr', {"search": "applied"}); 193 * 194 * // Do something with the data 195 * alert( data.length+" rows matched the search" ); 196 * } ); 197 */ 198 this._ = function ( sSelector, oOpts ) 199 { 200 return this.api(true).rows( sSelector, oOpts ).data(); 201 }; 202 203 204 /** 205 * Create a DataTables Api instance, with the currently selected tables for 206 * the Api's context. 207 * @param {boolean} [traditional=false] Set the API instance's context to be 208 * only the table referred to by the `DataTable.ext.iApiIndex` option, as was 209 * used in the API presented by DataTables 1.9- (i.e. the traditional mode), 210 * or if all tables captured in the jQuery object should be used. 211 * @return {DataTables.Api} 212 */ 213 this.api = function ( traditional ) 214 { 215 return traditional ? 216 new _Api( 217 _fnSettingsFromNode( this[ _ext.iApiIndex ] ) 218 ) : 219 new _Api( this ); 220 }; 221 222 223 /** 224 * Add a single new row or multiple rows of data to the table. Please note 225 * that this is suitable for client-side processing only - if you are using 226 * server-side processing (i.e. "bServerSide": true), then to add data, you 227 * must add it to the data source, i.e. the server-side, through an Ajax call. 228 * @param {array|object} data The data to be added to the table. This can be: 229 * <ul> 230 * <li>1D array of data - add a single row with the data provided</li> 231 * <li>2D array of arrays - add multiple rows in a single call</li> 232 * <li>object - data object when using <i>mData</i></li> 233 * <li>array of objects - multiple data objects when using <i>mData</i></li> 234 * </ul> 235 * @param {bool} [redraw=true] redraw the table or not 236 * @returns {array} An array of integers, representing the list of indexes in 237 * <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to 238 * the table. 239 * @dtopt API 240 * @deprecated Since v1.10 241 * 242 * @example 243 * // Global var for counter 244 * var giCount = 2; 245 * 246 * $(document).ready(function() { 247 * $('#example').dataTable(); 248 * } ); 249 * 250 * function fnClickAddRow() { 251 * $('#example').dataTable().fnAddData( [ 252 * giCount+".1", 253 * giCount+".2", 254 * giCount+".3", 255 * giCount+".4" ] 256 * ); 257 * 258 * giCount++; 259 * } 260 */ 261 this.fnAddData = function( data, redraw ) 262 { 263 var api = this.api( true ); 264 265 /* Check if we want to add multiple rows or not */ 266 var rows =
266$.isArray(data) && ( $
vendor: 18,409 bytes, lines 266-862
266.isArray(data[0]) || $.isPlainObject(data[0]) ) ? 267 api.rows.add( data ) : 268 api.row.add( data ); 269 270 if ( redraw === undefined || redraw ) { 271 api.draw(); 272 } 273 274 return rows.flatten().toArray(); 275 }; 276 277 278 /** 279 * This function will make DataTables recalculate the column sizes, based on the data 280 * contained in the table and the sizes applied to the columns (in the DOM, CSS or 281 * through the sWidth parameter). This can be useful when the width of the table's 282 * parent element changes (for example a window resize). 283 * @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to 284 * @dtopt API 285 * @deprecated Since v1.10 286 * 287 * @example 288 * $(document).ready(function() { 289 * var oTable = $('#example').dataTable( { 290 * "sScrollY": "200px", 291 * "bPaginate": false 292 * } ); 293 * 294 * $(window).on('resize', function () { 295 * oTable.fnAdjustColumnSizing(); 296 * } ); 297 * } ); 298 */ 299 this.fnAdjustColumnSizing = function ( bRedraw ) 300 { 301 var api = this.api( true ).columns.adjust(); 302 var settings = api.settings()[0]; 303 var scroll = settings.oScroll; 304 305 if ( bRedraw === undefined || bRedraw ) { 306 api.draw( false ); 307 } 308 else if ( scroll.sX !== "" || scroll.sY !== "" ) { 309 /* If not redrawing, but scrolling, we want to apply the new column sizes anyway */ 310 _fnScrollDraw( settings ); 311 } 312 }; 313 314 315 /** 316 * Quickly and simply clear a table 317 * @param {bool} [bRedraw=true] redraw the table or not 318 * @dtopt API 319 * @deprecated Since v1.10 320 * 321 * @example 322 * $(document).ready(function() { 323 * var oTable = $('#example').dataTable(); 324 * 325 * // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...) 326 * oTable.fnClearTable(); 327 * } ); 328 */ 329 this.fnClearTable = function( bRedraw ) 330 { 331 var api = this.api( true ).clear(); 332 333 if ( bRedraw === undefined || bRedraw ) { 334 api.draw(); 335 } 336 }; 337 338 339 /** 340 * The exact opposite of 'opening' a row, this function will close any rows which 341 * are currently 'open'. 342 * @param {node} nTr the table row to 'close' 343 * @returns {int} 0 on success, or 1 if failed (can't find the row) 344 * @dtopt API 345 * @deprecated Since v1.10 346 * 347 * @example 348 * $(document).ready(function() { 349 * var oTable; 350 * 351 * // 'open' an information row when a row is clicked on 352 * $('#example tbody tr').click( function () { 353 * if ( oTable.fnIsOpen(this) ) { 354 * oTable.fnClose( this ); 355 * } else { 356 * oTable.fnOpen( this, "Temporary row opened", "info_row" ); 357 * } 358 * } ); 359 * 360 * oTable = $('#example').dataTable(); 361 * } ); 362 */ 363 this.fnClose = function( nTr ) 364 { 365 this.api( true ).row( nTr ).child.hide(); 366 }; 367 368 369 /** 370 * Remove a row for the table 371 * @param {mixed} target The index of the row from aoData to be deleted, or 372 * the TR element you want to delete 373 * @param {function|null} [callBack] Callback function 374 * @param {bool} [redraw=true] Redraw the table or not 375 * @returns {array} The row that was deleted 376 * @dtopt API 377 * @deprecated Since v1.10 378 * 379 * @example 380 * $(document).ready(function() { 381 * var oTable = $('#example').dataTable(); 382 * 383 * // Immediately remove the first row 384 * oTable.fnDeleteRow( 0 ); 385 * } ); 386 */ 387 this.fnDeleteRow = function( target, callback, redraw ) 388 { 389 var api = this.api( true ); 390 var rows = api.rows( target ); 391 var settings = rows.settings()[0]; 392 var data = settings.aoData[ rows[0][0] ]; 393 394 rows.remove(); 395 396 if ( callback ) { 397 callback.call( this, settings, data ); 398 } 399 400 if ( redraw === undefined || redraw ) { 401 api.draw(); 402 } 403 404 return data; 405 }; 406 407 408 /** 409 * Restore the table to it's original state in the DOM by removing all of DataTables 410 * enhancements, alterations to the DOM structure of the table and event listeners. 411 * @param {boolean} [remove=false] Completely remove the table from the DOM 412 * @dtopt API 413 * @deprecated Since v1.10 414 * 415 * @example 416 * $(document).ready(function() { 417 * // This example is fairly pointless in reality, but shows how fnDestroy can be used 418 * var oTable = $('#example').dataTable(); 419 * oTable.fnDestroy(); 420 * } ); 421 */ 422 this.fnDestroy = function ( remove ) 423 { 424 this.api( true ).destroy( remove ); 425 }; 426 427 428 /** 429 * Redraw the table 430 * @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw. 431 * @dtopt API 432 * @deprecated Since v1.10 433 * 434 * @example 435 * $(document).ready(function() { 436 * var oTable = $('#example').dataTable(); 437 * 438 * // Re-draw the table - you wouldn't want to do it here, but it's an example :-) 439 * oTable.fnDraw(); 440 * } ); 441 */ 442 this.fnDraw = function( complete ) 443 { 444 // Note that this isn't an exact match to the old call to _fnDraw - it takes 445 // into account the new data, but can hold position. 446 this.api( true ).draw( complete ); 447 }; 448 449 450 /** 451 * Filter the input based on data 452 * @param {string} sInput String to filter the table on 453 * @param {int|null} [iColumn] Column to limit filtering to 454 * @param {bool} [bRegex=false] Treat as regular expression or not 455 * @param {bool} [bSmart=true] Perform smart filtering or not 456 * @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es) 457 * @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false) 458 * @dtopt API 459 * @deprecated Since v1.10 460 * 461 * @example 462 * $(document).ready(function() { 463 * var oTable = $('#example').dataTable(); 464 * 465 * // Sometime later - filter... 466 * oTable.fnFilter( 'test string' ); 467 * } ); 468 */ 469 this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive ) 470 { 471 var api = this.api( true ); 472 473 if ( iColumn === null || iColumn === undefined ) { 474 api.search( sInput, bRegex, bSmart, bCaseInsensitive ); 475 } 476 else { 477 api.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive ); 478 } 479 480 api.draw(); 481 }; 482 483 484 /** 485 * Get the data for the whole table, an individual row or an individual cell based on the 486 * provided parameters. 487 * @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as 488 * a TR node then the data source for the whole row will be returned. If given as a 489 * TD/TH cell node then iCol will be automatically calculated and the data for the 490 * cell returned. If given as an integer, then this is treated as the aoData internal 491 * data index for the row (see fnGetPosition) and the data for that row used. 492 * @param {int} [col] Optional column index that you want the data of. 493 * @returns {array|object|string} If mRow is undefined, then the data for all rows is 494 * returned. If mRow is defined, just data for that row, and is iCol is 495 * defined, only data for the designated cell is returned. 496 * @dtopt API 497 * @deprecated Since v1.10 498 * 499 * @example 500 * // Row data 501 * $(document).ready(function() { 502 * oTable = $('#example').dataTable(); 503 * 504 * oTable.$('tr').click( function () { 505 * var data = oTable.fnGetData( this ); 506 * // ... do something with the array / object of data for the row 507 * } ); 508 * } ); 509 * 510 * @example 511 * // Individual cell data 512 * $(document).ready(function() { 513 * oTable = $('#example').dataTable(); 514 * 515 * oTable.$('td').click( function () { 516 * var sData = oTable.fnGetData( this ); 517 * alert( 'The cell clicked on had the value of '+sData ); 518 * } ); 519 * } ); 520 */ 521 this.fnGetData = function( src, col ) 522 { 523 var api = this.api( true ); 524 525 if ( src !== undefined ) { 526 var type = src.nodeName ? src.nodeName.toLowerCase() : ''; 527 528 return col !== undefined || type == 'td' || type == 'th' ? 529 api.cell( src, col ).data() : 530 api.row( src ).data() || null; 531 } 532 533 return api.data().toArray(); 534 }; 535 536 537 /** 538 * Get an array of the TR nodes that are used in the table's body. Note that you will 539 * typically want to use the '$' API method in preference to this as it is more 540 * flexible. 541 * @param {int} [iRow] Optional row index for the TR element you want 542 * @returns {array|node} If iRow is undefined, returns an array of all TR elements 543 * in the table's body, or iRow is defined, just the TR element requested. 544 * @dtopt API 545 * @deprecated Since v1.10 546 * 547 * @example 548 * $(document).ready(function() { 549 * var oTable = $('#example').dataTable(); 550 * 551 * // Get the nodes from the table 552 * var nNodes = oTable.fnGetNodes( ); 553 * } ); 554 */ 555 this.fnGetNodes = function( iRow ) 556 { 557 var api = this.api( true ); 558 559 return iRow !== undefined ? 560 api.row( iRow ).node() : 561 api.rows().nodes().flatten().toArray(); 562 }; 563 564 565 /** 566 * Get the array indexes of a particular cell from it's DOM element 567 * and column index including hidden columns 568 * @param {node} node this can either be a TR, TD or TH in the table's body 569 * @returns {int} If nNode is given as a TR, then a single index is returned, or 570 * if given as a cell, an array of [row index, column index (visible), 571 * column index (all)] is given. 572 * @dtopt API 573 * @deprecated Since v1.10 574 * 575 * @example 576 * $(document).ready(function() { 577 * $('#example tbody td').click( function () { 578 * // Get the position of the current data from the node 579 * var aPos = oTable.fnGetPosition( this ); 580 * 581 * // Get the data array for this row 582 * var aData = oTable.fnGetData( aPos[0] ); 583 * 584 * // Update the data array and return the value 585 * aData[ aPos[1] ] = 'clicked'; 586 * this.innerHTML = 'clicked'; 587 * } ); 588 * 589 * // Init DataTables 590 * oTable = $('#example').dataTable(); 591 * } ); 592 */ 593 this.fnGetPosition = function( node ) 594 { 595 var api = this.api( true ); 596 var nodeName = node.nodeName.toUpperCase(); 597 598 if ( nodeName == 'TR' ) { 599 return api.row( node ).index(); 600 } 601 else if ( nodeName == 'TD' || nodeName == 'TH' ) { 602 var cell = api.cell( node ).index(); 603 604 return [ 605 cell.row, 606 cell.columnVisible, 607 cell.column 608 ]; 609 } 610 return null; 611 }; 612 613 614 /** 615 * Check to see if a row is 'open' or not. 616 * @param {node} nTr the table row to check 617 * @returns {boolean} true if the row is currently open, false otherwise 618 * @dtopt API 619 * @deprecated Since v1.10 620 * 621 * @example 622 * $(document).ready(function() { 623 * var oTable; 624 * 625 * // 'open' an information row when a row is clicked on 626 * $('#example tbody tr').click( function () { 627 * if ( oTable.fnIsOpen(this) ) { 628 * oTable.fnClose( this ); 629 * } else { 630 * oTable.fnOpen( this, "Temporary row opened", "info_row" ); 631 * } 632 * } ); 633 * 634 * oTable = $('#example').dataTable(); 635 * } ); 636 */ 637 this.fnIsOpen = function( nTr ) 638 { 639 return this.api( true ).row( nTr ).child.isShown(); 640 }; 641 642 643 /** 644 * This function will place a new row directly after a row which is currently 645 * on display on the page, with the HTML contents that is passed into the 646 * function. This can be used, for example, to ask for confirmation that a 647 * particular record should be deleted. 648 * @param {node} nTr The table row to 'open' 649 * @param {string|node|jQuery} mHtml The HTML to put into the row 650 * @param {string} sClass Class to give the new TD cell 651 * @returns {node} The row opened. Note that if the table row passed in as the 652 * first parameter, is not found in the table, this method will silently 653 * return. 654 * @dtopt API 655 * @deprecated Since v1.10 656 * 657 * @example 658 * $(document).ready(function() { 659 * var oTable; 660 * 661 * // 'open' an information row when a row is clicked on 662 * $('#example tbody tr').click( function () { 663 * if ( oTable.fnIsOpen(this) ) { 664 * oTable.fnClose( this ); 665 * } else { 666 * oTable.fnOpen( this, "Temporary row opened", "info_row" ); 667 * } 668 * } ); 669 * 670 * oTable = $('#example').dataTable(); 671 * } ); 672 */ 673 this.fnOpen = function( nTr, mHtml, sClass ) 674 { 675 return this.api( true ) 676 .row( nTr ) 677 .child( mHtml, sClass ) 678 .show() 679 .child()[0]; 680 }; 681 682 683 /** 684 * Change the pagination - provides the internal logic for pagination in a simple API 685 * function. With this function you can have a DataTables table go to the next, 686 * previous, first or last pages. 687 * @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last" 688 * or page number to jump to (integer), note that page 0 is the first page. 689 * @param {bool} [bRedraw=true] Redraw the table or not 690 * @dtopt API 691 * @deprecated Since v1.10 692 * 693 * @example 694 * $(document).ready(function() { 695 * var oTable = $('#example').dataTable(); 696 * oTable.fnPageChange( 'next' ); 697 * } ); 698 */ 699 this.fnPageChange = function ( mAction, bRedraw ) 700 { 701 var api = this.api( true ).page( mAction ); 702 703 if ( bRedraw === undefined || bRedraw ) { 704 api.draw(false); 705 } 706 }; 707 708 709 /** 710 * Show a particular column 711 * @param {int} iCol The column whose display should be changed 712 * @param {bool} bShow Show (true) or hide (false) the column 713 * @param {bool} [bRedraw=true] Redraw the table or not 714 * @dtopt API 715 * @deprecated Since v1.10 716 * 717 * @example 718 * $(document).ready(function() { 719 * var oTable = $('#example').dataTable(); 720 * 721 * // Hide the second column after initialisation 722 * oTable.fnSetColumnVis( 1, false ); 723 * } ); 724 */ 725 this.fnSetColumnVis = function ( iCol, bShow, bRedraw ) 726 { 727 var api = this.api( true ).column( iCol ).visible( bShow ); 728 729 if ( bRedraw === undefined || bRedraw ) { 730 api.columns.adjust().draw(); 731 } 732 }; 733 734 735 /** 736 * Get the settings for a particular table for external manipulation 737 * @returns {object} DataTables settings object. See 738 * {@link DataTable.models.oSettings} 739 * @dtopt API 740 * @deprecated Since v1.10 741 * 742 * @example 743 * $(document).ready(function() { 744 * var oTable = $('#example').dataTable(); 745 * var oSettings = oTable.fnSettings(); 746 * 747 * // Show an example parameter from the settings 748 * alert( oSettings._iDisplayStart ); 749 * } ); 750 */ 751 this.fnSettings = function() 752 { 753 return _fnSettingsFromNode( this[_ext.iApiIndex] ); 754 }; 755 756 757 /** 758 * Sort the table by a particular column 759 * @param {int} iCol the data index to sort on. Note that this will not match the 760 * 'display index' if you have hidden data entries 761 * @dtopt API 762 * @deprecated Since v1.10 763 * 764 * @example 765 * $(document).ready(function() { 766 * var oTable = $('#example').dataTable(); 767 * 768 * // Sort immediately with columns 0 and 1 769 * oTable.fnSort( [ [0,'asc'], [1,'asc'] ] ); 770 * } ); 771 */ 772 this.fnSort = function( aaSort ) 773 { 774 this.api( true ).order( aaSort ).draw(); 775 }; 776 777 778 /** 779 * Attach a sort listener to an element for a given column 780 * @param {node} nNode the element to attach the sort listener to 781 * @param {int} iColumn the column that a click on this node will sort on 782 * @param {function} [fnCallback] callback function when sort is run 783 * @dtopt API 784 * @deprecated Since v1.10 785 * 786 * @example 787 * $(document).ready(function() { 788 * var oTable = $('#example').dataTable(); 789 * 790 * // Sort on column 1, when 'sorter' is clicked on 791 * oTable.fnSortListener( document.getElementById('sorter'), 1 ); 792 * } ); 793 */ 794 this.fnSortListener = function( nNode, iColumn, fnCallback ) 795 { 796 this.api( true ).order.listener( nNode, iColumn, fnCallback ); 797 }; 798 799 800 /** 801 * Update a table cell or row - this method will accept either a single value to 802 * update the cell with, an array of values with one element for each column or 803 * an object in the same format as the original data source. The function is 804 * self-referencing in order to make the multi column updates easier. 805 * @param {object|array|string} mData Data to update the cell/row with 806 * @param {node|int} mRow TR element you want to update or the aoData index 807 * @param {int} [iColumn] The column to update, give as null or undefined to 808 * update a whole row. 809 * @param {bool} [bRedraw=true] Redraw the table or not 810 * @param {bool} [bAction=true] Perform pre-draw actions or not 811 * @returns {int} 0 on success, 1 on error 812 * @dtopt API 813 * @deprecated Since v1.10 814 * 815 * @example 816 * $(document).ready(function() { 817 * var oTable = $('#example').dataTable(); 818 * oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell 819 * oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row 820 * } ); 821 */ 822 this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction ) 823 { 824 var api = this.api( true ); 825 826 if ( iColumn === undefined || iColumn === null ) { 827 api.row( mRow ).data( mData ); 828 } 829 else { 830 api.cell( mRow, iColumn ).data( mData ); 831 } 832 833 if ( bAction === undefined || bAction ) { 834 api.columns.adjust(); 835 } 836 837 if ( bRedraw === undefined || bRedraw ) { 838 api.draw(); 839 } 840 return 0; 841 }; 842 843 844 /** 845 * Provide a common method for plug-ins to check the version of DataTables being used, in order 846 * to ensure compatibility. 847 * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the 848 * formats "X" and "X.Y" are also acceptable. 849 * @returns {boolean} true if this version of DataTables is greater or equal to the required 850 * version, or false if this version of DataTales is not suitable 851 * @method 852 * @dtopt API 853 * @deprecated Since v1.10 854 * 855 * @example 856 * $(document).ready(function() { 857 * var oTable = $('#example').dataTable(); 858 * alert( oTable.fnVersionCheck( '1.9.0' ) ); 859 * } ); 860 */ 861 this.fnVersionCheck = _ext.fnVersionCheck; 862
vendor: 57,429 bytes, lines 863-2872
863 864 var _that = this; 865 var emptyInit = options === undefined; 866 var len = this.length; 867 868 if ( emptyInit ) { 869 options = {}; 870 } 871 872 this.oApi = this.internal = _ext.internal; 873 874 // Extend with old style plug-in API methods 875 for ( var fn in DataTable.ext.internal ) { 876 if ( fn ) { 877 this[fn] = _fnExternApiFunc(fn); 878 } 879 } 880 881 this.each(function() { 882 // For each initialisation we want to give it a clean initialisation 883 // object that can be bashed around 884 var o = {}; 885 var oInit = len > 1 ? // optimisation for single table case 886 _fnExtend( o, options, true ) : 887 options; 888 889 /*global oInit,_that,emptyInit*/ 890 var i=0, iLen, j, jLen, k, kLen; 891 var sId = this.getAttribute( 'id' ); 892 var bInitHandedOff = false; 893 var defaults = DataTable.defaults; 894 var $this = $(this); 895 896 897 /* Sanity check */ 898 if ( this.nodeName.toLowerCase() != 'table' ) 899 { 900 _fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 ); 901 return; 902 } 903 904 /* Backwards compatibility for the defaults */ 905 _fnCompatOpts( defaults ); 906 _fnCompatCols( defaults.column ); 907 908 /* Convert the camel-case defaults to Hungarian */ 909 _fnCamelToHungarian( defaults, defaults, true ); 910 _fnCamelToHungarian( defaults.column, defaults.column, true ); 911 912 /* Setting up the initialisation object */ 913 _fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ) ); 914 915 916 917 /* Check to see if we are re-initialising a table */ 918 var allSettings = DataTable.settings; 919 for ( i=0, iLen=allSettings.length ; i<iLen ; i++ ) 920 { 921 var s = allSettings[i]; 922 923 /* Base check on table node */ 924 if ( s.nTable == this || s.nTHead.parentNode == this || (s.nTFoot && s.nTFoot.parentNode == this) ) 925 { 926 var bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve; 927 var bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy; 928 929 if ( emptyInit || bRetrieve ) 930 { 931 return s.oInstance; 932 } 933 else if ( bDestroy ) 934 { 935 s.oInstance.fnDestroy(); 936 break; 937 } 938 else 939 { 940 _fnLog( s, 0, 'Cannot reinitialise DataTable', 3 ); 941 return; 942 } 943 } 944 945 /* If the element we are initialising has the same ID as a table which was previously 946 * initialised, but the table nodes don't match (from before) then we destroy the old 947 * instance by simply deleting it. This is under the assumption that the table has been 948 * destroyed by other methods. Anyone using non-id selectors will need to do this manually 949 */ 950 if ( s.sTableId == this.id ) 951 { 952 allSettings.splice( i, 1 ); 953 break; 954 } 955 } 956 957 /* Ensure the table has an ID - required for accessibility */ 958 if ( sId === null || sId === "" ) 959 { 960 sId = "DataTables_Table_"+(DataTable.ext._unique++); 961 this.id = sId; 962 } 963 964 /* Create the settings object for this table and set some of the default parameters */ 965 var oSettings = $.extend( true, {}, DataTable.models.oSettings, { 966 "sDestroyWidth": $this[0].style.width, 967 "sInstance": sId, 968 "sTableId": sId 969 } ); 970 oSettings.nTable = this; 971 oSettings.oApi = _that.internal; 972 oSettings.oInit = oInit; 973 974 allSettings.push( oSettings ); 975 976 // Need to add the instance after the instance after the settings object has been added 977 // to the settings array, so we can self reference the table instance if more than one 978 oSettings.oInstance = (_that.length===1) ? _that : $this.dataTable(); 979 980 // Backwards compatibility, before we apply all the defaults 981 _fnCompatOpts( oInit ); 982 983 if ( oInit.oLanguage ) 984 { 985 _fnLanguageCompat( oInit.oLanguage ); 986 } 987 988 // If the length menu is given, but the init display length is not, use the length menu 989 if ( oInit.aLengthMenu && ! oInit.iDisplayLength ) 990 { 991 oInit.iDisplayLength = $.isArray( oInit.aLengthMenu[0] ) ? 992 oInit.aLengthMenu[0][0] : oInit.aLengthMenu[0]; 993 } 994 995 // Apply the defaults and init options to make a single init object will all 996 // options defined from defaults and instance options. 997 oInit = _fnExtend( $.extend( true, {}, defaults ), oInit ); 998 999 1000 // Map the initialisation options onto the settings object 1001 _fnMap( oSettings.oFeatures, oInit, [ 1002 "bPaginate", 1003 "bLengthChange", 1004 "bFilter", 1005 "bSort", 1006 "bSortMulti", 1007 "bInfo", 1008 "bProcessing", 1009 "bAutoWidth", 1010 "bSortClasses", 1011 "bServerSide", 1012 "bDeferRender" 1013 ] ); 1014 _fnMap( oSettings, oInit, [ 1015 "asStripeClasses", 1016 "ajax", 1017 "fnServerData", 1018 "fnFormatNumber", 1019 "sServerMethod", 1020 "aaSorting", 1021 "aaSortingFixed", 1022 "aLengthMenu", 1023 "sPaginationType", 1024 "sAjaxSource", 1025 "sAjaxDataProp", 1026 "iStateDuration", 1027 "sDom", 1028 "bSortCellsTop", 1029 "iTabIndex", 1030 "fnStateLoadCallback", 1031 "fnStateSaveCallback", 1032 "renderer", 1033 "searchDelay", 1034 "rowId", 1035 [ "iCookieDuration", "iStateDuration" ], // backwards compat 1036 [ "oSearch", "oPreviousSearch" ], 1037 [ "aoSearchCols", "aoPreSearchCols" ], 1038 [ "iDisplayLength", "_iDisplayLength" ] 1039 ] ); 1040 _fnMap( oSettings.oScroll, oInit, [ 1041 [ "sScrollX", "sX" ], 1042 [ "sScrollXInner", "sXInner" ], 1043 [ "sScrollY", "sY" ], 1044 [ "bScrollCollapse", "bCollapse" ] 1045 ] ); 1046 _fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" ); 1047 1048 /* Callback functions which are array driven */ 1049 _fnCallbackReg( oSettings, 'aoDrawCallback', oInit.fnDrawCallback, 'user' ); 1050 _fnCallbackReg( oSettings, 'aoServerParams', oInit.fnServerParams, 'user' ); 1051 _fnCallbackReg( oSettings, 'aoStateSaveParams', oInit.fnStateSaveParams, 'user' ); 1052 _fnCallbackReg( oSettings, 'aoStateLoadParams', oInit.fnStateLoadParams, 'user' ); 1053 _fnCallbackReg( oSettings, 'aoStateLoaded', oInit.fnStateLoaded, 'user' ); 1054 _fnCallbackReg( oSettings, 'aoRowCallback', oInit.fnRowCallback, 'user' ); 1055 _fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow, 'user' ); 1056 _fnCallbackReg( oSettings, 'aoHeaderCallback', oInit.fnHeaderCallback, 'user' ); 1057 _fnCallbackReg( oSettings, 'aoFooterCallback', oInit.fnFooterCallback, 'user' ); 1058 _fnCallbackReg( oSettings, 'aoInitComplete', oInit.fnInitComplete, 'user' ); 1059 _fnCallbackReg( oSettings, 'aoPreDrawCallback', oInit.fnPreDrawCallback, 'user' ); 1060 1061 oSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId ); 1062 1063 /* Browser support detection */ 1064 _fnBrowserDetect( oSettings ); 1065 1066 var oClasses = oSettings.oClasses; 1067 1068 $.extend( oClasses, DataTable.ext.classes, oInit.oClasses ); 1069 $this.addClass( oClasses.sTable ); 1070 1071 1072 if ( oSettings.iInitDisplayStart === undefined ) 1073 { 1074 /* Display start point, taking into account the save saving */ 1075 oSettings.iInitDisplayStart = oInit.iDisplayStart; 1076 oSettings._iDisplayStart = oInit.iDisplayStart; 1077 } 1078 1079 if ( oInit.iDeferLoading !== null ) 1080 { 1081 oSettings.bDeferLoading = true; 1082 var tmp = $.isArray( oInit.iDeferLoading ); 1083 oSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading; 1084 oSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading; 1085 } 1086 1087 /* Language definitions */ 1088 var oLanguage = oSettings.oLanguage; 1089 $.extend( true, oLanguage, oInit.oLanguage ); 1090 1091 if ( oLanguage.sUrl ) 1092 { 1093 /* Get the language definitions from a file - because this Ajax call makes the language 1094 * get async to the remainder of this function we use bInitHandedOff to indicate that 1095 * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor 1096 */ 1097 $.ajax( { 1098 dataType: 'json', 1099 url: oLanguage.sUrl, 1100 success: function ( json ) { 1101 _fnLanguageCompat( json ); 1102 _fnCamelToHungarian( defaults.oLanguage, json ); 1103 $.extend( true, oLanguage, json ); 1104 _fnInitialise( oSettings ); 1105 }, 1106 error: function () { 1107 // Error occurred loading language file, continue on as best we can 1108 _fnInitialise( oSettings ); 1109 } 1110 } ); 1111 bInitHandedOff = true; 1112 } 1113 1114 /* 1115 * Stripes 1116 */ 1117 if ( oInit.asStripeClasses === null ) 1118 { 1119 oSettings.asStripeClasses =[ 1120 oClasses.sStripeOdd, 1121 oClasses.sStripeEven 1122 ]; 1123 } 1124 1125 /* Remove row stripe classes if they are already on the table row */ 1126 var stripeClasses = oSettings.asStripeClasses; 1127 var rowOne = $this.children('tbody').find('tr').eq(0); 1128 if ( $.inArray( true, $.map( stripeClasses, function(el, i) { 1129 return rowOne.hasClass(el); 1130 } ) ) !== -1 ) { 1131 $('tbody tr', this).removeClass( stripeClasses.join(' ') ); 1132 oSettings.asDestroyStripes = stripeClasses.slice(); 1133 } 1134 1135 /* 1136 * Columns 1137 * See if we should load columns automatically or use defined ones 1138 */ 1139 var anThs = []; 1140 var aoColumnsInit; 1141 var nThead = this.getElementsByTagName('thead'); 1142 if ( nThead.length !== 0 ) 1143 { 1144 _fnDetectHeader( oSettings.aoHeader, nThead[0] ); 1145 anThs = _fnGetUniqueThs( oSettings ); 1146 } 1147 1148 /* If not given a column array, generate one with nulls */ 1149 if ( oInit.aoColumns === null ) 1150 { 1151 aoColumnsInit = []; 1152 for ( i=0, iLen=anThs.length ; i<iLen ; i++ ) 1153 { 1154 aoColumnsInit.push( null ); 1155 } 1156 } 1157 else 1158 { 1159 aoColumnsInit = oInit.aoColumns; 1160 } 1161 1162 /* Add the columns */ 1163 for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ ) 1164 { 1165 _fnAddColumn( oSettings, anThs ? anThs[i] : null ); 1166 } 1167 1168 /* Apply the column definitions */ 1169 _fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) { 1170 _fnColumnOptions( oSettings, iCol, oDef ); 1171 } ); 1172 1173 /* HTML5 attribute detection - build an mData object automatically if the 1174 * attributes are found 1175 */ 1176 if ( rowOne.length ) { 1177 var a = function ( cell, name ) { 1178 return cell.getAttribute( 'data-'+name ) !== null ? name : null; 1179 }; 1180 1181 $( rowOne[0] ).children('th, td').each( function (i, cell) { 1182 var col = oSettings.aoColumns[i]; 1183 1184 if ( col.mData === i ) { 1185 var sort = a( cell, 'sort' ) || a( cell, 'order' ); 1186 var filter = a( cell, 'filter' ) || a( cell, 'search' ); 1187 1188 if ( sort !== null || filter !== null ) { 1189 col.mData = { 1190 _: i+'.display', 1191 sort: sort !== null ? i+'.@data-'+sort : undefined, 1192 type: sort !== null ? i+'.@data-'+sort : undefined, 1193 filter: filter !== null ? i+'.@data-'+filter : undefined 1194 }; 1195 1196 _fnColumnOptions( oSettings, i ); 1197 } 1198 } 1199 } ); 1200 } 1201 1202 var features = oSettings.oFeatures; 1203 var loadedInit = function () { 1204 /* 1205 * Sorting 1206 * @todo For modularisation (1.11) this needs to do into a sort start up handler 1207 */ 1208 1209 // If aaSorting is not defined, then we use the first indicator in asSorting 1210 // in case that has been altered, so the default sort reflects that option 1211 if ( oInit.aaSorting === undefined ) { 1212 var sorting = oSettings.aaSorting; 1213 for ( i=0, iLen=sorting.length ; i<iLen ; i++ ) { 1214 sorting[i][1] = oSettings.aoColumns[ i ].asSorting[0]; 1215 } 1216 } 1217 1218 /* Do a first pass on the sorting classes (allows any size changes to be taken into 1219 * account, and also will apply sorting disabled classes if disabled 1220 */ 1221 _fnSortingClasses( oSettings ); 1222 1223 if ( features.bSort ) { 1224 _fnCallbackReg( oSettings, 'aoDrawCallback', function () { 1225 if ( oSettings.bSorted ) { 1226 var aSort = _fnSortFlatten( oSettings ); 1227 var sortedColumns = {}; 1228 1229 $.each( aSort, function (i, val) { 1230 sortedColumns[ val.src ] = val.dir; 1231 } ); 1232 1233 _fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] ); 1234 _fnSortAria( oSettings ); 1235 } 1236 } ); 1237 } 1238 1239 _fnCallbackReg( oSettings, 'aoDrawCallback', function () { 1240 if ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) { 1241 _fnSortingClasses( oSettings ); 1242 } 1243 }, 'sc' ); 1244 1245 1246 /* 1247 * Final init 1248 * Cache the header, body and footer as required, creating them if needed 1249 */ 1250 1251 // Work around for Webkit bug 83867 - store the caption-side before removing from doc 1252 var captions = $this.children('caption').each( function () { 1253 this._captionSide = $(this).css('caption-side'); 1254 } ); 1255 1256 var thead = $this.children('thead'); 1257 if ( thead.length === 0 ) { 1258 thead = $('<thead/>').appendTo($this); 1259 } 1260 oSettings.nTHead = thead[0]; 1261 1262 var tbody = $this.children('tbody'); 1263 if ( tbody.length === 0 ) { 1264 tbody = $('<tbody/>').appendTo($this); 1265 } 1266 oSettings.nTBody = tbody[0]; 1267 1268 var tfoot = $this.children('tfoot'); 1269 if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") ) { 1270 // If we are a scrolling table, and no footer has been given, then we need to create 1271 // a tfoot element for the caption element to be appended to 1272 tfoot = $('<tfoot/>').appendTo($this); 1273 } 1274 1275 if ( tfoot.length === 0 || tfoot.children().length === 0 ) { 1276 $this.addClass( oClasses.sNoFooter ); 1277 } 1278 else if ( tfoot.length > 0 ) { 1279 oSettings.nTFoot = tfoot[0]; 1280 _fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot ); 1281 } 1282 1283 /* Check if there is data passing into the constructor */ 1284 if ( oInit.aaData ) { 1285 for ( i=0 ; i<oInit.aaData.length ; i++ ) { 1286 _fnAddData( oSettings, oInit.aaData[ i ] ); 1287 } 1288 } 1289 else if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' ) { 1290 /* Grab the data from the page - only do this when deferred loading or no Ajax 1291 * source since there is no point in reading the DOM data if we are then going 1292 * to replace it with Ajax data 1293 */ 1294 _fnAddTr( oSettings, $(oSettings.nTBody).children('tr') ); 1295 } 1296 1297 /* Copy the data index array */ 1298 oSettings.aiDisplay = oSettings.aiDisplayMaster.slice(); 1299 1300 /* Initialisation complete - table can be drawn */ 1301 oSettings.bInitialised = true; 1302 1303 /* Check if we need to initialise the table (it might not have been handed off to the 1304 * language processor) 1305 */ 1306 if ( bInitHandedOff === false ) { 1307 _fnInitialise( oSettings ); 1308 } 1309 }; 1310 1311 /* Must be done after everything which can be overridden by the state saving! */ 1312 if ( oInit.bStateSave ) 1313 { 1314 features.bStateSave = true; 1315 _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' ); 1316 _fnLoadState( oSettings, oInit, loadedInit ); 1317 } 1318 else { 1319 loadedInit(); 1320 } 1321 1322 } ); 1323 _that = null; 1324 return this; 1325 }; 1326 1327 1328 /* 1329 * It is useful to have variables which are scoped locally so only the 1330 * DataTables functions can access them and they don't leak into global space. 1331 * At the same time these functions are often useful over multiple files in the 1332 * core and API, so we list, or at least document, all variables which are used 1333 * by DataTables as private variables here. This also ensures that there is no 1334 * clashing of variable names and that they can easily referenced for reuse. 1335 */ 1336 1337 1338 // Defined else where 1339 // _selector_run 1340 // _selector_opts 1341 // _selector_first 1342 // _selector_row_indexes 1343 1344 var _ext; // DataTable.ext 1345 var _Api; // DataTable.Api 1346 var _api_register; // DataTable.Api.register 1347 var _api_registerPlural; // DataTable.Api.registerPlural 1348 1349 var _re_dic = {}; 1350 var _re_new_lines = /[\r\n]/g; 1351 var _re_html = /<.*?>/g; 1352 1353 // This is not strict ISO8601 - Date.parse() is quite lax, although 1354 // implementations differ between browsers. 1355 var _re_date = /^\d{2,4}[\.\/\-]\d{1,2}[\.\/\-]\d{1,2}([T ]{1}\d{1,2}[:\.]\d{2}([\.:]\d{2})?)?$/; 1356 1357 // Escape regular expression special characters 1358 var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' ); 1359 1360 // http://en.wikipedia.org/wiki/Foreign_exchange_market 1361 // - \u20BD - Russian ruble. 1362 // - \u20a9 - South Korean Won 1363 // - \u20BA - Turkish Lira 1364 // - \u20B9 - Indian Rupee 1365 // - R - Brazil (R$) and South Africa 1366 // - fr - Swiss Franc 1367 // - kr - Swedish krona, Norwegian krone and Danish krone 1368 // - \u2009 is thin space and \u202F is narrow no-break space, both used in many 1369 // standards as thousands separators. 1370 var _re_formatted_numeric = /[',$£â¬Â¥%\u2009\u202F\u20BD\u20a9\u20BArfk]/gi; 1371 1372 1373 var _empty = function ( d ) { 1374 return !d || d === true || d === '-' ? true : false; 1375 }; 1376 1377 1378 var _intVal = function ( s ) { 1379 var integer = parseInt( s, 10 ); 1380 return !isNaN(integer) && isFinite(s) ? integer : null; 1381 }; 1382 1383 // Convert from a formatted number with characters other than `.` as the 1384 // decimal place, to a Javascript number 1385 var _numToDecimal = function ( num, decimalPoint ) { 1386 // Cache created regular expressions for speed as this function is called often 1387 if ( ! _re_dic[ decimalPoint ] ) { 1388 _re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' ); 1389 } 1390 return typeof num === 'string' && decimalPoint !== '.' ? 1391 num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) : 1392 num; 1393 }; 1394 1395 1396 var _isNumber = function ( d, decimalPoint, formatted ) { 1397 var strType = typeof d === 'string'; 1398 1399 // If empty return immediately so there must be a number if it is a 1400 // formatted string (this stops the string "k", or "kr", etc being detected 1401 // as a formatted number for currency 1402 if ( _empty( d ) ) { 1403 return true; 1404 } 1405 1406 if ( decimalPoint && strType ) { 1407 d = _numToDecimal( d, decimalPoint ); 1408 } 1409 1410 if ( formatted && strType ) { 1411 d = d.replace( _re_formatted_numeric, '' ); 1412 } 1413 1414 return !isNaN( parseFloat(d) ) && isFinite( d ); 1415 }; 1416 1417 1418 // A string without HTML in it can be considered to be HTML still 1419 var _isHtml = function ( d ) { 1420 return _empty( d ) || typeof d === 'string'; 1421 }; 1422 1423 1424 var _htmlNumeric = function ( d, decimalPoint, formatted ) { 1425 if ( _empty( d ) ) { 1426 return true; 1427 } 1428 1429 var html = _isHtml( d ); 1430 return ! html ? 1431 null : 1432 _isNumber( _stripHtml( d ), decimalPoint, formatted ) ? 1433 true : 1434 null; 1435 }; 1436 1437 1438 var _pluck = function ( a, prop, prop2 ) { 1439 var out = []; 1440 var i=0, ien=a.length; 1441 1442 // Could have the test in the loop for slightly smaller code, but speed 1443 // is essential here 1444 if ( prop2 !== undefined ) { 1445 for ( ; i<ien ; i++ ) { 1446 if ( a[i] && a[i][ prop ] ) { 1447 out.push( a[i][ prop ][ prop2 ] ); 1448 } 1449 } 1450 } 1451 else { 1452 for ( ; i<ien ; i++ ) { 1453 if ( a[i] ) { 1454 out.push( a[i][ prop ] ); 1455 } 1456 } 1457 } 1458 1459 return out; 1460 }; 1461 1462 1463 // Basically the same as _pluck, but rather than looping over `a` we use `order` 1464 // as the indexes to pick from `a` 1465 var _pluck_order = function ( a, order, prop, prop2 ) 1466 { 1467 var out = []; 1468 var i=0, ien=order.length; 1469 1470 // Could have the test in the loop for slightly smaller code, but speed 1471 // is essential here 1472 if ( prop2 !== undefined ) { 1473 for ( ; i<ien ; i++ ) { 1474 if ( a[ order[i] ][ prop ] ) { 1475 out.push( a[ order[i] ][ prop ][ prop2 ] ); 1476 } 1477 } 1478 } 1479 else { 1480 for ( ; i<ien ; i++ ) { 1481 out.push( a[ order[i] ][ prop ] ); 1482 } 1483 } 1484 1485 return out; 1486 }; 1487 1488 1489 var _range = function ( len, start ) 1490 { 1491 var out = []; 1492 var end; 1493 1494 if ( start === undefined ) { 1495 start = 0; 1496 end = len; 1497 } 1498 else { 1499 end = start; 1500 start = len; 1501 } 1502 1503 for ( var i=start ; i<end ; i++ ) { 1504 out.push( i ); 1505 } 1506 1507 return out; 1508 }; 1509 1510 1511 var _removeEmpty = function ( a ) 1512 { 1513 var out = []; 1514 1515 for ( var i=0, ien=a.length ; i<ien ; i++ ) { 1516 if ( a[i] ) { // careful - will remove all falsy values! 1517 out.push( a[i] ); 1518 } 1519 } 1520 1521 return out; 1522 }; 1523 1524 1525 var _stripHtml = function ( d ) { 1526 return d.replace( _re_html, '' ); 1527 }; 1528 1529 1530 /** 1531 * Determine if all values in the array are unique. This means we can short 1532 * cut the _unique method at the cost of a single loop. A sorted array is used 1533 * to easily check the values. 1534 * 1535 * @param {array} src Source array 1536 * @return {boolean} true if all unique, false otherwise 1537 * @ignore 1538 */ 1539 var _areAllUnique = function ( src ) { 1540 if ( src.length < 2 ) { 1541 return true; 1542 } 1543 1544 var sorted = src.slice().sort(); 1545 var last = sorted[0]; 1546 1547 for ( var i=1, ien=sorted.length ; i<ien ; i++ ) { 1548 if ( sorted[i] === last ) { 1549 return false; 1550 } 1551 1552 last = sorted[i]; 1553 } 1554 1555 return true; 1556 }; 1557 1558 1559 /** 1560 * Find the unique elements in a source array. 1561 * 1562 * @param {array} src Source array 1563 * @return {array} Array of unique items 1564 * @ignore 1565 */ 1566 var _unique = function ( src ) 1567 { 1568 if ( _areAllUnique( src ) ) { 1569 return src.slice(); 1570 } 1571 1572 // A faster unique method is to use object keys to identify used values, 1573 // but this doesn't work with arrays or objects, which we must also 1574 // consider. See jsperf.com/compare-array-unique-versions/4 for more 1575 // information. 1576 var 1577 out = [], 1578 val, 1579 i, ien=src.length, 1580 j, k=0; 1581 1582 again: for ( i=0 ; i<ien ; i++ ) { 1583 val = src[i]; 1584 1585 for ( j=0 ; j<k ; j++ ) { 1586 if ( out[j] === val ) { 1587 continue again; 1588 } 1589 } 1590 1591 out.push( val ); 1592 k++; 1593 } 1594 1595 return out; 1596 }; 1597 1598 1599 /** 1600 * DataTables utility methods 1601 * 1602 * This namespace provides helper methods that DataTables uses internally to 1603 * create a DataTable, but which are not exclusively used only for DataTables. 1604 * These methods can be used by extension authors to save the duplication of 1605 * code. 1606 * 1607 * @namespace 1608 */ 1609 DataTable.util = { 1610 /** 1611 * Throttle the calls to a function. Arguments and context are maintained 1612 * for the throttled function. 1613 * 1614 * @param {function} fn Function to be called 1615 * @param {integer} freq Call frequency in mS 1616 * @return {function} Wrapped function 1617 */ 1618 throttle: function ( fn, freq ) { 1619 var 1620 frequency = freq !== undefined ? freq : 200, 1621 last, 1622 timer; 1623 1624 return function () { 1625 var 1626 that = this, 1627 now = +new Date(), 1628 args = arguments; 1629 1630 if ( last && now < last + frequency ) { 1631 clearTimeout( timer ); 1632 1633 timer = setTimeout( function () { 1634 last = undefined; 1635 fn.apply( that, args ); 1636 }, frequency ); 1637 } 1638 else { 1639 last = now; 1640 fn.apply( that, args ); 1641 } 1642 }; 1643 }, 1644 1645 1646 /** 1647 * Escape a string such that it can be used in a regular expression 1648 * 1649 * @param {string} val string to escape 1650 * @returns {string} escaped string 1651 */ 1652 escapeRegex: function ( val ) { 1653 return val.replace( _re_escape_regex, '\\$1' ); 1654 } 1655 }; 1656 1657 1658 1659 /** 1660 * Create a mapping object that allows camel case parameters to be looked up 1661 * for their Hungarian counterparts. The mapping is stored in a private 1662 * parameter called `_hungarianMap` which can be accessed on the source object. 1663 * @param {object} o 1664 * @memberof DataTable#oApi 1665 */ 1666 function _fnHungarianMap ( o ) 1667 { 1668 var 1669 hungarian = 'a aa ai ao as b fn i m o s ', 1670 match, 1671 newKey, 1672 map = {}; 1673 1674 $.each( o, function (key, val) { 1675 match = key.match(/^([^A-Z]+?)([A-Z])/); 1676 1677 if ( match && hungarian.indexOf(match[1]+' ') !== -1 ) 1678 { 1679 newKey = key.replace( match[0], match[2].toLowerCase() ); 1680 map[ newKey ] = key; 1681 1682 if ( match[1] === 'o' ) 1683 { 1684 _fnHungarianMap( o[key] ); 1685 } 1686 } 1687 } ); 1688 1689 o._hungarianMap = map; 1690 } 1691 1692 1693 /** 1694 * Convert from camel case parameters to Hungarian, based on a Hungarian map 1695 * created by _fnHungarianMap. 1696 * @param {object} src The model object which holds all parameters that can be 1697 * mapped. 1698 * @param {object} user The object to convert from camel case to Hungarian. 1699 * @param {boolean} force When set to `true`, properties which already have a 1700 * Hungarian value in the `user` object will be overwritten. Otherwise they 1701 * won't be. 1702 * @memberof DataTable#oApi 1703 */ 1704 function _fnCamelToHungarian ( src, user, force ) 1705 { 1706 if ( ! src._hungarianMap ) { 1707 _fnHungarianMap( src ); 1708 } 1709 1710 var hungarianKey; 1711 1712 $.each( user, function (key, val) { 1713 hungarianKey = src._hungarianMap[ key ]; 1714 1715 if ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) ) 1716 { 1717 // For objects, we need to buzz down into the object to copy parameters 1718 if ( hungarianKey.charAt(0) === 'o' ) 1719 { 1720 // Copy the camelCase options over to the hungarian 1721 if ( ! user[ hungarianKey ] ) { 1722 user[ hungarianKey ] = {}; 1723 } 1724 $.extend( true, user[hungarianKey], user[key] ); 1725 1726 _fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force ); 1727 } 1728 else { 1729 user[hungarianKey] = user[ key ]; 1730 } 1731 } 1732 } ); 1733 } 1734 1735 1736 /** 1737 * Language compatibility - when certain options are given, and others aren't, we 1738 * need to duplicate the values over, in order to provide backwards compatibility 1739 * with older language files. 1740 * @param {object} oSettings dataTables settings object 1741 * @memberof DataTable#oApi 1742 */ 1743 function _fnLanguageCompat( lang ) 1744 { 1745 var defaults = DataTable.defaults.oLanguage; 1746 var zeroRecords = lang.sZeroRecords; 1747 1748 /* Backwards compatibility - if there is no sEmptyTable given, then use the same as 1749 * sZeroRecords - assuming that is given. 1750 */ 1751 if ( ! lang.sEmptyTable && zeroRecords && 1752 defaults.sEmptyTable === "No data available in table" ) 1753 { 1754 _fnMap( lang, lang, 'sZeroRecords', 'sEmptyTable' ); 1755 } 1756 1757 /* Likewise with loading records */ 1758 if ( ! lang.sLoadingRecords && zeroRecords && 1759 defaults.sLoadingRecords === "Loading..." ) 1760 { 1761 _fnMap( lang, lang, 'sZeroRecords', 'sLoadingRecords' ); 1762 } 1763 1764 // Old parameter name of the thousands separator mapped onto the new 1765 if ( lang.sInfoThousands ) { 1766 lang.sThousands = lang.sInfoThousands; 1767 } 1768 1769 var decimal = lang.sDecimal; 1770 if ( decimal ) { 1771 _addNumericSort( decimal ); 1772 } 1773 } 1774 1775 1776 /** 1777 * Map one parameter onto another 1778 * @param {object} o Object to map 1779 * @param {*} knew The new parameter name 1780 * @param {*} old The old parameter name 1781 */ 1782 var _fnCompatMap = function ( o, knew, old ) { 1783 if ( o[ knew ] !== undefined ) { 1784 o[ old ] = o[ knew ]; 1785 } 1786 }; 1787 1788 1789 /** 1790 * Provide backwards compatibility for the main DT options. Note that the new 1791 * options are mapped onto the old parameters, so this is an external interface 1792 * change only. 1793 * @param {object} init Object to map 1794 */ 1795 function _fnCompatOpts ( init ) 1796 { 1797 _fnCompatMap( init, 'ordering', 'bSort' ); 1798 _fnCompatMap( init, 'orderMulti', 'bSortMulti' ); 1799 _fnCompatMap( init, 'orderClasses', 'bSortClasses' ); 1800 _fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' ); 1801 _fnCompatMap( init, 'order', 'aaSorting' ); 1802 _fnCompatMap( init, 'orderFixed', 'aaSortingFixed' ); 1803 _fnCompatMap( init, 'paging', 'bPaginate' ); 1804 _fnCompatMap( init, 'pagingType', 'sPaginationType' ); 1805 _fnCompatMap( init, 'pageLength', 'iDisplayLength' ); 1806 _fnCompatMap( init, 'searching', 'bFilter' ); 1807 1808 // Boolean initialisation of x-scrolling 1809 if ( typeof init.sScrollX === 'boolean' ) { 1810 init.sScrollX = init.sScrollX ? '100%' : ''; 1811 } 1812 if ( typeof init.scrollX === 'boolean' ) { 1813 init.scrollX = init.scrollX ? '100%' : ''; 1814 } 1815 1816 // Column search objects are in an array, so it needs to be converted 1817 // element by element 1818 var searchCols = init.aoSearchCols; 1819 1820 if ( searchCols ) { 1821 for ( var i=0, ien=searchCols.length ; i<ien ; i++ ) { 1822 if ( searchCols[i] ) { 1823 _fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] ); 1824 } 1825 } 1826 } 1827 } 1828 1829 1830 /** 1831 * Provide backwards compatibility for column options. Note that the new options 1832 * are mapped onto the old parameters, so this is an external interface change 1833 * only. 1834 * @param {object} init Object to map 1835 */ 1836 function _fnCompatCols ( init ) 1837 { 1838 _fnCompatMap( init, 'orderable', 'bSortable' ); 1839 _fnCompatMap( init, 'orderData', 'aDataSort' ); 1840 _fnCompatMap( init, 'orderSequence', 'asSorting' ); 1841 _fnCompatMap( init, 'orderDataType', 'sortDataType' ); 1842 1843 // orderData can be given as an integer 1844 var dataSort = init.aDataSort; 1845 if ( typeof dataSort === 'number' && ! $.isArray( dataSort ) ) { 1846 init.aDataSort = [ dataSort ]; 1847 } 1848 } 1849 1850 1851 /** 1852 * Browser feature detection for capabilities, quirks 1853 * @param {object} settings dataTables settings object 1854 * @memberof DataTable#oApi 1855 */ 1856 function _fnBrowserDetect( settings ) 1857 { 1858 // We don't need to do this every time DataTables is constructed, the values 1859 // calculated are specific to the browser and OS configuration which we 1860 // don't expect to change between initialisations 1861 if ( ! DataTable.__browser ) { 1862 var browser = {}; 1863 DataTable.__browser = browser; 1864 1865 // Scrolling feature / quirks detection 1866 var n = $('<div/>') 1867 .css( { 1868 position: 'fixed', 1869 top: 0, 1870 left: $(window).scrollLeft()*-1, // allow for scrolling 1871 height: 1, 1872 width: 1, 1873 overflow: 'hidden' 1874 } ) 1875 .append( 1876 $('<div/>') 1877 .css( { 1878 position: 'absolute', 1879 top: 1, 1880 left: 1, 1881 width: 100, 1882 overflow: 'scroll' 1883 } ) 1884 .append( 1885 $('<div/>') 1886 .css( { 1887 width: '100%', 1888 height: 10 1889 } ) 1890 ) 1891 ) 1892 .appendTo( 'body' ); 1893 1894 var outer = n.children(); 1895 var inner = outer.children(); 1896 1897 // Numbers below, in order, are: 1898 // inner.offsetWidth, inner.clientWidth, outer.offsetWidth, outer.clientWidth 1899 // 1900 // IE6 XP: 100 100 100 83 1901 // IE7 Vista: 100 100 100 83 1902 // IE 8+ Windows: 83 83 100 83 1903 // Evergreen Windows: 83 83 100 83 1904 // Evergreen Mac with scrollbars: 85 85 100 85 1905 // Evergreen Mac without scrollbars: 100 100 100 100 1906 1907 // Get scrollbar width 1908 browser.barWidth = outer[0].offsetWidth - outer[0].clientWidth; 1909 1910 // IE6/7 will oversize a width 100% element inside a scrolling element, to 1911 // include the width of the scrollbar, while other browsers ensure the inner 1912 // element is contained without forcing scrolling 1913 browser.bScrollOversize = inner[0].offsetWidth === 100 && outer[0].clientWidth !== 100; 1914 1915 // In rtl text layout, some browsers (most, but not all) will place the 1916 // scrollbar on the left, rather than the right. 1917 browser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1; 1918 1919 // IE8- don't provide height and width for getBoundingClientRect 1920 browser.bBounding = n[0].getBoundingClientRect().width ? true : false; 1921 1922 n.remove(); 1923 } 1924 1925 $.extend( settings.oBrowser, DataTable.__browser ); 1926 settings.oScroll.iBarWidth = DataTable.__browser.barWidth; 1927 } 1928 1929 1930 /** 1931 * Array.prototype reduce[Right] method, used for browsers which don't support 1932 * JS 1.6. Done this way to reduce code size, since we iterate either way 1933 * @param {object} settings dataTables settings object 1934 * @memberof DataTable#oApi 1935 */ 1936 function _fnReduce ( that, fn, init, start, end, inc ) 1937 { 1938 var 1939 i = start, 1940 value, 1941 isSet = false; 1942 1943 if ( init !== undefined ) { 1944 value = init; 1945 isSet = true; 1946 } 1947 1948 while ( i !== end ) { 1949 if ( ! that.hasOwnProperty(i) ) { 1950 continue; 1951 } 1952 1953 value = isSet ? 1954 fn( value, that[i], i, that ) : 1955 that[i]; 1956 1957 isSet = true; 1958 i += inc; 1959 } 1960 1961 return value; 1962 } 1963 1964 /** 1965 * Add a column to the list used for the table with default values 1966 * @param {object} oSettings dataTables settings object 1967 * @param {node} nTh The th element for this column 1968 * @memberof DataTable#oApi 1969 */ 1970 function _fnAddColumn( oSettings, nTh ) 1971 { 1972 // Add column to aoColumns array 1973 var oDefaults = DataTable.defaults.column; 1974 var iCol = oSettings.aoColumns.length; 1975 var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, { 1976 "nTh": nTh ? nTh : document.createElement('th'), 1977 "sTitle": oDefaults.sTitle ? oDefaults.sTitle : nTh ? nTh.innerHTML : '', 1978 "aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol], 1979 "mData": oDefaults.mData ? oDefaults.mData : iCol, 1980 idx: iCol 1981 } ); 1982 oSettings.aoColumns.push( oCol ); 1983 1984 // Add search object for column specific search. Note that the `searchCols[ iCol ]` 1985 // passed into extend can be undefined. This allows the user to give a default 1986 // with only some of the parameters defined, and also not give a default 1987 var searchCols = oSettings.aoPreSearchCols; 1988 searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] ); 1989 1990 // Use the default column options function to initialise classes etc 1991 _fnColumnOptions( oSettings, iCol, $(nTh).data() ); 1992 } 1993 1994 1995 /** 1996 * Apply options for a column 1997 * @param {object} oSettings dataTables settings object 1998 * @param {int} iCol column index to consider 1999 * @param {object} oOptions object with sType, bVisible and bSearchable etc 2000 * @memberof DataTable#oApi 2001 */ 2002 function _fnColumnOptions( oSettings, iCol, oOptions ) 2003 { 2004 var oCol = oSettings.aoColumns[ iCol ]; 2005 var oClasses = oSettings.oClasses; 2006 var th = $(oCol.nTh); 2007 2008 // Try to get width information from the DOM. We can't get it from CSS 2009 // as we'd need to parse the CSS stylesheet. `width` option can override 2010 if ( ! oCol.sWidthOrig ) { 2011 // Width attribute 2012 oCol.sWidthOrig = th.attr('width') || null; 2013 2014 // Style attribute 2015 var t = (th.attr('style') || '').match(/width:\s*(\d+[pxem%]+)/); 2016 if ( t ) { 2017 oCol.sWidthOrig = t[1]; 2018 } 2019 } 2020 2021 /* User specified column options */ 2022 if ( oOptions !== undefined && oOptions !== null ) 2023 { 2024 // Backwards compatibility 2025 _fnCompatCols( oOptions ); 2026 2027 // Map camel case parameters to their Hungarian counterparts 2028 _fnCamelToHungarian( DataTable.defaults.column, oOptions ); 2029 2030 /* Backwards compatibility for mDataProp */ 2031 if ( oOptions.mDataProp !== undefined && !oOptions.mData ) 2032 { 2033 oOptions.mData = oOptions.mDataProp; 2034 } 2035 2036 if ( oOptions.sType ) 2037 { 2038 oCol._sManualType = oOptions.sType; 2039 } 2040 2041 // `class` is a reserved word in Javascript, so we need to provide 2042 // the ability to use a valid name for the camel case input 2043 if ( oOptions.className && ! oOptions.sClass ) 2044 { 2045 oOptions.sClass = oOptions.className; 2046 } 2047 if ( oOptions.sClass ) { 2048 th.addClass( oOptions.sClass ); 2049 } 2050 2051 $.extend( oCol, oOptions ); 2052 _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" ); 2053 2054 /* iDataSort to be applied (backwards compatibility), but aDataSort will take 2055 * priority if defined 2056 */ 2057 if ( oOptions.iDataSort !== undefined ) 2058 { 2059 oCol.aDataSort = [ oOptions.iDataSort ]; 2060 } 2061 _fnMap( oCol, oOptions, "aDataSort" ); 2062 } 2063 2064 /* Cache the data get and set functions for speed */ 2065 var mDataSrc = oCol.mData; 2066 var mData = _fnGetObjectDataFn( mDataSrc ); 2067 var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null; 2068 2069 var attrTest = function( src ) { 2070 return typeof src === 'string' && src.indexOf('@') !== -1; 2071 }; 2072 oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && ( 2073 attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter) 2074 ); 2075 oCol._setter = null; 2076 2077 oCol.fnGetData = function (rowData, type, meta) { 2078 var innerData = mData( rowData, type, undefined, meta ); 2079 2080 return mRender && type ? 2081 mRender( innerData, type, rowData, meta ) : 2082 innerData; 2083 }; 2084 oCol.fnSetData = function ( rowData, val, meta ) { 2085 return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta ); 2086 }; 2087 2088 // Indicate if DataTables should read DOM data as an object or array 2089 // Used in _fnGetRowElements 2090 if ( typeof mDataSrc !== 'number' ) { 2091 oSettings._rowReadObject = true; 2092 } 2093 2094 /* Feature sorting overrides column specific when off */ 2095 if ( !oSettings.oFeatures.bSort ) 2096 { 2097 oCol.bSortable = false; 2098 th.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called 2099 } 2100 2101 /* Check that the class assignment is correct for sorting */ 2102 var bAsc = $.inArray('asc', oCol.asSorting) !== -1; 2103 var bDesc = $.inArray('desc', oCol.asSorting) !== -1; 2104 if ( !oCol.bSortable || (!bAsc && !bDesc) ) 2105 { 2106 oCol.sSortingClass = oClasses.sSortableNone; 2107 oCol.sSortingClassJUI = ""; 2108 } 2109 else if ( bAsc && !bDesc ) 2110 { 2111 oCol.sSortingClass = oClasses.sSortableAsc; 2112 oCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed; 2113 } 2114 else if ( !bAsc && bDesc ) 2115 { 2116 oCol.sSortingClass = oClasses.sSortableDesc; 2117 oCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed; 2118 } 2119 else 2120 { 2121 oCol.sSortingClass = oClasses.sSortable; 2122 oCol.sSortingClassJUI = oClasses.sSortJUI; 2123 } 2124 } 2125 2126 2127 /** 2128 * Adjust the table column widths for new data. Note: you would probably want to 2129 * do a redraw after calling this function! 2130 * @param {object} settings dataTables settings object 2131 * @memberof DataTable#oApi 2132 */ 2133 function _fnAdjustColumnSizing ( settings ) 2134 { 2135 /* Not interested in doing column width calculation if auto-width is disabled */ 2136 if ( settings.oFeatures.bAutoWidth !== false ) 2137 { 2138 var columns = settings.aoColumns; 2139 2140 _fnCalculateColumnWidths( settings ); 2141 for ( var i=0 , iLen=columns.length ; i<iLen ; i++ ) 2142 { 2143 columns[i].nTh.style.width = columns[i].sWidth; 2144 } 2145 } 2146 2147 var scroll = settings.oScroll; 2148 if ( scroll.sY !== '' || scroll.sX !== '') 2149 { 2150 _fnScrollDraw( settings ); 2151 } 2152 2153 _fnCallbackFire( settings, null, 'column-sizing', [settings] ); 2154 } 2155 2156 2157 /** 2158 * Covert the index of a visible column to the index in the data array (take account 2159 * of hidden columns) 2160 * @param {object} oSettings dataTables settings object 2161 * @param {int} iMatch Visible column index to lookup 2162 * @returns {int} i the data index 2163 * @memberof DataTable#oApi 2164 */ 2165 function _fnVisibleToColumnIndex( oSettings, iMatch ) 2166 { 2167 var aiVis = _fnGetColumns( oSettings, 'bVisible' ); 2168 2169 return typeof aiVis[iMatch] === 'number' ? 2170 aiVis[iMatch] : 2171 null; 2172 } 2173 2174 2175 /** 2176 * Covert the index of an index in the data array and convert it to the visible 2177 * column index (take account of hidden columns) 2178 * @param {int} iMatch Column index to lookup 2179 * @param {object} oSettings dataTables settings object 2180 * @returns {int} i the data index 2181 * @memberof DataTable#oApi 2182 */ 2183 function _fnColumnIndexToVisible( oSettings, iMatch ) 2184 { 2185 var aiVis = _fnGetColumns( oSettings, 'bVisible' ); 2186 var iPos = $.inArray( iMatch, aiVis ); 2187 2188 return iPos !== -1 ? iPos : null; 2189 } 2190 2191 2192 /** 2193 * Get the number of visible columns 2194 * @param {object} oSettings dataTables settings object 2195 * @returns {int} i the number of visible columns 2196 * @memberof DataTable#oApi 2197 */ 2198 function _fnVisbleColumns( oSettings ) 2199 { 2200 var vis = 0; 2201 2202 // No reduce in IE8, use a loop for now 2203 $.each( oSettings.aoColumns, function ( i, col ) { 2204 if ( col.bVisible && $(col.nTh).css('display') !== 'none' ) { 2205 vis++; 2206 } 2207 } ); 2208 2209 return vis; 2210 } 2211 2212 2213 /** 2214 * Get an array of column indexes that match a given property 2215 * @param {object} oSettings dataTables settings object 2216 * @param {string} sParam Parameter in aoColumns to look for - typically 2217 * bVisible or bSearchable 2218 * @returns {array} Array of indexes with matched properties 2219 * @memberof DataTable#oApi 2220 */ 2221 function _fnGetColumns( oSettings, sParam ) 2222 { 2223 var a = []; 2224 2225 $.map( oSettings.aoColumns, function(val, i) { 2226 if ( val[sParam] ) { 2227 a.push( i ); 2228 } 2229 } ); 2230 2231 return a; 2232 } 2233 2234 2235 /** 2236 * Calculate the 'type' of a column 2237 * @param {object} settings dataTables settings object 2238 * @memberof DataTable#oApi 2239 */ 2240 function _fnColumnTypes ( settings ) 2241 { 2242 var columns = settings.aoColumns; 2243 var data = settings.aoData; 2244 var types = DataTable.ext.type.detect; 2245 var i, ien, j, jen, k, ken; 2246 var col, cell, detectedType, cache; 2247 2248 // For each column, spin over the 2249 for ( i=0, ien=columns.length ; i<ien ; i++ ) { 2250 col = columns[i]; 2251 cache = []; 2252 2253 if ( ! col.sType && col._sManualType ) { 2254 col.sType = col._sManualType; 2255 } 2256 else if ( ! col.sType ) { 2257 for ( j=0, jen=types.length ; j<jen ; j++ ) { 2258 for ( k=0, ken=data.length ; k<ken ; k++ ) { 2259 // Use a cache array so we only need to get the type data 2260 // from the formatter once (when using multiple detectors) 2261 if ( cache[k] === undefined ) { 2262 cache[k] = _fnGetCellData( settings, k, i, 'type' ); 2263 } 2264 2265 detectedType = types[j]( cache[k], settings ); 2266 2267 // If null, then this type can't apply to this column, so 2268 // rather than testing all cells, break out. There is an 2269 // exception for the last type which is `html`. We need to 2270 // scan all rows since it is possible to mix string and HTML 2271 // types 2272 if ( ! detectedType && j !== types.length-1 ) { 2273 break; 2274 } 2275 2276 // Only a single match is needed for html type since it is 2277 // bottom of the pile and very similar to string 2278 if ( detectedType === 'html' ) { 2279 break; 2280 } 2281 } 2282 2283 // Type is valid for all data points in the column - use this 2284 // type 2285 if ( detectedType ) { 2286 col.sType = detectedType; 2287 break; 2288 } 2289 } 2290 2291 // Fall back - if no type was detected, always use string 2292 if ( ! col.sType ) { 2293 col.sType = 'string'; 2294 } 2295 } 2296 } 2297 } 2298 2299 2300 /** 2301 * Take the column definitions and static columns arrays and calculate how 2302 * they relate to column indexes. The callback function will then apply the 2303 * definition found for a column to a suitable configuration object. 2304 * @param {object} oSettings dataTables settings object 2305 * @param {array} aoColDefs The aoColumnDefs array that is to be applied 2306 * @param {array} aoCols The aoColumns array that defines columns individually 2307 * @param {function} fn Callback function - takes two parameters, the calculated 2308 * column index and the definition for that column. 2309 * @memberof DataTable#oApi 2310 */ 2311 function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn ) 2312 { 2313 var i, iLen, j, jLen, k, kLen, def; 2314 var columns = oSettings.aoColumns; 2315 2316 // Column definitions with aTargets 2317 if ( aoColDefs ) 2318 { 2319 /* Loop over the definitions array - loop in reverse so first instance has priority */ 2320 for ( i=aoColDefs.length-1 ; i>=0 ; i-- ) 2321 { 2322 def = aoColDefs[i]; 2323 2324 /* Each definition can target multiple columns, as it is an array */ 2325 var aTargets = def.targets !== undefined ? 2326 def.targets : 2327 def.aTargets; 2328 2329 if ( ! $.isArray( aTargets ) ) 2330 { 2331 aTargets = [ aTargets ]; 2332 } 2333 2334 for ( j=0, jLen=aTargets.length ; j<jLen ; j++ ) 2335 { 2336 if ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 ) 2337 { 2338 /* Add columns that we don't yet know about */ 2339 while( columns.length <= aTargets[j] ) 2340 { 2341 _fnAddColumn( oSettings ); 2342 } 2343 2344 /* Integer, basic index */ 2345 fn( aTargets[j], def ); 2346 } 2347 else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 ) 2348 { 2349 /* Negative integer, right to left column counting */ 2350 fn( columns.length+aTargets[j], def ); 2351 } 2352 else if ( typeof aTargets[j] === 'string' ) 2353 { 2354 /* Class name matching on TH element */ 2355 for ( k=0, kLen=columns.length ; k<kLen ; k++ ) 2356 { 2357 if ( aTargets[j] == "_all" || 2358 $(columns[k].nTh).hasClass( aTargets[j] ) ) 2359 { 2360 fn( k, def ); 2361 } 2362 } 2363 } 2364 } 2365 } 2366 } 2367 2368 // Statically defined columns array 2369 if ( aoCols ) 2370 { 2371 for ( i=0, iLen=aoCols.length ; i<iLen ; i++ ) 2372 { 2373 fn( i, aoCols[i] ); 2374 } 2375 } 2376 } 2377 2378 /** 2379 * Add a data array to the table, creating DOM node etc. This is the parallel to 2380 * _fnGatherData, but for adding rows from a Javascript source, rather than a 2381 * DOM source. 2382 * @param {object} oSettings dataTables settings object 2383 * @param {array} aData data array to be added 2384 * @param {node} [nTr] TR element to add to the table - optional. If not given, 2385 * DataTables will create a row automatically 2386 * @param {array} [anTds] Array of TD|TH elements for the row - must be given 2387 * if nTr is. 2388 * @returns {int} >=0 if successful (index of new aoData entry), -1 if failed 2389 * @memberof DataTable#oApi 2390 */ 2391 function _fnAddData ( oSettings, aDataIn, nTr, anTds ) 2392 { 2393 /* Create the object for storing information about this new row */ 2394 var iRow = oSettings.aoData.length; 2395 var oData = $.extend( true, {}, DataTable.models.oRow, { 2396 src: nTr ? 'dom' : 'data', 2397 idx: iRow 2398 } ); 2399 2400 oData._aData = aDataIn; 2401 oSettings.aoData.push( oData ); 2402 2403 /* Create the cells */ 2404 var nTd, sThisType; 2405 var columns = oSettings.aoColumns; 2406 2407 // Invalidate the column types as the new data needs to be revalidated 2408 for ( var i=0, iLen=columns.length ; i<iLen ; i++ ) 2409 { 2410 columns[i].sType = null; 2411 } 2412 2413 /* Add to the display array */ 2414 oSettings.aiDisplayMaster.push( iRow ); 2415 2416 var id = oSettings.rowIdFn( aDataIn ); 2417 if ( id !== undefined ) { 2418 oSettings.aIds[ id ] = oData; 2419 } 2420 2421 /* Create the DOM information, or register it if already present */ 2422 if ( nTr || ! oSettings.oFeatures.bDeferRender ) 2423 { 2424 _fnCreateTr( oSettings, iRow, nTr, anTds ); 2425 } 2426 2427 return iRow; 2428 } 2429 2430 2431 /** 2432 * Add one or more TR elements to the table. Generally we'd expect to 2433 * use this for reading data from a DOM sourced table, but it could be 2434 * used for an TR element. Note that if a TR is given, it is used (i.e. 2435 * it is not cloned). 2436 * @param {object} settings dataTables settings object 2437 * @param {array|node|jQuery} trs The TR element(s) to add to the table 2438 * @returns {array} Array of indexes for the added rows 2439 * @memberof DataTable#oApi 2440 */ 2441 function _fnAddTr( settings, trs ) 2442 { 2443 var row; 2444 2445 // Allow an individual node to be passed in 2446 if ( ! (trs instanceof $) ) { 2447 trs = $(trs); 2448 } 2449 2450 return trs.map( function (i, el) { 2451 row = _fnGetRowElements( settings, el ); 2452 return _fnAddData( settings, row.data, el, row.cells ); 2453 } ); 2454 } 2455 2456 2457 /** 2458 * Take a TR element and convert it to an index in aoData 2459 * @param {object} oSettings dataTables settings object 2460 * @param {node} n the TR element to find 2461 * @returns {int} index if the node is found, null if not 2462 * @memberof DataTable#oApi 2463 */ 2464 function _fnNodeToDataIndex( oSettings, n ) 2465 { 2466 return (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null; 2467 } 2468 2469 2470 /** 2471 * Take a TD element and convert it into a column data index (not the visible index) 2472 * @param {object} oSettings dataTables settings object 2473 * @param {int} iRow The row number the TD/TH can be found in 2474 * @param {node} n The TD/TH element to find 2475 * @returns {int} index if the node is found, -1 if not 2476 * @memberof DataTable#oApi 2477 */ 2478 function _fnNodeToColumnIndex( oSettings, iRow, n ) 2479 { 2480 return $.inArray( n, oSettings.aoData[ iRow ].anCells ); 2481 } 2482 2483 2484 /** 2485 * Get the data for a given cell from the internal cache, taking into account data mapping 2486 * @param {object} settings dataTables settings object 2487 * @param {int} rowIdx aoData row id 2488 * @param {int} colIdx Column index 2489 * @param {string} type data get type ('display', 'type' 'filter' 'sort') 2490 * @returns {*} Cell data 2491 * @memberof DataTable#oApi 2492 */ 2493 function _fnGetCellData( settings, rowIdx, colIdx, type ) 2494 { 2495 var draw = settings.iDraw; 2496 var col = settings.aoColumns[colIdx]; 2497 var rowData = settings.aoData[rowIdx]._aData; 2498 var defaultContent = col.sDefaultContent; 2499 var cellData = col.fnGetData( rowData, type, { 2500 settings: settings, 2501 row: rowIdx, 2502 col: colIdx 2503 } ); 2504 2505 if ( cellData === undefined ) { 2506 if ( settings.iDrawError != draw && defaultContent === null ) { 2507 _fnLog( settings, 0, "Requested unknown parameter "+ 2508 (typeof col.mData=='function' ? '{function}' : "'"+col.mData+"'")+ 2509 " for row "+rowIdx+", column "+colIdx, 4 ); 2510 settings.iDrawError = draw; 2511 } 2512 return defaultContent; 2513 } 2514 2515 // When the data source is null and a specific data type is requested (i.e. 2516 // not the original data), we can use default column data 2517 if ( (cellData === rowData || cellData === null) && defaultContent !== null && type !== undefined ) { 2518 cellData = defaultContent; 2519 } 2520 else if ( typeof cellData === 'function' ) { 2521 // If the data source is a function, then we run it and use the return, 2522 // executing in the scope of the data object (for instances) 2523 return cellData.call( rowData ); 2524 } 2525 2526 if ( cellData === null && type == 'display' ) { 2527 return ''; 2528 } 2529 return cellData; 2530 } 2531 2532 2533 /** 2534 * Set the value for a specific cell, into the internal data cache 2535 * @param {object} settings dataTables settings object 2536 * @param {int} rowIdx aoData row id 2537 * @param {int} colIdx Column index 2538 * @param {*} val Value to set 2539 * @memberof DataTable#oApi 2540 */ 2541 function _fnSetCellData( settings, rowIdx, colIdx, val ) 2542 { 2543 var col = settings.aoColumns[colIdx]; 2544 var rowData = settings.aoData[rowIdx]._aData; 2545 2546 col.fnSetData( rowData, val, { 2547 settings: settings, 2548 row: rowIdx, 2549 col: colIdx 2550 } ); 2551 } 2552 2553 2554 // Private variable that is used to match action syntax in the data property object 2555 var __reArray = /\[.*?\]$/; 2556 var __reFn = /\(\)$/; 2557 2558 /** 2559 * Split string on periods, taking into account escaped periods 2560 * @param {string} str String to split 2561 * @return {array} Split string 2562 */ 2563 function _fnSplitObjNotation( str ) 2564 { 2565 return $.map( str.match(/(\\.|[^\.])+/g) || [''], function ( s ) { 2566 return s.replace(/\\\./g, '.'); 2567 } ); 2568 } 2569 2570 2571 /** 2572 * Return a function that can be used to get data from a source object, taking 2573 * into account the ability to use nested objects as a source 2574 * @param {string|int|function} mSource The data source for the object 2575 * @returns {function} Data get function 2576 * @memberof DataTable#oApi 2577 */ 2578 function _fnGetObjectDataFn( mSource ) 2579 { 2580 if ( $.isPlainObject( mSource ) ) 2581 { 2582 /* Build an object of get functions, and wrap them in a single call */ 2583 var o = {}; 2584 $.each( mSource, function (key, val) { 2585 if ( val ) { 2586 o[key] = _fnGetObjectDataFn( val ); 2587 } 2588 } ); 2589 2590 return function (data, type, row, meta) { 2591 var t = o[type] || o._; 2592 return t !== undefined ? 2593 t(data, type, row, meta) : 2594 data; 2595 }; 2596 } 2597 else if ( mSource === null ) 2598 { 2599 /* Give an empty string for rendering / sorting etc */ 2600 return function (data) { // type, row and meta also passed, but not used 2601 return data; 2602 }; 2603 } 2604 else if ( typeof mSource === 'function' ) 2605 { 2606 return function (data, type, row, meta) { 2607 return mSource( data, type, row, meta ); 2608 }; 2609 } 2610 else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 || 2611 mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) ) 2612 { 2613 /* If there is a . in the source string then the data source is in a 2614 * nested object so we loop over the data for each level to get the next 2615 * level down. On each loop we test for undefined, and if found immediately 2616 * return. This allows entire objects to be missing and sDefaultContent to 2617 * be used if defined, rather than throwing an error 2618 */ 2619 var fetchData = function (data, type, src) { 2620 var arrayNotation, funcNotation, out, innerSrc; 2621 2622 if ( src !== "" ) 2623 { 2624 var a = _fnSplitObjNotation( src ); 2625 2626 for ( var i=0, iLen=a.length ; i<iLen ; i++ ) 2627 { 2628 // Check if we are dealing with special notation 2629 arrayNotation = a[i].match(__reArray); 2630 funcNotation = a[i].match(__reFn); 2631 2632 if ( arrayNotation ) 2633 { 2634 // Array notation 2635 a[i] = a[i].replace(__reArray, ''); 2636 2637 // Condition allows simply [] to be passed in 2638 if ( a[i] !== "" ) { 2639 data = data[ a[i] ]; 2640 } 2641 out = []; 2642 2643 // Get the remainder of the nested object to get 2644 a.splice( 0, i+1 ); 2645 innerSrc = a.join('.'); 2646 2647 // Traverse each entry in the array getting the properties requested 2648 if ( $.isArray( data ) ) { 2649 for ( var j=0, jLen=data.length ; j<jLen ; j++ ) { 2650 out.push( fetchData( data[j], type, innerSrc ) ); 2651 } 2652 } 2653 2654 // If a string is given in between the array notation indicators, that 2655 // is used to join the strings together, otherwise an array is returned 2656 var join = arrayNotation[0].substring(1, arrayNotation[0].length-1); 2657 data = (join==="") ? out : out.join(join); 2658 2659 // The inner call to fetchData has already traversed through the remainder 2660 // of the source requested, so we exit from the loop 2661 break; 2662 } 2663 else if ( funcNotation ) 2664 { 2665 // Function call 2666 a[i] = a[i].replace(__reFn, ''); 2667 data = data[ a[i] ](); 2668 continue; 2669 } 2670 2671 if ( data === null || data[ a[i] ] === undefined ) 2672 { 2673 return undefined; 2674 } 2675 data = data[ a[i] ]; 2676 } 2677 } 2678 2679 return data; 2680 }; 2681 2682 return function (data, type) { // row and meta also passed, but not used 2683 return fetchData( data, type, mSource ); 2684 }; 2685 } 2686 else 2687 { 2688 /* Array or flat object mapping */ 2689 return function (data, type) { // row and meta also passed, but not used 2690 return data[mSource]; 2691 }; 2692 } 2693 } 2694 2695 2696 /** 2697 * Return a function that can be used to set data from a source object, taking 2698 * into account the ability to use nested objects as a source 2699 * @param {string|int|function} mSource The data source for the object 2700 * @returns {function} Data set function 2701 * @memberof DataTable#oApi 2702 */ 2703 function _fnSetObjectDataFn( mSource ) 2704 { 2705 if ( $.isPlainObject( mSource ) ) 2706 { 2707 /* Unlike get, only the underscore (global) option is used for for 2708 * setting data since we don't know the type here. This is why an object 2709 * option is not documented for `mData` (which is read/write), but it is 2710 * for `mRender` which is read only. 2711 */ 2712 return _fnSetObjectDataFn( mSource._ ); 2713 } 2714 else if ( mSource === null ) 2715 { 2716 /* Nothing to do when the data source is null */ 2717 return function () {}; 2718 } 2719 else if ( typeof mSource === 'function' ) 2720 { 2721 return function (data, val, meta) { 2722 mSource( data, 'set', val, meta ); 2723 }; 2724 } 2725 else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 || 2726 mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) ) 2727 { 2728 /* Like the get, we need to get data from a nested object */ 2729 var setData = function (data, val, src) { 2730 var a = _fnSplitObjNotation( src ), b; 2731 var aLast = a[a.length-1]; 2732 var arrayNotation, funcNotation, o, innerSrc; 2733 2734 for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ ) 2735 { 2736 // Check if we are dealing with an array notation request 2737 arrayNotation = a[i].match(__reArray); 2738 funcNotation = a[i].match(__reFn); 2739 2740 if ( arrayNotation ) 2741 { 2742 a[i] = a[i].replace(__reArray, ''); 2743 data[ a[i] ] = []; 2744 2745 // Get the remainder of the nested object to set so we can recurse 2746 b = a.slice(); 2747 b.splice( 0, i+1 ); 2748 innerSrc = b.join('.'); 2749 2750 // Traverse each entry in the array setting the properties requested 2751 if ( $.isArray( val ) ) 2752 { 2753 for ( var j=0, jLen=val.length ; j<jLen ; j++ ) 2754 { 2755 o = {}; 2756 setData( o, val[j], innerSrc ); 2757 data[ a[i] ].push( o ); 2758 } 2759 } 2760 else 2761 { 2762 // We've been asked to save data to an array, but it 2763 // isn't array data to be saved. Best that can be done 2764 // is to just save the value. 2765 data[ a[i] ] = val; 2766 } 2767 2768 // The inner call to setData has already traversed through the remainder 2769 // of the source and has set the data, thus we can exit here 2770 return; 2771 } 2772 else if ( funcNotation ) 2773 { 2774 // Function call 2775 a[i] = a[i].replace(__reFn, ''); 2776 data = data[ a[i] ]( val ); 2777 } 2778 2779 // If the nested object doesn't currently exist - since we are 2780 // trying to set the value - create it 2781 if ( data[ a[i] ] === null || data[ a[i] ] === undefined ) 2782 { 2783 data[ a[i] ] = {}; 2784 } 2785 data = data[ a[i] ]; 2786 } 2787 2788 // Last item in the input - i.e, the actual set 2789 if ( aLast.match(__reFn ) ) 2790 { 2791 // Function call 2792 data = data[ aLast.replace(__reFn, '') ]( val ); 2793 } 2794 else 2795 { 2796 // If array notation is used, we just want to strip it and use the property name 2797 // and assign the value. If it isn't used, then we get the result we want anyway 2798 data[ aLast.replace(__reArray, '') ] = val; 2799 } 2800 }; 2801 2802 return function (data, val) { // meta is also passed in, but not used 2803 return setData( data, val, mSource ); 2804 }; 2805 } 2806 else 2807 { 2808 /* Array or flat object mapping */ 2809 return function (data, val) { // meta is also passed in, but not used 2810 data[mSource] = val; 2811 }; 2812 } 2813 } 2814 2815 2816 /** 2817 * Return an array with the full table data 2818 * @param {object} oSettings dataTables settings object 2819 * @returns array {array} aData Master data array 2820 * @memberof DataTable#oApi 2821 */ 2822 function _fnGetDataMaster ( settings ) 2823 { 2824 return _pluck( settings.aoData, '_aData' ); 2825 } 2826 2827 2828 /** 2829 * Nuke the table 2830 * @param {object} oSettings dataTables settings object 2831 * @memberof DataTable#oApi 2832 */ 2833 function _fnClearTable( settings ) 2834 { 2835 settings.aoData.length = 0; 2836 settings.aiDisplayMaster.length = 0; 2837 settings.aiDisplay.length = 0; 2838 settings.aIds = {}; 2839 } 2840 2841 2842 /** 2843 * Take an array of integers (index array) and remove a target integer (value - not 2844 * the key!) 2845 * @param {array} a Index array to target 2846 * @param {int} iTarget value to find 2847 * @memberof DataTable#oApi 2848 */ 2849 function _fnDeleteIndex( a, iTarget, splice ) 2850 { 2851 var iTargetIndex = -1; 2852 2853 for ( var i=0, iLen=a.length ; i<iLen ; i++ ) 2854 { 2855 if ( a[i] == iTarget ) 2856 { 2857 iTargetIndex = i; 2858 } 2859 else if ( a[i] > iTarget ) 2860 { 2861 a[i]--; 2862 } 2863 } 2864 2865 if ( iTargetIndex != -1 && splice === undefined ) 2866 { 2867 a.splice( iTargetIndex, 1 ); 2868 } 2869 } 2870 2871 2872 /**
2873 * Mark cached data as invalid such that a re-read of the data will occur when 2874 * the cached data is next requested. Also update from the data source object. 2875 * 2876 * @param {object} settings DataTables settings object 2877 * @param {int} rowIdx Row index to invalidate 2878 * @param {string} [src] Source to invalidate from: undefined, 'auto', 'dom' 2879 * or 'data' 2880 * @param {int} [colIdx] Column index to invalidate. If undefined the whole 2881 * row will be invalidated 2882 * @memberof DataTable#oApi 2883 * 2884 * @todo For the modularisation of v1.11 this will need to become a callback, so 2885 * the sort and filter methods can subscribe to it. That will required 2886 * initialisation options for sorting, which is why it is not already baked in 2887 */ 2888 function _fnInvalidate( settings, rowIdx, src, colIdx ) 2889 { 2890 var row = settings.aoData[ rowIdx ]; 2891 var i, ien; 2892 var cellWrite = function ( cell, col ) { 2893 // This is very frustrating, but in IE if you just write directly 2894 // to innerHTML, and elements that are overwritten are GC'ed, 2895 // even if there is a reference to them elsewhere 2896 while ( cell.childNodes.length ) { 2897 cell.removeChild( cell.firstChild ); 2898 } 2899 2900 cell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' ); 2901 }; 2902 2903 // Are we reading last data from DOM or the data object? 2904 if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) { 2905 // Read the data from the DOM 2906 row._aData = _fnGetRowElements( 2907 settings, row, colIdx, colIdx === undefined ? undefined : row._aData 2908 ) 2909 .data; 2910 } 2911 else { 2912 // Reading from data object, update the DOM 2913 var cells = row.anCells; 2914 2915 if ( cells ) { 2916 if ( colIdx !== undefined ) { 2917 cellWrite( cells[colIdx], colIdx ); 2918 } 2919 else { 2920 for ( i=0, ien=cells.length ; i<ien ; i++ ) { 2921 cellWrite( cells[i], i ); 2922 } 2923 } 2924 } 2925 } 2926 2927 // For both row and cell invalidation, the cached data for sorting and 2928 // filtering is nulled out 2929 row._aSortData = null; 2930 row._aFilterData = null; 2931 2932 // Invalidate the type for a specific column (if given) or all columns since 2933 // the data might have changed 2934 var cols = settings.aoColumns; 2935 if ( colIdx !== undefined ) { 2936 cols[ colIdx ].sType = null; 2937 } 2938 else { 2939 for ( i=0, ien=cols.length ; i<ien ; i++ ) { 2940 cols[i].sType = null; 2941 } 2942 2943 // Update DataTables special `DT_*` attributes for the row 2944 _fnRowAttributes( settings, row ); 2945 } 2946 } 2947 2948 2949 /** 2950 * Build a data source object from an HTML row, reading the contents of the 2951 * cells that are in the row. 2952 * 2953 * @param {object} settings DataTables settings object 2954 * @param {node|object} TR element from which to read data or existing row 2955 * object from which to re-read the data from the cells 2956 * @param {int} [colIdx] Optional column index 2957 * @param {array|object} [d] Data source object. If `colIdx` is given then this 2958 * parameter should also be given and will be used to write the data into. 2959 * Only the column in question will be written 2960 * @returns {object} Object with two parameters: `data` the data read, in 2961 * document order, and `cells` and array of nodes (they can be useful to the 2962 * caller, so rather than needing a second traversal to get them, just return 2963 * them from here). 2964 * @memberof DataTable#oApi 2965 */ 2966 function _fnGetRowElements( settings, row, colIdx, d ) 2967 { 2968 var 2969 tds = [], 2970 td = row.firstChild, 2971 name, col, o, i=0, contents, 2972 columns = settings.aoColumns, 2973 objectRead = settings._rowReadObject; 2974 2975 // Allow the data object to be passed in, or construct 2976 d = d !== undefined ? 2977 d : 2978 objectRead ? 2979 {} : 2980 []; 2981 2982 var attr = function ( str, td ) { 2983 if ( typeof str === 'string' ) { 2984 var idx = str.indexOf('@'); 2985 2986 if ( idx !== -1 ) { 2987 var attr = str.substring( idx+1 ); 2988 var setter = _fnSetObjectDataFn( str ); 2989 setter( d, td.getAttribute( attr ) ); 2990 } 2991 } 2992 }; 2993 2994 // Read data from a cell and store into the data object 2995 var cellProcess = function ( cell ) { 2996 if ( colIdx === undefined || colIdx === i ) { 2997 col = columns[i]; 2998 contents = $.trim(cell.innerHTML); 2999 3000 if ( col && col._bAttrSrc ) { 3001 var setter = _fnSetObjectDataFn( col.mData._ ); 3002 setter( d, contents ); 3003 3004 attr( col.mData.sort, cell ); 3005 attr( col.mData.type, cell ); 3006 attr( col.mData.filter, cell ); 3007 } 3008 else { 3009 // Depending on the `data` option for the columns the data can 3010 // be read to either an object or an array.
vendor: 11,978 bytes, lines 3011-3468
3011 if ( objectRead ) { 3012 if ( ! col._setter ) { 3013 // Cache the setter function 3014 col._setter = _fnSetObjectDataFn( col.mData ); 3015 } 3016 col._setter( d, contents ); 3017 } 3018 else { 3019 d[i] = contents; 3020 } 3021 } 3022 } 3023 3024 i++; 3025 }; 3026 3027 if ( td ) { 3028 // `tr` element was passed in 3029 while ( td ) { 3030 name = td.nodeName.toUpperCase(); 3031 3032 if ( name == "TD" || name == "TH" ) { 3033 cellProcess( td ); 3034 tds.push( td ); 3035 } 3036 3037 td = td.nextSibling; 3038 } 3039 } 3040 else { 3041 // Existing row object passed in 3042 tds = row.anCells; 3043 3044 for ( var j=0, jen=tds.length ; j<jen ; j++ ) { 3045 cellProcess( tds[j] ); 3046 } 3047 } 3048 3049 // Read the ID from the DOM if present 3050 var rowNode = row.firstChild ? row : row.nTr; 3051 3052 if ( rowNode ) { 3053 var id = rowNode.getAttribute( 'id' ); 3054 3055 if ( id ) { 3056 _fnSetObjectDataFn( settings.rowId )( d, id ); 3057 } 3058 } 3059 3060 return { 3061 data: d, 3062 cells: tds 3063 }; 3064 } 3065 /** 3066 * Create a new TR element (and it's TD children) for a row 3067 * @param {object} oSettings dataTables settings object 3068 * @param {int} iRow Row to consider 3069 * @param {node} [nTrIn] TR element to add to the table - optional. If not given, 3070 * DataTables will create a row automatically 3071 * @param {array} [anTds] Array of TD|TH elements for the row - must be given 3072 * if nTr is. 3073 * @memberof DataTable#oApi 3074 */ 3075 function _fnCreateTr ( oSettings, iRow, nTrIn, anTds ) 3076 { 3077 var 3078 row = oSettings.aoData[iRow], 3079 rowData = row._aData, 3080 cells = [], 3081 nTr, nTd, oCol, 3082 i, iLen; 3083 3084 if ( row.nTr === null ) 3085 { 3086 nTr = nTrIn || document.createElement('tr'); 3087 3088 row.nTr = nTr; 3089 row.anCells = cells; 3090 3091 /* Use a private property on the node to allow reserve mapping from the node 3092 * to the aoData array for fast look up 3093 */ 3094 nTr._DT_RowIndex = iRow; 3095 3096 /* Special parameters can be given by the data source to be used on the row */ 3097 _fnRowAttributes( oSettings, row ); 3098 3099 /* Process each column */ 3100 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ ) 3101 { 3102 oCol = oSettings.aoColumns[i]; 3103 3104 nTd = nTrIn ? anTds[i] : document.createElement( oCol.sCellType ); 3105 nTd._DT_CellIndex = { 3106 row: iRow, 3107 column: i 3108 }; 3109 3110 cells.push( nTd ); 3111 3112 // Need to create the HTML if new, or if a rendering function is defined 3113 if ( (!nTrIn || oCol.mRender || oCol.mData !== i) && 3114 (!$.isPlainObject(oCol.mData) || oCol.mData._ !== i+'.display') 3115 ) { 3116 nTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' ); 3117 } 3118 3119 /* Add user defined class */ 3120 if ( oCol.sClass ) 3121 { 3122 nTd.className += ' '+oCol.sClass; 3123 } 3124 3125 // Visibility - add or remove as required 3126 if ( oCol.bVisible && ! nTrIn ) 3127 { 3128 nTr.appendChild( nTd ); 3129 } 3130 else if ( ! oCol.bVisible && nTrIn ) 3131 { 3132 nTd.parentNode.removeChild( nTd ); 3133 } 3134 3135 if ( oCol.fnCreatedCell ) 3136 { 3137 oCol.fnCreatedCell.call( oSettings.oInstance, 3138 nTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i 3139 ); 3140 } 3141 } 3142 3143 _fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [nTr, rowData, iRow] ); 3144 } 3145 3146 // Remove once webkit bug 131819 and Chromium bug 365619 have been resolved 3147 // and deployed 3148 row.nTr.setAttribute( 'role', 'row' ); 3149 } 3150 3151 3152 /** 3153 * Add attributes to a row based on the special `DT_*` parameters in a data 3154 * source object. 3155 * @param {object} settings DataTables settings object 3156 * @param {object} DataTables row object for the row to be modified 3157 * @memberof DataTable#oApi 3158 */ 3159 function _fnRowAttributes( settings, row ) 3160 { 3161 var tr = row.nTr; 3162 var data = row._aData; 3163 3164 if ( tr ) { 3165 var id = settings.rowIdFn( data ); 3166 3167 if ( id ) { 3168 tr.id = id; 3169 } 3170 3171 if ( data.DT_RowClass ) { 3172 // Remove any classes added by DT_RowClass before 3173 var a = data.DT_RowClass.split(' '); 3174 row.__rowc = row.__rowc ? 3175 _unique( row.__rowc.concat( a ) ) : 3176 a; 3177 3178 $(tr) 3179 .removeClass( row.__rowc.join(' ') ) 3180 .addClass( data.DT_RowClass ); 3181 } 3182 3183 if ( data.DT_RowAttr ) { 3184 $(tr).attr( data.DT_RowAttr ); 3185 } 3186 3187 if ( data.DT_RowData ) { 3188 $(tr).data( data.DT_RowData ); 3189 } 3190 } 3191 } 3192 3193 3194 /** 3195 * Create the HTML header for the table 3196 * @param {object} oSettings dataTables settings object 3197 * @memberof DataTable#oApi 3198 */ 3199 function _fnBuildHead( oSettings ) 3200 { 3201 var i, ien, cell, row, column; 3202 var thead = oSettings.nTHead; 3203 var tfoot = oSettings.nTFoot; 3204 var createHeader = $('th, td', thead).length === 0; 3205 var classes = oSettings.oClasses; 3206 var columns = oSettings.aoColumns; 3207 3208 if ( createHeader ) { 3209 row = $('<tr/>').appendTo( thead ); 3210 } 3211 3212 for ( i=0, ien=columns.length ; i<ien ; i++ ) { 3213 column = columns[i]; 3214 cell = $( column.nTh ).addClass( column.sClass ); 3215 3216 if ( createHeader ) { 3217 cell.appendTo( row ); 3218 } 3219 3220 // 1.11 move into sorting 3221 if ( oSettings.oFeatures.bSort ) { 3222 cell.addClass( column.sSortingClass ); 3223 3224 if ( column.bSortable !== false ) { 3225 cell 3226 .attr( 'tabindex', oSettings.iTabIndex ) 3227 .attr( 'aria-controls', oSettings.sTableId ); 3228 3229 _fnSortAttachListener( oSettings, column.nTh, i ); 3230 } 3231 } 3232 3233 if ( column.sTitle != cell[0].innerHTML ) { 3234 cell.html( column.sTitle ); 3235 } 3236 3237 _fnRenderer( oSettings, 'header' )( 3238 oSettings, cell, column, classes 3239 ); 3240 } 3241 3242 if ( createHeader ) { 3243 _fnDetectHeader( oSettings.aoHeader, thead ); 3244 } 3245 3246 /* ARIA role for the rows */ 3247 $(thead).find('>tr').attr('role', 'row'); 3248 3249 /* Deal with the footer - add classes if required */ 3250 $(thead).find('>tr>th, >tr>td').addClass( classes.sHeaderTH ); 3251 $(tfoot).find('>tr>th, >tr>td').addClass( classes.sFooterTH ); 3252 3253 // Cache the footer cells. Note that we only take the cells from the first 3254 // row in the footer. If there is more than one row the user wants to 3255 // interact with, they need to use the table().foot() method. Note also this 3256 // allows cells to be used for multiple columns using colspan 3257 if ( tfoot !== null ) { 3258 var cells = oSettings.aoFooter[0]; 3259 3260 for ( i=0, ien=cells.length ; i<ien ; i++ ) { 3261 column = columns[i]; 3262 column.nTf = cells[i].cell; 3263 3264 if ( column.sClass ) { 3265 $(column.nTf).addClass( column.sClass ); 3266 } 3267 } 3268 } 3269 } 3270 3271 3272 /** 3273 * Draw the header (or footer) element based on the column visibility states. The 3274 * methodology here is to use the layout array from _fnDetectHeader, modified for 3275 * the instantaneous column visibility, to construct the new layout. The grid is 3276 * traversed over cell at a time in a rows x columns grid fashion, although each 3277 * cell insert can cover multiple elements in the grid - which is tracks using the 3278 * aApplied array. Cell inserts in the grid will only occur where there isn't 3279 * already a cell in that position. 3280 * @param {object} oSettings dataTables settings object 3281 * @param array {objects} aoSource Layout array from _fnDetectHeader 3282 * @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc, 3283 * @memberof DataTable#oApi 3284 */ 3285 function _fnDrawHead( oSettings, aoSource, bIncludeHidden ) 3286 { 3287 var i, iLen, j, jLen, k, kLen, n, nLocalTr; 3288 var aoLocal = []; 3289 var aApplied = []; 3290 var iColumns = oSettings.aoColumns.length; 3291 var iRowspan, iColspan; 3292 3293 if ( ! aoSource ) 3294 { 3295 return; 3296 } 3297 3298 if ( bIncludeHidden === undefined ) 3299 { 3300 bIncludeHidden = false; 3301 } 3302 3303 /* Make a copy of the master layout array, but without the visible columns in it */ 3304 for ( i=0, iLen=aoSource.length ; i<iLen ; i++ ) 3305 { 3306 aoLocal[i] = aoSource[i].slice(); 3307 aoLocal[i].nTr = aoSource[i].nTr; 3308 3309 /* Remove any columns which are currently hidden */ 3310 for ( j=iColumns-1 ; j>=0 ; j-- ) 3311 { 3312 if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden ) 3313 { 3314 aoLocal[i].splice( j, 1 ); 3315 } 3316 } 3317 3318 /* Prep the applied array - it needs an element for each row */ 3319 aApplied.push( [] ); 3320 } 3321 3322 for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ ) 3323 { 3324 nLocalTr = aoLocal[i].nTr; 3325 3326 /* All cells are going to be replaced, so empty out the row */ 3327 if ( nLocalTr ) 3328 { 3329 while( (n = nLocalTr.firstChild) ) 3330 { 3331 nLocalTr.removeChild( n ); 3332 } 3333 } 3334 3335 for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ ) 3336 { 3337 iRowspan = 1; 3338 iColspan = 1; 3339 3340 /* Check to see if there is already a cell (row/colspan) covering our target 3341 * insert point. If there is, then there is nothing to do. 3342 */ 3343 if ( aApplied[i][j] === undefined ) 3344 { 3345 nLocalTr.appendChild( aoLocal[i][j].cell ); 3346 aApplied[i][j] = 1; 3347 3348 /* Expand the cell to cover as many rows as needed */ 3349 while ( aoLocal[i+iRowspan] !== undefined && 3350 aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell ) 3351 { 3352 aApplied[i+iRowspan][j] = 1; 3353 iRowspan++; 3354 } 3355 3356 /* Expand the cell to cover as many columns as needed */ 3357 while ( aoLocal[i][j+iColspan] !== undefined && 3358 aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell ) 3359 { 3360 /* Must update the applied array over the rows for the columns */ 3361 for ( k=0 ; k<iRowspan ; k++ ) 3362 { 3363 aApplied[i+k][j+iColspan] = 1; 3364 } 3365 iColspan++; 3366 } 3367 3368 /* Do the actual expansion in the DOM */ 3369 $(aoLocal[i][j].cell) 3370 .attr('rowspan', iRowspan) 3371 .attr('colspan', iColspan); 3372 } 3373 } 3374 } 3375 } 3376 3377 3378 /** 3379 * Insert the required TR nodes into the table for display 3380 * @param {object} oSettings dataTables settings object 3381 * @memberof DataTable#oApi 3382 */ 3383 function _fnDraw( oSettings ) 3384 { 3385 /* Provide a pre-callback function which can be used to cancel the draw is false is returned */ 3386 var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] ); 3387 if ( $.inArray( false, aPreDraw ) !== -1 ) 3388 { 3389 _fnProcessingDisplay( oSettings, false ); 3390 return; 3391 } 3392 3393 var i, iLen, n; 3394 var anRows = []; 3395 var iRowCount = 0; 3396 var asStripeClasses = oSettings.asStripeClasses; 3397 var iStripes = asStripeClasses.length; 3398 var iOpenRows = oSettings.aoOpenRows.length; 3399 var oLang = oSettings.oLanguage; 3400 var iInitDisplayStart = oSettings.iInitDisplayStart; 3401 var bServerSide = _fnDataSource( oSettings ) == 'ssp'; 3402 var aiDisplay = oSettings.aiDisplay; 3403 3404 oSettings.bDrawing = true; 3405 3406 /* Check and see if we have an initial draw position from state saving */ 3407 if ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 ) 3408 { 3409 oSettings._iDisplayStart = bServerSide ? 3410 iInitDisplayStart : 3411 iInitDisplayStart >= oSettings.fnRecordsDisplay() ? 3412 0 : 3413 iInitDisplayStart; 3414 3415 oSettings.iInitDisplayStart = -1; 3416 } 3417 3418 var iDisplayStart = oSettings._iDisplayStart; 3419 var iDisplayEnd = oSettings.fnDisplayEnd(); 3420 3421 /* Server-side processing draw intercept */ 3422 if ( oSettings.bDeferLoading ) 3423 { 3424 oSettings.bDeferLoading = false; 3425 oSettings.iDraw++; 3426 _fnProcessingDisplay( oSettings, false ); 3427 } 3428 else if ( !bServerSide ) 3429 { 3430 oSettings.iDraw++; 3431 } 3432 else if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) ) 3433 { 3434 return; 3435 } 3436 3437 if ( aiDisplay.length !== 0 ) 3438 { 3439 var iStart = bServerSide ? 0 : iDisplayStart; 3440 var iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd; 3441 3442 for ( var j=iStart ; j<iEnd ; j++ ) 3443 { 3444 var iDataIndex = aiDisplay[j]; 3445 var aoData = oSettings.aoData[ iDataIndex ]; 3446 if ( aoData.nTr === null ) 3447 { 3448 _fnCreateTr( oSettings, iDataIndex ); 3449 } 3450 3451 var nRow = aoData.nTr; 3452 3453 /* Remove the old striping classes and then add the new one */ 3454 if ( iStripes !== 0 ) 3455 { 3456 var sStripe = asStripeClasses[ iRowCount % iStripes ]; 3457 if ( aoData._sRowStripe != sStripe ) 3458 { 3459 $(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe ); 3460 aoData._sRowStripe = sStripe; 3461 } 3462 } 3463 3464 // Row callback functions - might want to manipulate the row 3465 // iRowCount and j are not currently documented. Are they at all 3466 // useful? 3467 _fnCallbackFire( oSettings, 'aoRowCallback', null, 3468 [nRow, aoData._aData, iRowCount, j
vendor: 9,503 bytes, lines 3468-3822
3468] ); 3469 3470 anRows.push( nRow ); 3471 iRowCount++; 3472 } 3473 } 3474 else 3475 { 3476 /* Table is empty - create a row with an empty message in it */ 3477 var sZero = oLang.sZeroRecords; 3478 if ( oSettings.iDraw == 1 && _fnDataSource( oSettings ) == 'ajax' ) 3479 { 3480 sZero = oLang.sLoadingRecords; 3481 } 3482 else if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 ) 3483 { 3484 sZero = oLang.sEmptyTable; 3485 } 3486 3487 anRows[ 0 ] = $( '<tr/>', { 'class': iStripes ? asStripeClasses[0] : '' } ) 3488 .append( $('<td />', { 3489 'valign': 'top', 3490 'colSpan': _fnVisbleColumns( oSettings ), 3491 'class': oSettings.oClasses.sRowEmpty 3492 } ).html( sZero ) )[0]; 3493 } 3494 3495 /* Header and footer callbacks */ 3496 _fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0], 3497 _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] ); 3498 3499 _fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0], 3500 _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] ); 3501 3502 var body = $(oSettings.nTBody); 3503 3504 body.children().detach(); 3505 body.append( $(anRows) ); 3506 3507 /* Call all required callback functions for the end of a draw */ 3508 _fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] ); 3509 3510 /* Draw is complete, sorting and filtering must be as well */ 3511 oSettings.bSorted = false; 3512 oSettings.bFiltered = false; 3513 oSettings.bDrawing = false; 3514 } 3515 3516 3517 /** 3518 * Redraw the table - taking account of the various features which are enabled 3519 * @param {object} oSettings dataTables settings object 3520 * @param {boolean} [holdPosition] Keep the current paging position. By default 3521 * the paging is reset to the first page 3522 * @memberof DataTable#oApi 3523 */ 3524 function _fnReDraw( settings, holdPosition ) 3525 { 3526 var 3527 features = settings.oFeatures, 3528 sort = features.bSort, 3529 filter = features.bFilter; 3530 3531 if ( sort ) { 3532 _fnSort( settings ); 3533 } 3534 3535 if ( filter ) { 3536 _fnFilterComplete( settings, settings.oPreviousSearch ); 3537 } 3538 else { 3539 // No filtering, so we want to just use the display master 3540 settings.aiDisplay = settings.aiDisplayMaster.slice(); 3541 } 3542 3543 if ( holdPosition !== true ) { 3544 settings._iDisplayStart = 0; 3545 } 3546 3547 // Let any modules know about the draw hold position state (used by 3548 // scrolling internally) 3549 settings._drawHold = holdPosition; 3550 3551 _fnDraw( settings ); 3552 3553 settings._drawHold = false; 3554 } 3555 3556 3557 /** 3558 * Add the options to the page HTML for the table 3559 * @param {object} oSettings dataTables settings object 3560 * @memberof DataTable#oApi 3561 */ 3562 function _fnAddOptionsHtml ( oSettings ) 3563 { 3564 var classes = oSettings.oClasses; 3565 var table = $(oSettings.nTable); 3566 var holding = $('<div/>').insertBefore( table ); // Holding element for speed 3567 var features = oSettings.oFeatures; 3568 3569 // All DataTables are wrapped in a div 3570 var insert = $('<div/>', { 3571 id: oSettings.sTableId+'_wrapper', 3572 'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter) 3573 } ); 3574 3575 oSettings.nHolding = holding[0]; 3576 oSettings.nTableWrapper = insert[0]; 3577 oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling; 3578 3579 /* Loop over the user set positioning and place the elements as needed */ 3580 var aDom = oSettings.sDom.split(''); 3581 var featureNode, cOption, nNewNode, cNext, sAttr, j; 3582 for ( var i=0 ; i<aDom.length ; i++ ) 3583 { 3584 featureNode = null; 3585 cOption = aDom[i]; 3586 3587 if ( cOption == '<' ) 3588 { 3589 /* New container div */ 3590 nNewNode = $('<div/>')[0]; 3591 3592 /* Check to see if we should append an id and/or a class name to the container */ 3593 cNext = aDom[i+1]; 3594 if ( cNext == "'" || cNext == '"' ) 3595 { 3596 sAttr = ""; 3597 j = 2; 3598 while ( aDom[i+j] != cNext ) 3599 { 3600 sAttr += aDom[i+j]; 3601 j++; 3602 } 3603 3604 /* Replace jQuery UI constants @todo depreciated */ 3605 if ( sAttr == "H" ) 3606 { 3607 sAttr = classes.sJUIHeader; 3608 } 3609 else if ( sAttr == "F" ) 3610 { 3611 sAttr = classes.sJUIFooter; 3612 } 3613 3614 /* The attribute can be in the format of "#id.class", "#id" or "class" This logic 3615 * breaks the string into parts and applies them as needed 3616 */ 3617 if ( sAttr.indexOf('.') != -1 ) 3618 { 3619 var aSplit = sAttr.split('.'); 3620 nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1); 3621 nNewNode.className = aSplit[1]; 3622 } 3623 else if ( sAttr.charAt(0) == "#" ) 3624 { 3625 nNewNode.id = sAttr.substr(1, sAttr.length-1); 3626 } 3627 else 3628 { 3629 nNewNode.className = sAttr; 3630 } 3631 3632 i += j; /* Move along the position array */ 3633 } 3634 3635 insert.append( nNewNode ); 3636 insert = $(nNewNode); 3637 } 3638 else if ( cOption == '>' ) 3639 { 3640 /* End container div */ 3641 insert = insert.parent(); 3642 } 3643 // @todo Move options into their own plugins? 3644 else if ( cOption == 'l' && features.bPaginate && features.bLengthChange ) 3645 { 3646 /* Length */ 3647 featureNode = _fnFeatureHtmlLength( oSettings ); 3648 } 3649 else if ( cOption == 'f' && features.bFilter ) 3650 { 3651 /* Filter */ 3652 featureNode = _fnFeatureHtmlFilter( oSettings ); 3653 } 3654 else if ( cOption == 'r' && features.bProcessing ) 3655 { 3656 /* pRocessing */ 3657 featureNode = _fnFeatureHtmlProcessing( oSettings ); 3658 } 3659 else if ( cOption == 't' ) 3660 { 3661 /* Table */ 3662 featureNode = _fnFeatureHtmlTable( oSettings ); 3663 } 3664 else if ( cOption == 'i' && features.bInfo ) 3665 { 3666 /* Info */ 3667 featureNode = _fnFeatureHtmlInfo( oSettings ); 3668 } 3669 else if ( cOption == 'p' && features.bPaginate ) 3670 { 3671 /* Pagination */ 3672 featureNode = _fnFeatureHtmlPaginate( oSettings ); 3673 } 3674 else if ( DataTable.ext.feature.length !== 0 ) 3675 { 3676 /* Plug-in features */ 3677 var aoFeatures = DataTable.ext.feature; 3678 for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ ) 3679 { 3680 if ( cOption == aoFeatures[k].cFeature ) 3681 { 3682 featureNode = aoFeatures[k].fnInit( oSettings ); 3683 break; 3684 } 3685 } 3686 } 3687 3688 /* Add to the 2D features array */ 3689 if ( featureNode ) 3690 { 3691 var aanFeatures = oSettings.aanFeatures; 3692 3693 if ( ! aanFeatures[cOption] ) 3694 { 3695 aanFeatures[cOption] = []; 3696 } 3697 3698 aanFeatures[cOption].push( featureNode ); 3699 insert.append( featureNode ); 3700 } 3701 } 3702 3703 /* Built our DOM structure - replace the holding div with what we want */ 3704 holding.replaceWith( insert ); 3705 oSettings.nHolding = null; 3706 } 3707 3708 3709 /** 3710 * Use the DOM source to create up an array of header cells. The idea here is to 3711 * create a layout grid (array) of rows x columns, which contains a reference 3712 * to the cell that that point in the grid (regardless of col/rowspan), such that 3713 * any column / row could be removed and the new grid constructed 3714 * @param array {object} aLayout Array to store the calculated layout in 3715 * @param {node} nThead The header/footer element for the table 3716 * @memberof DataTable#oApi 3717 */ 3718 function _fnDetectHeader ( aLayout, nThead ) 3719 { 3720 var nTrs = $(nThead).children('tr'); 3721 var nTr, nCell; 3722 var i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan; 3723 var bUnique; 3724 var fnShiftCol = function ( a, i, j ) { 3725 var k = a[i]; 3726 while ( k[j] ) { 3727 j++; 3728 } 3729 return j; 3730 }; 3731 3732 aLayout.splice( 0, aLayout.length ); 3733 3734 /* We know how many rows there are in the layout - so prep it */ 3735 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ ) 3736 { 3737 aLayout.push( [] ); 3738 } 3739 3740 /* Calculate a layout array */ 3741 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ ) 3742 { 3743 nTr = nTrs[i]; 3744 iColumn = 0; 3745 3746 /* For every cell in the row... */ 3747 nCell = nTr.firstChild; 3748 while ( nCell ) { 3749 if ( nCell.nodeName.toUpperCase() == "TD" || 3750 nCell.nodeName.toUpperCase() == "TH" ) 3751 { 3752 /* Get the col and rowspan attributes from the DOM and sanitise them */ 3753 iColspan = nCell.getAttribute('colspan') * 1; 3754 iRowspan = nCell.getAttribute('rowspan') * 1; 3755 iColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan; 3756 iRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan; 3757 3758 /* There might be colspan cells already in this row, so shift our target 3759 * accordingly 3760 */ 3761 iColShifted = fnShiftCol( aLayout, i, iColumn ); 3762 3763 /* Cache calculation for unique columns */ 3764 bUnique = iColspan === 1 ? true : false; 3765 3766 /* If there is col / rowspan, copy the information into the layout grid */ 3767 for ( l=0 ; l<iColspan ; l++ ) 3768 { 3769 for ( k=0 ; k<iRowspan ; k++ ) 3770 { 3771 aLayout[i+k][iColShifted+l] = { 3772 "cell": nCell, 3773 "unique": bUnique 3774 }; 3775 aLayout[i+k].nTr = nTr; 3776 } 3777 } 3778 } 3779 nCell = nCell.nextSibling; 3780 } 3781 } 3782 } 3783 3784 3785 /** 3786 * Get an array of unique th elements, one for each column 3787 * @param {object} oSettings dataTables settings object 3788 * @param {node} nHeader automatically detect the layout from this node - optional 3789 * @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional 3790 * @returns array {node} aReturn list of unique th's 3791 * @memberof DataTable#oApi 3792 */ 3793 function _fnGetUniqueThs ( oSettings, nHeader, aLayout ) 3794 { 3795 var aReturn = []; 3796 if ( !aLayout ) 3797 { 3798 aLayout = oSettings.aoHeader; 3799 if ( nHeader ) 3800 { 3801 aLayout = []; 3802 _fnDetectHeader( aLayout, nHeader ); 3803 } 3804 } 3805 3806 for ( var i=0, iLen=aLayout.length ; i<iLen ; i++ ) 3807 { 3808 for ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ ) 3809 { 3810 if ( aLayout[i][j].unique && 3811 (!aReturn[j] || !oSettings.bSortCellsTop) ) 3812 { 3813 aReturn[j] = aLayout[i][j].cell; 3814 } 3815 } 3816 } 3817 3818 return aReturn; 3819 } 3820 3821 /** 3822 *
3822Create an Ajax call based on the table's settings, taking into account that 3823 * parameters can have multiple forms, and backwards compatibility. 3824 * 3825 * @param {object} oSettings dataTables settings object 3826 * @param {array} data Data to send to the server, required by 3827 * DataTables - may be augmented by developer callbacks 3828 * @param {function} fn Callback function to run when data is obtained 3829 */ 3830 function _fnBuildAjax( oSettings, data, fn ) 3831 { 3832 // Compatibility with 1.9-, allow fnServerData and event to manipulate 3833 _fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] ); 3834 3835 // Convert to object based for 1.10+ if using the old array scheme which can 3836 // come from server-side processing or serverParams 3837 if ( data && $.isArray(data) ) { 3838 var tmp = {}; 3839 var rbracket = /(.*?)\[\]$/; 3840 3841 $.each( data, function (key, val) { 3842 var match = val.name.match(rbracket); 3843 3844 if ( match ) { 3845 // Support for arrays 3846 var name = match[0]; 3847 3848 if ( ! tmp[ name ] ) { 3849 tmp[ name ] = []; 3850 } 3851 tmp[ name ].push( val.value ); 3852 } 3853 else { 3854 tmp[val.name] = val.value; 3855 } 3856 } ); 3857 data = tmp; 3858 } 3859 3860 var ajaxData; 3861 var ajax = oSettings.ajax; 3862 var instance = oSettings.oInstance; 3863 var callback = function ( json ) { 3864 _fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR] ); 3865 fn( json ); 3866 }; 3867 3868 if ( $.isPlainObject( ajax ) && ajax.data ) 3869 { 3870 ajaxData = ajax.data; 3871 3872 var newData = $.isFunction( ajaxData ) ? 3873 ajaxData( data, oSettings ) : // fn can manipulate data or return 3874 ajaxData; // an object object or array to merge 3875 3876 // If the function returned something, use that alone 3877 data = $.isFunction( ajaxData ) && newData ? 3878 newData : 3879 $.extend( true, data, newData ); 3880 3881 // Remove the data property as we've resolved it already and don't want 3882 // jQuery to do it again (it is restored at the end of the function) 3883 delete ajax.data; 3884 } 3885 3886 var baseAjax = { 3887 "data": data, 3888 "success": function (json) { 3889 var error = json.error || json.sError; 3890 if ( error ) { 3891 _fnLog( oSettings, 0, error ); 3892 } 3893 3894 oSettings.json = json; 3895 callback( json ); 3896 }, 3897 "dataType": "json", 3898 "cache": false, 3899 "type": oSettings.sServerMethod, 3900 "error": function (xhr, error, thrown) { 3901 var ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR] ); 3902 3903 if ( $.inArray( true, ret ) === -1 ) { 3904 if ( error == "parsererror" ) { 3905 _fnLog( oSettings, 0, 'Invalid JSON response', 1 ); 3906 } 3907 else if ( xhr.readyState === 4 ) { 3908 _fnLog( oSettings, 0, 'Ajax error', 7 ); 3909 } 3910 } 3911 3912 _fnProcessingDisplay( oSettings, false ); 3913 } 3914 }; 3915 3916 // Store the data submitted for the API 3917 oSettings.oAjaxData = data; 3918 3919 // Allow plug-ins and external processes to modify the data 3920 _fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data] ); 3921 3922 if ( oSettings.fnServerData ) 3923 { 3924 // DataTables 1.9- compatibility 3925 oSettings.fnServerData.call( instance, 3926 oSettings.sAjaxSource, 3927 $.map( data, function (val, key) { // Need to convert back to 1.9 trad format 3928 return { name: key, value: val }; 3929 } ), 3930 callback, 3931 oSettings 3932 ); 3933 } 3934 else if ( oSettings.sAjaxSource || typeof ajax === 'string' ) 3935 { 3936 // DataTables 1.9- compatibility 3937 oSettings.jqXHR = $.ajax( $.extend( baseAjax, { 3938 url: ajax || oSettings.sAjaxSource 3939 } ) ); 3940 } 3941 else if ( $.isFunction( ajax ) ) 3942 { 3943 // Is a function - let the caller define what needs to be done 3944 oSettings.jqXHR = ajax.call( instance, data, callback, oSettings ); 3945 } 3946 else 3947 { 3948 // Object to extend the base settings 3949 oSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) ); 3950 3951 // Restore for next time around 3952 ajax.data = ajaxData; 3953 } 3954 } 3955 3956 3957 /** 3958 * Update the table using an Ajax call 3959 * @param {object} settings dataTables settings object 3960 * @returns {boolean} Block the table drawing or not 3961 * @memberof DataTable#oApi 3962 */ 3963 function _fnAjaxUpdate( settings ) 3964 { 3965 if ( settings.bAjaxDataGet ) { 3966 settings.iDraw++; 3967 _fnProcessingDisplay( settings, true ); 3968 3969 _fnBuildAjax( 3970 settings, 3971 _fnAjaxParameters( settings ), 3972 function(json) { 3973 _fnAjaxUpdateDraw( settings, json ); 3974 } 3975 ); 3976 3977 return false;
vendor: 43,145 bytes, lines 3978-5457
3978 } 3979 return true; 3980 } 3981 3982 3983 /** 3984 * Build up the parameters in an object needed for a server-side processing 3985 * request. Note that this is basically done twice, is different ways - a modern 3986 * method which is used by default in DataTables 1.10 which uses objects and 3987 * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if 3988 * the sAjaxSource option is used in the initialisation, or the legacyAjax 3989 * option is set. 3990 * @param {object} oSettings dataTables settings object 3991 * @returns {bool} block the table drawing or not 3992 * @memberof DataTable#oApi 3993 */ 3994 function _fnAjaxParameters( settings ) 3995 { 3996 var 3997 columns = settings.aoColumns, 3998 columnCount = columns.length, 3999 features = settings.oFeatures, 4000 preSearch = settings.oPreviousSearch, 4001 preColSearch = settings.aoPreSearchCols, 4002 i, data = [], dataProp, column, columnSearch, 4003 sort = _fnSortFlatten( settings ), 4004 displayStart = settings._iDisplayStart, 4005 displayLength = features.bPaginate !== false ? 4006 settings._iDisplayLength : 4007 -1; 4008 4009 var param = function ( name, value ) { 4010 data.push( { 'name': name, 'value': value } ); 4011 }; 4012 4013 // DataTables 1.9- compatible method 4014 param( 'sEcho', settings.iDraw ); 4015 param( 'iColumns', columnCount ); 4016 param( 'sColumns', _pluck( columns, 'sName' ).join(',') ); 4017 param( 'iDisplayStart', displayStart ); 4018 param( 'iDisplayLength', displayLength ); 4019 4020 // DataTables 1.10+ method 4021 var d = { 4022 draw: settings.iDraw, 4023 columns: [], 4024 order: [], 4025 start: displayStart, 4026 length: displayLength, 4027 search: { 4028 value: preSearch.sSearch, 4029 regex: preSearch.bRegex 4030 } 4031 }; 4032 4033 for ( i=0 ; i<columnCount ; i++ ) { 4034 column = columns[i]; 4035 columnSearch = preColSearch[i]; 4036 dataProp = typeof column.mData=="function" ? 'function' : column.mData ; 4037 4038 d.columns.push( { 4039 data: dataProp, 4040 name: column.sName, 4041 searchable: column.bSearchable, 4042 orderable: column.bSortable, 4043 search: { 4044 value: columnSearch.sSearch, 4045 regex: columnSearch.bRegex 4046 } 4047 } ); 4048 4049 param( "mDataProp_"+i, dataProp ); 4050 4051 if ( features.bFilter ) { 4052 param( 'sSearch_'+i, columnSearch.sSearch ); 4053 param( 'bRegex_'+i, columnSearch.bRegex ); 4054 param( 'bSearchable_'+i, column.bSearchable ); 4055 } 4056 4057 if ( features.bSort ) { 4058 param( 'bSortable_'+i, column.bSortable ); 4059 } 4060 } 4061 4062 if ( features.bFilter ) { 4063 param( 'sSearch', preSearch.sSearch ); 4064 param( 'bRegex', preSearch.bRegex ); 4065 } 4066 4067 if ( features.bSort ) { 4068 $.each( sort, function ( i, val ) { 4069 d.order.push( { column: val.col, dir: val.dir } ); 4070 4071 param( 'iSortCol_'+i, val.col ); 4072 param( 'sSortDir_'+i, val.dir ); 4073 } ); 4074 4075 param( 'iSortingCols', sort.length ); 4076 } 4077 4078 // If the legacy.ajax parameter is null, then we automatically decide which 4079 // form to use, based on sAjaxSource 4080 var legacy = DataTable.ext.legacy.ajax; 4081 if ( legacy === null ) { 4082 return settings.sAjaxSource ? data : d; 4083 } 4084 4085 // Otherwise, if legacy has been specified then we use that to decide on the 4086 // form 4087 return legacy ? data : d; 4088 } 4089 4090 4091 /** 4092 * Data the data from the server (nuking the old) and redraw the table 4093 * @param {object} oSettings dataTables settings object 4094 * @param {object} json json data return from the server. 4095 * @param {string} json.sEcho Tracking flag for DataTables to match requests 4096 * @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering 4097 * @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering 4098 * @param {array} json.aaData The data to display on this page 4099 * @param {string} [json.sColumns] Column ordering (sName, comma separated) 4100 * @memberof DataTable#oApi 4101 */ 4102 function _fnAjaxUpdateDraw ( settings, json ) 4103 { 4104 // v1.10 uses camelCase variables, while 1.9 uses Hungarian notation. 4105 // Support both 4106 var compat = function ( old, modern ) { 4107 return json[old] !== undefined ? json[old] : json[modern]; 4108 }; 4109 4110 var data = _fnAjaxDataSrc( settings, json ); 4111 var draw = compat( 'sEcho', 'draw' ); 4112 var recordsTotal = compat( 'iTotalRecords', 'recordsTotal' ); 4113 var recordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' ); 4114 4115 if ( draw ) { 4116 // Protect against out of sequence returns 4117 if ( draw*1 < settings.iDraw ) { 4118 return; 4119 } 4120 settings.iDraw = draw * 1; 4121 } 4122 4123 _fnClearTable( settings ); 4124 settings._iRecordsTotal = parseInt(recordsTotal, 10); 4125 settings._iRecordsDisplay = parseInt(recordsFiltered, 10); 4126 4127 for ( var i=0, ien=data.length ; i<ien ; i++ ) { 4128 _fnAddData( settings, data[i] ); 4129 } 4130 settings.aiDisplay = settings.aiDisplayMaster.slice(); 4131 4132 settings.bAjaxDataGet = false; 4133 _fnDraw( settings ); 4134 4135 if ( ! settings._bInitComplete ) { 4136 _fnInitComplete( settings, json ); 4137 } 4138 4139 settings.bAjaxDataGet = true; 4140 _fnProcessingDisplay( settings, false ); 4141 } 4142 4143 4144 /** 4145 * Get the data from the JSON data source to use for drawing a table. Using 4146 * `_fnGetObjectDataFn` allows the data to be sourced from a property of the 4147 * source object, or from a processing function. 4148 * @param {object} oSettings dataTables settings object 4149 * @param {object} json Data source object / array from the server 4150 * @return {array} Array of data to use 4151 */ 4152 function _fnAjaxDataSrc ( oSettings, json ) 4153 { 4154 var dataSrc = $.isPlainObject( oSettings.ajax ) && oSettings.ajax.dataSrc !== undefined ? 4155 oSettings.ajax.dataSrc : 4156 oSettings.sAjaxDataProp; // Compatibility with 1.9-. 4157 4158 // Compatibility with 1.9-. In order to read from aaData, check if the 4159 // default has been changed, if not, check for aaData 4160 if ( dataSrc === 'data' ) { 4161 return json.aaData || json[dataSrc]; 4162 } 4163 4164 return dataSrc !== "" ? 4165 _fnGetObjectDataFn( dataSrc )( json ) : 4166 json; 4167 } 4168 4169 /** 4170 * Generate the node required for filtering text 4171 * @returns {node} Filter control element 4172 * @param {object} oSettings dataTables settings object 4173 * @memberof DataTable#oApi 4174 */ 4175 function _fnFeatureHtmlFilter ( settings ) 4176 { 4177 var classes = settings.oClasses; 4178 var tableId = settings.sTableId; 4179 var language = settings.oLanguage; 4180 var previousSearch = settings.oPreviousSearch; 4181 var features = settings.aanFeatures; 4182 var input = '<input type="search" class="'+classes.sFilterInput+'"/>'; 4183 4184 var str = language.sSearch; 4185 str = str.match(/_INPUT_/) ? 4186 str.replace('_INPUT_', input) : 4187 str+input; 4188 4189 var filter = $('<div/>', { 4190 'id': ! features.f ? tableId+'_filter' : null, 4191 'class': classes.sFilter 4192 } ) 4193 .append( $('<label/>' ).append( str ) ); 4194 4195 var searchFn = function() { 4196 /* Update all other filter input elements for the new display */ 4197 var n = features.f; 4198 var val = !this.value ? "" : this.value; // mental IE8 fix :-( 4199 4200 /* Now do the filter */ 4201 if ( val != previousSearch.sSearch ) { 4202 _fnFilterComplete( settings, { 4203 "sSearch": val, 4204 "bRegex": previousSearch.bRegex, 4205 "bSmart": previousSearch.bSmart , 4206 "bCaseInsensitive": previousSearch.bCaseInsensitive 4207 } ); 4208 4209 // Need to redraw, without resorting 4210 settings._iDisplayStart = 0; 4211 _fnDraw( settings ); 4212 } 4213 }; 4214 4215 var searchDelay = settings.searchDelay !== null ? 4216 settings.searchDelay : 4217 _fnDataSource( settings ) === 'ssp' ? 4218 400 : 4219 0; 4220 4221 var jqFilter = $('input', filter) 4222 .val( previousSearch.sSearch ) 4223 .attr( 'placeholder', language.sSearchPlaceholder ) 4224 .on( 4225 'keyup.DT search.DT input.DT paste.DT cut.DT', 4226 searchDelay ? 4227 _fnThrottle( searchFn, searchDelay ) : 4228 searchFn 4229 ) 4230 .on( 'keypress.DT', function(e) { 4231 /* Prevent form submission */ 4232 if ( e.keyCode == 13 ) { 4233 return false; 4234 } 4235 } ) 4236 .attr('aria-controls', tableId); 4237 4238 // Update the input elements whenever the table is filtered 4239 $(settings.nTable).on( 'search.dt.DT', function ( ev, s ) { 4240 if ( settings === s ) { 4241 // IE9 throws an 'unknown error' if document.activeElement is used 4242 // inside an iframe or frame... 4243 try { 4244 if ( jqFilter[0] !== document.activeElement ) { 4245 jqFilter.val( previousSearch.sSearch ); 4246 } 4247 } 4248 catch ( e ) {} 4249 } 4250 } ); 4251 4252 return filter[0]; 4253 } 4254 4255 4256 /** 4257 * Filter the table using both the global filter and column based filtering 4258 * @param {object} oSettings dataTables settings object 4259 * @param {object} oSearch search information 4260 * @param {int} [iForce] force a research of the master array (1) or not (undefined or 0) 4261 * @memberof DataTable#oApi 4262 */ 4263 function _fnFilterComplete ( oSettings, oInput, iForce ) 4264 { 4265 var oPrevSearch = oSettings.oPreviousSearch; 4266 var aoPrevSearch = oSettings.aoPreSearchCols; 4267 var fnSaveFilter = function ( oFilter ) { 4268 /* Save the filtering values */ 4269 oPrevSearch.sSearch = oFilter.sSearch; 4270 oPrevSearch.bRegex = oFilter.bRegex; 4271 oPrevSearch.bSmart = oFilter.bSmart; 4272 oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive; 4273 }; 4274 var fnRegex = function ( o ) { 4275 // Backwards compatibility with the bEscapeRegex option 4276 return o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex; 4277 }; 4278 4279 // Resolve any column types that are unknown due to addition or invalidation 4280 // @todo As per sort - can this be moved into an event handler? 4281 _fnColumnTypes( oSettings ); 4282 4283 /* In server-side processing all filtering is done by the server, so no point hanging around here */ 4284 if ( _fnDataSource( oSettings ) != 'ssp' ) 4285 { 4286 /* Global filter */ 4287 _fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive ); 4288 fnSaveFilter( oInput ); 4289 4290 /* Now do the individual column filter */ 4291 for ( var i=0 ; i<aoPrevSearch.length ; i++ ) 4292 { 4293 _fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, fnRegex(aoPrevSearch[i]), 4294 aoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive ); 4295 } 4296 4297 /* Custom filtering */ 4298 _fnFilterCustom( oSettings ); 4299 } 4300 else 4301 { 4302 fnSaveFilter( oInput ); 4303 } 4304 4305 /* Tell the draw function we have been filtering */ 4306 oSettings.bFiltered = true; 4307 _fnCallbackFire( oSettings, null, 'search', [oSettings] ); 4308 } 4309 4310 4311 /** 4312 * Apply custom filtering functions 4313 * @param {object} oSettings dataTables settings object 4314 * @memberof DataTable#oApi 4315 */ 4316 function _fnFilterCustom( settings ) 4317 { 4318 var filters = DataTable.ext.search; 4319 var displayRows = settings.aiDisplay; 4320 var row, rowIdx; 4321 4322 for ( var i=0, ien=filters.length ; i<ien ; i++ ) { 4323 var rows = []; 4324 4325 // Loop over each row and see if it should be included 4326 for ( var j=0, jen=displayRows.length ; j<jen ; j++ ) { 4327 rowIdx = displayRows[ j ]; 4328 row = settings.aoData[ rowIdx ]; 4329 4330 if ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) { 4331 rows.push( rowIdx ); 4332 } 4333 } 4334 4335 // So the array reference doesn't break set the results into the 4336 // existing array 4337 displayRows.length = 0; 4338 $.merge( displayRows, rows ); 4339 } 4340 } 4341 4342 4343 /** 4344 * Filter the table on a per-column basis 4345 * @param {object} oSettings dataTables settings object 4346 * @param {string} sInput string to filter on 4347 * @param {int} iColumn column to filter 4348 * @param {bool} bRegex treat search string as a regular expression or not 4349 * @param {bool} bSmart use smart filtering or not 4350 * @param {bool} bCaseInsensitive Do case insenstive matching or not 4351 * @memberof DataTable#oApi 4352 */ 4353 function _fnFilterColumn ( settings, searchStr, colIdx, regex, smart, caseInsensitive ) 4354 { 4355 if ( searchStr === '' ) { 4356 return; 4357 } 4358 4359 var data; 4360 var out = []; 4361 var display = settings.aiDisplay; 4362 var rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive ); 4363 4364 for ( var i=0 ; i<display.length ; i++ ) { 4365 data = settings.aoData[ display[i] ]._aFilterData[ colIdx ]; 4366 4367 if ( rpSearch.test( data ) ) { 4368 out.push( display[i] ); 4369 } 4370 } 4371 4372 settings.aiDisplay = out; 4373 } 4374 4375 4376 /** 4377 * Filter the data table based on user input and draw the table 4378 * @param {object} settings dataTables settings object 4379 * @param {string} input string to filter on 4380 * @param {int} force optional - force a research of the master array (1) or not (undefined or 0) 4381 * @param {bool} regex treat as a regular expression or not 4382 * @param {bool} smart perform smart filtering or not 4383 * @param {bool} caseInsensitive Do case insenstive matching or not 4384 * @memberof DataTable#oApi 4385 */ 4386 function _fnFilter( settings, input, force, regex, smart, caseInsensitive ) 4387 { 4388 var rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive ); 4389 var prevSearch = settings.oPreviousSearch.sSearch; 4390 var displayMaster = settings.aiDisplayMaster; 4391 var display, invalidated, i; 4392 var filtered = []; 4393 4394 // Need to take account of custom filtering functions - always filter 4395 if ( DataTable.ext.search.length !== 0 ) { 4396 force = true; 4397 } 4398 4399 // Check if any of the rows were invalidated 4400 invalidated = _fnFilterData( settings ); 4401 4402 // If the input is blank - we just want the full data set 4403 if ( input.length <= 0 ) { 4404 settings.aiDisplay = displayMaster.slice(); 4405 } 4406 else { 4407 // New search - start from the master array 4408 if ( invalidated || 4409 force || 4410 prevSearch.length > input.length || 4411 input.indexOf(prevSearch) !== 0 || 4412 settings.bSorted // On resort, the display master needs to be 4413 // re-filtered since indexes will have changed 4414 ) { 4415 settings.aiDisplay = displayMaster.slice(); 4416 } 4417 4418 // Search the display array 4419 display = settings.aiDisplay; 4420 4421 for ( i=0 ; i<display.length ; i++ ) { 4422 if ( rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) { 4423 filtered.push( display[i] ); 4424 } 4425 } 4426 4427 settings.aiDisplay = filtered; 4428 } 4429 } 4430 4431 4432 /** 4433 * Build a regular expression object suitable for searching a table 4434 * @param {string} sSearch string to search for 4435 * @param {bool} bRegex treat as a regular expression or not 4436 * @param {bool} bSmart perform smart filtering or not 4437 * @param {bool} bCaseInsensitive Do case insensitive matching or not 4438 * @returns {RegExp} constructed object 4439 * @memberof DataTable#oApi 4440 */ 4441 function _fnFilterCreateSearch( search, regex, smart, caseInsensitive ) 4442 { 4443 search = regex ? 4444 search : 4445 _fnEscapeRegex( search ); 4446 4447 if ( smart ) { 4448 /* For smart filtering we want to allow the search to work regardless of 4449 * word order. We also want double quoted text to be preserved, so word 4450 * order is important - a la google. So this is what we want to 4451 * generate: 4452 * 4453 * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$ 4454 */ 4455 var a = $.map( search.match( /"[^"]+"|[^ ]+/g ) || [''], function ( word ) { 4456 if ( word.charAt(0) === '"' ) { 4457 var m = word.match( /^"(.*)"$/ ); 4458 word = m ? m[1] : word; 4459 } 4460 4461 return word.replace('"', ''); 4462 } ); 4463 4464 search = '^(?=.*?'+a.join( ')(?=.*?' )+').*$'; 4465 } 4466 4467 return new RegExp( search, caseInsensitive ? 'i' : '' ); 4468 } 4469 4470 4471 /** 4472 * Escape a string such that it can be used in a regular expression 4473 * @param {string} sVal string to escape 4474 * @returns {string} escaped string 4475 * @memberof DataTable#oApi 4476 */ 4477 var _fnEscapeRegex = DataTable.util.escapeRegex; 4478 4479 var __filter_div = $('<div>')[0]; 4480 var __filter_div_textContent = __filter_div.textContent !== undefined; 4481 4482 // Update the filtering data for each row if needed (by invalidation or first run) 4483 function _fnFilterData ( settings ) 4484 { 4485 var columns = settings.aoColumns; 4486 var column; 4487 var i, j, ien, jen, filterData, cellData, row; 4488 var fomatters = DataTable.ext.type.search; 4489 var wasInvalidated = false; 4490 4491 for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) { 4492 row = settings.aoData[i]; 4493 4494 if ( ! row._aFilterData ) { 4495 filterData = []; 4496 4497 for ( j=0, jen=columns.length ; j<jen ; j++ ) { 4498 column = columns[j]; 4499 4500 if ( column.bSearchable ) { 4501 cellData = _fnGetCellData( settings, i, j, 'filter' ); 4502 4503 if ( fomatters[ column.sType ] ) { 4504 cellData = fomatters[ column.sType ]( cellData ); 4505 } 4506 4507 // Search in DataTables 1.10 is string based. In 1.11 this 4508 // should be altered to also allow strict type checking. 4509 if ( cellData === null ) { 4510 cellData = ''; 4511 } 4512 4513 if ( typeof cellData !== 'string' && cellData.toString ) { 4514 cellData = cellData.toString(); 4515 } 4516 } 4517 else { 4518 cellData = ''; 4519 } 4520 4521 // If it looks like there is an HTML entity in the string, 4522 // attempt to decode it so sorting works as expected. Note that 4523 // we could use a single line of jQuery to do this, but the DOM 4524 // method used here is much faster http://jsperf.com/html-decode 4525 if ( cellData.indexOf && cellData.indexOf('&') !== -1 ) { 4526 __filter_div.innerHTML = cellData; 4527 cellData = __filter_div_textContent ? 4528 __filter_div.textContent : 4529 __filter_div.innerText; 4530 } 4531 4532 if ( cellData.replace ) { 4533 cellData = cellData.replace(/[\r\n]/g, ''); 4534 } 4535 4536 filterData.push( cellData ); 4537 } 4538 4539 row._aFilterData = filterData; 4540 row._sFilterRow = filterData.join(' '); 4541 wasInvalidated = true; 4542 } 4543 } 4544 4545 return wasInvalidated; 4546 } 4547 4548 4549 /** 4550 * Convert from the internal Hungarian notation to camelCase for external 4551 * interaction 4552 * @param {object} obj Object to convert 4553 * @returns {object} Inverted object 4554 * @memberof DataTable#oApi 4555 */ 4556 function _fnSearchToCamel ( obj ) 4557 { 4558 return { 4559 search: obj.sSearch, 4560 smart: obj.bSmart, 4561 regex: obj.bRegex, 4562 caseInsensitive: obj.bCaseInsensitive 4563 }; 4564 } 4565 4566 4567 4568 /** 4569 * Convert from camelCase notation to the internal Hungarian. We could use the 4570 * Hungarian convert function here, but this is cleaner 4571 * @param {object} obj Object to convert 4572 * @returns {object} Inverted object 4573 * @memberof DataTable#oApi 4574 */ 4575 function _fnSearchToHung ( obj ) 4576 { 4577 return { 4578 sSearch: obj.search, 4579 bSmart: obj.smart, 4580 bRegex: obj.regex, 4581 bCaseInsensitive: obj.caseInsensitive 4582 }; 4583 } 4584 4585 /** 4586 * Generate the node required for the info display 4587 * @param {object} oSettings dataTables settings object 4588 * @returns {node} Information element 4589 * @memberof DataTable#oApi 4590 */ 4591 function _fnFeatureHtmlInfo ( settings ) 4592 { 4593 var 4594 tid = settings.sTableId, 4595 nodes = settings.aanFeatures.i, 4596 n = $('<div/>', { 4597 'class': settings.oClasses.sInfo, 4598 'id': ! nodes ? tid+'_info' : null 4599 } ); 4600 4601 if ( ! nodes ) { 4602 // Update display on each draw 4603 settings.aoDrawCallback.push( { 4604 "fn": _fnUpdateInfo, 4605 "sName": "information" 4606 } ); 4607 4608 n 4609 .attr( 'role', 'status' ) 4610 .attr( 'aria-live', 'polite' ); 4611 4612 // Table is described by our info div 4613 $(settings.nTable).attr( 'aria-describedby', tid+'_info' ); 4614 } 4615 4616 return n[0]; 4617 } 4618 4619 4620 /** 4621 * Update the information elements in the display 4622 * @param {object} settings dataTables settings object 4623 * @memberof DataTable#oApi 4624 */ 4625 function _fnUpdateInfo ( settings ) 4626 { 4627 /* Show information about the table */ 4628 var nodes = settings.aanFeatures.i; 4629 if ( nodes.length === 0 ) { 4630 return; 4631 } 4632 4633 var 4634 lang = settings.oLanguage, 4635 start = settings._iDisplayStart+1, 4636 end = settings.fnDisplayEnd(), 4637 max = settings.fnRecordsTotal(), 4638 total = settings.fnRecordsDisplay(), 4639 out = total ? 4640 lang.sInfo : 4641 lang.sInfoEmpty; 4642 4643 if ( total !== max ) { 4644 /* Record set after filtering */ 4645 out += ' ' + lang.sInfoFiltered; 4646 } 4647 4648 // Convert the macros 4649 out += lang.sInfoPostFix; 4650 out = _fnInfoMacros( settings, out ); 4651 4652 var callback = lang.fnInfoCallback; 4653 if ( callback !== null ) { 4654 out = callback.call( settings.oInstance, 4655 settings, start, end, max, total, out 4656 ); 4657 } 4658 4659 $(nodes).html( out ); 4660 } 4661 4662 4663 function _fnInfoMacros ( settings, str ) 4664 { 4665 // When infinite scrolling, we are always starting at 1. _iDisplayStart is used only 4666 // internally 4667 var 4668 formatter = settings.fnFormatNumber, 4669 start = settings._iDisplayStart+1, 4670 len = settings._iDisplayLength, 4671 vis = settings.fnRecordsDisplay(), 4672 all = len === -1; 4673 4674 return str. 4675 replace(/_START_/g, formatter.call( settings, start ) ). 4676 replace(/_END_/g, formatter.call( settings, settings.fnDisplayEnd() ) ). 4677 replace(/_MAX_/g, formatter.call( settings, settings.fnRecordsTotal() ) ). 4678 replace(/_TOTAL_/g, formatter.call( settings, vis ) ). 4679 replace(/_PAGE_/g, formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ). 4680 replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) ); 4681 } 4682 4683 4684 4685 /** 4686 * Draw the table for the first time, adding all required features 4687 * @param {object} settings dataTables settings object 4688 * @memberof DataTable#oApi 4689 */ 4690 function _fnInitialise ( settings ) 4691 { 4692 var i, iLen, iAjaxStart=settings.iInitDisplayStart; 4693 var columns = settings.aoColumns, column; 4694 var features = settings.oFeatures; 4695 var deferLoading = settings.bDeferLoading; // value modified by the draw 4696 4697 /* Ensure that the table data is fully initialised */ 4698 if ( ! settings.bInitialised ) { 4699 setTimeout( function(){ _fnInitialise( settings ); }, 200 ); 4700 return; 4701 } 4702 4703 /* Show the display HTML options */ 4704 _fnAddOptionsHtml( settings ); 4705 4706 /* Build and draw the header / footer for the table */ 4707 _fnBuildHead( settings ); 4708 _fnDrawHead( settings, settings.aoHeader ); 4709 _fnDrawHead( settings, settings.aoFooter ); 4710 4711 /* Okay to show that something is going on now */ 4712 _fnProcessingDisplay( settings, true ); 4713 4714 /* Calculate sizes for columns */ 4715 if ( features.bAutoWidth ) { 4716 _fnCalculateColumnWidths( settings ); 4717 } 4718 4719 for ( i=0, iLen=columns.length ; i<iLen ; i++ ) { 4720 column = columns[i]; 4721 4722 if ( column.sWidth ) { 4723 column.nTh.style.width = _fnStringToCss( column.sWidth ); 4724 } 4725 } 4726 4727 _fnCallbackFire( settings, null, 'preInit', [settings] ); 4728 4729 // If there is default sorting required - let's do it. The sort function 4730 // will do the drawing for us. Otherwise we draw the table regardless of the 4731 // Ajax source - this allows the table to look initialised for Ajax sourcing 4732 // data (show 'loading' message possibly) 4733 _fnReDraw( settings ); 4734 4735 // Server-side processing init complete is done by _fnAjaxUpdateDraw 4736 var dataSrc = _fnDataSource( settings ); 4737 if ( dataSrc != 'ssp' || deferLoading ) { 4738 // if there is an ajax source load the data 4739 if ( dataSrc == 'ajax' ) { 4740 _fnBuildAjax( settings, [], function(json) { 4741 var aData = _fnAjaxDataSrc( settings, json ); 4742 4743 // Got the data - add it to the table 4744 for ( i=0 ; i<aData.length ; i++ ) { 4745 _fnAddData( settings, aData[i] ); 4746 } 4747 4748 // Reset the init display for cookie saving. We've already done 4749 // a filter, and therefore cleared it before. So we need to make 4750 // it appear 'fresh' 4751 settings.iInitDisplayStart = iAjaxStart; 4752 4753 _fnReDraw( settings ); 4754 4755 _fnProcessingDisplay( settings, false ); 4756 _fnInitComplete( settings, json ); 4757 }, settings ); 4758 } 4759 else { 4760 _fnProcessingDisplay( settings, false ); 4761 _fnInitComplete( settings ); 4762 } 4763 } 4764 } 4765 4766 4767 /** 4768 * Draw the table for the first time, adding all required features 4769 * @param {object} oSettings dataTables settings object 4770 * @param {object} [json] JSON from the server that completed the table, if using Ajax source 4771 * with client-side processing (optional) 4772 * @memberof DataTable#oApi 4773 */ 4774 function _fnInitComplete ( settings, json ) 4775 { 4776 settings._bInitComplete = true; 4777 4778 // When data was added after the initialisation (data or Ajax) we need to 4779 // calculate the column sizing 4780 if ( json || settings.oInit.aaData ) { 4781 _fnAdjustColumnSizing( settings ); 4782 } 4783 4784 _fnCallbackFire( settings, null, 'plugin-init', [settings, json] ); 4785 _fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] ); 4786 } 4787 4788 4789 function _fnLengthChange ( settings, val ) 4790 { 4791 var len = parseInt( val, 10 ); 4792 settings._iDisplayLength = len; 4793 4794 _fnLengthOverflow( settings ); 4795 4796 // Fire length change event 4797 _fnCallbackFire( settings, null, 'length', [settings, len] ); 4798 } 4799 4800 4801 /** 4802 * Generate the node required for user display length changing 4803 * @param {object} settings dataTables settings object 4804 * @returns {node} Display length feature node 4805 * @memberof DataTable#oApi 4806 */ 4807 function _fnFeatureHtmlLength ( settings ) 4808 { 4809 var 4810 classes = settings.oClasses, 4811 tableId = settings.sTableId, 4812 menu = settings.aLengthMenu, 4813 d2 = $.isArray( menu[0] ), 4814 lengths = d2 ? menu[0] : menu, 4815 language = d2 ? menu[1] : menu; 4816 4817 var select = $('<select/>', { 4818 'name': tableId+'_length', 4819 'aria-controls': tableId, 4820 'class': classes.sLengthSelect 4821 } ); 4822 4823 for ( var i=0, ien=lengths.length ; i<ien ; i++ ) { 4824 select[0][ i ] = new Option( 4825 typeof language[i] === 'number' ? 4826 settings.fnFormatNumber( language[i] ) : 4827 language[i], 4828 lengths[i] 4829 ); 4830 } 4831 4832 var div = $('<div><label/></div>').addClass( classes.sLength ); 4833 if ( ! settings.aanFeatures.l ) { 4834 div[0].id = tableId+'_length'; 4835 } 4836 4837 div.children().append( 4838 settings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML ) 4839 ); 4840 4841 // Can't use `select` variable as user might provide their own and the 4842 // reference is broken by the use of outerHTML 4843 $('select', div) 4844 .val( settings._iDisplayLength ) 4845 .on( 'change.DT', function(e) { 4846 _fnLengthChange( settings, $(this).val() ); 4847 _fnDraw( settings ); 4848 } ); 4849 4850 // Update node value whenever anything changes the table's length 4851 $(settings.nTable).on( 'length.dt.DT', function (e, s, len) { 4852 if ( settings === s ) { 4853 $('select', div).val( len ); 4854 } 4855 } ); 4856 4857 return div[0]; 4858 } 4859 4860 4861 4862 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 4863 * Note that most of the paging logic is done in 4864 * DataTable.ext.pager 4865 */ 4866 4867 /** 4868 * Generate the node required for default pagination 4869 * @param {object} oSettings dataTables settings object 4870 * @returns {node} Pagination feature node 4871 * @memberof DataTable#oApi 4872 */ 4873 function _fnFeatureHtmlPaginate ( settings ) 4874 { 4875 var 4876 type = settings.sPaginationType, 4877 plugin = DataTable.ext.pager[ type ], 4878 modern = typeof plugin === 'function', 4879 redraw = function( settings ) { 4880 _fnDraw( settings ); 4881 }, 4882 node = $('<div/>').addClass( settings.oClasses.sPaging + type )[0], 4883 features = settings.aanFeatures; 4884 4885 if ( ! modern ) { 4886 plugin.fnInit( settings, node, redraw ); 4887 } 4888 4889 /* Add a draw callback for the pagination on first instance, to update the paging display */ 4890 if ( ! features.p ) 4891 { 4892 node.id = settings.sTableId+'_paginate'; 4893 4894 settings.aoDrawCallback.push( { 4895 "fn": function( settings ) { 4896 if ( modern ) { 4897 var 4898 start = settings._iDisplayStart, 4899 len = settings._iDisplayLength, 4900 visRecords = settings.fnRecordsDisplay(), 4901 all = len === -1, 4902 page = all ? 0 : Math.ceil( start / len ), 4903 pages = all ? 1 : Math.ceil( visRecords / len ), 4904 buttons = plugin(page, pages), 4905 i, ien; 4906 4907 for ( i=0, ien=features.p.length ; i<ien ; i++ ) { 4908 _fnRenderer( settings, 'pageButton' )( 4909 settings, features.p[i], i, buttons, page, pages 4910 ); 4911 } 4912 } 4913 else { 4914 plugin.fnUpdate( settings, redraw ); 4915 } 4916 }, 4917 "sName": "pagination" 4918 } ); 4919 } 4920 4921 return node; 4922 } 4923 4924 4925 /** 4926 * Alter the display settings to change the page 4927 * @param {object} settings DataTables settings object 4928 * @param {string|int} action Paging action to take: "first", "previous", 4929 * "next" or "last" or page number to jump to (integer) 4930 * @param [bool] redraw Automatically draw the update or not 4931 * @returns {bool} true page has changed, false - no change 4932 * @memberof DataTable#oApi 4933 */ 4934 function _fnPageChange ( settings, action, redraw ) 4935 { 4936 var 4937 start = settings._iDisplayStart, 4938 len = settings._iDisplayLength, 4939 records = settings.fnRecordsDisplay(); 4940 4941 if ( records === 0 || len === -1 ) 4942 { 4943 start = 0; 4944 } 4945 else if ( typeof action === "number" ) 4946 { 4947 start = action * len; 4948 4949 if ( start > records ) 4950 { 4951 start = 0; 4952 } 4953 } 4954 else if ( action == "first" ) 4955 { 4956 start = 0; 4957 } 4958 else if ( action == "previous" ) 4959 { 4960 start = len >= 0 ? 4961 start - len : 4962 0; 4963 4964 if ( start < 0 ) 4965 { 4966 start = 0; 4967 } 4968 } 4969 else if ( action == "next" ) 4970 { 4971 if ( start + len < records ) 4972 { 4973 start += len; 4974 } 4975 } 4976 else if ( action == "last" ) 4977 { 4978 start = Math.floor( (records-1) / len) * len; 4979 } 4980 else 4981 { 4982 _fnLog( settings, 0, "Unknown paging action: "+action, 5 ); 4983 } 4984 4985 var changed = settings._iDisplayStart !== start; 4986 settings._iDisplayStart = start; 4987 4988 if ( changed ) { 4989 _fnCallbackFire( settings, null, 'page', [settings] ); 4990 4991 if ( redraw ) { 4992 _fnDraw( settings ); 4993 } 4994 } 4995 4996 return changed; 4997 } 4998 4999 5000 5001 /** 5002 * Generate the node required for the processing node 5003 * @param {object} settings dataTables settings object 5004 * @returns {node} Processing element 5005 * @memberof DataTable#oApi 5006 */ 5007 function _fnFeatureHtmlProcessing ( settings ) 5008 { 5009 return $('<div/>', { 5010 'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null, 5011 'class': settings.oClasses.sProcessing 5012 } ) 5013 .html( settings.oLanguage.sProcessing ) 5014 .insertBefore( settings.nTable )[0]; 5015 } 5016 5017 5018 /** 5019 * Display or hide the processing indicator 5020 * @param {object} settings dataTables settings object 5021 * @param {bool} show Show the processing indicator (true) or not (false) 5022 * @memberof DataTable#oApi 5023 */ 5024 function _fnProcessingDisplay ( settings, show ) 5025 { 5026 if ( settings.oFeatures.bProcessing ) { 5027 $(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' ); 5028 } 5029 5030 _fnCallbackFire( settings, null, 'processing', [settings, show] ); 5031 } 5032 5033 /** 5034 * Add any control elements for the table - specifically scrolling 5035 * @param {object} settings dataTables settings object 5036 * @returns {node} Node to add to the DOM 5037 * @memberof DataTable#oApi 5038 */ 5039 function _fnFeatureHtmlTable ( settings ) 5040 { 5041 var table = $(settings.nTable); 5042 5043 // Add the ARIA grid role to the table 5044 table.attr( 'role', 'grid' ); 5045 5046 // Scrolling from here on in 5047 var scroll = settings.oScroll; 5048 5049 if ( scroll.sX === '' && scroll.sY === '' ) { 5050 return settings.nTable; 5051 } 5052 5053 var scrollX = scroll.sX; 5054 var scrollY = scroll.sY; 5055 var classes = settings.oClasses; 5056 var caption = table.children('caption'); 5057 var captionSide = caption.length ? caption[0]._captionSide : null; 5058 var headerClone = $( table[0].cloneNode(false) ); 5059 var footerClone = $( table[0].cloneNode(false) ); 5060 var footer = table.children('tfoot'); 5061 var _div = '<div/>'; 5062 var size = function ( s ) { 5063 return !s ? null : _fnStringToCss( s ); 5064 }; 5065 5066 if ( ! footer.length ) { 5067 footer = null; 5068 } 5069 5070 /* 5071 * The HTML structure that we want to generate in this function is: 5072 * div - scroller 5073 * div - scroll head 5074 * div - scroll head inner 5075 * table - scroll head table 5076 * thead - thead 5077 * div - scroll body 5078 * table - table (master table) 5079 * thead - thead clone for sizing 5080 * tbody - tbody 5081 * div - scroll foot 5082 * div - scroll foot inner 5083 * table - scroll foot table 5084 * tfoot - tfoot 5085 */ 5086 var scroller = $( _div, { 'class': classes.sScrollWrapper } ) 5087 .append( 5088 $(_div, { 'class': classes.sScrollHead } ) 5089 .css( { 5090 overflow: 'hidden', 5091 position: 'relative', 5092 border: 0, 5093 width: scrollX ? size(scrollX) : '100%' 5094 } ) 5095 .append( 5096 $(_div, { 'class': classes.sScrollHeadInner } ) 5097 .css( { 5098 'box-sizing': 'content-box', 5099 width: scroll.sXInner || '100%' 5100 } ) 5101 .append( 5102 headerClone 5103 .removeAttr('id') 5104 .css( 'margin-left', 0 ) 5105 .append( captionSide === 'top' ? caption : null ) 5106 .append( 5107 table.children('thead') 5108 ) 5109 ) 5110 ) 5111 ) 5112 .append( 5113 $(_div, { 'class': classes.sScrollBody } ) 5114 .css( { 5115 position: 'relative', 5116 overflow: 'auto', 5117 width: size( scrollX ) 5118 } ) 5119 .append( table ) 5120 ); 5121 5122 if ( footer ) { 5123 scroller.append( 5124 $(_div, { 'class': classes.sScrollFoot } ) 5125 .css( { 5126 overflow: 'hidden', 5127 border: 0, 5128 width: scrollX ? size(scrollX) : '100%' 5129 } ) 5130 .append( 5131 $(_div, { 'class': classes.sScrollFootInner } ) 5132 .append( 5133 footerClone 5134 .removeAttr('id') 5135 .css( 'margin-left', 0 ) 5136 .append( captionSide === 'bottom' ? caption : null ) 5137 .append( 5138 table.children('tfoot') 5139 ) 5140 ) 5141 ) 5142 ); 5143 } 5144 5145 var children = scroller.children(); 5146 var scrollHead = children[0]; 5147 var scrollBody = children[1]; 5148 var scrollFoot = footer ? children[2] : null; 5149 5150 // When the body is scrolled, then we also want to scroll the headers 5151 if ( scrollX ) { 5152 $(scrollBody).on( 'scroll.DT', function (e) { 5153 var scrollLeft = this.scrollLeft; 5154 5155 scrollHead.scrollLeft = scrollLeft; 5156 5157 if ( footer ) { 5158 scrollFoot.scrollLeft = scrollLeft; 5159 } 5160 } ); 5161 } 5162 5163 $(scrollBody).css( 5164 scrollY && scroll.bCollapse ? 'max-height' : 'height', 5165 scrollY 5166 ); 5167 5168 settings.nScrollHead = scrollHead; 5169 settings.nScrollBody = scrollBody; 5170 settings.nScrollFoot = scrollFoot; 5171 5172 // On redraw - align columns 5173 settings.aoDrawCallback.push( { 5174 "fn": _fnScrollDraw, 5175 "sName": "scrolling" 5176 } ); 5177 5178 return scroller[0]; 5179 } 5180 5181 5182 5183 /** 5184 * Update the header, footer and body tables for resizing - i.e. column 5185 * alignment. 5186 * 5187 * Welcome to the most horrible function DataTables. The process that this 5188 * function follows is basically: 5189 * 1. Re-create the table inside the scrolling div 5190 * 2. Take live measurements from the DOM 5191 * 3. Apply the measurements to align the columns 5192 * 4. Clean up 5193 * 5194 * @param {object} settings dataTables settings object 5195 * @memberof DataTable#oApi 5196 */ 5197 function _fnScrollDraw ( settings ) 5198 { 5199 // Given that this is such a monster function, a lot of variables are use 5200 // to try and keep the minimised size as small as possible 5201 var 5202 scroll = settings.oScroll, 5203 scrollX = scroll.sX, 5204 scrollXInner = scroll.sXInner, 5205 scrollY = scroll.sY, 5206 barWidth = scroll.iBarWidth, 5207 divHeader = $(settings.nScrollHead), 5208 divHeaderStyle = divHeader[0].style, 5209 divHeaderInner = divHeader.children('div'), 5210 divHeaderInnerStyle = divHeaderInner[0].style, 5211 divHeaderTable = divHeaderInner.children('table'), 5212 divBodyEl = settings.nScrollBody, 5213 divBody = $(divBodyEl), 5214 divBodyStyle = divBodyEl.style, 5215 divFooter = $(settings.nScrollFoot), 5216 divFooterInner = divFooter.children('div'), 5217 divFooterTable = divFooterInner.children('table'), 5218 header = $(settings.nTHead), 5219 table = $(settings.nTable), 5220 tableEl = table[0], 5221 tableStyle = tableEl.style, 5222 footer = settings.nTFoot ? $(settings.nTFoot) : null, 5223 browser = settings.oBrowser, 5224 ie67 = browser.bScrollOversize, 5225 dtHeaderCells = _pluck( settings.aoColumns, 'nTh' ), 5226 headerTrgEls, footerTrgEls, 5227 headerSrcEls, footerSrcEls, 5228 headerCopy, footerCopy, 5229 headerWidths=[], footerWidths=[], 5230 headerContent=[], footerContent=[], 5231 idx, correction, sanityWidth, 5232 zeroOut = function(nSizer) { 5233 var style = nSizer.style; 5234 style.paddingTop = "0"; 5235 style.paddingBottom = "0"; 5236 style.borderTopWidth = "0"; 5237 style.borderBottomWidth = "0"; 5238 style.height = 0; 5239 }; 5240 5241 // If the scrollbar visibility has changed from the last draw, we need to 5242 // adjust the column sizes as the table width will have changed to account 5243 // for the scrollbar 5244 var scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight; 5245 5246 if ( settings.scrollBarVis !== scrollBarVis && settings.scrollBarVis !== undefined ) { 5247 settings.scrollBarVis = scrollBarVis; 5248 _fnAdjustColumnSizing( settings ); 5249 return; // adjust column sizing will call this function again 5250 } 5251 else { 5252 settings.scrollBarVis = scrollBarVis; 5253 } 5254 5255 /* 5256 * 1. Re-create the table inside the scrolling div 5257 */ 5258 5259 // Remove the old minimised thead and tfoot elements in the inner table 5260 table.children('thead, tfoot').remove(); 5261 5262 if ( footer ) { 5263 footerCopy = footer.clone().prependTo( table ); 5264 footerTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized 5265 footerSrcEls = footerCopy.find('tr'); 5266 } 5267 5268 // Clone the current header and footer elements and then place it into the inner table 5269 headerCopy = header.clone().prependTo( table ); 5270 headerTrgEls = header.find('tr'); // original header is in its own table 5271 headerSrcEls = headerCopy.find('tr'); 5272 headerCopy.find('th, td').removeAttr('tabindex'); 5273 5274 5275 /* 5276 * 2. Take live measurements from the DOM - do not alter the DOM itself! 5277 */ 5278 5279 // Remove old sizing and apply the calculated column widths 5280 // Get the unique column headers in the newly created (cloned) header. We want to apply the 5281 // calculated sizes to this header 5282 if ( ! scrollX ) 5283 { 5284 divBodyStyle.width = '100%'; 5285 divHeader[0].style.width = '100%'; 5286 } 5287 5288 $.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) { 5289 idx = _fnVisibleToColumnIndex( settings, i ); 5290 el.style.width = settings.aoColumns[idx].sWidth; 5291 } ); 5292 5293 if ( footer ) { 5294 _fnApplyToChildren( function(n) { 5295 n.style.width = ""; 5296 }, footerSrcEls ); 5297 } 5298 5299 // Size the table as a whole 5300 sanityWidth = table.outerWidth(); 5301 if ( scrollX === "" ) { 5302 // No x scrolling 5303 tableStyle.width = "100%"; 5304 5305 // IE7 will make the width of the table when 100% include the scrollbar 5306 // - which is shouldn't. When there is a scrollbar we need to take this 5307 // into account. 5308 if ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight || 5309 divBody.css('overflow-y') == "scroll") 5310 ) { 5311 tableStyle.width = _fnStringToCss( table.outerWidth() - barWidth); 5312 } 5313 5314 // Recalculate the sanity width 5315 sanityWidth = table.outerWidth(); 5316 } 5317 else if ( scrollXInner !== "" ) { 5318 // legacy x scroll inner has been given - use it 5319 tableStyle.width = _fnStringToCss(scrollXInner); 5320 5321 // Recalculate the sanity width 5322 sanityWidth = table.outerWidth(); 5323 } 5324 5325 // Hidden header should have zero height, so remove padding and borders. Then 5326 // set the width based on the real headers 5327 5328 // Apply all styles in one pass 5329 _fnApplyToChildren( zeroOut, headerSrcEls ); 5330 5331 // Read all widths in next pass 5332 _fnApplyToChildren( function(nSizer) { 5333 headerContent.push( nSizer.innerHTML ); 5334 headerWidths.push( _fnStringToCss( $(nSizer).css('width') ) ); 5335 }, headerSrcEls ); 5336 5337 // Apply all widths in final pass 5338 _fnApplyToChildren( function(nToSize, i) { 5339 // Only apply widths to the DataTables detected header cells - this 5340 // prevents complex headers from having contradictory sizes applied 5341 if ( $.inArray( nToSize, dtHeaderCells ) !== -1 ) { 5342 nToSize.style.width = headerWidths[i]; 5343 } 5344 }, headerTrgEls ); 5345 5346 $(headerSrcEls).height(0); 5347 5348 /* Same again with the footer if we have one */ 5349 if ( footer ) 5350 { 5351 _fnApplyToChildren( zeroOut, footerSrcEls ); 5352 5353 _fnApplyToChildren( function(nSizer) { 5354 footerContent.push( nSizer.innerHTML ); 5355 footerWidths.push( _fnStringToCss( $(nSizer).css('width') ) ); 5356 }, footerSrcEls ); 5357 5358 _fnApplyToChildren( function(nToSize, i) { 5359 nToSize.style.width = footerWidths[i]; 5360 }, footerTrgEls ); 5361 5362 $(footerSrcEls).height(0); 5363 } 5364 5365 5366 /* 5367 * 3. Apply the measurements 5368 */ 5369 5370 // "Hide" the header and footer that we used for the sizing. We need to keep 5371 // the content of the cell so that the width applied to the header and body 5372 // both match, but we want to hide it completely. We want to also fix their 5373 // width to what they currently are 5374 _fnApplyToChildren( function(nSizer, i) { 5375 nSizer.innerHTML = '<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+headerContent[i]+'</div>'; 5376 nSizer.style.width = headerWidths[i]; 5377 }, headerSrcEls ); 5378 5379 if ( footer ) 5380 { 5381 _fnApplyToChildren( function(nSizer, i) { 5382 nSizer.innerHTML = '<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+footerContent[i]+'</div>'; 5383 nSizer.style.width = footerWidths[i]; 5384 }, footerSrcEls ); 5385 } 5386 5387 // Sanity check that the table is of a sensible width. If not then we are going to get 5388 // misalignment - try to prevent this by not allowing the table to shrink below its min width 5389 if ( table.outerWidth() < sanityWidth ) 5390 { 5391 // The min width depends upon if we have a vertical scrollbar visible or not */ 5392 correction = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight || 5393 divBody.css('overflow-y') == "scroll")) ? 5394 sanityWidth+barWidth : 5395 sanityWidth; 5396 5397 // IE6/7 are a law unto themselves... 5398 if ( ie67 && (divBodyEl.scrollHeight > 5399 divBodyEl.offsetHeight || divBody.css('overflow-y') == "scroll") 5400 ) { 5401 tableStyle.width = _fnStringToCss( correction-barWidth ); 5402 } 5403 5404 // And give the user a warning that we've stopped the table getting too small 5405 if ( scrollX === "" || scrollXInner !== "" ) { 5406 _fnLog( settings, 1, 'Possible column misalignment', 6 ); 5407 } 5408 } 5409 else 5410 { 5411 correction = '100%'; 5412 } 5413 5414 // Apply to the container elements 5415 divBodyStyle.width = _fnStringToCss( correction ); 5416 divHeaderStyle.width = _fnStringToCss( correction ); 5417 5418 if ( footer ) { 5419 settings.nScrollFoot.style.width = _fnStringToCss( correction ); 5420 } 5421 5422 5423 /* 5424 * 4. Clean up 5425 */ 5426 if ( ! scrollY ) { 5427 /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting 5428 * the scrollbar height from the visible display, rather than adding it on. We need to 5429 * set the height in order to sort this. Don't want to do it in any other browsers. 5430 */ 5431 if ( ie67 ) { 5432 divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth ); 5433 } 5434 } 5435 5436 /* Finally set the width's of the header and footer tables */ 5437 var iOuterWidth = table.outerWidth(); 5438 divHeaderTable[0].style.width = _fnStringToCss( iOuterWidth ); 5439 divHeaderInnerStyle.width = _fnStringToCss( iOuterWidth ); 5440 5441 // Figure out if there are scrollbar present - if so then we need a the header and footer to 5442 // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar) 5443 var bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll"; 5444 var padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' ); 5445 divHeaderInnerStyle[ padding ] = bScrolling ? barWidth+"px" : "0px"; 5446 5447 if ( footer ) { 5448 divFooterTable[0].style.width = _fnStringToCss( iOuterWidth ); 5449 divFooterInner[0].style.width = _fnStringToCss( iOuterWidth ); 5450 divFooterInner[0].style[padding] = bScrolling ? barWidth+"px" : "0px"; 5451 } 5452 5453 // Correct DOM ordering for colgroup - comes before the thead 5454 table.children('colgroup').insertBefore( table.children('thead') ); 5455 5456 /* Adjust the position of the header in case we loose the y-scrollbar */ 5457 divBody.scroll(
vendor: 11,594 bytes, lines 5457-5855
5457); 5458 5459 // If sorting or filtering has occurred, jump the scrolling back to the top 5460 // only if we aren't holding the position 5461 if ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) { 5462 divBodyEl.scrollTop = 0; 5463 } 5464 } 5465 5466 5467 5468 /** 5469 * Apply a given function to the display child nodes of an element array (typically 5470 * TD children of TR rows 5471 * @param {function} fn Method to apply to the objects 5472 * @param array {nodes} an1 List of elements to look through for display children 5473 * @param array {nodes} an2 Another list (identical structure to the first) - optional 5474 * @memberof DataTable#oApi 5475 */ 5476 function _fnApplyToChildren( fn, an1, an2 ) 5477 { 5478 var index=0, i=0, iLen=an1.length; 5479 var nNode1, nNode2; 5480 5481 while ( i < iLen ) { 5482 nNode1 = an1[i].firstChild; 5483 nNode2 = an2 ? an2[i].firstChild : null; 5484 5485 while ( nNode1 ) { 5486 if ( nNode1.nodeType === 1 ) { 5487 if ( an2 ) { 5488 fn( nNode1, nNode2, index ); 5489 } 5490 else { 5491 fn( nNode1, index ); 5492 } 5493 5494 index++; 5495 } 5496 5497 nNode1 = nNode1.nextSibling; 5498 nNode2 = an2 ? nNode2.nextSibling : null; 5499 } 5500 5501 i++; 5502 } 5503 } 5504 5505 5506 5507 var __re_html_remove = /<.*?>/g; 5508 5509 5510 /** 5511 * Calculate the width of columns for the table 5512 * @param {object} oSettings dataTables settings object 5513 * @memberof DataTable#oApi 5514 */ 5515 function _fnCalculateColumnWidths ( oSettings ) 5516 { 5517 var 5518 table = oSettings.nTable, 5519 columns = oSettings.aoColumns, 5520 scroll = oSettings.oScroll, 5521 scrollY = scroll.sY, 5522 scrollX = scroll.sX, 5523 scrollXInner = scroll.sXInner, 5524 columnCount = columns.length, 5525 visibleColumns = _fnGetColumns( oSettings, 'bVisible' ), 5526 headerCells = $('th', oSettings.nTHead), 5527 tableWidthAttr = table.getAttribute('width'), // from DOM element 5528 tableContainer = table.parentNode, 5529 userInputs = false, 5530 i, column, columnIdx, width, outerWidth, 5531 browser = oSettings.oBrowser, 5532 ie67 = browser.bScrollOversize; 5533 5534 var styleWidth = table.style.width; 5535 if ( styleWidth && styleWidth.indexOf('%') !== -1 ) { 5536 tableWidthAttr = styleWidth; 5537 } 5538 5539 /* Convert any user input sizes into pixel sizes */ 5540 for ( i=0 ; i<visibleColumns.length ; i++ ) { 5541 column = columns[ visibleColumns[i] ]; 5542 5543 if ( column.sWidth !== null ) { 5544 column.sWidth = _fnConvertToWidth( column.sWidthOrig, tableContainer ); 5545 5546 userInputs = true; 5547 } 5548 } 5549 5550 /* If the number of columns in the DOM equals the number that we have to 5551 * process in DataTables, then we can use the offsets that are created by 5552 * the web- browser. No custom sizes can be set in order for this to happen, 5553 * nor scrolling used 5554 */ 5555 if ( ie67 || ! userInputs && ! scrollX && ! scrollY && 5556 columnCount == _fnVisbleColumns( oSettings ) && 5557 columnCount == headerCells.length 5558 ) { 5559 for ( i=0 ; i<columnCount ; i++ ) { 5560 var colIdx = _fnVisibleToColumnIndex( oSettings, i ); 5561 5562 if ( colIdx !== null ) { 5563 columns[ colIdx ].sWidth = _fnStringToCss( headerCells.eq(i).width() ); 5564 } 5565 } 5566 } 5567 else 5568 { 5569 // Otherwise construct a single row, worst case, table with the widest 5570 // node in the data, assign any user defined widths, then insert it into 5571 // the DOM and allow the browser to do all the hard work of calculating 5572 // table widths 5573 var tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table 5574 .css( 'visibility', 'hidden' ) 5575 .removeAttr( 'id' ); 5576 5577 // Clean up the table body 5578 tmpTable.find('tbody tr').remove(); 5579 var tr = $('<tr/>').appendTo( tmpTable.find('tbody') ); 5580 5581 // Clone the table header and footer - we can't use the header / footer 5582 // from the cloned table, since if scrolling is active, the table's 5583 // real header and footer are contained in different table tags 5584 tmpTable.find('thead, tfoot').remove(); 5585 tmpTable 5586 .append( $(oSettings.nTHead).clone() ) 5587 .append( $(oSettings.nTFoot).clone() ); 5588 5589 // Remove any assigned widths from the footer (from scrolling) 5590 tmpTable.find('tfoot th, tfoot td').css('width', ''); 5591 5592 // Apply custom sizing to the cloned header 5593 headerCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] ); 5594 5595 for ( i=0 ; i<visibleColumns.length ; i++ ) { 5596 column = columns[ visibleColumns[i] ]; 5597 5598 headerCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ? 5599 _fnStringToCss( column.sWidthOrig ) : 5600 ''; 5601 5602 // For scrollX we need to force the column width otherwise the 5603 // browser will collapse it. If this width is smaller than the 5604 // width the column requires, then it will have no effect 5605 if ( column.sWidthOrig && scrollX ) { 5606 $( headerCells[i] ).append( $('<div/>').css( { 5607 width: column.sWidthOrig, 5608 margin: 0, 5609 padding: 0, 5610 border: 0, 5611 height: 1 5612 } ) ); 5613 } 5614 } 5615 5616 // Find the widest cell for each column and put it into the table 5617 if ( oSettings.aoData.length ) { 5618 for ( i=0 ; i<visibleColumns.length ; i++ ) { 5619 columnIdx = visibleColumns[i]; 5620 column = columns[ columnIdx ]; 5621 5622 $( _fnGetWidestNode( oSettings, columnIdx ) ) 5623 .clone( false ) 5624 .append( column.sContentPadding ) 5625 .appendTo( tr ); 5626 } 5627 } 5628 5629 // Tidy the temporary table - remove name attributes so there aren't 5630 // duplicated in the dom (radio elements for example) 5631 $('[name]', tmpTable).removeAttr('name'); 5632 5633 // Table has been built, attach to the document so we can work with it. 5634 // A holding element is used, positioned at the top of the container 5635 // with minimal height, so it has no effect on if the container scrolls 5636 // or not. Otherwise it might trigger scrolling when it actually isn't 5637 // needed 5638 var holder = $('<div/>').css( scrollX || scrollY ? 5639 { 5640 position: 'absolute', 5641 top: 0, 5642 left: 0, 5643 height: 1, 5644 right: 0, 5645 overflow: 'hidden' 5646 } : 5647 {} 5648 ) 5649 .append( tmpTable ) 5650 .appendTo( tableContainer ); 5651 5652 // When scrolling (X or Y) we want to set the width of the table as 5653 // appropriate. However, when not scrolling leave the table width as it 5654 // is. This results in slightly different, but I think correct behaviour 5655 if ( scrollX && scrollXInner ) { 5656 tmpTable.width( scrollXInner ); 5657 } 5658 else if ( scrollX ) { 5659 tmpTable.css( 'width', 'auto' ); 5660 tmpTable.removeAttr('width'); 5661 5662 // If there is no width attribute or style, then allow the table to 5663 // collapse 5664 if ( tmpTable.width() < tableContainer.clientWidth && tableWidthAttr ) { 5665 tmpTable.width( tableContainer.clientWidth ); 5666 } 5667 } 5668 else if ( scrollY ) { 5669 tmpTable.width( tableContainer.clientWidth ); 5670 } 5671 else if ( tableWidthAttr ) { 5672 tmpTable.width( tableWidthAttr ); 5673 } 5674 5675 // Get the width of each column in the constructed table - we need to 5676 // know the inner width (so it can be assigned to the other table's 5677 // cells) and the outer width so we can calculate the full width of the 5678 // table. This is safe since DataTables requires a unique cell for each 5679 // column, but if ever a header can span multiple columns, this will 5680 // need to be modified. 5681 var total = 0; 5682 for ( i=0 ; i<visibleColumns.length ; i++ ) { 5683 var cell = $(headerCells[i]); 5684 var border = cell.outerWidth() - cell.width(); 5685 5686 // Use getBounding... where possible (not IE8-) because it can give 5687 // sub-pixel accuracy, which we then want to round up! 5688 var bounding = browser.bBounding ? 5689 Math.ceil( headerCells[i].getBoundingClientRect().width ) : 5690 cell.outerWidth(); 5691 5692 // Total is tracked to remove any sub-pixel errors as the outerWidth 5693 // of the table might not equal the total given here (IE!). 5694 total += bounding; 5695 5696 // Width for each column to use 5697 columns[ visibleColumns[i] ].sWidth = _fnStringToCss( bounding - border ); 5698 } 5699 5700 table.style.width = _fnStringToCss( total ); 5701 5702 // Finished with the table - ditch it 5703 holder.remove(); 5704 } 5705 5706 // If there is a width attr, we want to attach an event listener which 5707 // allows the table sizing to automatically adjust when the window is 5708 // resized. Use the width attr rather than CSS, since we can't know if the 5709 // CSS is a relative value or absolute - DOM read is always px. 5710 if ( tableWidthAttr ) { 5711 table.style.width = _fnStringToCss( tableWidthAttr ); 5712 } 5713 5714 if ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) { 5715 var bindResize = function () { 5716 $(window).on('resize.DT-'+oSettings.sInstance, _fnThrottle( function () { 5717 _fnAdjustColumnSizing( oSettings ); 5718 } ) ); 5719 }; 5720 5721 // IE6/7 will crash if we bind a resize event handler on page load. 5722 // To be removed in 1.11 which drops IE6/7 support 5723 if ( ie67 ) { 5724 setTimeout( bindResize, 1000 ); 5725 } 5726 else { 5727 bindResize(); 5728 } 5729 5730 oSettings._reszEvt = true; 5731 } 5732 } 5733 5734 5735 /** 5736 * Throttle the calls to a function. Arguments and context are maintained for 5737 * the throttled function 5738 * @param {function} fn Function to be called 5739 * @param {int} [freq=200] call frequency in mS 5740 * @returns {function} wrapped function 5741 * @memberof DataTable#oApi 5742 */ 5743 var _fnThrottle = DataTable.util.throttle; 5744 5745 5746 /** 5747 * Convert a CSS unit width to pixels (e.g. 2em) 5748 * @param {string} width width to be converted 5749 * @param {node} parent parent to get the with for (required for relative widths) - optional 5750 * @returns {int} width in pixels 5751 * @memberof DataTable#oApi 5752 */ 5753 function _fnConvertToWidth ( width, parent ) 5754 { 5755 if ( ! width ) { 5756 return 0; 5757 } 5758 5759 var n = $('<div/>') 5760 .css( 'width', _fnStringToCss( width ) ) 5761 .appendTo( parent || document.body ); 5762 5763 var val = n[0].offsetWidth; 5764 n.remove(); 5765 5766 return val; 5767 } 5768 5769 5770 /** 5771 * Get the widest node 5772 * @param {object} settings dataTables settings object 5773 * @param {int} colIdx column of interest 5774 * @returns {node} widest table node 5775 * @memberof DataTable#oApi 5776 */ 5777 function _fnGetWidestNode( settings, colIdx ) 5778 { 5779 var idx = _fnGetMaxLenString( settings, colIdx ); 5780 if ( idx < 0 ) { 5781 return null; 5782 } 5783 5784 var data = settings.aoData[ idx ]; 5785 return ! data.nTr ? // Might not have been created when deferred rendering 5786 $('<td/>').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] : 5787 data.anCells[ colIdx ]; 5788 } 5789 5790 5791 /** 5792 * Get the maximum strlen for each data column 5793 * @param {object} settings dataTables settings object 5794 * @param {int} colIdx column of interest 5795 * @returns {string} max string length for each column 5796 * @memberof DataTable#oApi 5797 */ 5798 function _fnGetMaxLenString( settings, colIdx ) 5799 { 5800 var s, max=-1, maxIdx = -1; 5801 5802 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) { 5803 s = _fnGetCellData( settings, i, colIdx, 'display' )+''; 5804 s = s.replace( __re_html_remove, '' ); 5805 s = s.replace( / /g, ' ' ); 5806 5807 if ( s.length > max ) { 5808 max = s.length; 5809 maxIdx = i; 5810 } 5811 } 5812 5813 return maxIdx; 5814 } 5815 5816 5817 /** 5818 * Append a CSS unit (only if required) to a string 5819 * @param {string} value to css-ify 5820 * @returns {string} value with css unit 5821 * @memberof DataTable#oApi 5822 */ 5823 function _fnStringToCss( s ) 5824 { 5825 if ( s === null ) { 5826 return '0px'; 5827 } 5828 5829 if ( typeof s == 'number' ) { 5830 return s < 0 ? 5831 '0px' : 5832 s+'px'; 5833 } 5834 5835 // Check it has a unit character already 5836 return s.match(/\d$/) ? 5837 s+'px' : 5838 s; 5839 } 5840 5841 5842 5843 function _fnSortFlatten ( settings ) 5844 { 5845 var 5846 i, iLen, k, kLen, 5847 aSort = [], 5848 aiOrig = [], 5849 aoColumns = settings.aoColumns, 5850 aDataSort, iCol, sType, srcCol, 5851 fixed = settings.aaSortingFixed, 5852 fixedObj = $.isPlainObject( fixed ), 5853 nestedSort = [], 5854 add = function ( a ) { 5855 if ( a.length && !
vendor: 39,755 bytes, lines 5855-7376
5855$.isArray( a[0] ) ) { 5856 // 1D array 5857 nestedSort.push( a ); 5858 } 5859 else { 5860 // 2D array 5861 $.merge( nestedSort, a ); 5862 } 5863 }; 5864 5865 // Build the sort array, with pre-fix and post-fix options if they have been 5866 // specified 5867 if ( $.isArray( fixed ) ) { 5868 add( fixed ); 5869 } 5870 5871 if ( fixedObj && fixed.pre ) { 5872 add( fixed.pre ); 5873 } 5874 5875 add( settings.aaSorting ); 5876 5877 if (fixedObj && fixed.post ) { 5878 add( fixed.post ); 5879 } 5880 5881 for ( i=0 ; i<nestedSort.length ; i++ ) 5882 { 5883 srcCol = nestedSort[i][0]; 5884 aDataSort = aoColumns[ srcCol ].aDataSort; 5885 5886 for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ ) 5887 { 5888 iCol = aDataSort[k]; 5889 sType = aoColumns[ iCol ].sType || 'string'; 5890 5891 if ( nestedSort[i]._idx === undefined ) { 5892 nestedSort[i]._idx = $.inArray( nestedSort[i][1], aoColumns[iCol].asSorting ); 5893 } 5894 5895 aSort.push( { 5896 src: srcCol, 5897 col: iCol, 5898 dir: nestedSort[i][1], 5899 index: nestedSort[i]._idx, 5900 type: sType, 5901 formatter: DataTable.ext.type.order[ sType+"-pre" ] 5902 } ); 5903 } 5904 } 5905 5906 return aSort; 5907 } 5908 5909 /** 5910 * Change the order of the table 5911 * @param {object} oSettings dataTables settings object 5912 * @memberof DataTable#oApi 5913 * @todo This really needs split up! 5914 */ 5915 function _fnSort ( oSettings ) 5916 { 5917 var 5918 i, ien, iLen, j, jLen, k, kLen, 5919 sDataType, nTh, 5920 aiOrig = [], 5921 oExtSort = DataTable.ext.type.order, 5922 aoData = oSettings.aoData, 5923 aoColumns = oSettings.aoColumns, 5924 aDataSort, data, iCol, sType, oSort, 5925 formatters = 0, 5926 sortCol, 5927 displayMaster = oSettings.aiDisplayMaster, 5928 aSort; 5929 5930 // Resolve any column types that are unknown due to addition or invalidation 5931 // @todo Can this be moved into a 'data-ready' handler which is called when 5932 // data is going to be used in the table? 5933 _fnColumnTypes( oSettings ); 5934 5935 aSort = _fnSortFlatten( oSettings ); 5936 5937 for ( i=0, ien=aSort.length ; i<ien ; i++ ) { 5938 sortCol = aSort[i]; 5939 5940 // Track if we can use the fast sort algorithm 5941 if ( sortCol.formatter ) { 5942 formatters++; 5943 } 5944 5945 // Load the data needed for the sort, for each cell 5946 _fnSortData( oSettings, sortCol.col ); 5947 } 5948 5949 /* No sorting required if server-side or no sorting array */ 5950 if ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 ) 5951 { 5952 // Create a value - key array of the current row positions such that we can use their 5953 // current position during the sort, if values match, in order to perform stable sorting 5954 for ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) { 5955 aiOrig[ displayMaster[i] ] = i; 5956 } 5957 5958 /* Do the sort - here we want multi-column sorting based on a given data source (column) 5959 * and sorting function (from oSort) in a certain direction. It's reasonably complex to 5960 * follow on it's own, but this is what we want (example two column sorting): 5961 * fnLocalSorting = function(a,b){ 5962 * var iTest; 5963 * iTest = oSort['string-asc']('data11', 'data12'); 5964 * if (iTest !== 0) 5965 * return iTest; 5966 * iTest = oSort['numeric-desc']('data21', 'data22'); 5967 * if (iTest !== 0) 5968 * return iTest; 5969 * return oSort['numeric-asc']( aiOrig[a], aiOrig[b] ); 5970 * } 5971 * Basically we have a test for each sorting column, if the data in that column is equal, 5972 * test the next column. If all columns match, then we use a numeric sort on the row 5973 * positions in the original data array to provide a stable sort. 5974 * 5975 * Note - I know it seems excessive to have two sorting methods, but the first is around 5976 * 15% faster, so the second is only maintained for backwards compatibility with sorting 5977 * methods which do not have a pre-sort formatting function. 5978 */ 5979 if ( formatters === aSort.length ) { 5980 // All sort types have formatting functions 5981 displayMaster.sort( function ( a, b ) { 5982 var 5983 x, y, k, test, sort, 5984 len=aSort.length, 5985 dataA = aoData[a]._aSortData, 5986 dataB = aoData[b]._aSortData; 5987 5988 for ( k=0 ; k<len ; k++ ) { 5989 sort = aSort[k]; 5990 5991 x = dataA[ sort.col ]; 5992 y = dataB[ sort.col ]; 5993 5994 test = x<y ? -1 : x>y ? 1 : 0; 5995 if ( test !== 0 ) { 5996 return sort.dir === 'asc' ? test : -test; 5997 } 5998 } 5999 6000 x = aiOrig[a]; 6001 y = aiOrig[b]; 6002 return x<y ? -1 : x>y ? 1 : 0; 6003 } ); 6004 } 6005 else { 6006 // Depreciated - remove in 1.11 (providing a plug-in option) 6007 // Not all sort types have formatting methods, so we have to call their sorting 6008 // methods. 6009 displayMaster.sort( function ( a, b ) { 6010 var 6011 x, y, k, l, test, sort, fn, 6012 len=aSort.length, 6013 dataA = aoData[a]._aSortData, 6014 dataB = aoData[b]._aSortData; 6015 6016 for ( k=0 ; k<len ; k++ ) { 6017 sort = aSort[k]; 6018 6019 x = dataA[ sort.col ]; 6020 y = dataB[ sort.col ]; 6021 6022 fn = oExtSort[ sort.type+"-"+sort.dir ] || oExtSort[ "string-"+sort.dir ]; 6023 test = fn( x, y ); 6024 if ( test !== 0 ) { 6025 return test; 6026 } 6027 } 6028 6029 x = aiOrig[a]; 6030 y = aiOrig[b]; 6031 return x<y ? -1 : x>y ? 1 : 0; 6032 } ); 6033 } 6034 } 6035 6036 /* Tell the draw function that we have sorted the data */ 6037 oSettings.bSorted = true; 6038 } 6039 6040 6041 function _fnSortAria ( settings ) 6042 { 6043 var label; 6044 var nextSort; 6045 var columns = settings.aoColumns; 6046 var aSort = _fnSortFlatten( settings ); 6047 var oAria = settings.oLanguage.oAria; 6048 6049 // ARIA attributes - need to loop all columns, to update all (removing old 6050 // attributes as needed) 6051 for ( var i=0, iLen=columns.length ; i<iLen ; i++ ) 6052 { 6053 var col = columns[i]; 6054 var asSorting = col.asSorting; 6055 var sTitle = col.sTitle.replace( /<.*?>/g, "" ); 6056 var th = col.nTh; 6057 6058 // IE7 is throwing an error when setting these properties with jQuery's 6059 // attr() and removeAttr() methods... 6060 th.removeAttribute('aria-sort'); 6061 6062 /* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */ 6063 if ( col.bSortable ) { 6064 if ( aSort.length > 0 && aSort[0].col == i ) { 6065 th.setAttribute('aria-sort', aSort[0].dir=="asc" ? "ascending" : "descending" ); 6066 nextSort = asSorting[ aSort[0].index+1 ] || asSorting[0]; 6067 } 6068 else { 6069 nextSort = asSorting[0]; 6070 } 6071 6072 label = sTitle + ( nextSort === "asc" ? 6073 oAria.sSortAscending : 6074 oAria.sSortDescending 6075 ); 6076 } 6077 else { 6078 label = sTitle; 6079 } 6080 6081 th.setAttribute('aria-label', label); 6082 } 6083 } 6084 6085 6086 /** 6087 * Function to run on user sort request 6088 * @param {object} settings dataTables settings object 6089 * @param {node} attachTo node to attach the handler to 6090 * @param {int} colIdx column sorting index 6091 * @param {boolean} [append=false] Append the requested sort to the existing 6092 * sort if true (i.e. multi-column sort) 6093 * @param {function} [callback] callback function 6094 * @memberof DataTable#oApi 6095 */ 6096 function _fnSortListener ( settings, colIdx, append, callback ) 6097 { 6098 var col = settings.aoColumns[ colIdx ]; 6099 var sorting = settings.aaSorting; 6100 var asSorting = col.asSorting; 6101 var nextSortIdx; 6102 var next = function ( a, overflow ) { 6103 var idx = a._idx; 6104 if ( idx === undefined ) { 6105 idx = $.inArray( a[1], asSorting ); 6106 } 6107 6108 return idx+1 < asSorting.length ? 6109 idx+1 : 6110 overflow ? 6111 null : 6112 0; 6113 }; 6114 6115 // Convert to 2D array if needed 6116 if ( typeof sorting[0] === 'number' ) { 6117 sorting = settings.aaSorting = [ sorting ]; 6118 } 6119 6120 // If appending the sort then we are multi-column sorting 6121 if ( append && settings.oFeatures.bSortMulti ) { 6122 // Are we already doing some kind of sort on this column? 6123 var sortIdx = $.inArray( colIdx, _pluck(sorting, '0') ); 6124 6125 if ( sortIdx !== -1 ) { 6126 // Yes, modify the sort 6127 nextSortIdx = next( sorting[sortIdx], true ); 6128 6129 if ( nextSortIdx === null && sorting.length === 1 ) { 6130 nextSortIdx = 0; // can't remove sorting completely 6131 } 6132 6133 if ( nextSortIdx === null ) { 6134 sorting.splice( sortIdx, 1 ); 6135 } 6136 else { 6137 sorting[sortIdx][1] = asSorting[ nextSortIdx ]; 6138 sorting[sortIdx]._idx = nextSortIdx; 6139 } 6140 } 6141 else { 6142 // No sort on this column yet 6143 sorting.push( [ colIdx, asSorting[0], 0 ] ); 6144 sorting[sorting.length-1]._idx = 0; 6145 } 6146 } 6147 else if ( sorting.length && sorting[0][0] == colIdx ) { 6148 // Single column - already sorting on this column, modify the sort 6149 nextSortIdx = next( sorting[0] ); 6150 6151 sorting.length = 1; 6152 sorting[0][1] = asSorting[ nextSortIdx ]; 6153 sorting[0]._idx = nextSortIdx; 6154 } 6155 else { 6156 // Single column - sort only on this column 6157 sorting.length = 0; 6158 sorting.push( [ colIdx, asSorting[0] ] ); 6159 sorting[0]._idx = 0; 6160 } 6161 6162 // Run the sort by calling a full redraw 6163 _fnReDraw( settings ); 6164 6165 // callback used for async user interaction 6166 if ( typeof callback == 'function' ) { 6167 callback( settings ); 6168 } 6169 } 6170 6171 6172 /** 6173 * Attach a sort handler (click) to a node 6174 * @param {object} settings dataTables settings object 6175 * @param {node} attachTo node to attach the handler to 6176 * @param {int} colIdx column sorting index 6177 * @param {function} [callback] callback function 6178 * @memberof DataTable#oApi 6179 */ 6180 function _fnSortAttachListener ( settings, attachTo, colIdx, callback ) 6181 { 6182 var col = settings.aoColumns[ colIdx ]; 6183 6184 _fnBindAction( attachTo, {}, function (e) { 6185 /* If the column is not sortable - don't to anything */ 6186 if ( col.bSortable === false ) { 6187 return; 6188 } 6189 6190 // If processing is enabled use a timeout to allow the processing 6191 // display to be shown - otherwise to it synchronously 6192 if ( settings.oFeatures.bProcessing ) { 6193 _fnProcessingDisplay( settings, true ); 6194 6195 setTimeout( function() { 6196 _fnSortListener( settings, colIdx, e.shiftKey, callback ); 6197 6198 // In server-side processing, the draw callback will remove the 6199 // processing display 6200 if ( _fnDataSource( settings ) !== 'ssp' ) { 6201 _fnProcessingDisplay( settings, false ); 6202 } 6203 }, 0 ); 6204 } 6205 else { 6206 _fnSortListener( settings, colIdx, e.shiftKey, callback ); 6207 } 6208 } ); 6209 } 6210 6211 6212 /** 6213 * Set the sorting classes on table's body, Note: it is safe to call this function 6214 * when bSort and bSortClasses are false 6215 * @param {object} oSettings dataTables settings object 6216 * @memberof DataTable#oApi 6217 */ 6218 function _fnSortingClasses( settings ) 6219 { 6220 var oldSort = settings.aLastSort; 6221 var sortClass = settings.oClasses.sSortColumn; 6222 var sort = _fnSortFlatten( settings ); 6223 var features = settings.oFeatures; 6224 var i, ien, colIdx; 6225 6226 if ( features.bSort && features.bSortClasses ) { 6227 // Remove old sorting classes 6228 for ( i=0, ien=oldSort.length ; i<ien ; i++ ) { 6229 colIdx = oldSort[i].src; 6230 6231 // Remove column sorting 6232 $( _pluck( settings.aoData, 'anCells', colIdx ) ) 6233 .removeClass( sortClass + (i<2 ? i+1 : 3) ); 6234 } 6235 6236 // Add new column sorting 6237 for ( i=0, ien=sort.length ; i<ien ; i++ ) { 6238 colIdx = sort[i].src; 6239 6240 $( _pluck( settings.aoData, 'anCells', colIdx ) ) 6241 .addClass( sortClass + (i<2 ? i+1 : 3) ); 6242 } 6243 } 6244 6245 settings.aLastSort = sort; 6246 } 6247 6248 6249 // Get the data to sort a column, be it from cache, fresh (populating the 6250 // cache), or from a sort formatter 6251 function _fnSortData( settings, idx ) 6252 { 6253 // Custom sorting function - provided by the sort data type 6254 var column = settings.aoColumns[ idx ]; 6255 var customSort = DataTable.ext.order[ column.sSortDataType ]; 6256 var customData; 6257 6258 if ( customSort ) { 6259 customData = customSort.call( settings.oInstance, settings, idx, 6260 _fnColumnIndexToVisible( settings, idx ) 6261 ); 6262 } 6263 6264 // Use / populate cache 6265 var row, cellData; 6266 var formatter = DataTable.ext.type.order[ column.sType+"-pre" ]; 6267 6268 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) { 6269 row = settings.aoData[i]; 6270 6271 if ( ! row._aSortData ) { 6272 row._aSortData = []; 6273 } 6274 6275 if ( ! row._aSortData[idx] || customSort ) { 6276 cellData = customSort ? 6277 customData[i] : // If there was a custom sort function, use data from there 6278 _fnGetCellData( settings, i, idx, 'sort' ); 6279 6280 row._aSortData[ idx ] = formatter ? 6281 formatter( cellData ) : 6282 cellData; 6283 } 6284 } 6285 } 6286 6287 6288 6289 /** 6290 * Save the state of a table 6291 * @param {object} oSettings dataTables settings object 6292 * @memberof DataTable#oApi 6293 */ 6294 function _fnSaveState ( settings ) 6295 { 6296 if ( !settings.oFeatures.bStateSave || settings.bDestroying ) 6297 { 6298 return; 6299 } 6300 6301 /* Store the interesting variables */ 6302 var state = { 6303 time: +new Date(), 6304 start: settings._iDisplayStart, 6305 length: settings._iDisplayLength, 6306 order: $.extend( true, [], settings.aaSorting ), 6307 search: _fnSearchToCamel( settings.oPreviousSearch ), 6308 columns: $.map( settings.aoColumns, function ( col, i ) { 6309 return { 6310 visible: col.bVisible, 6311 search: _fnSearchToCamel( settings.aoPreSearchCols[i] ) 6312 }; 6313 } ) 6314 }; 6315 6316 _fnCallbackFire( settings, "aoStateSaveParams", 'stateSaveParams', [settings, state] ); 6317 6318 settings.oSavedState = state; 6319 settings.fnStateSaveCallback.call( settings.oInstance, settings, state ); 6320 } 6321 6322 6323 /** 6324 * Attempt to load a saved table state 6325 * @param {object} oSettings dataTables settings object 6326 * @param {object} oInit DataTables init object so we can override settings 6327 * @param {function} callback Callback to execute when the state has been loaded 6328 * @memberof DataTable#oApi 6329 */ 6330 function _fnLoadState ( settings, oInit, callback ) 6331 { 6332 var i, ien; 6333 var columns = settings.aoColumns; 6334 var loaded = function ( s ) { 6335 if ( ! s || ! s.time ) { 6336 callback(); 6337 return; 6338 } 6339 6340 // Allow custom and plug-in manipulation functions to alter the saved data set and 6341 // cancelling of loading by returning false 6342 var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, s] ); 6343 if ( $.inArray( false, abStateLoad ) !== -1 ) { 6344 callback(); 6345 return; 6346 } 6347 6348 // Reject old data 6349 var duration = settings.iStateDuration; 6350 if ( duration > 0 && s.time < +new Date() - (duration*1000) ) { 6351 callback(); 6352 return; 6353 } 6354 6355 // Number of columns have changed - all bets are off, no restore of settings 6356 if ( s.columns && columns.length !== s.columns.length ) { 6357 callback(); 6358 return; 6359 } 6360 6361 // Store the saved state so it might be accessed at any time 6362 settings.oLoadedState = $.extend( true, {}, s ); 6363 6364 // Restore key features - todo - for 1.11 this needs to be done by 6365 // subscribed events 6366 if ( s.start !== undefined ) { 6367 settings._iDisplayStart = s.start; 6368 settings.iInitDisplayStart = s.start; 6369 } 6370 if ( s.length !== undefined ) { 6371 settings._iDisplayLength = s.length; 6372 } 6373 6374 // Order 6375 if ( s.order !== undefined ) { 6376 settings.aaSorting = []; 6377 $.each( s.order, function ( i, col ) { 6378 settings.aaSorting.push( col[0] >= columns.length ? 6379 [ 0, col[1] ] : 6380 col 6381 ); 6382 } ); 6383 } 6384 6385 // Search 6386 if ( s.search !== undefined ) { 6387 $.extend( settings.oPreviousSearch, _fnSearchToHung( s.search ) ); 6388 } 6389 6390 // Columns 6391 // 6392 if ( s.columns ) { 6393 for ( i=0, ien=s.columns.length ; i<ien ; i++ ) { 6394 var col = s.columns[i]; 6395 6396 // Visibility 6397 if ( col.visible !== undefined ) { 6398 columns[i].bVisible = col.visible; 6399 } 6400 6401 // Search 6402 if ( col.search !== undefined ) { 6403 $.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) ); 6404 } 6405 } 6406 } 6407 6408 _fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, s] ); 6409 callback(); 6410 } 6411 6412 if ( ! settings.oFeatures.bStateSave ) { 6413 callback(); 6414 return; 6415 } 6416 6417 var state = settings.fnStateLoadCallback.call( settings.oInstance, settings, loaded ); 6418 6419 if ( state !== undefined ) { 6420 loaded( state ); 6421 } 6422 // otherwise, wait for the loaded callback to be executed 6423 } 6424 6425 6426 /** 6427 * Return the settings object for a particular table 6428 * @param {node} table table we are using as a dataTable 6429 * @returns {object} Settings object - or null if not found 6430 * @memberof DataTable#oApi 6431 */ 6432 function _fnSettingsFromNode ( table ) 6433 { 6434 var settings = DataTable.settings; 6435 var idx = $.inArray( table, _pluck( settings, 'nTable' ) ); 6436 6437 return idx !== -1 ? 6438 settings[ idx ] : 6439 null; 6440 } 6441 6442 6443 /** 6444 * Log an error message 6445 * @param {object} settings dataTables settings object 6446 * @param {int} level log error messages, or display them to the user 6447 * @param {string} msg error message 6448 * @param {int} tn Technical note id to get more information about the error. 6449 * @memberof DataTable#oApi 6450 */ 6451 function _fnLog( settings, level, msg, tn ) 6452 { 6453 msg = 'DataTables warning: '+ 6454 (settings ? 'table id='+settings.sTableId+' - ' : '')+msg; 6455 6456 if ( tn ) { 6457 msg += '. For more information about this error, please see '+ 6458 'http://datatables.net/tn/'+tn; 6459 } 6460 6461 if ( ! level ) { 6462 // Backwards compatibility pre 1.10 6463 var ext = DataTable.ext; 6464 var type = ext.sErrMode || ext.errMode; 6465 6466 if ( settings ) { 6467 _fnCallbackFire( settings, null, 'error', [ settings, tn, msg ] ); 6468 } 6469 6470 if ( type == 'alert' ) { 6471 alert( msg ); 6472 } 6473 else if ( type == 'throw' ) { 6474 throw new Error(msg); 6475 } 6476 else if ( typeof type == 'function' ) { 6477 type( settings, tn, msg ); 6478 } 6479 } 6480 else if ( window.console && console.log ) { 6481 console.log( msg ); 6482 } 6483 } 6484 6485 6486 /** 6487 * See if a property is defined on one object, if so assign it to the other object 6488 * @param {object} ret target object 6489 * @param {object} src source object 6490 * @param {string} name property 6491 * @param {string} [mappedName] name to map too - optional, name used if not given 6492 * @memberof DataTable#oApi 6493 */ 6494 function _fnMap( ret, src, name, mappedName ) 6495 { 6496 if ( $.isArray( name ) ) { 6497 $.each( name, function (i, val) { 6498 if ( $.isArray( val ) ) { 6499 _fnMap( ret, src, val[0], val[1] ); 6500 } 6501 else { 6502 _fnMap( ret, src, val ); 6503 } 6504 } ); 6505 6506 return; 6507 } 6508 6509 if ( mappedName === undefined ) { 6510 mappedName = name; 6511 } 6512 6513 if ( src[name] !== undefined ) { 6514 ret[mappedName] = src[name]; 6515 } 6516 } 6517 6518 6519 /** 6520 * Extend objects - very similar to jQuery.extend, but deep copy objects, and 6521 * shallow copy arrays. The reason we need to do this, is that we don't want to 6522 * deep copy array init values (such as aaSorting) since the dev wouldn't be 6523 * able to override them, but we do want to deep copy arrays. 6524 * @param {object} out Object to extend 6525 * @param {object} extender Object from which the properties will be applied to 6526 * out 6527 * @param {boolean} breakRefs If true, then arrays will be sliced to take an 6528 * independent copy with the exception of the `data` or `aaData` parameters 6529 * if they are present. This is so you can pass in a collection to 6530 * DataTables and have that used as your data source without breaking the 6531 * references 6532 * @returns {object} out Reference, just for convenience - out === the return. 6533 * @memberof DataTable#oApi 6534 * @todo This doesn't take account of arrays inside the deep copied objects. 6535 */ 6536 function _fnExtend( out, extender, breakRefs ) 6537 { 6538 var val; 6539 6540 for ( var prop in extender ) { 6541 if ( extender.hasOwnProperty(prop) ) { 6542 val = extender[prop]; 6543 6544 if ( $.isPlainObject( val ) ) { 6545 if ( ! $.isPlainObject( out[prop] ) ) { 6546 out[prop] = {}; 6547 } 6548 $.extend( true, out[prop], val ); 6549 } 6550 else if ( breakRefs && prop !== 'data' && prop !== 'aaData' && $.isArray(val) ) { 6551 out[prop] = val.slice(); 6552 } 6553 else { 6554 out[prop] = val; 6555 } 6556 } 6557 } 6558 6559 return out; 6560 } 6561 6562 6563 /** 6564 * Bind an event handers to allow a click or return key to activate the callback. 6565 * This is good for accessibility since a return on the keyboard will have the 6566 * same effect as a click, if the element has focus. 6567 * @param {element} n Element to bind the action to 6568 * @param {object} oData Data object to pass to the triggered function 6569 * @param {function} fn Callback function for when the event is triggered 6570 * @memberof DataTable#oApi 6571 */ 6572 function _fnBindAction( n, oData, fn ) 6573 { 6574 $(n) 6575 .on( 'click.DT', oData, function (e) { 6576 n.blur(); // Remove focus outline for mouse users 6577 fn(e); 6578 } ) 6579 .on( 'keypress.DT', oData, function (e){ 6580 if ( e.which === 13 ) { 6581 e.preventDefault(); 6582 fn(e); 6583 } 6584 } ) 6585 .on( 'selectstart.DT', function () { 6586 /* Take the brutal approach to cancelling text selection */ 6587 return false; 6588 } ); 6589 } 6590 6591 6592 /** 6593 * Register a callback function. Easily allows a callback function to be added to 6594 * an array store of callback functions that can then all be called together. 6595 * @param {object} oSettings dataTables settings object 6596 * @param {string} sStore Name of the array storage for the callbacks in oSettings 6597 * @param {function} fn Function to be called back 6598 * @param {string} sName Identifying name for the callback (i.e. a label) 6599 * @memberof DataTable#oApi 6600 */ 6601 function _fnCallbackReg( oSettings, sStore, fn, sName ) 6602 { 6603 if ( fn ) 6604 { 6605 oSettings[sStore].push( { 6606 "fn": fn, 6607 "sName": sName 6608 } ); 6609 } 6610 } 6611 6612 6613 /** 6614 * Fire callback functions and trigger events. Note that the loop over the 6615 * callback array store is done backwards! Further note that you do not want to 6616 * fire off triggers in time sensitive applications (for example cell creation) 6617 * as its slow. 6618 * @param {object} settings dataTables settings object 6619 * @param {string} callbackArr Name of the array storage for the callbacks in 6620 * oSettings 6621 * @param {string} eventName Name of the jQuery custom event to trigger. If 6622 * null no trigger is fired 6623 * @param {array} args Array of arguments to pass to the callback function / 6624 * trigger 6625 * @memberof DataTable#oApi 6626 */ 6627 function _fnCallbackFire( settings, callbackArr, eventName, args ) 6628 { 6629 var ret = []; 6630 6631 if ( callbackArr ) { 6632 ret = $.map( settings[callbackArr].slice().reverse(), function (val, i) { 6633 return val.fn.apply( settings.oInstance, args ); 6634 } ); 6635 } 6636 6637 if ( eventName !== null ) { 6638 var e = $.Event( eventName+'.dt' ); 6639 6640 $(settings.nTable).trigger( e, args ); 6641 6642 ret.push( e.result ); 6643 } 6644 6645 return ret; 6646 } 6647 6648 6649 function _fnLengthOverflow ( settings ) 6650 { 6651 var 6652 start = settings._iDisplayStart, 6653 end = settings.fnDisplayEnd(), 6654 len = settings._iDisplayLength; 6655 6656 /* If we have space to show extra rows (backing up from the end point - then do so */ 6657 if ( start >= end ) 6658 { 6659 start = end - len; 6660 } 6661 6662 // Keep the start record on the current page 6663 start -= (start % len); 6664 6665 if ( len === -1 || start < 0 ) 6666 { 6667 start = 0; 6668 } 6669 6670 settings._iDisplayStart = start; 6671 } 6672 6673 6674 function _fnRenderer( settings, type ) 6675 { 6676 var renderer = settings.renderer; 6677 var host = DataTable.ext.renderer[type]; 6678 6679 if ( $.isPlainObject( renderer ) && renderer[type] ) { 6680 // Specific renderer for this type. If available use it, otherwise use 6681 // the default. 6682 return host[renderer[type]] || host._; 6683 } 6684 else if ( typeof renderer === 'string' ) { 6685 // Common renderer - if there is one available for this type use it, 6686 // otherwise use the default 6687 return host[renderer] || host._; 6688 } 6689 6690 // Use the default 6691 return host._; 6692 } 6693 6694 6695 /** 6696 * Detect the data source being used for the table. Used to simplify the code 6697 * a little (ajax) and to make it compress a little smaller. 6698 * 6699 * @param {object} settings dataTables settings object 6700 * @returns {string} Data source 6701 * @memberof DataTable#oApi 6702 */ 6703 function _fnDataSource ( settings ) 6704 { 6705 if ( settings.oFeatures.bServerSide ) { 6706 return 'ssp'; 6707 } 6708 else if ( settings.ajax || settings.sAjaxSource ) { 6709 return 'ajax'; 6710 } 6711 return 'dom'; 6712 } 6713 6714 6715 6716 6717 /** 6718 * Computed structure of the DataTables API, defined by the options passed to 6719 * `DataTable.Api.register()` when building the API. 6720 * 6721 * The structure is built in order to speed creation and extension of the Api 6722 * objects since the extensions are effectively pre-parsed. 6723 * 6724 * The array is an array of objects with the following structure, where this 6725 * base array represents the Api prototype base: 6726 * 6727 * [ 6728 * { 6729 * name: 'data' -- string - Property name 6730 * val: function () {}, -- function - Api method (or undefined if just an object 6731 * methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result 6732 * propExt: [ ... ] -- array - Array of Api object definitions to extend the property 6733 * }, 6734 * { 6735 * name: 'row' 6736 * val: {}, 6737 * methodExt: [ ... ], 6738 * propExt: [ 6739 * { 6740 * name: 'data' 6741 * val: function () {}, 6742 * methodExt: [ ... ], 6743 * propExt: [ ... ] 6744 * }, 6745 * ... 6746 * ] 6747 * } 6748 * ] 6749 * 6750 * @type {Array} 6751 * @ignore 6752 */ 6753 var __apiStruct = []; 6754 6755 6756 /** 6757 * `Array.prototype` reference. 6758 * 6759 * @type object 6760 * @ignore 6761 */ 6762 var __arrayProto = Array.prototype; 6763 6764 6765 /** 6766 * Abstraction for `context` parameter of the `Api` constructor to allow it to 6767 * take several different forms for ease of use. 6768 * 6769 * Each of the input parameter types will be converted to a DataTables settings 6770 * object where possible. 6771 * 6772 * @param {string|node|jQuery|object} mixed DataTable identifier. Can be one 6773 * of: 6774 * 6775 * * `string` - jQuery selector. Any DataTables' matching the given selector 6776 * with be found and used. 6777 * * `node` - `TABLE` node which has already been formed into a DataTable. 6778 * * `jQuery` - A jQuery object of `TABLE` nodes. 6779 * * `object` - DataTables settings object 6780 * * `DataTables.Api` - API instance 6781 * @return {array|null} Matching DataTables settings objects. `null` or 6782 * `undefined` is returned if no matching DataTable is found. 6783 * @ignore 6784 */ 6785 var _toSettings = function ( mixed ) 6786 { 6787 var idx, jq; 6788 var settings = DataTable.settings; 6789 var tables = $.map( settings, function (el, i) { 6790 return el.nTable; 6791 } ); 6792 6793 if ( ! mixed ) { 6794 return []; 6795 } 6796 else if ( mixed.nTable && mixed.oApi ) { 6797 // DataTables settings object 6798 return [ mixed ]; 6799 } 6800 else if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) { 6801 // Table node 6802 idx = $.inArray( mixed, tables ); 6803 return idx !== -1 ? [ settings[idx] ] : null; 6804 } 6805 else if ( mixed && typeof mixed.settings === 'function' ) { 6806 return mixed.settings().toArray(); 6807 } 6808 else if ( typeof mixed === 'string' ) { 6809 // jQuery selector 6810 jq = $(mixed); 6811 } 6812 else if ( mixed instanceof $ ) { 6813 // jQuery object (also DataTables instance) 6814 jq = mixed; 6815 } 6816 6817 if ( jq ) { 6818 return jq.map( function(i) { 6819 idx = $.inArray( this, tables ); 6820 return idx !== -1 ? settings[idx] : null; 6821 } ).toArray(); 6822 } 6823 }; 6824 6825 6826 /** 6827 * DataTables API class - used to control and interface with one or more 6828 * DataTables enhanced tables. 6829 * 6830 * The API class is heavily based on jQuery, presenting a chainable interface 6831 * that you can use to interact with tables. Each instance of the API class has 6832 * a "context" - i.e. the tables that it will operate on. This could be a single 6833 * table, all tables on a page or a sub-set thereof. 6834 * 6835 * Additionally the API is designed to allow you to easily work with the data in 6836 * the tables, retrieving and manipulating it as required. This is done by 6837 * presenting the API class as an array like interface. The contents of the 6838 * array depend upon the actions requested by each method (for example 6839 * `rows().nodes()` will return an array of nodes, while `rows().data()` will 6840 * return an array of objects or arrays depending upon your table's 6841 * configuration). The API object has a number of array like methods (`push`, 6842 * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`, 6843 * `unique` etc) to assist your working with the data held in a table. 6844 * 6845 * Most methods (those which return an Api instance) are chainable, which means 6846 * the return from a method call also has all of the methods available that the 6847 * top level object had. For example, these two calls are equivalent: 6848 * 6849 * // Not chained 6850 * api.row.add( {...} ); 6851 * api.draw(); 6852 * 6853 * // Chained 6854 * api.row.add( {...} ).draw(); 6855 * 6856 * @class DataTable.Api 6857 * @param {array|object|string|jQuery} context DataTable identifier. This is 6858 * used to define which DataTables enhanced tables this API will operate on. 6859 * Can be one of: 6860 * 6861 * * `string` - jQuery selector. Any DataTables' matching the given selector 6862 * with be found and used. 6863 * * `node` - `TABLE` node which has already been formed into a DataTable. 6864 * * `jQuery` - A jQuery object of `TABLE` nodes. 6865 * * `object` - DataTables settings object 6866 * @param {array} [data] Data to initialise the Api instance with. 6867 * 6868 * @example 6869 * // Direct initialisation during DataTables construction 6870 * var api = $('#example').DataTable(); 6871 * 6872 * @example 6873 * // Initialisation using a DataTables jQuery object 6874 * var api = $('#example').dataTable().api(); 6875 * 6876 * @example 6877 * // Initialisation as a constructor 6878 * var api = new $.fn.DataTable.Api( 'table.dataTable' ); 6879 */ 6880 _Api = function ( context, data ) 6881 { 6882 if ( ! (this instanceof _Api) ) { 6883 return new _Api( context, data ); 6884 } 6885 6886 var settings = []; 6887 var ctxSettings = function ( o ) { 6888 var a = _toSettings( o ); 6889 if ( a ) { 6890 settings = settings.concat( a ); 6891 } 6892 }; 6893 6894 if ( $.isArray( context ) ) { 6895 for ( var i=0, ien=context.length ; i<ien ; i++ ) { 6896 ctxSettings( context[i] ); 6897 } 6898 } 6899 else { 6900 ctxSettings( context ); 6901 } 6902 6903 // Remove duplicates 6904 this.context = _unique( settings ); 6905 6906 // Initial data 6907 if ( data ) { 6908 $.merge( this, data ); 6909 } 6910 6911 // selector 6912 this.selector = { 6913 rows: null, 6914 cols: null, 6915 opts: null 6916 }; 6917 6918 _Api.extend( this, this, __apiStruct ); 6919 }; 6920 6921 DataTable.Api = _Api; 6922 6923 // Don't destroy the existing prototype, just extend it. Required for jQuery 2's 6924 // isPlainObject. 6925 $.extend( _Api.prototype, { 6926 any: function () 6927 { 6928 return this.count() !== 0; 6929 }, 6930 6931 6932 concat: __arrayProto.concat, 6933 6934 6935 context: [], // array of table settings objects 6936 6937 6938 count: function () 6939 { 6940 return this.flatten().length; 6941 }, 6942 6943 6944 each: function ( fn ) 6945 { 6946 for ( var i=0, ien=this.length ; i<ien; i++ ) { 6947 fn.call( this, this[i], i, this ); 6948 } 6949 6950 return this; 6951 }, 6952 6953 6954 eq: function ( idx ) 6955 { 6956 var ctx = this.context; 6957 6958 return ctx.length > idx ? 6959 new _Api( ctx[idx], this[idx] ) : 6960 null; 6961 }, 6962 6963 6964 filter: function ( fn ) 6965 { 6966 var a = []; 6967 6968 if ( __arrayProto.filter ) { 6969 a = __arrayProto.filter.call( this, fn, this ); 6970 } 6971 else { 6972 // Compatibility for browsers without EMCA-252-5 (JS 1.6) 6973 for ( var i=0, ien=this.length ; i<ien ; i++ ) { 6974 if ( fn.call( this, this[i], i, this ) ) { 6975 a.push( this[i] ); 6976 } 6977 } 6978 } 6979 6980 return new _Api( this.context, a ); 6981 }, 6982 6983 6984 flatten: function () 6985 { 6986 var a = []; 6987 return new _Api( this.context, a.concat.apply( a, this.toArray() ) ); 6988 }, 6989 6990 6991 join: __arrayProto.join, 6992 6993 6994 indexOf: __arrayProto.indexOf || function (obj, start) 6995 { 6996 for ( var i=(start || 0), ien=this.length ; i<ien ; i++ ) { 6997 if ( this[i] === obj ) { 6998 return i; 6999 } 7000 } 7001 return -1; 7002 }, 7003 7004 iterator: function ( flatten, type, fn, alwaysNew ) { 7005 var 7006 a = [], ret, 7007 i, ien, j, jen, 7008 context = this.context, 7009 rows, items, item, 7010 selector = this.selector; 7011 7012 // Argument shifting 7013 if ( typeof flatten === 'string' ) { 7014 alwaysNew = fn; 7015 fn = type; 7016 type = flatten; 7017 flatten = false; 7018 } 7019 7020 for ( i=0, ien=context.length ; i<ien ; i++ ) { 7021 var apiInst = new _Api( context[i] ); 7022 7023 if ( type === 'table' ) { 7024 ret = fn.call( apiInst, context[i], i ); 7025 7026 if ( ret !== undefined ) { 7027 a.push( ret ); 7028 } 7029 } 7030 else if ( type === 'columns' || type === 'rows' ) { 7031 // this has same length as context - one entry for each table 7032 ret = fn.call( apiInst, context[i], this[i], i ); 7033 7034 if ( ret !== undefined ) { 7035 a.push( ret ); 7036 } 7037 } 7038 else if ( type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) { 7039 // columns and rows share the same structure. 7040 // 'this' is an array of column indexes for each context 7041 items = this[i]; 7042 7043 if ( type === 'column-rows' ) { 7044 rows = _selector_row_indexes( context[i], selector.opts ); 7045 } 7046 7047 for ( j=0, jen=items.length ; j<jen ; j++ ) { 7048 item = items[j]; 7049 7050 if ( type === 'cell' ) { 7051 ret = fn.call( apiInst, context[i], item.row, item.column, i, j ); 7052 } 7053 else { 7054 ret = fn.call( apiInst, context[i], item, i, j, rows ); 7055 } 7056 7057 if ( ret !== undefined ) { 7058 a.push( ret ); 7059 } 7060 } 7061 } 7062 } 7063 7064 if ( a.length || alwaysNew ) { 7065 var api = new _Api( context, flatten ? a.concat.apply( [], a ) : a ); 7066 var apiSelector = api.selector; 7067 apiSelector.rows = selector.rows; 7068 apiSelector.cols = selector.cols; 7069 apiSelector.opts = selector.opts; 7070 return api; 7071 } 7072 return this; 7073 }, 7074 7075 7076 lastIndexOf: __arrayProto.lastIndexOf || function (obj, start) 7077 { 7078 // Bit cheeky... 7079 return this.indexOf.apply( this.toArray.reverse(), arguments ); 7080 }, 7081 7082 7083 length: 0, 7084 7085 7086 map: function ( fn ) 7087 { 7088 var a = []; 7089 7090 if ( __arrayProto.map ) { 7091 a = __arrayProto.map.call( this, fn, this ); 7092 } 7093 else { 7094 // Compatibility for browsers without EMCA-252-5 (JS 1.6) 7095 for ( var i=0, ien=this.length ; i<ien ; i++ ) { 7096 a.push( fn.call( this, this[i], i ) ); 7097 } 7098 } 7099 7100 return new _Api( this.context, a ); 7101 }, 7102 7103 7104 pluck: function ( prop ) 7105 { 7106 return this.map( function ( el ) { 7107 return el[ prop ]; 7108 } ); 7109 }, 7110 7111 pop: __arrayProto.pop, 7112 7113 7114 push: __arrayProto.push, 7115 7116 7117 // Does not return an API instance 7118 reduce: __arrayProto.reduce || function ( fn, init ) 7119 { 7120 return _fnReduce( this, fn, init, 0, this.length, 1 ); 7121 }, 7122 7123 7124 reduceRight: __arrayProto.reduceRight || function ( fn, init ) 7125 { 7126 return _fnReduce( this, fn, init, this.length-1, -1, -1 ); 7127 }, 7128 7129 7130 reverse: __arrayProto.reverse, 7131 7132 7133 // Object with rows, columns and opts 7134 selector: null, 7135 7136 7137 shift: __arrayProto.shift, 7138 7139 7140 slice: function () { 7141 return new _Api( this.context, this ); 7142 }, 7143 7144 7145 sort: __arrayProto.sort, // ? name - order? 7146 7147 7148 splice: __arrayProto.splice, 7149 7150 7151 toArray: function () 7152 { 7153 return __arrayProto.slice.call( this ); 7154 }, 7155 7156 7157 to$: function () 7158 { 7159 return $( this ); 7160 }, 7161 7162 7163 toJQuery: function () 7164 { 7165 return $( this ); 7166 }, 7167 7168 7169 unique: function () 7170 { 7171 return new _Api( this.context, _unique(this) ); 7172 }, 7173 7174 7175 unshift: __arrayProto.unshift 7176 } ); 7177 7178 7179 _Api.extend = function ( scope, obj, ext ) 7180 { 7181 // Only extend API instances and static properties of the API 7182 if ( ! ext.length || ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) { 7183 return; 7184 } 7185 7186 var 7187 i, ien, 7188 j, jen, 7189 struct, inner, 7190 methodScoping = function ( scope, fn, struc ) { 7191 return function () { 7192 var ret = fn.apply( scope, arguments ); 7193 7194 // Method extension 7195 _Api.extend( ret, ret, struc.methodExt ); 7196 return ret; 7197 }; 7198 }; 7199 7200 for ( i=0, ien=ext.length ; i<ien ; i++ ) { 7201 struct = ext[i]; 7202 7203 // Value 7204 obj[ struct.name ] = typeof struct.val === 'function' ? 7205 methodScoping( scope, struct.val, struct ) : 7206 $.isPlainObject( struct.val ) ? 7207 {} : 7208 struct.val; 7209 7210 obj[ struct.name ].__dt_wrapper = true; 7211 7212 // Property extension 7213 _Api.extend( scope, obj[ struct.name ], struct.propExt ); 7214 } 7215 }; 7216 7217 7218 // @todo - Is there need for an augment function? 7219 // _Api.augment = function ( inst, name ) 7220 // { 7221 // // Find src object in the structure from the name 7222 // var parts = name.split('.'); 7223 7224 // _Api.extend( inst, obj ); 7225 // }; 7226 7227 7228 // [ 7229 // { 7230 // name: 'data' -- string - Property name 7231 // val: function () {}, -- function - Api method (or undefined if just an object 7232 // methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result 7233 // propExt: [ ... ] -- array - Array of Api object definitions to extend the property 7234 // }, 7235 // { 7236 // name: 'row' 7237 // val: {}, 7238 // methodExt: [ ... ], 7239 // propExt: [ 7240 // { 7241 // name: 'data' 7242 // val: function () {}, 7243 // methodExt: [ ... ], 7244 // propExt: [ ... ] 7245 // }, 7246 // ... 7247 // ] 7248 // } 7249 // ] 7250 7251 _Api.register = _api_register = function ( name, val ) 7252 { 7253 if ( $.isArray( name ) ) { 7254 for ( var j=0, jen=name.length ; j<jen ; j++ ) { 7255 _Api.register( name[j], val ); 7256 } 7257 return; 7258 } 7259 7260 var 7261 i, ien, 7262 heir = name.split('.'), 7263 struct = __apiStruct, 7264 key, method; 7265 7266 var find = function ( src, name ) { 7267 for ( var i=0, ien=src.length ; i<ien ; i++ ) { 7268 if ( src[i].name === name ) { 7269 return src[i]; 7270 } 7271 } 7272 return null; 7273 }; 7274 7275 for ( i=0, ien=heir.length ; i<ien ; i++ ) { 7276 method = heir[i].indexOf('()') !== -1; 7277 key = method ? 7278 heir[i].replace('()', '') : 7279 heir[i]; 7280 7281 var src = find( struct, key ); 7282 if ( ! src ) { 7283 src = { 7284 name: key, 7285 val: {}, 7286 methodExt: [], 7287 propExt: [] 7288 }; 7289 struct.push( src ); 7290 } 7291 7292 if ( i === ien-1 ) { 7293 src.val = val; 7294 } 7295 else { 7296 struct = method ? 7297 src.methodExt : 7298 src.propExt; 7299 } 7300 } 7301 }; 7302 7303 7304 _Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) { 7305 _Api.register( pluralName, val ); 7306 7307 _Api.register( singularName, function () { 7308 var ret = val.apply( this, arguments ); 7309 7310 if ( ret === this ) { 7311 // Returned item is the API instance that was passed in, return it 7312 return this; 7313 } 7314 else if ( ret instanceof _Api ) { 7315 // New API instance returned, want the value from the first item 7316 // in the returned array for the singular result. 7317 return ret.length ? 7318 $.isArray( ret[0] ) ? 7319 new _Api( ret.context, ret[0] ) : // Array results are 'enhanced' 7320 ret[0] : 7321 undefined; 7322 } 7323 7324 // Non-API return - just fire it back 7325 return ret; 7326 } ); 7327 }; 7328 7329 7330 /** 7331 * Selector for HTML tables. Apply the given selector to the give array of 7332 * DataTables settings objects. 7333 * 7334 * @param {string|integer} [selector] jQuery selector string or integer 7335 * @param {array} Array of DataTables settings objects to be filtered 7336 * @return {array} 7337 * @ignore 7338 */ 7339 var __table_selector = function ( selector, a ) 7340 { 7341 // Integer is used to pick out a table by index 7342 if ( typeof selector === 'number' ) { 7343 return [ a[ selector ] ]; 7344 } 7345 7346 // Perform a jQuery selector on the table nodes 7347 var nodes = $.map( a, function (el, i) { 7348 return el.nTable; 7349 } ); 7350 7351 return $(nodes) 7352 .filter( selector ) 7353 .map( function (i) { 7354 // Need to translate back from the table node to the settings 7355 var idx = $.inArray( this, nodes ); 7356 return a[ idx ]; 7357 } ) 7358 .toArray(); 7359 }; 7360 7361 7362 7363 /** 7364 * Context selector for the API's context (i.e. the tables the API instance 7365 * refers to. 7366 * 7367 * @name DataTable.Api#tables 7368 * @param {string|integer} [selector] Selector to pick which tables the iterator 7369 * should operate on. If not given, all tables in the current context are 7370 * used. This can be given as a jQuery selector (for example `':gt(0)'`) to 7371 * select multiple tables or as an integer to select a single table. 7372 * @returns {DataTable.Api} Returns a new API instance if a selector is given. 7373 */ 7374 _api_register( 'tables()', function ( selector ) { 7375 // A new instance is created if there was a selector specified 7376 return selector
vendor: 9,632 bytes, lines 7376-7724
7376 ? 7377 new _Api( __table_selector( selector, this.context ) ) : 7378 this; 7379 } ); 7380 7381 7382 _api_register( 'table()', function ( selector ) { 7383 var tables = this.tables( selector ); 7384 var ctx = tables.context; 7385 7386 // Truncate to the first matched table 7387 return ctx.length ? 7388 new _Api( ctx[0] ) : 7389 tables; 7390 } ); 7391 7392 7393 _api_registerPlural( 'tables().nodes()', 'table().node()' , function () { 7394 return this.iterator( 'table', function ( ctx ) { 7395 return ctx.nTable; 7396 }, 1 ); 7397 } ); 7398 7399 7400 _api_registerPlural( 'tables().body()', 'table().body()' , function () { 7401 return this.iterator( 'table', function ( ctx ) { 7402 return ctx.nTBody; 7403 }, 1 ); 7404 } ); 7405 7406 7407 _api_registerPlural( 'tables().header()', 'table().header()' , function () { 7408 return this.iterator( 'table', function ( ctx ) { 7409 return ctx.nTHead; 7410 }, 1 ); 7411 } ); 7412 7413 7414 _api_registerPlural( 'tables().footer()', 'table().footer()' , function () { 7415 return this.iterator( 'table', function ( ctx ) { 7416 return ctx.nTFoot; 7417 }, 1 ); 7418 } ); 7419 7420 7421 _api_registerPlural( 'tables().containers()', 'table().container()' , function () { 7422 return this.iterator( 'table', function ( ctx ) { 7423 return ctx.nTableWrapper; 7424 }, 1 ); 7425 } ); 7426 7427 7428 7429 /** 7430 * Redraw the tables in the current context. 7431 */ 7432 _api_register( 'draw()', function ( paging ) { 7433 return this.iterator( 'table', function ( settings ) { 7434 if ( paging === 'page' ) { 7435 _fnDraw( settings ); 7436 } 7437 else { 7438 if ( typeof paging === 'string' ) { 7439 paging = paging === 'full-hold' ? 7440 false : 7441 true; 7442 } 7443 7444 _fnReDraw( settings, paging===false ); 7445 } 7446 } ); 7447 } ); 7448 7449 7450 7451 /** 7452 * Get the current page index. 7453 * 7454 * @return {integer} Current page index (zero based) 7455 *//** 7456 * Set the current page. 7457 * 7458 * Note that if you attempt to show a page which does not exist, DataTables will 7459 * not throw an error, but rather reset the paging. 7460 * 7461 * @param {integer|string} action The paging action to take. This can be one of: 7462 * * `integer` - The page index to jump to 7463 * * `string` - An action to take: 7464 * * `first` - Jump to first page. 7465 * * `next` - Jump to the next page 7466 * * `previous` - Jump to previous page 7467 * * `last` - Jump to the last page. 7468 * @returns {DataTables.Api} this 7469 */ 7470 _api_register( 'page()', function ( action ) { 7471 if ( action === undefined ) { 7472 return this.page.info().page; // not an expensive call 7473 } 7474 7475 // else, have an action to take on all tables 7476 return this.iterator( 'table', function ( settings ) { 7477 _fnPageChange( settings, action ); 7478 } ); 7479 } ); 7480 7481 7482 /** 7483 * Paging information for the first table in the current context. 7484 * 7485 * If you require paging information for another table, use the `table()` method 7486 * with a suitable selector. 7487 * 7488 * @return {object} Object with the following properties set: 7489 * * `page` - Current page index (zero based - i.e. the first page is `0`) 7490 * * `pages` - Total number of pages 7491 * * `start` - Display index for the first record shown on the current page 7492 * * `end` - Display index for the last record shown on the current page 7493 * * `length` - Display length (number of records). Note that generally `start 7494 * + length = end`, but this is not always true, for example if there are 7495 * only 2 records to show on the final page, with a length of 10. 7496 * * `recordsTotal` - Full data set length 7497 * * `recordsDisplay` - Data set length once the current filtering criterion 7498 * are applied. 7499 */ 7500 _api_register( 'page.info()', function ( action ) { 7501 if ( this.context.length === 0 ) { 7502 return undefined; 7503 } 7504 7505 var 7506 settings = this.context[0], 7507 start = settings._iDisplayStart, 7508 len = settings.oFeatures.bPaginate ? settings._iDisplayLength : -1, 7509 visRecords = settings.fnRecordsDisplay(), 7510 all = len === -1; 7511 7512 return { 7513 "page": all ? 0 : Math.floor( start / len ), 7514 "pages": all ? 1 : Math.ceil( visRecords / len ), 7515 "start": start, 7516 "end": settings.fnDisplayEnd(), 7517 "length": len, 7518 "recordsTotal": settings.fnRecordsTotal(), 7519 "recordsDisplay": visRecords, 7520 "serverSide": _fnDataSource( settings ) === 'ssp' 7521 }; 7522 } ); 7523 7524 7525 /** 7526 * Get the current page length. 7527 * 7528 * @return {integer} Current page length. Note `-1` indicates that all records 7529 * are to be shown. 7530 *//** 7531 * Set the current page length. 7532 * 7533 * @param {integer} Page length to set. Use `-1` to show all records. 7534 * @returns {DataTables.Api} this 7535 */ 7536 _api_register( 'page.len()', function ( len ) { 7537 // Note that we can't call this function 'length()' because `length` 7538 // is a Javascript property of functions which defines how many arguments 7539 // the function expects. 7540 if ( len === undefined ) { 7541 return this.context.length !== 0 ? 7542 this.context[0]._iDisplayLength : 7543 undefined; 7544 } 7545 7546 // else, set the page length 7547 return this.iterator( 'table', function ( settings ) { 7548 _fnLengthChange( settings, len ); 7549 } ); 7550 } ); 7551 7552 7553 7554 var __reload = function ( settings, holdPosition, callback ) { 7555 // Use the draw event to trigger a callback 7556 if ( callback ) { 7557 var api = new _Api( settings ); 7558 7559 api.one( 'draw', function () { 7560 callback( api.ajax.json() ); 7561 } ); 7562 } 7563 7564 if ( _fnDataSource( settings ) == 'ssp' ) { 7565 _fnReDraw( settings, holdPosition ); 7566 } 7567 else { 7568 _fnProcessingDisplay( settings, true ); 7569 7570 // Cancel an existing request 7571 var xhr = settings.jqXHR; 7572 if ( xhr && xhr.readyState !== 4 ) { 7573 xhr.abort(); 7574 } 7575 7576 // Trigger xhr 7577 _fnBuildAjax( settings, [], function( json ) { 7578 _fnClearTable( settings ); 7579 7580 var data = _fnAjaxDataSrc( settings, json ); 7581 for ( var i=0, ien=data.length ; i<ien ; i++ ) { 7582 _fnAddData( settings, data[i] ); 7583 } 7584 7585 _fnReDraw( settings, holdPosition ); 7586 _fnProcessingDisplay( settings, false ); 7587 } ); 7588 } 7589 }; 7590 7591 7592 /** 7593 * Get the JSON response from the last Ajax request that DataTables made to the 7594 * server. Note that this returns the JSON from the first table in the current 7595 * context. 7596 * 7597 * @return {object} JSON received from the server. 7598 */ 7599 _api_register( 'ajax.json()', function () { 7600 var ctx = this.context; 7601 7602 if ( ctx.length > 0 ) { 7603 return ctx[0].json; 7604 } 7605 7606 // else return undefined; 7607 } ); 7608 7609 7610 /** 7611 * Get the data submitted in the last Ajax request 7612 */ 7613 _api_register( 'ajax.params()', function () { 7614 var ctx = this.context; 7615 7616 if ( ctx.length > 0 ) { 7617 return ctx[0].oAjaxData; 7618 } 7619 7620 // else return undefined; 7621 } ); 7622 7623 7624 /** 7625 * Reload tables from the Ajax data source. Note that this function will 7626 * automatically re-draw the table when the remote data has been loaded. 7627 * 7628 * @param {boolean} [reset=true] Reset (default) or hold the current paging 7629 * position. A full re-sort and re-filter is performed when this method is 7630 * called, which is why the pagination reset is the default action. 7631 * @returns {DataTables.Api} this 7632 */ 7633 _api_register( 'ajax.reload()', function ( callback, resetPaging ) { 7634 return this.iterator( 'table', function (settings) { 7635 __reload( settings, resetPaging===false, callback ); 7636 } ); 7637 } ); 7638 7639 7640 /** 7641 * Get the current Ajax URL. Note that this returns the URL from the first 7642 * table in the current context. 7643 * 7644 * @return {string} Current Ajax source URL 7645 *//** 7646 * Set the Ajax URL. Note that this will set the URL for all tables in the 7647 * current context. 7648 * 7649 * @param {string} url URL to set. 7650 * @returns {DataTables.Api} this 7651 */ 7652 _api_register( 'ajax.url()', function ( url ) { 7653 var ctx = this.context; 7654 7655 if ( url === undefined ) { 7656 // get 7657 if ( ctx.length === 0 ) { 7658 return undefined; 7659 } 7660 ctx = ctx[0]; 7661 7662 return ctx.ajax ? 7663 $.isPlainObject( ctx.ajax ) ? 7664 ctx.ajax.url : 7665 ctx.ajax : 7666 ctx.sAjaxSource; 7667 } 7668 7669 // set 7670 return this.iterator( 'table', function ( settings ) { 7671 if ( $.isPlainObject( settings.ajax ) ) { 7672 settings.ajax.url = url; 7673 } 7674 else { 7675 settings.ajax = url; 7676 } 7677 // No need to consider sAjaxSource here since DataTables gives priority 7678 // to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any 7679 // value of `sAjaxSource` redundant. 7680 } ); 7681 } ); 7682 7683 7684 /** 7685 * Load data from the newly set Ajax URL. Note that this method is only 7686 * available when `ajax.url()` is used to set a URL. Additionally, this method 7687 * has the same effect as calling `ajax.reload()` but is provided for 7688 * convenience when setting a new URL. Like `ajax.reload()` it will 7689 * automatically redraw the table once the remote data has been loaded. 7690 * 7691 * @returns {DataTables.Api} this 7692 */ 7693 _api_register( 'ajax.url().load()', function ( callback, resetPaging ) { 7694 // Same as a reload, but makes sense to present it for easy access after a 7695 // url change 7696 return this.iterator( 'table', function ( ctx ) { 7697 __reload( ctx, resetPaging===false, callback ); 7698 } ); 7699 } ); 7700 7701 7702 7703 7704 var _selector_run = function ( type, selector, selectFn, settings, opts ) 7705 { 7706 var 7707 out = [], res, 7708 a, i, ien, j, jen, 7709 selectorType = typeof selector; 7710 7711 // Can't just check for isArray here, as an API or jQuery instance might be 7712 // given with their array like look 7713 if ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) { 7714 selector = [ selector ]; 7715 } 7716 7717 for ( i=0, ien=selector.length ; i<ien ; i++ ) { 7718 // Only split on simple strings - complex expressions will be jQuery selectors 7719 a = selector[i] && selector[i].split && ! selector[i].match(/[\[\(:]/) ? 7720 selector[i].split(',') : 7721 [ selector[i] ]; 7722 7723 for ( j=0, jen=a.length ; j<jen ; j++ ) { 7724 res = selectFn( typeof a[j] === 'string' ?
vendor: 45,155 bytes, lines 7724-9427
7724$.trim(a[j]) : a[j] ); 7725 7726 if ( res && res.length ) { 7727 out = out.concat( res ); 7728 } 7729 } 7730 } 7731 7732 // selector extensions 7733 var ext = _ext.selector[ type ]; 7734 if ( ext.length ) { 7735 for ( i=0, ien=ext.length ; i<ien ; i++ ) { 7736 out = ext[i]( settings, opts, out ); 7737 } 7738 } 7739 7740 return _unique( out ); 7741 }; 7742 7743 7744 var _selector_opts = function ( opts ) 7745 { 7746 if ( ! opts ) { 7747 opts = {}; 7748 } 7749 7750 // Backwards compatibility for 1.9- which used the terminology filter rather 7751 // than search 7752 if ( opts.filter && opts.search === undefined ) { 7753 opts.search = opts.filter; 7754 } 7755 7756 return $.extend( { 7757 search: 'none', 7758 order: 'current', 7759 page: 'all' 7760 }, opts ); 7761 }; 7762 7763 7764 var _selector_first = function ( inst ) 7765 { 7766 // Reduce the API instance to the first item found 7767 for ( var i=0, ien=inst.length ; i<ien ; i++ ) { 7768 if ( inst[i].length > 0 ) { 7769 // Assign the first element to the first item in the instance 7770 // and truncate the instance and context 7771 inst[0] = inst[i]; 7772 inst[0].length = 1; 7773 inst.length = 1; 7774 inst.context = [ inst.context[i] ]; 7775 7776 return inst; 7777 } 7778 } 7779 7780 // Not found - return an empty instance 7781 inst.length = 0; 7782 return inst; 7783 }; 7784 7785 7786 var _selector_row_indexes = function ( settings, opts ) 7787 { 7788 var 7789 i, ien, tmp, a=[], 7790 displayFiltered = settings.aiDisplay, 7791 displayMaster = settings.aiDisplayMaster; 7792 7793 var 7794 search = opts.search, // none, applied, removed 7795 order = opts.order, // applied, current, index (original - compatibility with 1.9) 7796 page = opts.page; // all, current 7797 7798 if ( _fnDataSource( settings ) == 'ssp' ) { 7799 // In server-side processing mode, most options are irrelevant since 7800 // rows not shown don't exist and the index order is the applied order 7801 // Removed is a special case - for consistency just return an empty 7802 // array 7803 return search === 'removed' ? 7804 [] : 7805 _range( 0, displayMaster.length ); 7806 } 7807 else if ( page == 'current' ) { 7808 // Current page implies that order=current and fitler=applied, since it is 7809 // fairly senseless otherwise, regardless of what order and search actually 7810 // are 7811 for ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) { 7812 a.push( displayFiltered[i] ); 7813 } 7814 } 7815 else if ( order == 'current' || order == 'applied' ) { 7816 a = search == 'none' ? 7817 displayMaster.slice() : // no search 7818 search == 'applied' ? 7819 displayFiltered.slice() : // applied search 7820 $.map( displayMaster, function (el, i) { // removed search 7821 return $.inArray( el, displayFiltered ) === -1 ? el : null; 7822 } ); 7823 } 7824 else if ( order == 'index' || order == 'original' ) { 7825 for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) { 7826 if ( search == 'none' ) { 7827 a.push( i ); 7828 } 7829 else { // applied | removed 7830 tmp = $.inArray( i, displayFiltered ); 7831 7832 if ((tmp === -1 && search == 'removed') || 7833 (tmp >= 0 && search == 'applied') ) 7834 { 7835 a.push( i ); 7836 } 7837 } 7838 } 7839 } 7840 7841 return a; 7842 }; 7843 7844 7845 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 7846 * Rows 7847 * 7848 * {} - no selector - use all available rows 7849 * {integer} - row aoData index 7850 * {node} - TR node 7851 * {string} - jQuery selector to apply to the TR elements 7852 * {array} - jQuery array of nodes, or simply an array of TR nodes 7853 * 7854 */ 7855 7856 7857 var __row_selector = function ( settings, selector, opts ) 7858 { 7859 var rows; 7860 var run = function ( sel ) { 7861 var selInt = _intVal( sel ); 7862 var i, ien; 7863 7864 // Short cut - selector is a number and no options provided (default is 7865 // all records, so no need to check if the index is in there, since it 7866 // must be - dev error if the index doesn't exist). 7867 if ( selInt !== null && ! opts ) { 7868 return [ selInt ]; 7869 } 7870 7871 if ( ! rows ) { 7872 rows = _selector_row_indexes( settings, opts ); 7873 } 7874 7875 if ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) { 7876 // Selector - integer 7877 return [ selInt ]; 7878 } 7879 else if ( sel === null || sel === undefined || sel === '' ) { 7880 // Selector - none 7881 return rows; 7882 } 7883 7884 // Selector - function 7885 if ( typeof sel === 'function' ) { 7886 return $.map( rows, function (idx) { 7887 var row = settings.aoData[ idx ]; 7888 return sel( idx, row._aData, row.nTr ) ? idx : null; 7889 } ); 7890 } 7891 7892 // Get nodes in the order from the `rows` array with null values removed 7893 var nodes = _removeEmpty( 7894 _pluck_order( settings.aoData, rows, 'nTr' ) 7895 ); 7896 7897 // Selector - node 7898 if ( sel.nodeName ) { 7899 if ( sel._DT_RowIndex !== undefined ) { 7900 return [ sel._DT_RowIndex ]; // Property added by DT for fast lookup 7901 } 7902 else if ( sel._DT_CellIndex ) { 7903 return [ sel._DT_CellIndex.row ]; 7904 } 7905 else { 7906 var host = $(sel).closest('*[data-dt-row]'); 7907 return host.length ? 7908 [ host.data('dt-row') ] : 7909 []; 7910 } 7911 } 7912 7913 // ID selector. Want to always be able to select rows by id, regardless 7914 // of if the tr element has been created or not, so can't rely upon 7915 // jQuery here - hence a custom implementation. This does not match 7916 // Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything, 7917 // but to select it using a CSS selector engine (like Sizzle or 7918 // querySelect) it would need to need to be escaped for some characters. 7919 // DataTables simplifies this for row selectors since you can select 7920 // only a row. A # indicates an id any anything that follows is the id - 7921 // unescaped. 7922 if ( typeof sel === 'string' && sel.charAt(0) === '#' ) { 7923 // get row index from id 7924 var rowObj = settings.aIds[ sel.replace( /^#/, '' ) ]; 7925 if ( rowObj !== undefined ) { 7926 return [ rowObj.idx ]; 7927 } 7928 7929 // need to fall through to jQuery in case there is DOM id that 7930 // matches 7931 } 7932 7933 // Selector - jQuery selector string, array of nodes or jQuery object/ 7934 // As jQuery's .filter() allows jQuery objects to be passed in filter, 7935 // it also allows arrays, so this will cope with all three options 7936 return $(nodes) 7937 .filter( sel ) 7938 .map( function () { 7939 return this._DT_RowIndex; 7940 } ) 7941 .toArray(); 7942 }; 7943 7944 return _selector_run( 'row', selector, run, settings, opts ); 7945 }; 7946 7947 7948 _api_register( 'rows()', function ( selector, opts ) { 7949 // argument shifting 7950 if ( selector === undefined ) { 7951 selector = ''; 7952 } 7953 else if ( $.isPlainObject( selector ) ) { 7954 opts = selector; 7955 selector = ''; 7956 } 7957 7958 opts = _selector_opts( opts ); 7959 7960 var inst = this.iterator( 'table', function ( settings ) { 7961 return __row_selector( settings, selector, opts ); 7962 }, 1 ); 7963 7964 // Want argument shifting here and in __row_selector? 7965 inst.selector.rows = selector; 7966 inst.selector.opts = opts; 7967 7968 return inst; 7969 } ); 7970 7971 _api_register( 'rows().nodes()', function () { 7972 return this.iterator( 'row', function ( settings, row ) { 7973 return settings.aoData[ row ].nTr || undefined; 7974 }, 1 ); 7975 } ); 7976 7977 _api_register( 'rows().data()', function () { 7978 return this.iterator( true, 'rows', function ( settings, rows ) { 7979 return _pluck_order( settings.aoData, rows, '_aData' ); 7980 }, 1 ); 7981 } ); 7982 7983 _api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) { 7984 return this.iterator( 'row', function ( settings, row ) { 7985 var r = settings.aoData[ row ]; 7986 return type === 'search' ? r._aFilterData : r._aSortData; 7987 }, 1 ); 7988 } ); 7989 7990 _api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) { 7991 return this.iterator( 'row', function ( settings, row ) { 7992 _fnInvalidate( settings, row, src ); 7993 } ); 7994 } ); 7995 7996 _api_registerPlural( 'rows().indexes()', 'row().index()', function () { 7997 return this.iterator( 'row', function ( settings, row ) { 7998 return row; 7999 }, 1 ); 8000 } ); 8001 8002 _api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) { 8003 var a = []; 8004 var context = this.context; 8005 8006 // `iterator` will drop undefined values, but in this case we want them 8007 for ( var i=0, ien=context.length ; i<ien ; i++ ) { 8008 for ( var j=0, jen=this[i].length ; j<jen ; j++ ) { 8009 var id = context[i].rowIdFn( context[i].aoData[ this[i][j] ]._aData ); 8010 a.push( (hash === true ? '#' : '' )+ id ); 8011 } 8012 } 8013 8014 return new _Api( context, a ); 8015 } ); 8016 8017 _api_registerPlural( 'rows().remove()', 'row().remove()', function () { 8018 var that = this; 8019 8020 this.iterator( 'row', function ( settings, row, thatIdx ) { 8021 var data = settings.aoData; 8022 var rowData = data[ row ]; 8023 var i, ien, j, jen; 8024 var loopRow, loopCells; 8025 8026 data.splice( row, 1 ); 8027 8028 // Update the cached indexes 8029 for ( i=0, ien=data.length ; i<ien ; i++ ) { 8030 loopRow = data[i]; 8031 loopCells = loopRow.anCells; 8032 8033 // Rows 8034 if ( loopRow.nTr !== null ) { 8035 loopRow.nTr._DT_RowIndex = i; 8036 } 8037 8038 // Cells 8039 if ( loopCells !== null ) { 8040 for ( j=0, jen=loopCells.length ; j<jen ; j++ ) { 8041 loopCells[j]._DT_CellIndex.row = i; 8042 } 8043 } 8044 } 8045 8046 // Delete from the display arrays 8047 _fnDeleteIndex( settings.aiDisplayMaster, row ); 8048 _fnDeleteIndex( settings.aiDisplay, row ); 8049 _fnDeleteIndex( that[ thatIdx ], row, false ); // maintain local indexes 8050 8051 // For server-side processing tables - subtract the deleted row from the count 8052 if ( settings._iRecordsDisplay > 0 ) { 8053 settings._iRecordsDisplay--; 8054 } 8055 8056 // Check for an 'overflow' they case for displaying the table 8057 _fnLengthOverflow( settings ); 8058 8059 // Remove the row's ID reference if there is one 8060 var id = settings.rowIdFn( rowData._aData ); 8061 if ( id !== undefined ) { 8062 delete settings.aIds[ id ]; 8063 } 8064 } ); 8065 8066 this.iterator( 'table', function ( settings ) { 8067 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) { 8068 settings.aoData[i].idx = i; 8069 } 8070 } ); 8071 8072 return this; 8073 } ); 8074 8075 8076 _api_register( 'rows.add()', function ( rows ) { 8077 var newRows = this.iterator( 'table', function ( settings ) { 8078 var row, i, ien; 8079 var out = []; 8080 8081 for ( i=0, ien=rows.length ; i<ien ; i++ ) { 8082 row = rows[i]; 8083 8084 if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) { 8085 out.push( _fnAddTr( settings, row )[0] ); 8086 } 8087 else { 8088 out.push( _fnAddData( settings, row ) ); 8089 } 8090 } 8091 8092 return out; 8093 }, 1 ); 8094 8095 // Return an Api.rows() extended instance, so rows().nodes() etc can be used 8096 var modRows = this.rows( -1 ); 8097 modRows.pop(); 8098 $.merge( modRows, newRows ); 8099 8100 return modRows; 8101 } ); 8102 8103 8104 8105 8106 8107 /** 8108 * 8109 */ 8110 _api_register( 'row()', function ( selector, opts ) { 8111 return _selector_first( this.rows( selector, opts ) ); 8112 } ); 8113 8114 8115 _api_register( 'row().data()', function ( data ) { 8116 var ctx = this.context; 8117 8118 if ( data === undefined ) { 8119 // Get 8120 return ctx.length && this.length ? 8121 ctx[0].aoData[ this[0] ]._aData : 8122 undefined; 8123 } 8124 8125 // Set 8126 ctx[0].aoData[ this[0] ]._aData = data; 8127 8128 // Automatically invalidate 8129 _fnInvalidate( ctx[0], this[0], 'data' ); 8130 8131 return this; 8132 } ); 8133 8134 8135 _api_register( 'row().node()', function () { 8136 var ctx = this.context; 8137 8138 return ctx.length && this.length ? 8139 ctx[0].aoData[ this[0] ].nTr || null : 8140 null; 8141 } ); 8142 8143 8144 _api_register( 'row.add()', function ( row ) { 8145 // Allow a jQuery object to be passed in - only a single row is added from 8146 // it though - the first element in the set 8147 if ( row instanceof $ && row.length ) { 8148 row = row[0]; 8149 } 8150 8151 var rows = this.iterator( 'table', function ( settings ) { 8152 if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) { 8153 return _fnAddTr( settings, row )[0]; 8154 } 8155 return _fnAddData( settings, row ); 8156 } ); 8157 8158 // Return an Api.rows() extended instance, with the newly added row selected 8159 return this.row( rows[0] ); 8160 } ); 8161 8162 8163 8164 var __details_add = function ( ctx, row, data, klass ) 8165 { 8166 // Convert to array of TR elements 8167 var rows = []; 8168 var addRow = function ( r, k ) { 8169 // Recursion to allow for arrays of jQuery objects 8170 if ( $.isArray( r ) || r instanceof $ ) { 8171 for ( var i=0, ien=r.length ; i<ien ; i++ ) { 8172 addRow( r[i], k ); 8173 } 8174 return; 8175 } 8176 8177 // If we get a TR element, then just add it directly - up to the dev 8178 // to add the correct number of columns etc 8179 if ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) { 8180 rows.push( r ); 8181 } 8182 else { 8183 // Otherwise create a row with a wrapper 8184 var created = $('<tr><td/></tr>').addClass( k ); 8185 $('td', created) 8186 .addClass( k ) 8187 .html( r ) 8188 [0].colSpan = _fnVisbleColumns( ctx ); 8189 8190 rows.push( created[0] ); 8191 } 8192 }; 8193 8194 addRow( data, klass ); 8195 8196 if ( row._details ) { 8197 row._details.detach(); 8198 } 8199 8200 row._details = $(rows); 8201 8202 // If the children were already shown, that state should be retained 8203 if ( row._detailsShow ) { 8204 row._details.insertAfter( row.nTr ); 8205 } 8206 }; 8207 8208 8209 var __details_remove = function ( api, idx ) 8210 { 8211 var ctx = api.context; 8212 8213 if ( ctx.length ) { 8214 var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ]; 8215 8216 if ( row && row._details ) { 8217 row._details.remove(); 8218 8219 row._detailsShow = undefined; 8220 row._details = undefined; 8221 } 8222 } 8223 }; 8224 8225 8226 var __details_display = function ( api, show ) { 8227 var ctx = api.context; 8228 8229 if ( ctx.length && api.length ) { 8230 var row = ctx[0].aoData[ api[0] ]; 8231 8232 if ( row._details ) { 8233 row._detailsShow = show; 8234 8235 if ( show ) { 8236 row._details.insertAfter( row.nTr ); 8237 } 8238 else { 8239 row._details.detach(); 8240 } 8241 8242 __details_events( ctx[0] ); 8243 } 8244 } 8245 }; 8246 8247 8248 var __details_events = function ( settings ) 8249 { 8250 var api = new _Api( settings ); 8251 var namespace = '.dt.DT_details'; 8252 var drawEvent = 'draw'+namespace; 8253 var colvisEvent = 'column-visibility'+namespace; 8254 var destroyEvent = 'destroy'+namespace; 8255 var data = settings.aoData; 8256 8257 api.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent ); 8258 8259 if ( _pluck( data, '_details' ).length > 0 ) { 8260 // On each draw, insert the required elements into the document 8261 api.on( drawEvent, function ( e, ctx ) { 8262 if ( settings !== ctx ) { 8263 return; 8264 } 8265 8266 api.rows( {page:'current'} ).eq(0).each( function (idx) { 8267 // Internal data grab 8268 var row = data[ idx ]; 8269 8270 if ( row._detailsShow ) { 8271 row._details.insertAfter( row.nTr ); 8272 } 8273 } ); 8274 } ); 8275 8276 // Column visibility change - update the colspan 8277 api.on( colvisEvent, function ( e, ctx, idx, vis ) { 8278 if ( settings !== ctx ) { 8279 return; 8280 } 8281 8282 // Update the colspan for the details rows (note, only if it already has 8283 // a colspan) 8284 var row, visible = _fnVisbleColumns( ctx ); 8285 8286 for ( var i=0, ien=data.length ; i<ien ; i++ ) { 8287 row = data[i]; 8288 8289 if ( row._details ) { 8290 row._details.children('td[colspan]').attr('colspan', visible ); 8291 } 8292 } 8293 } ); 8294 8295 // Table destroyed - nuke any child rows 8296 api.on( destroyEvent, function ( e, ctx ) { 8297 if ( settings !== ctx ) { 8298 return; 8299 } 8300 8301 for ( var i=0, ien=data.length ; i<ien ; i++ ) { 8302 if ( data[i]._details ) { 8303 __details_remove( api, i ); 8304 } 8305 } 8306 } ); 8307 } 8308 }; 8309 8310 // Strings for the method names to help minification 8311 var _emp = ''; 8312 var _child_obj = _emp+'row().child'; 8313 var _child_mth = _child_obj+'()'; 8314 8315 // data can be: 8316 // tr 8317 // string 8318 // jQuery or array of any of the above 8319 _api_register( _child_mth, function ( data, klass ) { 8320 var ctx = this.context; 8321 8322 if ( data === undefined ) { 8323 // get 8324 return ctx.length && this.length ? 8325 ctx[0].aoData[ this[0] ]._details : 8326 undefined; 8327 } 8328 else if ( data === true ) { 8329 // show 8330 this.child.show(); 8331 } 8332 else if ( data === false ) { 8333 // remove 8334 __details_remove( this ); 8335 } 8336 else if ( ctx.length && this.length ) { 8337 // set 8338 __details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass ); 8339 } 8340 8341 return this; 8342 } ); 8343 8344 8345 _api_register( [ 8346 _child_obj+'.show()', 8347 _child_mth+'.show()' // only when `child()` was called with parameters (without 8348 ], function ( show ) { // it returns an object and this method is not executed) 8349 __details_display( this, true ); 8350 return this; 8351 } ); 8352 8353 8354 _api_register( [ 8355 _child_obj+'.hide()', 8356 _child_mth+'.hide()' // only when `child()` was called with parameters (without 8357 ], function () { // it returns an object and this method is not executed) 8358 __details_display( this, false ); 8359 return this; 8360 } ); 8361 8362 8363 _api_register( [ 8364 _child_obj+'.remove()', 8365 _child_mth+'.remove()' // only when `child()` was called with parameters (without 8366 ], function () { // it returns an object and this method is not executed) 8367 __details_remove( this ); 8368 return this; 8369 } ); 8370 8371 8372 _api_register( _child_obj+'.isShown()', function () { 8373 var ctx = this.context; 8374 8375 if ( ctx.length && this.length ) { 8376 // _detailsShown as false or undefined will fall through to return false 8377 return ctx[0].aoData[ this[0] ]._detailsShow || false; 8378 } 8379 return false; 8380 } ); 8381 8382 8383 8384 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 8385 * Columns 8386 * 8387 * {integer} - column index (>=0 count from left, <0 count from right) 8388 * "{integer}:visIdx" - visible column index (i.e. translate to column index) (>=0 count from left, <0 count from right) 8389 * "{integer}:visible" - alias for {integer}:visIdx (>=0 count from left, <0 count from right) 8390 * "{string}:name" - column name 8391 * "{string}" - jQuery selector on column header nodes 8392 * 8393 */ 8394 8395 // can be an array of these items, comma separated list, or an array of comma 8396 // separated lists 8397 8398 var __re_column_selector = /^([^:]+):(name|visIdx|visible)$/; 8399 8400 8401 // r1 and r2 are redundant - but it means that the parameters match for the 8402 // iterator callback in columns().data() 8403 var __columnData = function ( settings, column, r1, r2, rows ) { 8404 var a = []; 8405 for ( var row=0, ien=rows.length ; row<ien ; row++ ) { 8406 a.push( _fnGetCellData( settings, rows[row], column ) ); 8407 } 8408 return a; 8409 }; 8410 8411 8412 var __column_selector = function ( settings, selector, opts ) 8413 { 8414 var 8415 columns = settings.aoColumns, 8416 names = _pluck( columns, 'sName' ), 8417 nodes = _pluck( columns, 'nTh' ); 8418 8419 var run = function ( s ) { 8420 var selInt = _intVal( s ); 8421 8422 // Selector - all 8423 if ( s === '' ) { 8424 return _range( columns.length ); 8425 } 8426 8427 // Selector - index 8428 if ( selInt !== null ) { 8429 return [ selInt >= 0 ? 8430 selInt : // Count from left 8431 columns.length + selInt // Count from right (+ because its a negative value) 8432 ]; 8433 } 8434 8435 // Selector = function 8436 if ( typeof s === 'function' ) { 8437 var rows = _selector_row_indexes( settings, opts ); 8438 8439 return $.map( columns, function (col, idx) { 8440 return s( 8441 idx, 8442 __columnData( settings, idx, 0, 0, rows ), 8443 nodes[ idx ] 8444 ) ? idx : null; 8445 } ); 8446 } 8447 8448 // jQuery or string selector 8449 var match = typeof s === 'string' ? 8450 s.match( __re_column_selector ) : 8451 ''; 8452 8453 if ( match ) { 8454 switch( match[2] ) { 8455 case 'visIdx': 8456 case 'visible': 8457 var idx = parseInt( match[1], 10 ); 8458 // Visible index given, convert to column index 8459 if ( idx < 0 ) { 8460 // Counting from the right 8461 var visColumns = $.map( columns, function (col,i) { 8462 return col.bVisible ? i : null; 8463 } ); 8464 return [ visColumns[ visColumns.length + idx ] ]; 8465 } 8466 // Counting from the left 8467 return [ _fnVisibleToColumnIndex( settings, idx ) ]; 8468 8469 case 'name': 8470 // match by name. `names` is column index complete and in order 8471 return $.map( names, function (name, i) { 8472 return name === match[1] ? i : null; 8473 } ); 8474 8475 default: 8476 return []; 8477 } 8478 } 8479 8480 // Cell in the table body 8481 if ( s.nodeName && s._DT_CellIndex ) { 8482 return [ s._DT_CellIndex.column ]; 8483 } 8484 8485 // jQuery selector on the TH elements for the columns 8486 var jqResult = $( nodes ) 8487 .filter( s ) 8488 .map( function () { 8489 return $.inArray( this, nodes ); // `nodes` is column index complete and in order 8490 } ) 8491 .toArray(); 8492 8493 if ( jqResult.length || ! s.nodeName ) { 8494 return jqResult; 8495 } 8496 8497 // Otherwise a node which might have a `dt-column` data attribute, or be 8498 // a child or such an element 8499 var host = $(s).closest('*[data-dt-column]'); 8500 return host.length ? 8501 [ host.data('dt-column') ] : 8502 []; 8503 }; 8504 8505 return _selector_run( 'column', selector, run, settings, opts ); 8506 }; 8507 8508 8509 var __setColumnVis = function ( settings, column, vis ) { 8510 var 8511 cols = settings.aoColumns, 8512 col = cols[ column ], 8513 data = settings.aoData, 8514 row, cells, i, ien, tr; 8515 8516 // Get 8517 if ( vis === undefined ) { 8518 return col.bVisible; 8519 } 8520 8521 // Set 8522 // No change 8523 if ( col.bVisible === vis ) { 8524 return; 8525 } 8526 8527 if ( vis ) { 8528 // Insert column 8529 // Need to decide if we should use appendChild or insertBefore 8530 var insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 ); 8531 8532 for ( i=0, ien=data.length ; i<ien ; i++ ) { 8533 tr = data[i].nTr; 8534 cells = data[i].anCells; 8535 8536 if ( tr ) { 8537 // insertBefore can act like appendChild if 2nd arg is null 8538 tr.insertBefore( cells[ column ], cells[ insertBefore ] || null ); 8539 } 8540 } 8541 } 8542 else { 8543 // Remove column 8544 $( _pluck( settings.aoData, 'anCells', column ) ).detach(); 8545 } 8546 8547 // Common actions 8548 col.bVisible = vis; 8549 _fnDrawHead( settings, settings.aoHeader ); 8550 _fnDrawHead( settings, settings.aoFooter ); 8551 8552 _fnSaveState( settings ); 8553 }; 8554 8555 8556 _api_register( 'columns()', function ( selector, opts ) { 8557 // argument shifting 8558 if ( selector === undefined ) { 8559 selector = ''; 8560 } 8561 else if ( $.isPlainObject( selector ) ) { 8562 opts = selector; 8563 selector = ''; 8564 } 8565 8566 opts = _selector_opts( opts ); 8567 8568 var inst = this.iterator( 'table', function ( settings ) { 8569 return __column_selector( settings, selector, opts ); 8570 }, 1 ); 8571 8572 // Want argument shifting here and in _row_selector? 8573 inst.selector.cols = selector; 8574 inst.selector.opts = opts; 8575 8576 return inst; 8577 } ); 8578 8579 _api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) { 8580 return this.iterator( 'column', function ( settings, column ) { 8581 return settings.aoColumns[column].nTh; 8582 }, 1 ); 8583 } ); 8584 8585 _api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) { 8586 return this.iterator( 'column', function ( settings, column ) { 8587 return settings.aoColumns[column].nTf; 8588 }, 1 ); 8589 } ); 8590 8591 _api_registerPlural( 'columns().data()', 'column().data()', function () { 8592 return this.iterator( 'column-rows', __columnData, 1 ); 8593 } ); 8594 8595 _api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () { 8596 return this.iterator( 'column', function ( settings, column ) { 8597 return settings.aoColumns[column].mData; 8598 }, 1 ); 8599 } ); 8600 8601 _api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) { 8602 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) { 8603 return _pluck_order( settings.aoData, rows, 8604 type === 'search' ? '_aFilterData' : '_aSortData', column 8605 ); 8606 }, 1 ); 8607 } ); 8608 8609 _api_registerPlural( 'columns().nodes()', 'column().nodes()', function () { 8610 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) { 8611 return _pluck_order( settings.aoData, rows, 'anCells', column ) ; 8612 }, 1 ); 8613 } ); 8614 8615 _api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) { 8616 var ret = this.iterator( 'column', function ( settings, column ) { 8617 if ( vis === undefined ) { 8618 return settings.aoColumns[ column ].bVisible; 8619 } // else 8620 __setColumnVis( settings, column, vis ); 8621 } ); 8622 8623 // Group the column visibility changes 8624 if ( vis !== undefined ) { 8625 // Second loop once the first is done for events 8626 this.iterator( 'column', function ( settings, column ) { 8627 _fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis, calc] ); 8628 } ); 8629 8630 if ( calc === undefined || calc ) { 8631 this.columns.adjust(); 8632 } 8633 } 8634 8635 return ret; 8636 } ); 8637 8638 _api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) { 8639 return this.iterator( 'column', function ( settings, column ) { 8640 return type === 'visible' ? 8641 _fnColumnIndexToVisible( settings, column ) : 8642 column; 8643 }, 1 ); 8644 } ); 8645 8646 _api_register( 'columns.adjust()', function () { 8647 return this.iterator( 'table', function ( settings ) { 8648 _fnAdjustColumnSizing( settings ); 8649 }, 1 ); 8650 } ); 8651 8652 _api_register( 'column.index()', function ( type, idx ) { 8653 if ( this.context.length !== 0 ) { 8654 var ctx = this.context[0]; 8655 8656 if ( type === 'fromVisible' || type === 'toData' ) { 8657 return _fnVisibleToColumnIndex( ctx, idx ); 8658 } 8659 else if ( type === 'fromData' || type === 'toVisible' ) { 8660 return _fnColumnIndexToVisible( ctx, idx ); 8661 } 8662 } 8663 } ); 8664 8665 _api_register( 'column()', function ( selector, opts ) { 8666 return _selector_first( this.columns( selector, opts ) ); 8667 } ); 8668 8669 8670 8671 var __cell_selector = function ( settings, selector, opts ) 8672 { 8673 var data = settings.aoData; 8674 var rows = _selector_row_indexes( settings, opts ); 8675 var cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) ); 8676 var allCells = $( [].concat.apply([], cells) ); 8677 var row; 8678 var columns = settings.aoColumns.length; 8679 var a, i, ien, j, o, host; 8680 8681 var run = function ( s ) { 8682 var fnSelector = typeof s === 'function'; 8683 8684 if ( s === null || s === undefined || fnSelector ) { 8685 // All cells and function selectors 8686 a = []; 8687 8688 for ( i=0, ien=rows.length ; i<ien ; i++ ) { 8689 row = rows[i]; 8690 8691 for ( j=0 ; j<columns ; j++ ) { 8692 o = { 8693 row: row, 8694 column: j 8695 }; 8696 8697 if ( fnSelector ) { 8698 // Selector - function 8699 host = data[ row ]; 8700 8701 if ( s( o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null ) ) { 8702 a.push( o ); 8703 } 8704 } 8705 else { 8706 // Selector - all 8707 a.push( o ); 8708 } 8709 } 8710 } 8711 8712 return a; 8713 } 8714 8715 // Selector - index 8716 if ( $.isPlainObject( s ) ) { 8717 return [s]; 8718 } 8719 8720 // Selector - jQuery filtered cells 8721 var jqResult = allCells 8722 .filter( s ) 8723 .map( function (i, el) { 8724 return { // use a new object, in case someone changes the values 8725 row: el._DT_CellIndex.row, 8726 column: el._DT_CellIndex.column 8727 }; 8728 } ) 8729 .toArray(); 8730 8731 if ( jqResult.length || ! s.nodeName ) { 8732 return jqResult; 8733 } 8734 8735 // Otherwise the selector is a node, and there is one last option - the 8736 // element might be a child of an element which has dt-row and dt-column 8737 // data attributes 8738 host = $(s).closest('*[data-dt-row]'); 8739 return host.length ? 8740 [ { 8741 row: host.data('dt-row'), 8742 column: host.data('dt-column') 8743 } ] : 8744 []; 8745 }; 8746 8747 return _selector_run( 'cell', selector, run, settings, opts ); 8748 }; 8749 8750 8751 8752 8753 _api_register( 'cells()', function ( rowSelector, columnSelector, opts ) { 8754 // Argument shifting 8755 if ( $.isPlainObject( rowSelector ) ) { 8756 // Indexes 8757 if ( rowSelector.row === undefined ) { 8758 // Selector options in first parameter 8759 opts = rowSelector; 8760 rowSelector = null; 8761 } 8762 else { 8763 // Cell index objects in first parameter 8764 opts = columnSelector; 8765 columnSelector = null; 8766 } 8767 } 8768 if ( $.isPlainObject( columnSelector ) ) { 8769 opts = columnSelector; 8770 columnSelector = null; 8771 } 8772 8773 // Cell selector 8774 if ( columnSelector === null || columnSelector === undefined ) { 8775 return this.iterator( 'table', function ( settings ) { 8776 return __cell_selector( settings, rowSelector, _selector_opts( opts ) ); 8777 } ); 8778 } 8779 8780 // Row + column selector 8781 var columns = this.columns( columnSelector, opts ); 8782 var rows = this.rows( rowSelector, opts ); 8783 var a, i, ien, j, jen; 8784 8785 var cells = this.iterator( 'table', function ( settings, idx ) { 8786 a = []; 8787 8788 for ( i=0, ien=rows[idx].length ; i<ien ; i++ ) { 8789 for ( j=0, jen=columns[idx].length ; j<jen ; j++ ) { 8790 a.push( { 8791 row: rows[idx][i], 8792 column: columns[idx][j] 8793 } ); 8794 } 8795 } 8796 8797 return a; 8798 }, 1 ); 8799 8800 $.extend( cells.selector, { 8801 cols: columnSelector, 8802 rows: rowSelector, 8803 opts: opts 8804 } ); 8805 8806 return cells; 8807 } ); 8808 8809 8810 _api_registerPlural( 'cells().nodes()', 'cell().node()', function () { 8811 return this.iterator( 'cell', function ( settings, row, column ) { 8812 var data = settings.aoData[ row ]; 8813 8814 return data && data.anCells ? 8815 data.anCells[ column ] : 8816 undefined; 8817 }, 1 ); 8818 } ); 8819 8820 8821 _api_register( 'cells().data()', function () { 8822 return this.iterator( 'cell', function ( settings, row, column ) { 8823 return _fnGetCellData( settings, row, column ); 8824 }, 1 ); 8825 } ); 8826 8827 8828 _api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) { 8829 type = type === 'search' ? '_aFilterData' : '_aSortData'; 8830 8831 return this.iterator( 'cell', function ( settings, row, column ) { 8832 return settings.aoData[ row ][ type ][ column ]; 8833 }, 1 ); 8834 } ); 8835 8836 8837 _api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) { 8838 return this.iterator( 'cell', function ( settings, row, column ) { 8839 return _fnGetCellData( settings, row, column, type ); 8840 }, 1 ); 8841 } ); 8842 8843 8844 _api_registerPlural( 'cells().indexes()', 'cell().index()', function () { 8845 return this.iterator( 'cell', function ( settings, row, column ) { 8846 return { 8847 row: row, 8848 column: column, 8849 columnVisible: _fnColumnIndexToVisible( settings, column ) 8850 }; 8851 }, 1 ); 8852 } ); 8853 8854 8855 _api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) { 8856 return this.iterator( 'cell', function ( settings, row, column ) { 8857 _fnInvalidate( settings, row, src, column ); 8858 } ); 8859 } ); 8860 8861 8862 8863 _api_register( 'cell()', function ( rowSelector, columnSelector, opts ) { 8864 return _selector_first( this.cells( rowSelector, columnSelector, opts ) ); 8865 } ); 8866 8867 8868 _api_register( 'cell().data()', function ( data ) { 8869 var ctx = this.context; 8870 var cell = this[0]; 8871 8872 if ( data === undefined ) { 8873 // Get 8874 return ctx.length && cell.length ? 8875 _fnGetCellData( ctx[0], cell[0].row, cell[0].column ) : 8876 undefined; 8877 } 8878 8879 // Set 8880 _fnSetCellData( ctx[0], cell[0].row, cell[0].column, data ); 8881 _fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column ); 8882 8883 return this; 8884 } ); 8885 8886 8887 8888 /** 8889 * Get current ordering (sorting) that has been applied to the table. 8890 * 8891 * @returns {array} 2D array containing the sorting information for the first 8892 * table in the current context. Each element in the parent array represents 8893 * a column being sorted upon (i.e. multi-sorting with two columns would have 8894 * 2 inner arrays). The inner arrays may have 2 or 3 elements. The first is 8895 * the column index that the sorting condition applies to, the second is the 8896 * direction of the sort (`desc` or `asc`) and, optionally, the third is the 8897 * index of the sorting order from the `column.sorting` initialisation array. 8898 *//** 8899 * Set the ordering for the table. 8900 * 8901 * @param {integer} order Column index to sort upon. 8902 * @param {string} direction Direction of the sort to be applied (`asc` or `desc`) 8903 * @returns {DataTables.Api} this 8904 *//** 8905 * Set the ordering for the table. 8906 * 8907 * @param {array} order 1D array of sorting information to be applied. 8908 * @param {array} [...] Optional additional sorting conditions 8909 * @returns {DataTables.Api} this 8910 *//** 8911 * Set the ordering for the table. 8912 * 8913 * @param {array} order 2D array of sorting information to be applied. 8914 * @returns {DataTables.Api} this 8915 */ 8916 _api_register( 'order()', function ( order, dir ) { 8917 var ctx = this.context; 8918 8919 if ( order === undefined ) { 8920 // get 8921 return ctx.length !== 0 ? 8922 ctx[0].aaSorting : 8923 undefined; 8924 } 8925 8926 // set 8927 if ( typeof order === 'number' ) { 8928 // Simple column / direction passed in 8929 order = [ [ order, dir ] ]; 8930 } 8931 else if ( order.length && ! $.isArray( order[0] ) ) { 8932 // Arguments passed in (list of 1D arrays) 8933 order = Array.prototype.slice.call( arguments ); 8934 } 8935 // otherwise a 2D array was passed in 8936 8937 return this.iterator( 'table', function ( settings ) { 8938 settings.aaSorting = order.slice(); 8939 } ); 8940 } ); 8941 8942 8943 /** 8944 * Attach a sort listener to an element for a given column 8945 * 8946 * @param {node|jQuery|string} node Identifier for the element(s) to attach the 8947 * listener to. This can take the form of a single DOM node, a jQuery 8948 * collection of nodes or a jQuery selector which will identify the node(s). 8949 * @param {integer} column the column that a click on this node will sort on 8950 * @param {function} [callback] callback function when sort is run 8951 * @returns {DataTables.Api} this 8952 */ 8953 _api_register( 'order.listener()', function ( node, column, callback ) { 8954 return this.iterator( 'table', function ( settings ) { 8955 _fnSortAttachListener( settings, node, column, callback ); 8956 } ); 8957 } ); 8958 8959 8960 _api_register( 'order.fixed()', function ( set ) { 8961 if ( ! set ) { 8962 var ctx = this.context; 8963 var fixed = ctx.length ? 8964 ctx[0].aaSortingFixed : 8965 undefined; 8966 8967 return $.isArray( fixed ) ? 8968 { pre: fixed } : 8969 fixed; 8970 } 8971 8972 return this.iterator( 'table', function ( settings ) { 8973 settings.aaSortingFixed = $.extend( true, {}, set ); 8974 } ); 8975 } ); 8976 8977 8978 // Order by the selected column(s) 8979 _api_register( [ 8980 'columns().order()', 8981 'column().order()' 8982 ], function ( dir ) { 8983 var that = this; 8984 8985 return this.iterator( 'table', function ( settings, i ) { 8986 var sort = []; 8987 8988 $.each( that[i], function (j, col) { 8989 sort.push( [ col, dir ] ); 8990 } ); 8991 8992 settings.aaSorting = sort; 8993 } ); 8994 } ); 8995 8996 8997 8998 _api_register( 'search()', function ( input, regex, smart, caseInsen ) { 8999 var ctx = this.context; 9000 9001 if ( input === undefined ) { 9002 // get 9003 return ctx.length !== 0 ? 9004 ctx[0].oPreviousSearch.sSearch : 9005 undefined; 9006 } 9007 9008 // set 9009 return this.iterator( 'table', function ( settings ) { 9010 if ( ! settings.oFeatures.bFilter ) { 9011 return; 9012 } 9013 9014 _fnFilterComplete( settings, $.extend( {}, settings.oPreviousSearch, { 9015 "sSearch": input+"", 9016 "bRegex": regex === null ? false : regex, 9017 "bSmart": smart === null ? true : smart, 9018 "bCaseInsensitive": caseInsen === null ? true : caseInsen 9019 } ), 1 ); 9020 } ); 9021 } ); 9022 9023 9024 _api_registerPlural( 9025 'columns().search()', 9026 'column().search()', 9027 function ( input, regex, smart, caseInsen ) { 9028 return this.iterator( 'column', function ( settings, column ) { 9029 var preSearch = settings.aoPreSearchCols; 9030 9031 if ( input === undefined ) { 9032 // get 9033 return preSearch[ column ].sSearch; 9034 } 9035 9036 // set 9037 if ( ! settings.oFeatures.bFilter ) { 9038 return; 9039 } 9040 9041 $.extend( preSearch[ column ], { 9042 "sSearch": input+"", 9043 "bRegex": regex === null ? false : regex, 9044 "bSmart": smart === null ? true : smart, 9045 "bCaseInsensitive": caseInsen === null ? true : caseInsen 9046 } ); 9047 9048 _fnFilterComplete( settings, settings.oPreviousSearch, 1 ); 9049 } ); 9050 } 9051 ); 9052 9053 /* 9054 * State API methods 9055 */ 9056 9057 _api_register( 'state()', function () { 9058 return this.context.length ? 9059 this.context[0].oSavedState : 9060 null; 9061 } ); 9062 9063 9064 _api_register( 'state.clear()', function () { 9065 return this.iterator( 'table', function ( settings ) { 9066 // Save an empty object 9067 settings.fnStateSaveCallback.call( settings.oInstance, settings, {} ); 9068 } ); 9069 } ); 9070 9071 9072 _api_register( 'state.loaded()', function () { 9073 return this.context.length ? 9074 this.context[0].oLoadedState : 9075 null; 9076 } ); 9077 9078 9079 _api_register( 'state.save()', function () { 9080 return this.iterator( 'table', function ( settings ) { 9081 _fnSaveState( settings ); 9082 } ); 9083 } ); 9084 9085 9086 9087 /** 9088 * Provide a common method for plug-ins to check the version of DataTables being 9089 * used, in order to ensure compatibility. 9090 * 9091 * @param {string} version Version string to check for, in the format "X.Y.Z". 9092 * Note that the formats "X" and "X.Y" are also acceptable. 9093 * @returns {boolean} true if this version of DataTables is greater or equal to 9094 * the required version, or false if this version of DataTales is not 9095 * suitable 9096 * @static 9097 * @dtopt API-Static 9098 * 9099 * @example 9100 * alert( $.fn.dataTable.versionCheck( '1.9.0' ) ); 9101 */ 9102 DataTable.versionCheck = DataTable.fnVersionCheck = function( version ) 9103 { 9104 var aThis = DataTable.version.split('.'); 9105 var aThat = version.split('.'); 9106 var iThis, iThat; 9107 9108 for ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) { 9109 iThis = parseInt( aThis[i], 10 ) || 0; 9110 iThat = parseInt( aThat[i], 10 ) || 0; 9111 9112 // Parts are the same, keep comparing 9113 if (iThis === iThat) { 9114 continue; 9115 } 9116 9117 // Parts are different, return immediately 9118 return iThis > iThat; 9119 } 9120 9121 return true; 9122 }; 9123 9124 9125 /** 9126 * Check if a `<table>` node is a DataTable table already or not. 9127 * 9128 * @param {node|jquery|string} table Table node, jQuery object or jQuery 9129 * selector for the table to test. Note that if more than more than one 9130 * table is passed on, only the first will be checked 9131 * @returns {boolean} true the table given is a DataTable, or false otherwise 9132 * @static 9133 * @dtopt API-Static 9134 * 9135 * @example 9136 * if ( ! $.fn.DataTable.isDataTable( '#example' ) ) { 9137 * $('#example').dataTable(); 9138 * } 9139 */ 9140 DataTable.isDataTable = DataTable.fnIsDataTable = function ( table ) 9141 { 9142 var t = $(table).get(0); 9143 var is = false; 9144 9145 if ( table instanceof DataTable.Api ) { 9146 return true; 9147 } 9148 9149 $.each( DataTable.settings, function (i, o) { 9150 var head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null; 9151 var foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null; 9152 9153 if ( o.nTable === t || head === t || foot === t ) { 9154 is = true; 9155 } 9156 } ); 9157 9158 return is; 9159 }; 9160 9161 9162 /** 9163 * Get all DataTable tables that have been initialised - optionally you can 9164 * select to get only currently visible tables. 9165 * 9166 * @param {boolean} [visible=false] Flag to indicate if you want all (default) 9167 * or visible tables only. 9168 * @returns {array} Array of `table` nodes (not DataTable instances) which are 9169 * DataTables 9170 * @static 9171 * @dtopt API-Static 9172 * 9173 * @example 9174 * $.each( $.fn.dataTable.tables(true), function () { 9175 * $(table).DataTable().columns.adjust(); 9176 * } ); 9177 */ 9178 DataTable.tables = DataTable.fnTables = function ( visible ) 9179 { 9180 var api = false; 9181 9182 if ( $.isPlainObject( visible ) ) { 9183 api = visible.api; 9184 visible = visible.visible; 9185 } 9186 9187 var a = $.map( DataTable.settings, function (o) { 9188 if ( !visible || (visible && $(o.nTable).is(':visible')) ) { 9189 return o.nTable; 9190 } 9191 } ); 9192 9193 return api ? 9194 new _Api( a ) : 9195 a; 9196 }; 9197 9198 9199 /** 9200 * Convert from camel case parameters to Hungarian notation. This is made public 9201 * for the extensions to provide the same ability as DataTables core to accept 9202 * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase 9203 * parameters. 9204 * 9205 * @param {object} src The model object which holds all parameters that can be 9206 * mapped. 9207 * @param {object} user The object to convert from camel case to Hungarian. 9208 * @param {boolean} force When set to `true`, properties which already have a 9209 * Hungarian value in the `user` object will be overwritten. Otherwise they 9210 * won't be. 9211 */ 9212 DataTable.camelToHungarian = _fnCamelToHungarian; 9213 9214 9215 9216 /** 9217 * 9218 */ 9219 _api_register( '$()', function ( selector, opts ) { 9220 var 9221 rows = this.rows( opts ).nodes(), // Get all rows 9222 jqRows = $(rows); 9223 9224 return $( [].concat( 9225 jqRows.filter( selector ).toArray(), 9226 jqRows.find( selector ).toArray() 9227 ) ); 9228 } ); 9229 9230 9231 // jQuery functions to operate on the tables 9232 $.each( [ 'on', 'one', 'off' ], function (i, key) { 9233 _api_register( key+'()', function ( /* event, handler */ ) { 9234 var args = Array.prototype.slice.call(arguments); 9235 9236 // Add the `dt` namespace automatically if it isn't already present 9237 args[0] = $.map( args[0].split( /\s/ ), function ( e ) { 9238 return ! e.match(/\.dt\b/) ? 9239 e+'.dt' : 9240 e; 9241 } ).join( ' ' ); 9242 9243 var inst = $( this.tables().nodes() ); 9244 inst[key].apply( inst, args ); 9245 return this; 9246 } ); 9247 } ); 9248 9249 9250 _api_register( 'clear()', function () { 9251 return this.iterator( 'table', function ( settings ) { 9252 _fnClearTable( settings ); 9253 } ); 9254 } ); 9255 9256 9257 _api_register( 'settings()', function () { 9258 return new _Api( this.context, this.context ); 9259 } ); 9260 9261 9262 _api_register( 'init()', function () { 9263 var ctx = this.context; 9264 return ctx.length ? ctx[0].oInit : null; 9265 } ); 9266 9267 9268 _api_register( 'data()', function () { 9269 return this.iterator( 'table', function ( settings ) { 9270 return _pluck( settings.aoData, '_aData' ); 9271 } ).flatten(); 9272 } ); 9273 9274 9275 _api_register( 'destroy()', function ( remove ) { 9276 remove = remove || false; 9277 9278 return this.iterator( 'table', function ( settings ) { 9279 var orig = settings.nTableWrapper.parentNode; 9280 var classes = settings.oClasses; 9281 var table = settings.nTable; 9282 var tbody = settings.nTBody; 9283 var thead = settings.nTHead; 9284 var tfoot = settings.nTFoot; 9285 var jqTable = $(table); 9286 var jqTbody = $(tbody); 9287 var jqWrapper = $(settings.nTableWrapper); 9288 var rows = $.map( settings.aoData, function (r) { return r.nTr; } ); 9289 var i, ien; 9290 9291 // Flag to note that the table is currently being destroyed - no action 9292 // should be taken 9293 settings.bDestroying = true; 9294 9295 // Fire off the destroy callbacks for plug-ins etc 9296 _fnCallbackFire( settings, "aoDestroyCallback", "destroy", [settings] ); 9297 9298 // If not being removed from the document, make all columns visible 9299 if ( ! remove ) { 9300 new _Api( settings ).columns().visible( true ); 9301 } 9302 9303 // Blitz all `DT` namespaced events (these are internal events, the 9304 // lowercase, `dt` events are user subscribed and they are responsible 9305 // for removing them 9306 jqWrapper.off('.DT').find(':not(tbody *)').off('.DT'); 9307 $(window).off('.DT-'+settings.sInstance); 9308 9309 // When scrolling we had to break the table up - restore it 9310 if ( table != thead.parentNode ) { 9311 jqTable.children('thead').detach(); 9312 jqTable.append( thead ); 9313 } 9314 9315 if ( tfoot && table != tfoot.parentNode ) { 9316 jqTable.children('tfoot').detach(); 9317 jqTable.append( tfoot ); 9318 } 9319 9320 settings.aaSorting = []; 9321 settings.aaSortingFixed = []; 9322 _fnSortingClasses( settings ); 9323 9324 $( rows ).removeClass( settings.asStripeClasses.join(' ') ); 9325 9326 $('th, td', thead).removeClass( classes.sSortable+' '+ 9327 classes.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone 9328 ); 9329 9330 // Add the TR elements back into the table in their original order 9331 jqTbody.children().detach(); 9332 jqTbody.append( rows ); 9333 9334 // Remove the DataTables generated nodes, events and classes 9335 var removedMethod = remove ? 'remove' : 'detach'; 9336 jqTable[ removedMethod ](); 9337 jqWrapper[ removedMethod ](); 9338 9339 // If we need to reattach the table to the document 9340 if ( ! remove && orig ) { 9341 // insertBefore acts like appendChild if !arg[1] 9342 orig.insertBefore( table, settings.nTableReinsertBefore ); 9343 9344 // Restore the width of the original table - was read from the style property, 9345 // so we can restore directly to that 9346 jqTable 9347 .css( 'width', settings.sDestroyWidth ) 9348 .removeClass( classes.sTable ); 9349 9350 // If the were originally stripe classes - then we add them back here. 9351 // Note this is not fool proof (for example if not all rows had stripe 9352 // classes - but it's a good effort without getting carried away 9353 ien = settings.asDestroyStripes.length; 9354 9355 if ( ien ) { 9356 jqTbody.children().each( function (i) { 9357 $(this).addClass( settings.asDestroyStripes[i % ien] ); 9358 } ); 9359 } 9360 } 9361 9362 /* Remove the settings object from the settings array */ 9363 var idx = $.inArray( settings, DataTable.settings ); 9364 if ( idx !== -1 ) { 9365 DataTable.settings.splice( idx, 1 ); 9366 } 9367 } ); 9368 } ); 9369 9370 9371 // Add the `every()` method for rows, columns and cells in a compact form 9372 $.each( [ 'column', 'row', 'cell' ], function ( i, type ) { 9373 _api_register( type+'s().every()', function ( fn ) { 9374 var opts = this.selector.opts; 9375 var api = this; 9376 9377 return this.iterator( type, function ( settings, arg1, arg2, arg3, arg4 ) { 9378 // Rows and columns: 9379 // arg1 - index 9380 // arg2 - table counter 9381 // arg3 - loop counter 9382 // arg4 - undefined 9383 // Cells: 9384 // arg1 - row index 9385 // arg2 - column index 9386 // arg3 - table counter 9387 // arg4 - loop counter 9388 fn.call( 9389 api[ type ]( 9390 arg1, 9391 type==='cell' ? arg2 : opts, 9392 type==='cell' ? opts : undefined 9393 ), 9394 arg1, arg2, arg3, arg4 9395 ); 9396 } ); 9397 } ); 9398 } ); 9399 9400 9401 // i18n method for extensions to be able to use the language object from the 9402 // DataTable 9403 _api_register( 'i18n()', function ( token, def, plural ) { 9404 var ctx = this.context[0]; 9405 var resolved = _fnGetObjectDataFn( token )( ctx.oLanguage ); 9406 9407 if ( resolved === undefined ) { 9408 resolved = def; 9409 } 9410 9411 if ( plural !== undefined && $.isPlainObject( resolved ) ) { 9412 resolved = resolved[ plural ] !== undefined ? 9413 resolved[ plural ] : 9414 resolved._; 9415 } 9416 9417 return resolved.replace( '%d', plural ); // nb: plural might be undefined, 9418 } ); 9419 9420 /** 9421 * Version string for plug-ins to check compatibility. Allowed format is 9422 * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used 9423 * only for non-release builds. See http://semver.org/ for more information. 9424 * @member 9425 * @type string 9426 * @default Version number 9427 */
9428 DataTable.version = "1.10.16"; 9429 9430 /** 9431 * Private data store, containing all of the settings objects that are 9432 * created for the tables on a given page. 9433 * 9434 * Note that the `DataTable.settings` object is aliased to 9435 * `jQuery.fn.dataTableExt` through which it may be accessed and 9436 * manipulated, or `jQuery.fn.dataTable.settings`. 9437 * @member 9438 * @type array 9439 * @default [] 9440 * @private 9441 */ 9442 DataTable.settings = []; 9443 9444 /** 9445 * Object models container, for the various models that DataTables has 9446 * available to it. These models define the objects that are used to hold 9447 * the active state and configuration of the table. 9448 * @namespace 9449 */ 9450 DataTable.models = {}; 9451 9452 9453 9454 /** 9455 * Template object for the way in which DataTables holds information about 9456 * search information for the global filter and individual column filters. 9457 * @namespace 9458 */ 9459 DataTable.models.oSearch = { 9460 /** 9461 * Flag to indicate if the filtering should be case insensitive or not 9462 * @type boolean 9463 * @default true 9464 */ 9465 "bCaseInsensitive": true, 9466 9467 /** 9468 * Applied search term 9469 * @type string 9470 * @default <i>Empty string</i> 9471 */ 9472 "sSearch": "", 9473 9474 /** 9475 * Flag to indicate if the search term should be interpreted as a 9476 * regular expression (true) or not (false) and therefore and special 9477 * regex characters escaped. 9478 * @type boolean 9479 * @default false 9480 */ 9481 "bRegex": false, 9482 9483 /** 9484 * Flag to indicate if DataTables is to use its smart filtering or not. 9485 * @type boolean 9486 * @default true 9487 */ 9488 "bSmart": true 9489 }; 9490 9491 9492 9493 9494 /** 9495 * Template object for the way in which DataTables holds information about 9496 * each individual row. This is the object format used for the settings 9497 * aoData array. 9498 * @namespace 9499 */ 9500 DataTable.models.oRow = { 9501 /** 9502 * TR element for the row 9503 * @type node 9504 * @default null 9505 */ 9506 "nTr": null, 9507 9508 /** 9509 * Array of TD elements for each row. This is null until the row has been 9510 * created. 9511 * @type array nodes 9512 * @default [] 9513 */ 9514 "anCells": null, 9515 9516 /** 9517 * Data object from the original data source for the row. This is either 9518 * an array if using the traditional form of DataTables, or an object if 9519 * using mData options. The exact type will depend on the passed in 9520 * data from the data source, or will be an array if using DOM a data 9521 * source. 9522 * @type array|object 9523 * @default [] 9524 */ 9525 "_aData": [], 9526 9527 /** 9528 * Sorting data cache - this array is ostensibly the same length as the 9529 * number of columns (although each index is generated only as it is 9530 * needed), and holds the data that is used for sorting each column in the 9531 * row. We do this cache generation at the start of the sort in order that 9532 * the formatting of the sort data need be done only once for each cell 9533 * per sort. This array should not be read from or written to by anything 9534 * other than the master sorting methods. 9535 * @type array 9536 * @default null 9537 * @private 9538 */ 9539 "_aSortData": null, 9540 9541 /** 9542 * Per cell filtering data cache. As per the sort data cache, used to 9543 * increase the performance of the filtering in DataTables 9544 * @type array 9545 * @default null 9546 * @private 9547 */ 9548 "_aFilterData": null, 9549 9550 /** 9551 * Filtering data cache. This is the same as the cell filtering cache, but 9552 * in this case a string rather than an array. This is easily computed with 9553 * a join on `_aFilterData`, but is provided as a cache so the join isn't 9554 * needed on every search (memory traded for performance) 9555 * @type array 9556 * @default null 9557 * @private 9558 */ 9559 "_sFilterRow": null, 9560 9561 /** 9562 * Cache of the class name that DataTables has applied to the row, so we 9563 * can quickly look at this variable rather than needing to do a DOM check 9564 * on className for the nTr property. 9565 * @type string 9566 * @default <i>Empty string</i> 9567 * @private 9568 */ 9569 "_sRowStripe": "", 9570 9571 /** 9572 * Denote if the original data source was from the DOM, or the data source 9573 * object. This is used for invalidating data, so DataTables can 9574 * automatically read data from the original source, unless uninstructed 9575 * otherwise. 9576 * @type string 9577 * @default null 9578 * @private 9579 */ 9580 "src": null, 9581 9582 /** 9583 * Index in the aoData array. This saves an indexOf lookup when we have the 9584 * object, but want to know the index 9585 * @type integer 9586 * @default -1 9587 * @private 9588 */ 9589 "idx": -1 9590 }; 9591 9592 9593 /** 9594 * Template object for the column information object in DataTables. This object 9595 * is held in the settings aoColumns array and contains all the information that 9596 * DataTables needs about each individual column. 9597 * 9598 * Note that this object is related to {@link DataTable.defaults.column} 9599 * but this one is the internal data store for DataTables's cache of columns. 9600 * It should NOT be manipulated outside of DataTables. Any configuration should 9601 * be done through the initialisation options. 9602 * @namespace 9603 */ 9604 DataTable.models.oColumn = { 9605 /** 9606 * Column index. This could be worked out on-the-fly with $.inArray, but it 9607 * is faster to just hold it as a variable 9608 * @type integer 9609 * @default null 9610 */ 9611 "idx": null, 9612 9613 /** 9614 * A list of the columns that sorting should occur on when this column 9615 * is sorted. That this property is an array allows multi-column s
9615orting 9616 * to be defined for a column (for example first name / last name columns 9617 * would benefit from this). The values are integers pointing to the 9618 * columns to be sorted on (typically it will be a single integer pointing 9619 * at itself, but that doesn't need to be the case). 9620 * @type array 9621 */ 9622 "aDataSort": null, 9623 9624 /** 9625 * Define the sorting directions that are applied to the column, in sequence 9626 * as the column is repeatedly sorted upon - i.e. the first value is used 9627 * as the sorting direction when the column if first sorted (clicked on). 9628 * Sort it again (click again) and it will move on to the next index. 9629 * Repeat until loop. 9630 * @type array 9631 */ 9632 "asSorting": null, 9633 9634 /** 9635 * Flag to indicate if the column is searchable, and thus should be included 9636 * in the filtering or not. 9637 * @type boolean 9638 */ 9639 "bSearchable": null, 9640 9641 /** 9642 * Flag to indicate if the column is sortable or not. 9643 * @type boolean 9644 */ 9645 "bSortable": null, 9646 9647 /** 9648 * Flag to indicate if the column is currently visible in the table or not 9649 * @type boolean 9650 */ 9651 "bVisible": null, 9652 9653 /** 9654 * Store for manual type assignment using the `column.type` option. This 9655 * is held in store so we can manipulate the column's `sType` property. 9656 * @type string 9657 * @default null 9658 * @private 9659 */ 9660 "_sManualType": null, 9661 9662 /** 9663 * Flag to indicate if HTML5 data attributes should be used as the data 9664 * source for filtering or sorting. True is either are. 9665 * @type boolean 9666 * @default false 9667 * @private 9668 */ 9669 "_bAttrSrc": false, 9670 9671 /** 9672 * Developer definable function that is called whenever a cell is created (Ajax source, 9673 * etc) or processed for input (DOM source). This can be used as a compliment to mRender 9674 * allowing you to modify the DOM element (add background colour for example) when the 9675 * element is available. 9676 * @type function 9677 * @param {element} nTd The TD node that has been created 9678 * @param {*} sData The Data for the cell 9679 * @param {array|object} oData The data for the whole row 9680 * @param {int} iRow The row index for the aoData data store 9681 * @default null 9682 */ 9683 "fnCreatedCell": null, 9684 9685 /** 9686 * Function to get data from a cell in a column. You should <b>never</b> 9687 * access data directly through _aData internally in DataTables - always use 9688 * the method attached to this property. It allows mData to function as 9689 * required. This function is automatically assigned by the column 9690 * initialisation method 9691 * @type function 9692 * @param {array|object} oData The data array/object for the array 9693 * (i.e. aoData[]._aData) 9694 * @param {string} sSpecific The specific data type you want to get - 9695 * 'display', 'type' 'filter' 'sort' 9696 * @returns {*} The data for the cell from the given row's data 9697 * @default null 9698 */ 9699 "fnGetData": null, 9700 9701 /** 9702 * Function to set data for a cell in the column. You should <b>never</b> 9703 * set the data directly to _aData internally in DataTables - always use 9704 * this method. It allows mData to function as required. This function 9705 * is automatically assigned by the column initialisation method 9706 * @type function 9707 * @param {array|object} oData The data array/object for the array 9708 * (i.e. aoData[]._aData) 9709 * @param {*} sValue Value to set 9710 * @default null 9711 */ 9712 "fnSetData": null, 9713 9714 /** 9715 * Property to read the value for the cells in the column from the data 9716 * source array / object. If null, then the default content is used, if a 9717 * function is given then the return from the function is used. 9718 * @type function|int|string|null 9719 * @default null 9720 */ 9721 "mData": null, 9722 9723 /** 9724 * Partner property to mData which is used (only when defined) to get 9725 * the data - i.e. it is basically the same as mData, but without the 9726 * 'set' option, and also the data fed to it is the result from mData. 9727 * This is the rendering method to match the data method of mData. 9728 * @type function|int|string|null 9729 * @default null 9730 */ 9731 "mRender": null, 9732 9733 /** 9734 * Unique header TH/TD element for this column - this is what the sorting 9735 * listener is attached to (if sorting is enabled.) 9736 * @type node 9737 * @default null 9738 */ 9739 "nTh": null, 9740 9741 /** 9742 * Unique footer TH/TD element for this column (if there is one). Not used
9743 * in DataTables as such, but can be used for plug-ins to reference the 9744 * footer for each column. 9745 * @type node 9746 * @default null 9747 */ 9748 "nTf": null, 9749 9750 /** 9751 * The class to apply to all TD elements in the table's TBODY for the column 9752 * @type string 9753 * @default null 9754 */ 9755 "sClass": null, 9756 9757 /** 9758 * When DataTables calculates the column widths to assign to each column, 9759 * it finds the longest string in each column and then constructs a 9760 * temporary table and reads the widths from that. The problem with this 9761 * is that "mmm" is much wider then "iiii", but the latter is a longer 9762 * string - thus the calculation can go wrong (doing it properly and putting 9763 * it into an DOM object and measuring that is horribly(!) slow). Thus as 9764 * a "work around" we provide this option. It will append its value to the 9765 * text that is found to be the longest string for the column - i.e. padding. 9766 * @type string 9767 */ 9768 "sContentPadding": null, 9769 9770 /** 9771 * Allows a default value to be given for a column's data, and will be used 9772 * whenever a null data source is encountered (this can be because mData 9773 * is set to null, or because the data source itself is null). 9774 * @type string 9775 * @default null 9776 */ 9777 "sDefaultContent": null, 9778 9779 /** 9780 * Name for the column, allowing reference to the column by name as well as 9781 * by index (needs a lookup to work by name). 9782 * @type string 9783 */ 9784 "sName": null, 9785 9786 /** 9787 * Custom sorting data type - defines which of the available plug-ins in 9788 * afnSortData the custom sorting will use - if any is defined. 9789 * @type string 9790 * @default std 9791 */ 9792 "sSortDataType": 'std', 9793 9794 /** 9795 * Class to be applied to the header element when sorting on this column 9796 * @type string 9797 * @default null 9798 */ 9799 "sSortingClass": null, 9800 9801 /** 9802 * Class to be applied to the header element when sorting on this column - 9803 * when jQuery UI theming is used. 9804 * @type string 9805 * @default null 9806 */ 9807 "sSortingClassJUI": null, 9808 9809 /** 9810 * Title of the column - what is seen in the TH element (nTh). 9811 * @type string 9812 */ 9813 "sTitle": null, 9814 9815 /** 9816 * Column sorting and filtering type 9817 * @type string 9818 * @default null 9819 */ 9820 "sType": null, 9821 9822 /** 9823 * Width of the column 9824 * @type string 9825 * @default null 9826 */ 9827 "sWidth": null, 9828 9829 /** 9830 * Width of the column when it was first "encountered" 9831 * @type string 9832 * @default null 9833 */ 9834 "sWidthOrig": null 9835 }; 9836 9837 9838 /* 9839 * Developer note: The properties of the object below are given in Hungarian 9840 * notation, that was used as the interface for DataTables prior to v1.10, however 9841 * from v1.10 onwards the primary interface is camel case. In order to avoid 9842 * breaking backwards compatibility utterly with this change, the Hungarian 9843 * version is still, internally the primary interface, but is is not documented 9844 * - hence the @name tags in each doc comment. This allows a Javascript function 9845 * to create a map from Hungarian notation to camel case (going the other direction 9846 * would require each property to be listed, which would at around 3K to the size 9847 * of DataTables, while this method is about a 0.5K hit
vendor: 57,087 bytes, lines 9847-11623
9847. 9848 * 9849 * Ultimately this does pave the way for Hungarian notation to be dropped 9850 * completely, but that is a massive amount of work and will break current 9851 * installs (therefore is on-hold until v2). 9852 */ 9853 9854 /** 9855 * Initialisation options that can be given to DataTables at initialisation 9856 * time. 9857 * @namespace 9858 */ 9859 DataTable.defaults = { 9860 /** 9861 * An array of data to use for the table, passed in at initialisation which 9862 * will be used in preference to any data which is already in the DOM. This is 9863 * particularly useful for constructing tables purely in Javascript, for 9864 * example with a custom Ajax call. 9865 * @type array 9866 * @default null 9867 * 9868 * @dtopt Option 9869 * @name DataTable.defaults.data 9870 * 9871 * @example 9872 * // Using a 2D array data source 9873 * $(document).ready( function () { 9874 * $('#example').dataTable( { 9875 * "data": [ 9876 * ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'], 9877 * ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'], 9878 * ], 9879 * "columns": [ 9880 * { "title": "Engine" }, 9881 * { "title": "Browser" }, 9882 * { "title": "Platform" }, 9883 * { "title": "Version" }, 9884 * { "title": "Grade" } 9885 * ] 9886 * } ); 9887 * } ); 9888 * 9889 * @example 9890 * // Using an array of objects as a data source (`data`) 9891 * $(document).ready( function () { 9892 * $('#example').dataTable( { 9893 * "data": [ 9894 * { 9895 * "engine": "Trident", 9896 * "browser": "Internet Explorer 4.0", 9897 * "platform": "Win 95+", 9898 * "version": 4, 9899 * "grade": "X" 9900 * }, 9901 * { 9902 * "engine": "Trident", 9903 * "browser": "Internet Explorer 5.0", 9904 * "platform": "Win 95+", 9905 * "version": 5, 9906 * "grade": "C" 9907 * } 9908 * ], 9909 * "columns": [ 9910 * { "title": "Engine", "data": "engine" }, 9911 * { "title": "Browser", "data": "browser" }, 9912 * { "title": "Platform", "data": "platform" }, 9913 * { "title": "Version", "data": "version" }, 9914 * { "title": "Grade", "data": "grade" } 9915 * ] 9916 * } ); 9917 * } ); 9918 */ 9919 "aaData": null, 9920 9921 9922 /** 9923 * If ordering is enabled, then DataTables will perform a first pass sort on 9924 * initialisation. You can define which column(s) the sort is performed 9925 * upon, and the sorting direction, with this variable. The `sorting` array 9926 * should contain an array for each column to be sorted initially containing 9927 * the column's index and a direction string ('asc' or 'desc'). 9928 * @type array 9929 * @default [[0,'asc']] 9930 * 9931 * @dtopt Option 9932 * @name DataTable.defaults.order 9933 * 9934 * @example 9935 * // Sort by 3rd column first, and then 4th column 9936 * $(document).ready( function() { 9937 * $('#example').dataTable( { 9938 * "order": [[2,'asc'], [3,'desc']] 9939 * } ); 9940 * } ); 9941 * 9942 * // No initial sorting 9943 * $(document).ready( function() { 9944 * $('#example').dataTable( { 9945 * "order": [] 9946 * } ); 9947 * } ); 9948 */ 9949 "aaSorting": [[0,'asc']], 9950 9951 9952 /** 9953 * This parameter is basically identical to the `sorting` parameter, but 9954 * cannot be overridden by user interaction with the table. What this means 9955 * is that you could have a column (visible or hidden) which the sorting 9956 * will always be forced on first - any sorting after that (from the user) 9957 * will then be performed as required. This can be useful for grouping rows 9958 * together. 9959 * @type array 9960 * @default null 9961 * 9962 * @dtopt Option 9963 * @name DataTable.defaults.orderFixed 9964 * 9965 * @example 9966 * $(document).ready( function() { 9967 * $('#example').dataTable( { 9968 * "orderFixed": [[0,'asc']] 9969 * } ); 9970 * } ) 9971 */ 9972 "aaSortingFixed": [], 9973 9974 9975 /** 9976 * DataTables can be instructed to load data to display in the table from a 9977 * Ajax source. This option defines how that Ajax call is made and where to. 9978 * 9979 * The `ajax` property has three different modes of operation, depending on 9980 * how it is defined. These are: 9981 * 9982 * * `string` - Set the URL from where the data should be loaded from. 9983 * * `object` - Define properties for `jQuery.ajax`. 9984 * * `function` - Custom data get function 9985 * 9986 * `string` 9987 * -------- 9988 * 9989 * As a string, the `ajax` property simply defines the URL from which 9990 * DataTables will load data. 9991 * 9992 * `object` 9993 * -------- 9994 * 9995 * As an object, the parameters in the object are passed to 9996 * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control 9997 * of the Ajax request. DataTables has a number of default parameters which 9998 * you can override using this option. Please refer to the jQuery 9999 * documentation for a full description of the options available, although 10000 * the following parameters provide additional options in DataTables or 10001 * require special consideration: 10002 * 10003 * * `data` - As with jQuery, `data` can be provided as an object, but it 10004 * can also be used as a function to manipulate the data DataTables sends 10005 * to the server. The function takes a single parameter, an object of 10006 * parameters with the values that DataTables has readied for sending. An 10007 * object may be returned which will be merged into the DataTables 10008 * defaults, or you can add the items to the object that was passed in and 10009 * not return anything from the function. This supersedes `fnServerParams` 10010 * from DataTables 1.9-. 10011 * 10012 * * `dataSrc` - By default DataTables will look for the property `data` (or 10013 * `aaData` for compatibility with DataTables 1.9-) when obtaining data 10014 * from an Ajax source or for server-side processing - this parameter 10015 * allows that property to be changed. You can use Javascript dotted 10016 * object notation to get a data source for multiple levels of nesting, or 10017 * it my be used as a function. As a function it takes a single parameter, 10018 * the JSON returned from the server, which can be manipulated as 10019 * required, with the returned value being that used by DataTables as the 10020 * data source for the table. This supersedes `sAjaxDataProp` from 10021 * DataTables 1.9-. 10022 * 10023 * * `success` - Should not be overridden it is used internally in 10024 * DataTables. To manipulate / transform the data returned by the server 10025 * use `ajax.dataSrc`, or use `ajax` as a function (see below). 10026 * 10027 * `function` 10028 * ---------- 10029 * 10030 * As a function, making the Ajax call is left up to yourself allowing 10031 * complete control of the Ajax request. Indeed, if desired, a method other 10032 * than Ajax could be used to obtain the required data, such as Web storage 10033 * or an AIR database. 10034 * 10035 * The function is given four parameters and no return is required. The 10036 * parameters are: 10037 * 10038 * 1. _object_ - Data to send to the server 10039 * 2. _function_ - Callback function that must be executed when the required 10040 * data has been obtained. That data should be passed into the callback 10041 * as the only parameter 10042 * 3. _object_ - DataTables settings object for the table 10043 * 10044 * Note that this supersedes `fnServerData` from DataTables 1.9-. 10045 * 10046 * @type string|object|function 10047 * @default null 10048 * 10049 * @dtopt Option 10050 * @name DataTable.defaults.ajax 10051 * @since 1.10.0 10052 * 10053 * @example 10054 * // Get JSON data from a file via Ajax. 10055 * // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default). 10056 * $('#example').dataTable( { 10057 * "ajax": "data.json" 10058 * } ); 10059 * 10060 * @example 10061 * // Get JSON data from a file via Ajax, using `dataSrc` to change 10062 * // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`) 10063 * $('#example').dataTable( { 10064 * "ajax": { 10065 * "url": "data.json", 10066 * "dataSrc": "tableData" 10067 * } 10068 * } ); 10069 * 10070 * @example 10071 * // Get JSON data from a file via Ajax, using `dataSrc` to read data 10072 * // from a plain array rather than an array in an object 10073 * $('#example').dataTable( { 10074 * "ajax": { 10075 * "url": "data.json", 10076 * "dataSrc": "" 10077 * } 10078 * } ); 10079 * 10080 * @example 10081 * // Manipulate the data returned from the server - add a link to data 10082 * // (note this can, should, be done using `render` for the column - this 10083 * // is just a simple example of how the data can be manipulated). 10084 * $('#example').dataTable( { 10085 * "ajax": { 10086 * "url": "data.json", 10087 * "dataSrc": function ( json ) { 10088 * for ( var i=0, ien=json.length ; i<ien ; i++ ) { 10089 * json[i][0] = '<a href="/message/'+json[i][0]+'>View message</a>'; 10090 * } 10091 * return json; 10092 * } 10093 * } 10094 * } ); 10095 * 10096 * @example 10097 * // Add data to the request 10098 * $('#example').dataTable( { 10099 * "ajax": { 10100 * "url": "data.json", 10101 * "data": function ( d ) { 10102 * return { 10103 * "extra_search": $('#extra').val() 10104 * }; 10105 * } 10106 * } 10107 * } ); 10108 * 10109 * @example 10110 * // Send request as POST 10111 * $('#example').dataTable( { 10112 * "ajax": { 10113 * "url": "data.json", 10114 * "type": "POST" 10115 * } 10116 * } ); 10117 * 10118 * @example 10119 * // Get the data from localStorage (could interface with a form for 10120 * // adding, editing and removing rows). 10121 * $('#example').dataTable( { 10122 * "ajax": function (data, callback, settings) { 10123 * callback( 10124 * JSON.parse( localStorage.getItem('dataTablesData') ) 10125 * ); 10126 * } 10127 * } ); 10128 */ 10129 "ajax": null, 10130 10131 10132 /** 10133 * This parameter allows you to readily specify the entries in the length drop 10134 * down menu that DataTables shows when pagination is enabled. It can be 10135 * either a 1D array of options which will be used for both the displayed 10136 * option and the value, or a 2D array which will use the array in the first 10137 * position as the value, and the array in the second position as the 10138 * displayed options (useful for language strings such as 'All'). 10139 * 10140 * Note that the `pageLength` property will be automatically set to the 10141 * first value given in this array, unless `pageLength` is also provided. 10142 * @type array 10143 * @default [ 10, 25, 50, 100 ] 10144 * 10145 * @dtopt Option 10146 * @name DataTable.defaults.lengthMenu 10147 * 10148 * @example 10149 * $(document).ready( function() { 10150 * $('#example').dataTable( { 10151 * "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]] 10152 * } ); 10153 * } ); 10154 */ 10155 "aLengthMenu": [ 10, 25, 50, 100 ], 10156 10157 10158 /** 10159 * The `columns` option in the initialisation parameter allows you to define 10160 * details about the way individual columns behave. For a full list of 10161 * column options that can be set, please see 10162 * {@link DataTable.defaults.column}. Note that if you use `columns` to 10163 * define your columns, you must have an entry in the array for every single 10164 * column that you have in your table (these can be null if you don't which 10165 * to specify any options). 10166 * @member 10167 * 10168 * @name DataTable.defaults.column 10169 */ 10170 "aoColumns": null, 10171 10172 /** 10173 * Very similar to `columns`, `columnDefs` allows you to target a specific 10174 * column, multiple columns, or all columns, using the `targets` property of 10175 * each object in the array. This allows great flexibility when creating 10176 * tables, as the `columnDefs` arrays can be of any length, targeting the 10177 * columns you specifically want. `columnDefs` may use any of the column 10178 * options available: {@link DataTable.defaults.column}, but it _must_ 10179 * have `targets` defined in each object in the array. Values in the `targets` 10180 * array may be: 10181 * <ul> 10182 * <li>a string - class name will be matched on the TH for the column</li> 10183 * <li>0 or a positive integer - column index counting from the left</li> 10184 * <li>a negative integer - column index counting from the right</li> 10185 * <li>the string "_all" - all columns (i.e. assign a default)</li> 10186 * </ul> 10187 * @member 10188 * 10189 * @name DataTable.defaults.columnDefs 10190 */ 10191 "aoColumnDefs": null, 10192 10193 10194 /** 10195 * Basically the same as `search`, this parameter defines the individual column 10196 * filtering state at initialisation time. The array must be of the same size 10197 * as the number of columns, and each element be an object with the parameters 10198 * `search` and `escapeRegex` (the latter is optional). 'null' is also 10199 * accepted and the default will be used. 10200 * @type array 10201 * @default [] 10202 * 10203 * @dtopt Option 10204 * @name DataTable.defaults.searchCols 10205 * 10206 * @example 10207 * $(document).ready( function() { 10208 * $('#example').dataTable( { 10209 * "searchCols": [ 10210 * null, 10211 * { "search": "My filter" }, 10212 * null, 10213 * { "search": "^[0-9]", "escapeRegex": false } 10214 * ] 10215 * } ); 10216 * } ) 10217 */ 10218 "aoSearchCols": [], 10219 10220 10221 /** 10222 * An array of CSS classes that should be applied to displayed rows. This 10223 * array may be of any length, and DataTables will apply each class 10224 * sequentially, looping when required. 10225 * @type array 10226 * @default null <i>Will take the values determined by the `oClasses.stripe*` 10227 * options</i> 10228 * 10229 * @dtopt Option 10230 * @name DataTable.defaults.stripeClasses 10231 * 10232 * @example 10233 * $(document).ready( function() { 10234 * $('#example').dataTable( { 10235 * "stripeClasses": [ 'strip1', 'strip2', 'strip3' ] 10236 * } ); 10237 * } ) 10238 */ 10239 "asStripeClasses": null, 10240 10241 10242 /** 10243 * Enable or disable automatic column width calculation. This can be disabled 10244 * as an optimisation (it takes some time to calculate the widths) if the 10245 * tables widths are passed in using `columns`. 10246 * @type boolean 10247 * @default true 10248 * 10249 * @dtopt Features 10250 * @name DataTable.defaults.autoWidth 10251 * 10252 * @example 10253 * $(document).ready( function () { 10254 * $('#example').dataTable( { 10255 * "autoWidth": false 10256 * } ); 10257 * } ); 10258 */ 10259 "bAutoWidth": true, 10260 10261 10262 /** 10263 * Deferred rendering can provide DataTables with a huge speed boost when you 10264 * are using an Ajax or JS data source for the table. This option, when set to 10265 * true, will cause DataTables to defer the creation of the table elements for 10266 * each row until they are needed for a draw - saving a significant amount of 10267 * time. 10268 * @type boolean 10269 * @default false 10270 * 10271 * @dtopt Features 10272 * @name DataTable.defaults.deferRender 10273 * 10274 * @example 10275 * $(document).ready( function() { 10276 * $('#example').dataTable( { 10277 * "ajax": "sources/arrays.txt", 10278 * "deferRender": true 10279 * } ); 10280 * } ); 10281 */ 10282 "bDeferRender": false, 10283 10284 10285 /** 10286 * Replace a DataTable which matches the given selector and replace it with 10287 * one which has the properties of the new initialisation object passed. If no 10288 * table matches the selector, then the new DataTable will be constructed as 10289 * per normal. 10290 * @type boolean 10291 * @default false 10292 * 10293 * @dtopt Options 10294 * @name DataTable.defaults.destroy 10295 * 10296 * @example 10297 * $(document).ready( function() { 10298 * $('#example').dataTable( { 10299 * "srollY": "200px", 10300 * "paginate": false 10301 * } ); 10302 * 10303 * // Some time later.... 10304 * $('#example').dataTable( { 10305 * "filter": false, 10306 * "destroy": true 10307 * } ); 10308 * } ); 10309 */ 10310 "bDestroy": false, 10311 10312 10313 /** 10314 * Enable or disable filtering of data. Filtering in DataTables is "smart" in 10315 * that it allows the end user to input multiple words (space separated) and 10316 * will match a row containing those words, even if not in the order that was 10317 * specified (this allow matching across multiple columns). Note that if you 10318 * wish to use filtering in DataTables this must remain 'true' - to remove the 10319 * default filtering input box and retain filtering abilities, please use 10320 * {@link DataTable.defaults.dom}. 10321 * @type boolean 10322 * @default true 10323 * 10324 * @dtopt Features 10325 * @name DataTable.defaults.searching 10326 * 10327 * @example 10328 * $(document).ready( function () { 10329 * $('#example').dataTable( { 10330 * "searching": false 10331 * } ); 10332 * } ); 10333 */ 10334 "bFilter": true, 10335 10336 10337 /** 10338 * Enable or disable the table information display. This shows information 10339 * about the data that is currently visible on the page, including information 10340 * about filtered data if that action is being performed. 10341 * @type boolean 10342 * @default true 10343 * 10344 * @dtopt Features 10345 * @name DataTable.defaults.info 10346 * 10347 * @example 10348 * $(document).ready( function () { 10349 * $('#example').dataTable( { 10350 * "info": false 10351 * } ); 10352 * } ); 10353 */ 10354 "bInfo": true, 10355 10356 10357 /** 10358 * Allows the end user to select the size of a formatted page from a select 10359 * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`). 10360 * @type boolean 10361 * @default true 10362 * 10363 * @dtopt Features 10364 * @name DataTable.defaults.lengthChange 10365 * 10366 * @example 10367 * $(document).ready( function () { 10368 * $('#example').dataTable( { 10369 * "lengthChange": false 10370 * } ); 10371 * } ); 10372 */ 10373 "bLengthChange": true, 10374 10375 10376 /** 10377 * Enable or disable pagination. 10378 * @type boolean 10379 * @default true 10380 * 10381 * @dtopt Features 10382 * @name DataTable.defaults.paging 10383 * 10384 * @example 10385 * $(document).ready( function () { 10386 * $('#example').dataTable( { 10387 * "paging": false 10388 * } ); 10389 * } ); 10390 */ 10391 "bPaginate": true, 10392 10393 10394 /** 10395 * Enable or disable the display of a 'processing' indicator when the table is 10396 * being processed (e.g. a sort). This is particularly useful for tables with 10397 * large amounts of data where it can take a noticeable amount of time to sort 10398 * the entries. 10399 * @type boolean 10400 * @default false 10401 * 10402 * @dtopt Features 10403 * @name DataTable.defaults.processing 10404 * 10405 * @example 10406 * $(document).ready( function () { 10407 * $('#example').dataTable( { 10408 * "processing": true 10409 * } ); 10410 * } ); 10411 */ 10412 "bProcessing": false, 10413 10414 10415 /** 10416 * Retrieve the DataTables object for the given selector. Note that if the 10417 * table has already been initialised, this parameter will cause DataTables 10418 * to simply return the object that has already been set up - it will not take 10419 * account of any changes you might have made to the initialisation object 10420 * passed to DataTables (setting this parameter to true is an acknowledgement 10421 * that you understand this). `destroy` can be used to reinitialise a table if 10422 * you need. 10423 * @type boolean 10424 * @default false 10425 * 10426 * @dtopt Options 10427 * @name DataTable.defaults.retrieve 10428 * 10429 * @example 10430 * $(document).ready( function() { 10431 * initTable(); 10432 * tableActions(); 10433 * } ); 10434 * 10435 * function initTable () 10436 * { 10437 * return $('#example').dataTable( { 10438 * "scrollY": "200px", 10439 * "paginate": false, 10440 * "retrieve": true 10441 * } ); 10442 * } 10443 * 10444 * function tableActions () 10445 * { 10446 * var table = initTable(); 10447 * // perform API operations with oTable 10448 * } 10449 */ 10450 "bRetrieve": false, 10451 10452 10453 /** 10454 * When vertical (y) scrolling is enabled, DataTables will force the height of 10455 * the table's viewport to the given height at all times (useful for layout). 10456 * However, this can look odd when filtering data down to a small data set, 10457 * and the footer is left "floating" further down. This parameter (when 10458 * enabled) will cause DataTables to collapse the table's viewport down when 10459 * the result set will fit within the given Y height. 10460 * @type boolean 10461 * @default false 10462 * 10463 * @dtopt Options 10464 * @name DataTable.defaults.scrollCollapse 10465 * 10466 * @example 10467 * $(document).ready( function() { 10468 * $('#example').dataTable( { 10469 * "scrollY": "200", 10470 * "scrollCollapse": true 10471 * } ); 10472 * } ); 10473 */ 10474 "bScrollCollapse": false, 10475 10476 10477 /** 10478 * Configure DataTables to use server-side processing. Note that the 10479 * `ajax` parameter must also be given in order to give DataTables a 10480 * source to obtain the required data for each draw. 10481 * @type boolean 10482 * @default false 10483 * 10484 * @dtopt Features 10485 * @dtopt Server-side 10486 * @name DataTable.defaults.serverSide 10487 * 10488 * @example 10489 * $(document).ready( function () { 10490 * $('#example').dataTable( { 10491 * "serverSide": true, 10492 * "ajax": "xhr.php" 10493 * } ); 10494 * } ); 10495 */ 10496 "bServerSide": false, 10497 10498 10499 /** 10500 * Enable or disable sorting of columns. Sorting of individual columns can be 10501 * disabled by the `sortable` option for each column. 10502 * @type boolean 10503 * @default true 10504 * 10505 * @dtopt Features 10506 * @name DataTable.defaults.ordering 10507 * 10508 * @example 10509 * $(document).ready( function () { 10510 * $('#example').dataTable( { 10511 * "ordering": false 10512 * } ); 10513 * } ); 10514 */ 10515 "bSort": true, 10516 10517 10518 /** 10519 * Enable or display DataTables' ability to sort multiple columns at the 10520 * same time (activated by shift-click by the user). 10521 * @type boolean 10522 * @default true 10523 * 10524 * @dtopt Options 10525 * @name DataTable.defaults.orderMulti 10526 * 10527 * @example 10528 * // Disable multiple column sorting ability 10529 * $(document).ready( function () { 10530 * $('#example').dataTable( { 10531 * "orderMulti": false 10532 * } ); 10533 * } ); 10534 */ 10535 "bSortMulti": true, 10536 10537 10538 /** 10539 * Allows control over whether DataTables should use the top (true) unique 10540 * cell that is found for a single column, or the bottom (false - default). 10541 * This is useful when using complex headers. 10542 * @type boolean 10543 * @default false 10544 * 10545 * @dtopt Options 10546 * @name DataTable.defaults.orderCellsTop 10547 * 10548 * @example 10549 * $(document).ready( function() { 10550 * $('#example').dataTable( { 10551 * "orderCellsTop": true 10552 * } ); 10553 * } ); 10554 */ 10555 "bSortCellsTop": false, 10556 10557 10558 /** 10559 * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and 10560 * `sorting\_3` to the columns which are currently being sorted on. This is 10561 * presented as a feature switch as it can increase processing time (while 10562 * classes are removed and added) so for large data sets you might want to 10563 * turn this off. 10564 * @type boolean 10565 * @default true 10566 * 10567 * @dtopt Features 10568 * @name DataTable.defaults.orderClasses 10569 * 10570 * @example 10571 * $(document).ready( function () { 10572 * $('#example').dataTable( { 10573 * "orderClasses": false 10574 * } ); 10575 * } ); 10576 */ 10577 "bSortClasses": true, 10578 10579 10580 /** 10581 * Enable or disable state saving. When enabled HTML5 `localStorage` will be 10582 * used to save table display information such as pagination information, 10583 * display length, filtering and sorting. As such when the end user reloads 10584 * the page the display display will match what thy had previously set up. 10585 * 10586 * Due to the use of `localStorage` the default state saving is not supported 10587 * in IE6 or 7. If state saving is required in those browsers, use 10588 * `stateSaveCallback` to provide a storage solution such as cookies. 10589 * @type boolean 10590 * @default false 10591 * 10592 * @dtopt Features 10593 * @name DataTable.defaults.stateSave 10594 * 10595 * @example 10596 * $(document).ready( function () { 10597 * $('#example').dataTable( { 10598 * "stateSave": true 10599 * } ); 10600 * } ); 10601 */ 10602 "bStateSave": false, 10603 10604 10605 /** 10606 * This function is called when a TR element is created (and all TD child 10607 * elements have been inserted), or registered if using a DOM source, allowing 10608 * manipulation of the TR element (adding classes etc). 10609 * @type function 10610 * @param {node} row "TR" element for the current row 10611 * @param {array} data Raw data array for this row 10612 * @param {int} dataIndex The index of this row in the internal aoData array 10613 * 10614 * @dtopt Callbacks 10615 * @name DataTable.defaults.createdRow 10616 * 10617 * @example 10618 * $(document).ready( function() { 10619 * $('#example').dataTable( { 10620 * "createdRow": function( row, data, dataIndex ) { 10621 * // Bold the grade for all 'A' grade browsers 10622 * if ( data[4] == "A" ) 10623 * { 10624 * $('td:eq(4)', row).html( '<b>A</b>' ); 10625 * } 10626 * } 10627 * } ); 10628 * } ); 10629 */ 10630 "fnCreatedRow": null, 10631 10632 10633 /** 10634 * This function is called on every 'draw' event, and allows you to 10635 * dynamically modify any aspect you want about the created DOM. 10636 * @type function 10637 * @param {object} settings DataTables settings object 10638 * 10639 * @dtopt Callbacks 10640 * @name DataTable.defaults.drawCallback 10641 * 10642 * @example 10643 * $(document).ready( function() { 10644 * $('#example').dataTable( { 10645 * "drawCallback": function( settings ) { 10646 * alert( 'DataTables has redrawn the table' ); 10647 * } 10648 * } ); 10649 * } ); 10650 */ 10651 "fnDrawCallback": null, 10652 10653 10654 /** 10655 * Identical to fnHeaderCallback() but for the table footer this function 10656 * allows you to modify the table footer on every 'draw' event. 10657 * @type function 10658 * @param {node} foot "TR" element for the footer 10659 * @param {array} data Full table data (as derived from the original HTML) 10660 * @param {int} start Index for the current display starting point in the 10661 * display array 10662 * @param {int} end Index for the current display ending point in the 10663 * display array 10664 * @param {array int} display Index array to translate the visual position 10665 * to the full data array 10666 * 10667 * @dtopt Callbacks 10668 * @name DataTable.defaults.footerCallback 10669 * 10670 * @example 10671 * $(document).ready( function() { 10672 * $('#example').dataTable( { 10673 * "footerCallback": function( tfoot, data, start, end, display ) { 10674 * tfoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+start; 10675 * } 10676 * } ); 10677 * } ) 10678 */ 10679 "fnFooterCallback": null, 10680 10681 10682 /** 10683 * When rendering large numbers in the information element for the table 10684 * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers 10685 * to have a comma separator for the 'thousands' units (e.g. 1 million is 10686 * rendered as "1,000,000") to help readability for the end user. This 10687 * function will override the default method DataTables uses. 10688 * @type function 10689 * @member 10690 * @param {int} toFormat number to be formatted 10691 * @returns {string} formatted string for DataTables to show the number 10692 * 10693 * @dtopt Callbacks 10694 * @name DataTable.defaults.formatNumber 10695 * 10696 * @example 10697 * // Format a number using a single quote for the separator (note that 10698 * // this can also be done with the language.thousands option) 10699 * $(document).ready( function() { 10700 * $('#example').dataTable( { 10701 * "formatNumber": function ( toFormat ) { 10702 * return toFormat.toString().replace( 10703 * /\B(?=(\d{3})+(?!\d))/g, "'" 10704 * ); 10705 * }; 10706 * } ); 10707 * } ); 10708 */ 10709 "fnFormatNumber": function ( toFormat ) { 10710 return toFormat.toString().replace( 10711 /\B(?=(\d{3})+(?!\d))/g, 10712 this.oLanguage.sThousands 10713 ); 10714 }, 10715 10716 10717 /** 10718 * This function is called on every 'draw' event, and allows you to 10719 * dynamically modify the header row. This can be used to calculate and 10720 * display useful information about the table. 10721 * @type function 10722 * @param {node} head "TR" element for the header 10723 * @param {array} data Full table data (as derived from the original HTML) 10724 * @param {int} start Index for the current display starting point in the 10725 * display array 10726 * @param {int} end Index for the current display ending point in the 10727 * display array 10728 * @param {array int} display Index array to translate the visual position 10729 * to the full data array 10730 * 10731 * @dtopt Callbacks 10732 * @name DataTable.defaults.headerCallback 10733 * 10734 * @example 10735 * $(document).ready( function() { 10736 * $('#example').dataTable( { 10737 * "fheaderCallback": function( head, data, start, end, display ) { 10738 * head.getElementsByTagName('th')[0].innerHTML = "Displaying "+(end-start)+" records"; 10739 * } 10740 * } ); 10741 * } ) 10742 */ 10743 "fnHeaderCallback": null, 10744 10745 10746 /** 10747 * The information element can be used to convey information about the current 10748 * state of the table. Although the internationalisation options presented by 10749 * DataTables are quite capable of dealing with most customisations, there may 10750 * be times where you wish to customise the string further. This callback 10751 * allows you to do exactly that. 10752 * @type function 10753 * @param {object} oSettings DataTables settings object 10754 * @param {int} start Starting position in data for the draw 10755 * @param {int} end End position in data for the draw 10756 * @param {int} max Total number of rows in the table (regardless of 10757 * filtering) 10758 * @param {int} total Total number of rows in the data set, after filtering 10759 * @param {string} pre The string that DataTables has formatted using it's 10760 * own rules 10761 * @returns {string} The string to be displayed in the information element. 10762 * 10763 * @dtopt Callbacks 10764 * @name DataTable.defaults.infoCallback 10765 * 10766 * @example 10767 * $('#example').dataTable( { 10768 * "infoCallback": function( settings, start, end, max, total, pre ) { 10769 * return start +" to "+ end; 10770 * } 10771 * } ); 10772 */ 10773 "fnInfoCallback": null, 10774 10775 10776 /** 10777 * Called when the table has been initialised. Normally DataTables will 10778 * initialise sequentially and there will be no need for this function, 10779 * however, this does not hold true when using external language information 10780 * since that is obtained using an async XHR call. 10781 * @type function 10782 * @param {object} settings DataTables settings object 10783 * @param {object} json The JSON object request from the server - only 10784 * present if client-side Ajax sourced data is used 10785 * 10786 * @dtopt Callbacks 10787 * @name DataTable.defaults.initComplete 10788 * 10789 * @example 10790 * $(document).ready( function() { 10791 * $('#example').dataTable( { 10792 * "initComplete": function(settings, json) { 10793 * alert( 'DataTables has finished its initialisation.' ); 10794 * } 10795 * } ); 10796 * } ) 10797 */ 10798 "fnInitComplete": null, 10799 10800 10801 /** 10802 * Called at the very start of each table draw and can be used to cancel the 10803 * draw by returning false, any other return (including undefined) results in 10804 * the full draw occurring). 10805 * @type function 10806 * @param {object} settings DataTables settings object 10807 * @returns {boolean} False will cancel the draw, anything else (including no 10808 * return) will allow it to complete. 10809 * 10810 * @dtopt Callbacks 10811 * @name DataTable.defaults.preDrawCallback 10812 * 10813 * @example 10814 * $(document).ready( function() { 10815 * $('#example').dataTable( { 10816 * "preDrawCallback": function( settings ) { 10817 * if ( $('#test').val() == 1 ) { 10818 * return false; 10819 * } 10820 * } 10821 * } ); 10822 * } ); 10823 */ 10824 "fnPreDrawCallback": null, 10825 10826 10827 /** 10828 * This function allows you to 'post process' each row after it have been 10829 * generated for each table draw, but before it is rendered on screen. This 10830 * function might be used for setting the row class name etc. 10831 * @type function 10832 * @param {node} row "TR" element for the current row 10833 * @param {array} data Raw data array for this row 10834 * @param {int} displayIndex The display index for the current table draw 10835 * @param {int} displayIndexFull The index of the data in the full list of 10836 * rows (after filtering) 10837 * 10838 * @dtopt Callbacks 10839 * @name DataTable.defaults.rowCallback 10840 * 10841 * @example 10842 * $(document).ready( function() { 10843 * $('#example').dataTable( { 10844 * "rowCallback": function( row, data, displayIndex, displayIndexFull ) { 10845 * // Bold the grade for all 'A' grade browsers 10846 * if ( data[4] == "A" ) { 10847 * $('td:eq(4)', row).html( '<b>A</b>' ); 10848 * } 10849 * } 10850 * } ); 10851 * } ); 10852 */ 10853 "fnRowCallback": null, 10854 10855 10856 /** 10857 * __Deprecated__ The functionality provided by this parameter has now been 10858 * superseded by that provided through `ajax`, which should be used instead. 10859 * 10860 * This parameter allows you to override the default function which obtains 10861 * the data from the server so something more suitable for your application. 10862 * For example you could use POST data, or pull information from a Gears or 10863 * AIR database. 10864 * @type function 10865 * @member 10866 * @param {string} source HTTP source to obtain the data from (`ajax`) 10867 * @param {array} data A key/value pair object containing the data to send 10868 * to the server 10869 * @param {function} callback to be called on completion of the data get 10870 * process that will draw the data on the page. 10871 * @param {object} settings DataTables settings object 10872 * 10873 * @dtopt Callbacks 10874 * @dtopt Server-side 10875 * @name DataTable.defaults.serverData 10876 * 10877 * @deprecated 1.10. Please use `ajax` for this functionality now. 10878 */ 10879 "fnServerData": null, 10880 10881 10882 /** 10883 * __Deprecated__ The functionality provided by this parameter has now been 10884 * superseded by that provided through `ajax`, which should be used instead. 10885 * 10886 * It is often useful to send extra data to the server when making an Ajax 10887 * request - for example custom filtering information, and this callback 10888 * function makes it trivial to send extra information to the server. The 10889 * passed in parameter is the data set that has been constructed by 10890 * DataTables, and you can add to this or modify it as you require. 10891 * @type function 10892 * @param {array} data Data array (array of objects which are name/value 10893 * pairs) that has been constructed by DataTables and will be sent to the 10894 * server. In the case of Ajax sourced data with server-side processing 10895 * this will be an empty array, for server-side processing there will be a 10896 * significant number of parameters! 10897 * @returns {undefined} Ensure that you modify the data array passed in, 10898 * as this is passed by reference. 10899 * 10900 * @dtopt Callbacks 10901 * @dtopt Server-side 10902 * @name DataTable.defaults.serverParams 10903 * 10904 * @deprecated 1.10. Please use `ajax` for this functionality now. 10905 */ 10906 "fnServerParams": null, 10907 10908 10909 /** 10910 * Load the table state. With this function you can define from where, and how, the 10911 * state of a table is loaded. By default DataTables will load from `localStorage` 10912 * but you might wish to use a server-side database or cookies. 10913 * @type function 10914 * @member 10915 * @param {object} settings DataTables settings object 10916 * @param {object} callback Callback that can be executed when done. It 10917 * should be passed the loaded state object. 10918 * @return {object} The DataTables state object to be loaded 10919 * 10920 * @dtopt Callbacks 10921 * @name DataTable.defaults.stateLoadCallback 10922 * 10923 * @example 10924 * $(document).ready( function() { 10925 * $('#example').dataTable( { 10926 * "stateSave": true, 10927 * "stateLoadCallback": function (settings, callback) { 10928 * $.ajax( { 10929 * "url": "/state_load", 10930 * "dataType": "json", 10931 * "success": function (json) { 10932 * callback( json ); 10933 * } 10934 * } ); 10935 * } 10936 * } ); 10937 * } ); 10938 */ 10939 "fnStateLoadCallback": function ( settings ) { 10940 try { 10941 return JSON.parse( 10942 (settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem( 10943 'DataTables_'+settings.sInstance+'_'+location.pathname 10944 ) 10945 ); 10946 } catch (e) {} 10947 }, 10948 10949 10950 /** 10951 * Callback which allows modification of the saved state prior to loading that state. 10952 * This callback is called when the table is loading state from the stored data, but 10953 * prior to the settings object being modified by the saved state. Note that for 10954 * plug-in authors, you should use the `stateLoadParams` event to load parameters for 10955 * a plug-in. 10956 * @type function 10957 * @param {object} settings DataTables settings object 10958 * @param {object} data The state object that is to be loaded 10959 * 10960 * @dtopt Callbacks 10961 * @name DataTable.defaults.stateLoadParams 10962 * 10963 * @example 10964 * // Remove a saved filter, so filtering is never loaded 10965 * $(document).ready( function() { 10966 * $('#example').dataTable( { 10967 * "stateSave": true, 10968 * "stateLoadParams": function (settings, data) { 10969 * data.oSearch.sSearch = ""; 10970 * } 10971 * } ); 10972 * } ); 10973 * 10974 * @example 10975 * // Disallow state loading by returning false 10976 * $(document).ready( function() { 10977 * $('#example').dataTable( { 10978 * "stateSave": true, 10979 * "stateLoadParams": function (settings, data) { 10980 * return false; 10981 * } 10982 * } ); 10983 * } ); 10984 */ 10985 "fnStateLoadParams": null, 10986 10987 10988 /** 10989 * Callback that is called when the state has been loaded from the state saving method 10990 * and the DataTables settings object has been modified as a result of the loaded state. 10991 * @type function 10992 * @param {object} settings DataTables settings object 10993 * @param {object} data The state object that was loaded 10994 * 10995 * @dtopt Callbacks 10996 * @name DataTable.defaults.stateLoaded 10997 * 10998 * @example 10999 * // Show an alert with the filtering value that was saved 11000 * $(document).ready( function() { 11001 * $('#example').dataTable( { 11002 * "stateSave": true, 11003 * "stateLoaded": function (settings, data) { 11004 * alert( 'Saved filter was: '+data.oSearch.sSearch ); 11005 * } 11006 * } ); 11007 * } ); 11008 */ 11009 "fnStateLoaded": null, 11010 11011 11012 /** 11013 * Save the table state. This function allows you to define where and how the state 11014 * information for the table is stored By default DataTables will use `localStorage` 11015 * but you might wish to use a server-side database or cookies. 11016 * @type function 11017 * @member 11018 * @param {object} settings DataTables settings object 11019 * @param {object} data The state object to be saved 11020 * 11021 * @dtopt Callbacks 11022 * @name DataTable.defaults.stateSaveCallback 11023 * 11024 * @example 11025 * $(document).ready( function() { 11026 * $('#example').dataTable( { 11027 * "stateSave": true, 11028 * "stateSaveCallback": function (settings, data) { 11029 * // Send an Ajax request to the server with the state object 11030 * $.ajax( { 11031 * "url": "/state_save", 11032 * "data": data, 11033 * "dataType": "json", 11034 * "method": "POST" 11035 * "success": function () {} 11036 * } ); 11037 * } 11038 * } ); 11039 * } ); 11040 */ 11041 "fnStateSaveCallback": function ( settings, data ) { 11042 try { 11043 (settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem( 11044 'DataTables_'+settings.sInstance+'_'+location.pathname, 11045 JSON.stringify( data ) 11046 ); 11047 } catch (e) {} 11048 }, 11049 11050 11051 /** 11052 * Callback which allows modification of the state to be saved. Called when the table 11053 * has changed state a new state save is required. This method allows modification of 11054 * the state saving object prior to actually doing the save, including addition or 11055 * other state properties or modification. Note that for plug-in authors, you should 11056 * use the `stateSaveParams` event to save parameters for a plug-in. 11057 * @type function 11058 * @param {object} settings DataTables settings object 11059 * @param {object} data The state object to be saved 11060 * 11061 * @dtopt Callbacks 11062 * @name DataTable.defaults.stateSaveParams 11063 * 11064 * @example 11065 * // Remove a saved filter, so filtering is never saved 11066 * $(document).ready( function() { 11067 * $('#example').dataTable( { 11068 * "stateSave": true, 11069 * "stateSaveParams": function (settings, data) { 11070 * data.oSearch.sSearch = ""; 11071 * } 11072 * } ); 11073 * } ); 11074 */ 11075 "fnStateSaveParams": null, 11076 11077 11078 /** 11079 * Duration for which the saved state information is considered valid. After this period 11080 * has elapsed the state will be returned to the default. 11081 * Value is given in seconds. 11082 * @type int 11083 * @default 7200 <i>(2 hours)</i> 11084 * 11085 * @dtopt Options 11086 * @name DataTable.defaults.stateDuration 11087 * 11088 * @example 11089 * $(document).ready( function() { 11090 * $('#example').dataTable( { 11091 * "stateDuration": 60*60*24; // 1 day 11092 * } ); 11093 * } ) 11094 */ 11095 "iStateDuration": 7200, 11096 11097 11098 /** 11099 * When enabled DataTables will not make a request to the server for the first 11100 * page draw - rather it will use the data already on the page (no sorting etc 11101 * will be applied to it), thus saving on an XHR at load time. `deferLoading` 11102 * is used to indicate that deferred loading is required, but it is also used 11103 * to tell DataTables how many records there are in the full table (allowing 11104 * the information element and pagination to be displayed correctly). In the case 11105 * where a filtering is applied to the table on initial load, this can be 11106 * indicated by giving the parameter as an array, where the first element is 11107 * the number of records available after filtering and the second element is the 11108 * number of records without filtering (allowing the table information element 11109 * to be shown correctly). 11110 * @type int | array 11111 * @default null 11112 * 11113 * @dtopt Options 11114 * @name DataTable.defaults.deferLoading 11115 * 11116 * @example 11117 * // 57 records available in the table, no filtering applied 11118 * $(document).ready( function() { 11119 * $('#example').dataTable( { 11120 * "serverSide": true, 11121 * "ajax": "scripts/server_processing.php", 11122 * "deferLoading": 57 11123 * } ); 11124 * } ); 11125 * 11126 * @example 11127 * // 57 records after filtering, 100 without filtering (an initial filter applied) 11128 * $(document).ready( function() { 11129 * $('#example').dataTable( { 11130 * "serverSide": true, 11131 * "ajax": "scripts/server_processing.php", 11132 * "deferLoading": [ 57, 100 ], 11133 * "search": { 11134 * "search": "my_filter" 11135 * } 11136 * } ); 11137 * } ); 11138 */ 11139 "iDeferLoading": null, 11140 11141 11142 /** 11143 * Number of rows to display on a single page when using pagination. If 11144 * feature enabled (`lengthChange`) then the end user will be able to override 11145 * this to a custom setting using a pop-up menu. 11146 * @type int 11147 * @default 10 11148 * 11149 * @dtopt Options 11150 * @name DataTable.defaults.pageLength 11151 * 11152 * @example 11153 * $(document).ready( function() { 11154 * $('#example').dataTable( { 11155 * "pageLength": 50 11156 * } ); 11157 * } ) 11158 */ 11159 "iDisplayLength": 10, 11160 11161 11162 /** 11163 * Define the starting point for data display when using DataTables with 11164 * pagination. Note that this parameter is the number of records, rather than 11165 * the page number, so if you have 10 records per page and want to start on 11166 * the third page, it should be "20". 11167 * @type int 11168 * @default 0 11169 * 11170 * @dtopt Options 11171 * @name DataTable.defaults.displayStart 11172 * 11173 * @example 11174 * $(document).ready( function() { 11175 * $('#example').dataTable( { 11176 * "displayStart": 20 11177 * } ); 11178 * } ) 11179 */ 11180 "iDisplayStart": 0, 11181 11182 11183 /** 11184 * By default DataTables allows keyboard navigation of the table (sorting, paging, 11185 * and filtering) by adding a `tabindex` attribute to the required elements. This 11186 * allows you to tab through the controls and press the enter key to activate them. 11187 * The tabindex is default 0, meaning that the tab follows the flow of the document. 11188 * You can overrule this using this parameter if you wish. Use a value of -1 to 11189 * disable built-in keyboard navigation. 11190 * @type int 11191 * @default 0 11192 * 11193 * @dtopt Options 11194 * @name DataTable.defaults.tabIndex 11195 * 11196 * @example 11197 * $(document).ready( function() { 11198 * $('#example').dataTable( { 11199 * "tabIndex": 1 11200 * } ); 11201 * } ); 11202 */ 11203 "iTabIndex": 0, 11204 11205 11206 /** 11207 * Classes that DataTables assigns to the various components and features 11208 * that it adds to the HTML table. This allows classes to be configured 11209 * during initialisation in addition to through the static 11210 * {@link DataTable.ext.oStdClasses} object). 11211 * @namespace 11212 * @name DataTable.defaults.classes 11213 */ 11214 "oClasses": {}, 11215 11216 11217 /** 11218 * All strings that DataTables uses in the user interface that it creates 11219 * are defined in this object, allowing you to modified them individually or 11220 * completely replace them all as required. 11221 * @namespace 11222 * @name DataTable.defaults.language 11223 */ 11224 "oLanguage": { 11225 /** 11226 * Strings that are used for WAI-ARIA labels and controls only (these are not 11227 * actually visible on the page, but will be read by screenreaders, and thus 11228 * must be internationalised as well). 11229 * @namespace 11230 * @name DataTable.defaults.language.aria 11231 */ 11232 "oAria": { 11233 /** 11234 * ARIA label that is added to the table headers when the column may be 11235 * sorted ascending by activing the column (click or return when focused). 11236 * Note that the column header is prefixed to this string. 11237 * @type string 11238 * @default : activate to sort column ascending 11239 * 11240 * @dtopt Language 11241 * @name DataTable.defaults.language.aria.sortAscending 11242 * 11243 * @example 11244 * $(document).ready( function() { 11245 * $('#example').dataTable( { 11246 * "language": { 11247 * "aria": { 11248 * "sortAscending": " - click/return to sort ascending" 11249 * } 11250 * } 11251 * } ); 11252 * } ); 11253 */ 11254 "sSortAscending": ": activate to sort column ascending", 11255 11256 /** 11257 * ARIA label that is added to the table headers when the column may be 11258 * sorted descending by activing the column (click or return when focused). 11259 * Note that the column header is prefixed to this string. 11260 * @type string 11261 * @default : activate to sort column ascending 11262 * 11263 * @dtopt Language 11264 * @name DataTable.defaults.language.aria.sortDescending 11265 * 11266 * @example 11267 * $(document).ready( function() { 11268 * $('#example').dataTable( { 11269 * "language": { 11270 * "aria": { 11271 * "sortDescending": " - click/return to sort descending" 11272 * } 11273 * } 11274 * } ); 11275 * } ); 11276 */ 11277 "sSortDescending": ": activate to sort column descending" 11278 }, 11279 11280 /** 11281 * Pagination string used by DataTables for the built-in pagination 11282 * control types. 11283 * @namespace 11284 * @name DataTable.defaults.language.paginate 11285 */ 11286 "oPaginate": { 11287 /** 11288 * Text to use when using the 'full_numbers' type of pagination for the 11289 * button to take the user to the first page. 11290 * @type string 11291 * @default First 11292 * 11293 * @dtopt Language 11294 * @name DataTable.defaults.language.paginate.first 11295 * 11296 * @example 11297 * $(document).ready( function() { 11298 * $('#example').dataTable( { 11299 * "language": { 11300 * "paginate": { 11301 * "first": "First page" 11302 * } 11303 * } 11304 * } ); 11305 * } ); 11306 */ 11307 "sFirst": "First", 11308 11309 11310 /** 11311 * Text to use when using the 'full_numbers' type of pagination for the 11312 * button to take the user to the last page. 11313 * @type string 11314 * @default Last 11315 * 11316 * @dtopt Language 11317 * @name DataTable.defaults.language.paginate.last 11318 * 11319 * @example 11320 * $(document).ready( function() { 11321 * $('#example').dataTable( { 11322 * "language": { 11323 * "paginate": { 11324 * "last": "Last page" 11325 * } 11326 * } 11327 * } ); 11328 * } ); 11329 */ 11330 "sLast": "Last", 11331 11332 11333 /** 11334 * Text to use for the 'next' pagination button (to take the user to the 11335 * next page). 11336 * @type string 11337 * @default Next 11338 * 11339 * @dtopt Language 11340 * @name DataTable.defaults.language.paginate.next 11341 * 11342 * @example 11343 * $(document).ready( function() { 11344 * $('#example').dataTable( { 11345 * "language": { 11346 * "paginate": { 11347 * "next": "Next page" 11348 * } 11349 * } 11350 * } ); 11351 * } ); 11352 */ 11353 "sNext": "Next", 11354 11355 11356 /** 11357 * Text to use for the 'previous' pagination button (to take the user to 11358 * the previous page). 11359 * @type string 11360 * @default Previous 11361 * 11362 * @dtopt Language 11363 * @name DataTable.defaults.language.paginate.previous 11364 * 11365 * @example 11366 * $(document).ready( function() { 11367 * $('#example').dataTable( { 11368 * "language": { 11369 * "paginate": { 11370 * "previous": "Previous page" 11371 * } 11372 * } 11373 * } ); 11374 * } ); 11375 */ 11376 "sPrevious": "Previous" 11377 }, 11378 11379 /** 11380 * This string is shown in preference to `zeroRecords` when the table is 11381 * empty of data (regardless of filtering). Note that this is an optional 11382 * parameter - if it is not given, the value of `zeroRecords` will be used 11383 * instead (either the default or given value). 11384 * @type string 11385 * @default No data available in table 11386 * 11387 * @dtopt Language 11388 * @name DataTable.defaults.language.emptyTable 11389 * 11390 * @example 11391 * $(document).ready( function() { 11392 * $('#example').dataTable( { 11393 * "language": { 11394 * "emptyTable": "No data available in table" 11395 * } 11396 * } ); 11397 * } ); 11398 */ 11399 "sEmptyTable": "No data available in table", 11400 11401 11402 /** 11403 * This string gives information to the end user about the information 11404 * that is current on display on the page. The following tokens can be 11405 * used in the string and will be dynamically replaced as the table 11406 * display updates. This tokens can be placed anywhere in the string, or 11407 * removed as needed by the language requires: 11408 * 11409 * * `\_START\_` - Display index of the first record on the current page 11410 * * `\_END\_` - Display index of the last record on the current page 11411 * * `\_TOTAL\_` - Number of records in the table after filtering 11412 * * `\_MAX\_` - Number of records in the table without filtering 11413 * * `\_PAGE\_` - Current page number 11414 * * `\_PAGES\_` - Total number of pages of data in the table 11415 * 11416 * @type string 11417 * @default Showing _START_ to _END_ of _TOTAL_ entries 11418 * 11419 * @dtopt Language 11420 * @name DataTable.defaults.language.info 11421 * 11422 * @example 11423 * $(document).ready( function() { 11424 * $('#example').dataTable( { 11425 * "language": { 11426 * "info": "Showing page _PAGE_ of _PAGES_" 11427 * } 11428 * } ); 11429 * } ); 11430 */ 11431 "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries", 11432 11433 11434 /** 11435 * Display information string for when the table is empty. Typically the 11436 * format of this string should match `info`. 11437 * @type string 11438 * @default Showing 0 to 0 of 0 entries 11439 * 11440 * @dtopt Language 11441 * @name DataTable.defaults.language.infoEmpty 11442 * 11443 * @example 11444 * $(document).ready( function() { 11445 * $('#example').dataTable( { 11446 * "language": { 11447 * "infoEmpty": "No entries to show" 11448 * } 11449 * } ); 11450 * } ); 11451 */ 11452 "sInfoEmpty": "Showing 0 to 0 of 0 entries", 11453 11454 11455 /** 11456 * When a user filters the information in a table, this string is appended 11457 * to the information (`info`) to give an idea of how strong the filtering 11458 * is. The variable _MAX_ is dynamically updated. 11459 * @type string 11460 * @default (filtered from _MAX_ total entries) 11461 * 11462 * @dtopt Language 11463 * @name DataTable.defaults.language.infoFiltered 11464 * 11465 * @example 11466 * $(document).ready( function() { 11467 * $('#example').dataTable( { 11468 * "language": { 11469 * "infoFiltered": " - filtering from _MAX_ records" 11470 * } 11471 * } ); 11472 * } ); 11473 */ 11474 "sInfoFiltered": "(filtered from _MAX_ total entries)", 11475 11476 11477 /** 11478 * If can be useful to append extra information to the info string at times, 11479 * and this variable does exactly that. This information will be appended to 11480 * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are 11481 * being used) at all times. 11482 * @type string 11483 * @default <i>Empty string</i> 11484 * 11485 * @dtopt Language 11486 * @name DataTable.defaults.language.infoPostFix 11487 * 11488 * @example 11489 * $(document).ready( function() { 11490 * $('#example').dataTable( { 11491 * "language": { 11492 * "infoPostFix": "All records shown are derived from real information." 11493 * } 11494 * } ); 11495 * } ); 11496 */ 11497 "sInfoPostFix": "", 11498 11499 11500 /** 11501 * This decimal place operator is a little different from the other 11502 * language options since DataTables doesn't output floating point 11503 * numbers, so it won't ever use this for display of a number. Rather, 11504 * what this parameter does is modify the sort methods of the table so 11505 * that numbers which are in a format which has a character other than 11506 * a period (`.`) as a decimal place will be sorted numerically. 11507 * 11508 * Note that numbers with different decimal places cannot be shown in 11509 * the same table and still be sortable, the table must be consistent. 11510 * However, multiple different tables on the page can use different 11511 * decimal place characters. 11512 * @type string 11513 * @default 11514 * 11515 * @dtopt Language 11516 * @name DataTable.defaults.language.decimal 11517 * 11518 * @example 11519 * $(document).ready( function() { 11520 * $('#example').dataTable( { 11521 * "language": { 11522 * "decimal": "," 11523 * "thousands": "." 11524 * } 11525 * } ); 11526 * } ); 11527 */ 11528 "sDecimal": "", 11529 11530 11531 /** 11532 * DataTables has a build in number formatter (`formatNumber`) which is 11533 * used to format large numbers that are used in the table information. 11534 * By default a comma is used, but this can be trivially changed to any 11535 * character you wish with this parameter. 11536 * @type string 11537 * @default , 11538 * 11539 * @dtopt Language 11540 * @name DataTable.defaults.language.thousands 11541 * 11542 * @example 11543 * $(document).ready( function() { 11544 * $('#example').dataTable( { 11545 * "language": { 11546 * "thousands": "'" 11547 * } 11548 * } ); 11549 * } ); 11550 */ 11551 "sThousands": ",", 11552 11553 11554 /** 11555 * Detail the action that will be taken when the drop down menu for the 11556 * pagination length option is changed. The '_MENU_' variable is replaced 11557 * with a default select list of 10, 25, 50 and 100, and can be replaced 11558 * with a custom select box if required. 11559 * @type string 11560 * @default Show _MENU_ entries 11561 * 11562 * @dtopt Language 11563 * @name DataTable.defaults.language.lengthMenu 11564 * 11565 * @example 11566 * // Language change only 11567 * $(document).ready( function() { 11568 * $('#example').dataTable( { 11569 * "language": { 11570 * "lengthMenu": "Display _MENU_ records" 11571 * } 11572 * } ); 11573 * } ); 11574 * 11575 * @example 11576 * // Language and options change 11577 * $(document).ready( function() { 11578 * $('#example').dataTable( { 11579 * "language": { 11580 * "lengthMenu": 'Display <select>'+ 11581 * '<option value="10">10</option>'+ 11582 * '<option value="20">20</option>'+ 11583 * '<option value="30">30</option>'+ 11584 * '<option value="40">40</option>'+ 11585 * '<option value="50">50</option>'+ 11586 * '<option value="-1">All</option>'+ 11587 * '</select> records' 11588 * } 11589 * } ); 11590 * } ); 11591 */ 11592 "sLengthMenu": "Show _MENU_ entries", 11593 11594 11595 /** 11596 * When using Ajax sourced data and during the first draw when DataTables is 11597 * gathering the data, this message is shown in an empty row in the table to 11598 * indicate to the end user the the data is being loaded. Note that this 11599 * parameter is not used when loading data by server-side processing, just 11600 * Ajax sourced data with client-side processing. 11601 * @type string 11602 * @default Loading... 11603 * 11604 * @dtopt Language 11605 * @name DataTable.defaults.language.loadingRecords 11606 * 11607 * @example 11608 * $(document).ready( function() { 11609 * $('#example').dataTable( { 11610 * "language": { 11611 * "loadingRecords": "Please wait - loading..." 11612 * } 11613 * } ); 11614 * } ); 11615 */ 11616 "sLoadingRecords": "Loading...", 11617 11618 11619 /** 11620 * Text which is displayed when the table is processing a user action 11621 * (usually a sort command or similar). 11622 * @type string 11623 *
11623 @default Processing... 11624 * 11625 * @dtopt Language 11626 * @name DataTable.defaults.language.processing 11627 * 11628 * @example 11629 * $(document).ready( function() { 11630 * $('#example').dataTable( { 11631 * "language": { 11632 * "processing": "DataTables is currently busy" 11633 * } 11634 * } ); 11635 * } ); 11636 */ 11637 "sProcessing": "Processing...
vendor: 24,082 bytes, lines 11637-12366
11637", 11638 11639 11640 /** 11641 * Details the actions that will be taken when the user types into the 11642 * filtering input text box. The variable "_INPUT_", if used in the string, 11643 * is replaced with the HTML text box for the filtering input allowing 11644 * control over where it appears in the string. If "_INPUT_" is not given 11645 * then the input box is appended to the string automatically. 11646 * @type string 11647 * @default Search: 11648 * 11649 * @dtopt Language 11650 * @name DataTable.defaults.language.search 11651 * 11652 * @example 11653 * // Input text box will be appended at the end automatically 11654 * $(document).ready( function() { 11655 * $('#example').dataTable( { 11656 * "language": { 11657 * "search": "Filter records:" 11658 * } 11659 * } ); 11660 * } ); 11661 * 11662 * @example 11663 * // Specify where the filter should appear 11664 * $(document).ready( function() { 11665 * $('#example').dataTable( { 11666 * "language": { 11667 * "search": "Apply filter _INPUT_ to table" 11668 * } 11669 * } ); 11670 * } ); 11671 */ 11672 "sSearch": "Search:", 11673 11674 11675 /** 11676 * Assign a `placeholder` attribute to the search `input` element 11677 * @type string 11678 * @default 11679 * 11680 * @dtopt Language 11681 * @name DataTable.defaults.language.searchPlaceholder 11682 */ 11683 "sSearchPlaceholder": "", 11684 11685 11686 /** 11687 * All of the language information can be stored in a file on the 11688 * server-side, which DataTables will look up if this parameter is passed. 11689 * It must store the URL of the language file, which is in a JSON format, 11690 * and the object has the same properties as the oLanguage object in the 11691 * initialiser object (i.e. the above parameters). Please refer to one of 11692 * the example language files to see how this works in action. 11693 * @type string 11694 * @default <i>Empty string - i.e. disabled</i> 11695 * 11696 * @dtopt Language 11697 * @name DataTable.defaults.language.url 11698 * 11699 * @example 11700 * $(document).ready( function() { 11701 * $('#example').dataTable( { 11702 * "language": { 11703 * "url": "http://www.sprymedia.co.uk/dataTables/lang.txt" 11704 * } 11705 * } ); 11706 * } ); 11707 */ 11708 "sUrl": "", 11709 11710 11711 /** 11712 * Text shown inside the table records when the is no information to be 11713 * displayed after filtering. `emptyTable` is shown when there is simply no 11714 * information in the table at all (regardless of filtering). 11715 * @type string 11716 * @default No matching records found 11717 * 11718 * @dtopt Language 11719 * @name DataTable.defaults.language.zeroRecords 11720 * 11721 * @example 11722 * $(document).ready( function() { 11723 * $('#example').dataTable( { 11724 * "language": { 11725 * "zeroRecords": "No records to display" 11726 * } 11727 * } ); 11728 * } ); 11729 */ 11730 "sZeroRecords": "No matching records found" 11731 }, 11732 11733 11734 /** 11735 * This parameter allows you to have define the global filtering state at 11736 * initialisation time. As an object the `search` parameter must be 11737 * defined, but all other parameters are optional. When `regex` is true, 11738 * the search string will be treated as a regular expression, when false 11739 * (default) it will be treated as a straight string. When `smart` 11740 * DataTables will use it's smart filtering methods (to word match at 11741 * any point in the data), when false this will not be done. 11742 * @namespace 11743 * @extends DataTable.models.oSearch 11744 * 11745 * @dtopt Options 11746 * @name DataTable.defaults.search 11747 * 11748 * @example 11749 * $(document).ready( function() { 11750 * $('#example').dataTable( { 11751 * "search": {"search": "Initial search"} 11752 * } ); 11753 * } ) 11754 */ 11755 "oSearch": $.extend( {}, DataTable.models.oSearch ), 11756 11757 11758 /** 11759 * __Deprecated__ The functionality provided by this parameter has now been 11760 * superseded by that provided through `ajax`, which should be used instead. 11761 * 11762 * By default DataTables will look for the property `data` (or `aaData` for 11763 * compatibility with DataTables 1.9-) when obtaining data from an Ajax 11764 * source or for server-side processing - this parameter allows that 11765 * property to be changed. You can use Javascript dotted object notation to 11766 * get a data source for multiple levels of nesting. 11767 * @type string 11768 * @default data 11769 * 11770 * @dtopt Options 11771 * @dtopt Server-side 11772 * @name DataTable.defaults.ajaxDataProp 11773 * 11774 * @deprecated 1.10. Please use `ajax` for this functionality now. 11775 */ 11776 "sAjaxDataProp": "data", 11777 11778 11779 /** 11780 * __Deprecated__ The functionality provided by this parameter has now been 11781 * superseded by that provided through `ajax`, which should be used instead. 11782 * 11783 * You can instruct DataTables to load data from an external 11784 * source using this parameter (use aData if you want to pass data in you 11785 * already have). Simply provide a url a JSON object can be obtained from. 11786 * @type string 11787 * @default null 11788 * 11789 * @dtopt Options 11790 * @dtopt Server-side 11791 * @name DataTable.defaults.ajaxSource 11792 * 11793 * @deprecated 1.10. Please use `ajax` for this functionality now. 11794 */ 11795 "sAjaxSource": null, 11796 11797 11798 /** 11799 * This initialisation variable allows you to specify exactly where in the 11800 * DOM you want DataTables to inject the various controls it adds to the page 11801 * (for example you might want the pagination controls at the top of the 11802 * table). DIV elements (with or without a custom class) can also be added to 11803 * aid styling. The follow syntax is used: 11804 * <ul> 11805 * <li>The following options are allowed: 11806 * <ul> 11807 * <li>'l' - Length changing</li> 11808 * <li>'f' - Filtering input</li> 11809 * <li>'t' - The table!</li> 11810 * <li>'i' - Information</li> 11811 * <li>'p' - Pagination</li> 11812 * <li>'r' - pRocessing</li> 11813 * </ul> 11814 * </li> 11815 * <li>The following constants are allowed: 11816 * <ul> 11817 * <li>'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li> 11818 * <li>'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li> 11819 * </ul> 11820 * </li> 11821 * <li>The following syntax is expected: 11822 * <ul> 11823 * <li>'<' and '>' - div elements</li> 11824 * <li>'<"class" and '>' - div with a class</li> 11825 * <li>'<"#id" and '>' - div with an ID</li> 11826 * </ul> 11827 * </li> 11828 * <li>Examples: 11829 * <ul> 11830 * <li>'<"wrapper"flipt>'</li> 11831 * <li>'<lf<t>ip>'</li> 11832 * </ul> 11833 * </li> 11834 * </ul> 11835 * @type string 11836 * @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b> 11837 * <"H"lfr>t<"F"ip> <i>(when `jQueryUI` is true)</i> 11838 * 11839 * @dtopt Options 11840 * @name DataTable.defaults.dom 11841 * 11842 * @example 11843 * $(document).ready( function() { 11844 * $('#example').dataTable( { 11845 * "dom": '<"top"i>rt<"bottom"flp><"clear">' 11846 * } ); 11847 * } ); 11848 */ 11849 "sDom": "lfrtip", 11850 11851 11852 /** 11853 * Search delay option. This will throttle full table searches that use the 11854 * DataTables provided search input element (it does not effect calls to 11855 * `dt-api search()`, providing a delay before the search is made. 11856 * @type integer 11857 * @default 0 11858 * 11859 * @dtopt Options 11860 * @name DataTable.defaults.searchDelay 11861 * 11862 * @example 11863 * $(document).ready( function() { 11864 * $('#example').dataTable( { 11865 * "searchDelay": 200 11866 * } ); 11867 * } ) 11868 */ 11869 "searchDelay": null, 11870 11871 11872 /** 11873 * DataTables features six different built-in options for the buttons to 11874 * display for pagination control: 11875 * 11876 * * `numbers` - Page number buttons only 11877 * * `simple` - 'Previous' and 'Next' buttons only 11878 * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers 11879 * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons 11880 * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus page numbers 11881 * * `first_last_numbers` - 'First' and 'Last' buttons, plus page numbers 11882 * 11883 * Further methods can be added using {@link DataTable.ext.oPagination}. 11884 * @type string 11885 * @default simple_numbers 11886 * 11887 * @dtopt Options 11888 * @name DataTable.defaults.pagingType 11889 * 11890 * @example 11891 * $(document).ready( function() { 11892 * $('#example').dataTable( { 11893 * "pagingType": "full_numbers" 11894 * } ); 11895 * } ) 11896 */ 11897 "sPaginationType": "simple_numbers", 11898 11899 11900 /** 11901 * Enable horizontal scrolling. When a table is too wide to fit into a 11902 * certain layout, or you have a large number of columns in the table, you 11903 * can enable x-scrolling to show the table in a viewport, which can be 11904 * scrolled. This property can be `true` which will allow the table to 11905 * scroll horizontally when needed, or any CSS unit, or a number (in which 11906 * case it will be treated as a pixel measurement). Setting as simply `true` 11907 * is recommended. 11908 * @type boolean|string 11909 * @default <i>blank string - i.e. disabled</i> 11910 * 11911 * @dtopt Features 11912 * @name DataTable.defaults.scrollX 11913 * 11914 * @example 11915 * $(document).ready( function() { 11916 * $('#example').dataTable( { 11917 * "scrollX": true, 11918 * "scrollCollapse": true 11919 * } ); 11920 * } ); 11921 */ 11922 "sScrollX": "", 11923 11924 11925 /** 11926 * This property can be used to force a DataTable to use more width than it 11927 * might otherwise do when x-scrolling is enabled. For example if you have a 11928 * table which requires to be well spaced, this parameter is useful for 11929 * "over-sizing" the table, and thus forcing scrolling. This property can by 11930 * any CSS unit, or a number (in which case it will be treated as a pixel 11931 * measurement). 11932 * @type string 11933 * @default <i>blank string - i.e. disabled</i> 11934 * 11935 * @dtopt Options 11936 * @name DataTable.defaults.scrollXInner 11937 * 11938 * @example 11939 * $(document).ready( function() { 11940 * $('#example').dataTable( { 11941 * "scrollX": "100%", 11942 * "scrollXInner": "110%" 11943 * } ); 11944 * } ); 11945 */ 11946 "sScrollXInner": "", 11947 11948 11949 /** 11950 * Enable vertical scrolling. Vertical scrolling will constrain the DataTable 11951 * to the given height, and enable scrolling for any data which overflows the 11952 * current viewport. This can be used as an alternative to paging to display 11953 * a lot of data in a small area (although paging and scrolling can both be 11954 * enabled at the same time). This property can be any CSS unit, or a number 11955 * (in which case it will be treated as a pixel measurement). 11956 * @type string 11957 * @default <i>blank string - i.e. disabled</i> 11958 * 11959 * @dtopt Features 11960 * @name DataTable.defaults.scrollY 11961 * 11962 * @example 11963 * $(document).ready( function() { 11964 * $('#example').dataTable( { 11965 * "scrollY": "200px", 11966 * "paginate": false 11967 * } ); 11968 * } ); 11969 */ 11970 "sScrollY": "", 11971 11972 11973 /** 11974 * __Deprecated__ The functionality provided by this parameter has now been 11975 * superseded by that provided through `ajax`, which should be used instead. 11976 * 11977 * Set the HTTP method that is used to make the Ajax call for server-side 11978 * processing or Ajax sourced data. 11979 * @type string 11980 * @default GET 11981 * 11982 * @dtopt Options 11983 * @dtopt Server-side 11984 * @name DataTable.defaults.serverMethod 11985 * 11986 * @deprecated 1.10. Please use `ajax` for this functionality now. 11987 */ 11988 "sServerMethod": "GET", 11989 11990 11991 /** 11992 * DataTables makes use of renderers when displaying HTML elements for 11993 * a table. These renderers can be added or modified by plug-ins to 11994 * generate suitable mark-up for a site. For example the Bootstrap 11995 * integration plug-in for DataTables uses a paging button renderer to 11996 * display pagination buttons in the mark-up required by Bootstrap. 11997 * 11998 * For further information about the renderers available see 11999 * DataTable.ext.renderer 12000 * @type string|object 12001 * @default null 12002 * 12003 * @name DataTable.defaults.renderer 12004 * 12005 */ 12006 "renderer": null, 12007 12008 12009 /** 12010 * Set the data property name that DataTables should use to get a row's id 12011 * to set as the `id` property in the node. 12012 * @type string 12013 * @default DT_RowId 12014 * 12015 * @name DataTable.defaults.rowId 12016 */ 12017 "rowId": "DT_RowId" 12018 }; 12019 12020 _fnHungarianMap( DataTable.defaults ); 12021 12022 12023 12024 /* 12025 * Developer note - See note in model.defaults.js about the use of Hungarian 12026 * notation and camel case. 12027 */ 12028 12029 /** 12030 * Column options that can be given to DataTables at initialisation time. 12031 * @namespace 12032 */ 12033 DataTable.defaults.column = { 12034 /** 12035 * Define which column(s) an order will occur on for this column. This 12036 * allows a column's ordering to take multiple columns into account when 12037 * doing a sort or use the data from a different column. For example first 12038 * name / last name columns make sense to do a multi-column sort over the 12039 * two columns. 12040 * @type array|int 12041 * @default null <i>Takes the value of the column index automatically</i> 12042 * 12043 * @name DataTable.defaults.column.orderData 12044 * @dtopt Columns 12045 * 12046 * @example 12047 * // Using `columnDefs` 12048 * $(document).ready( function() { 12049 * $('#example').dataTable( { 12050 * "columnDefs": [ 12051 * { "orderData": [ 0, 1 ], "targets": [ 0 ] }, 12052 * { "orderData": [ 1, 0 ], "targets": [ 1 ] }, 12053 * { "orderData": 2, "targets": [ 2 ] } 12054 * ] 12055 * } ); 12056 * } ); 12057 * 12058 * @example 12059 * // Using `columns` 12060 * $(document).ready( function() { 12061 * $('#example').dataTable( { 12062 * "columns": [ 12063 * { "orderData": [ 0, 1 ] }, 12064 * { "orderData": [ 1, 0 ] }, 12065 * { "orderData": 2 }, 12066 * null, 12067 * null 12068 * ] 12069 * } ); 12070 * } ); 12071 */ 12072 "aDataSort": null, 12073 "iDataSort": -1, 12074 12075 12076 /** 12077 * You can control the default ordering direction, and even alter the 12078 * behaviour of the sort handler (i.e. only allow ascending ordering etc) 12079 * using this parameter. 12080 * @type array 12081 * @default [ 'asc', 'desc' ] 12082 * 12083 * @name DataTable.defaults.column.orderSequence 12084 * @dtopt Columns 12085 * 12086 * @example 12087 * // Using `columnDefs` 12088 * $(document).ready( function() { 12089 * $('#example').dataTable( { 12090 * "columnDefs": [ 12091 * { "orderSequence": [ "asc" ], "targets": [ 1 ] }, 12092 * { "orderSequence": [ "desc", "asc", "asc" ], "targets": [ 2 ] }, 12093 * { "orderSequence": [ "desc" ], "targets": [ 3 ] } 12094 * ] 12095 * } ); 12096 * } ); 12097 * 12098 * @example 12099 * // Using `columns` 12100 * $(document).ready( function() { 12101 * $('#example').dataTable( { 12102 * "columns": [ 12103 * null, 12104 * { "orderSequence": [ "asc" ] }, 12105 * { "orderSequence": [ "desc", "asc", "asc" ] }, 12106 * { "orderSequence": [ "desc" ] }, 12107 * null 12108 * ] 12109 * } ); 12110 * } ); 12111 */ 12112 "asSorting": [ 'asc', 'desc' ], 12113 12114 12115 /** 12116 * Enable or disable filtering on the data in this column. 12117 * @type boolean 12118 * @default true 12119 * 12120 * @name DataTable.defaults.column.searchable 12121 * @dtopt Columns 12122 * 12123 * @example 12124 * // Using `columnDefs` 12125 * $(document).ready( function() { 12126 * $('#example').dataTable( { 12127 * "columnDefs": [ 12128 * { "searchable": false, "targets": [ 0 ] } 12129 * ] } ); 12130 * } ); 12131 * 12132 * @example 12133 * // Using `columns` 12134 * $(document).ready( function() { 12135 * $('#example').dataTable( { 12136 * "columns": [ 12137 * { "searchable": false }, 12138 * null, 12139 * null, 12140 * null, 12141 * null 12142 * ] } ); 12143 * } ); 12144 */ 12145 "bSearchable": true, 12146 12147 12148 /** 12149 * Enable or disable ordering on this column. 12150 * @type boolean 12151 * @default true 12152 * 12153 * @name DataTable.defaults.column.orderable 12154 * @dtopt Columns 12155 * 12156 * @example 12157 * // Using `columnDefs` 12158 * $(document).ready( function() { 12159 * $('#example').dataTable( { 12160 * "columnDefs": [ 12161 * { "orderable": false, "targets": [ 0 ] } 12162 * ] } ); 12163 * } ); 12164 * 12165 * @example 12166 * // Using `columns` 12167 * $(document).ready( function() { 12168 * $('#example').dataTable( { 12169 * "columns": [ 12170 * { "orderable": false }, 12171 * null, 12172 * null, 12173 * null, 12174 * null 12175 * ] } ); 12176 * } ); 12177 */ 12178 "bSortable": true, 12179 12180 12181 /** 12182 * Enable or disable the display of this column. 12183 * @type boolean 12184 * @default true 12185 * 12186 * @name DataTable.defaults.column.visible 12187 * @dtopt Columns 12188 * 12189 * @example 12190 * // Using `columnDefs` 12191 * $(document).ready( function() { 12192 * $('#example').dataTable( { 12193 * "columnDefs": [ 12194 * { "visible": false, "targets": [ 0 ] } 12195 * ] } ); 12196 * } ); 12197 * 12198 * @example 12199 * // Using `columns` 12200 * $(document).ready( function() { 12201 * $('#example').dataTable( { 12202 * "columns": [ 12203 * { "visible": false }, 12204 * null, 12205 * null, 12206 * null, 12207 * null 12208 * ] } ); 12209 * } ); 12210 */ 12211 "bVisible": true, 12212 12213 12214 /** 12215 * Developer definable function that is called whenever a cell is created (Ajax source, 12216 * etc) or processed for input (DOM source). This can be used as a compliment to mRender 12217 * allowing you to modify the DOM element (add background colour for example) when the 12218 * element is available. 12219 * @type function 12220 * @param {element} td The TD node that has been created 12221 * @param {*} cellData The Data for the cell 12222 * @param {array|object} rowData The data for the whole row 12223 * @param {int} row The row index for the aoData data store 12224 * @param {int} col The column index for aoColumns 12225 * 12226 * @name DataTable.defaults.column.createdCell 12227 * @dtopt Columns 12228 * 12229 * @example 12230 * $(document).ready( function() { 12231 * $('#example').dataTable( { 12232 * "columnDefs": [ { 12233 * "targets": [3], 12234 * "createdCell": function (td, cellData, rowData, row, col) { 12235 * if ( cellData == "1.7" ) { 12236 * $(td).css('color', 'blue') 12237 * } 12238 * } 12239 * } ] 12240 * }); 12241 * } ); 12242 */ 12243 "fnCreatedCell": null, 12244 12245 12246 /** 12247 * This parameter has been replaced by `data` in DataTables to ensure naming 12248 * consistency. `dataProp` can still be used, as there is backwards 12249 * compatibility in DataTables for this option, but it is strongly 12250 * recommended that you use `data` in preference to `dataProp`. 12251 * @name DataTable.defaults.column.dataProp 12252 */ 12253 12254 12255 /** 12256 * This property can be used to read data from any data source property, 12257 * including deeply nested objects / properties. `data` can be given in a 12258 * number of different ways which effect its behaviour: 12259 * 12260 * * `integer` - treated as an array index for the data source. This is the 12261 * default that DataTables uses (incrementally increased for each column). 12262 * * `string` - read an object property from the data source. There are 12263 * three 'special' options that can be used in the string to alter how 12264 * DataTables reads the data from the source object: 12265 * * `.` - Dotted Javascript notation. Just as you use a `.` in 12266 * Javascript to read from nested objects, so to can the options 12267 * specified in `data`. For example: `browser.version` or 12268 * `browser.name`. If your object parameter name contains a period, use 12269 * `\\` to escape it - i.e. `first\\.name`. 12270 * * `[]` - Array notation. DataTables can automatically combine data 12271 * from and array source, joining the data with the characters provided 12272 * between the two brackets. For example: `name[, ]` would provide a 12273 * comma-space separated list from the source array. If no characters 12274 * are provided between the brackets, the original array source is 12275 * returned. 12276 * * `()` - Function notation. Adding `()` to the end of a parameter will 12277 * execute a function of the name given. For example: `browser()` for a 12278 * simple function on the data source, `browser.version()` for a 12279 * function in a nested property or even `browser().version` to get an 12280 * object property if the function called returns an object. Note that 12281 * function notation is recommended for use in `render` rather than 12282 * `data` as it is much simpler to use as a renderer. 12283 * * `null` - use the original data source for the row rather than plucking 12284 * data directly from it. This action has effects on two other 12285 * initialisation options: 12286 * * `defaultContent` - When null is given as the `data` option and 12287 * `defaultContent` is specified for the column, the value defined by 12288 * `defaultContent` will be used for the cell. 12289 * * `render` - When null is used for the `data` option and the `render` 12290 * option is specified for the column, the whole data source for the 12291 * row is used for the renderer. 12292 * * `function` - the function given will be executed whenever DataTables 12293 * needs to set or get the data for a cell in the column. The function 12294 * takes three parameters: 12295 * * Parameters: 12296 * * `{array|object}` The data source for the row 12297 * * `{string}` The type call data requested - this will be 'set' when 12298 * setting data or 'filter', 'display', 'type', 'sort' or undefined 12299 * when gathering data. Note that when `undefined` is given for the 12300 * type DataTables expects to get the raw data for the object back< 12301 * * `{*}` Data to set when the second parameter is 'set'. 12302 * * Return: 12303 * * The return value from the function is not required when 'set' is 12304 * the type of call, but otherwise the return is what will be used 12305 * for the data requested. 12306 * 12307 * Note that `data` is a getter and setter option. If you just require 12308 * formatting of data for output, you will likely want to use `render` which 12309 * is simply a getter and thus simpler to use. 12310 * 12311 * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The 12312 * name change reflects the flexibility of this property and is consistent 12313 * with the naming of mRender. If 'mDataProp' is given, then it will still 12314 * be used by DataTables, as it automatically maps the old name to the new 12315 * if required. 12316 * 12317 * @type string|int|function|null 12318 * @default null <i>Use automatically calculated column index</i> 12319 * 12320 * @name DataTable.defaults.column.data 12321 * @dtopt Columns 12322 * 12323 * @example 12324 * // Read table data from objects 12325 * // JSON structure for each row: 12326 * // { 12327 * // "engine": {value}, 12328 * // "browser": {value}, 12329 * // "platform": {value}, 12330 * // "version": {value}, 12331 * // "grade": {value} 12332 * // } 12333 * $(document).ready( function() { 12334 * $('#example').dataTable( { 12335 * "ajaxSource": "sources/objects.txt", 12336 * "columns": [ 12337 * { "data": "engine" }, 12338 * { "data": "browser" }, 12339 * { "data": "platform" }, 12340 * { "data": "version" }, 12341 * { "data": "grade" } 12342 * ] 12343 * } ); 12344 * } ); 12345 * 12346 * @example 12347 * // Read information from deeply nested objects 12348 * // JSON structure for each row: 12349 * // { 12350 * // "engine": {value}, 12351 * // "browser": {value}, 12352 * // "platform": { 12353 * // "inner": {value} 12354 * // }, 12355 * // "details": [ 12356 * // {value}, {value} 12357 * // ] 12358 * // } 12359 * $(document).ready( function() { 12360 * $('#example').dataTable( { 12361 * "ajaxSource": "sources/deep.txt", 12362 * "columns": [ 12363 * { "data": "engine" }, 12364 * { "data": "browser" }, 12365 * { "data": "platform.inner" }, 12366 * { "data": "
12366platform.details.0" }, 12367 * { "data": "platform.details.1" } 12368 * ] 12369 * } ); 12370 * } ); 12371 * 12372 * @example 12373 * // Using `data` as a function to provide different information for 12374 * // sorting, filtering and display. In this case, currency (price) 12375 * $(document).ready( function() { 12376 * $('#example').dataTable( { 12377 * "columnDefs": [ { 12378 * "targets": [ 0 ], 12379 * "data": function ( source, type, val ) { 12380 * if (type === 'set') { 12381 * source.price = val; 12382 * // Store the computed dis
vendor: 18,284 bytes, lines 12382-12931
12382lay and filter values for efficiency 12383 * source.price_display = val=="" ? "" : "$"+numberFormat(val); 12384 * source.price_filter = val=="" ? "" : "$"+numberFormat(val)+" "+val; 12385 * return; 12386 * } 12387 * else if (type === 'display') { 12388 * return source.price_display; 12389 * } 12390 * else if (type === 'filter') { 12391 * return source.price_filter; 12392 * } 12393 * // 'sort', 'type' and undefined all just use the integer 12394 * return source.price; 12395 * } 12396 * } ] 12397 * } ); 12398 * } ); 12399 * 12400 * @example 12401 * // Using default content 12402 * $(document).ready( function() { 12403 * $('#example').dataTable( { 12404 * "columnDefs": [ { 12405 * "targets": [ 0 ], 12406 * "data": null, 12407 * "defaultContent": "Click to edit" 12408 * } ] 12409 * } ); 12410 * } ); 12411 * 12412 * @example 12413 * // Using array notation - outputting a list from an array 12414 * $(document).ready( function() { 12415 * $('#example').dataTable( { 12416 * "columnDefs": [ { 12417 * "targets": [ 0 ], 12418 * "data": "name[, ]" 12419 * } ] 12420 * } ); 12421 * } ); 12422 * 12423 */ 12424 "mData": null, 12425 12426 12427 /** 12428 * This property is the rendering partner to `data` and it is suggested that 12429 * when you want to manipulate data for display (including filtering, 12430 * sorting etc) without altering the underlying data for the table, use this 12431 * property. `render` can be considered to be the the read only companion to 12432 * `data` which is read / write (then as such more complex). Like `data` 12433 * this option can be given in a number of different ways to effect its 12434 * behaviour: 12435 * 12436 * * `integer` - treated as an array index for the data source. This is the 12437 * default that DataTables uses (incrementally increased for each column). 12438 * * `string` - read an object property from the data source. There are 12439 * three 'special' options that can be used in the string to alter how 12440 * DataTables reads the data from the source object: 12441 * * `.` - Dotted Javascript notation. Just as you use a `.` in 12442 * Javascript to read from nested objects, so to can the options 12443 * specified in `data`. For example: `browser.version` or 12444 * `browser.name`. If your object parameter name contains a period, use 12445 * `\\` to escape it - i.e. `first\\.name`. 12446 * * `[]` - Array notation. DataTables can automatically combine data 12447 * from and array source, joining the data with the characters provided 12448 * between the two brackets. For example: `name[, ]` would provide a 12449 * comma-space separated list from the source array. If no characters 12450 * are provided between the brackets, the original array source is 12451 * returned. 12452 * * `()` - Function notation. Adding `()` to the end of a parameter will 12453 * execute a function of the name given. For example: `browser()` for a 12454 * simple function on the data source, `browser.version()` for a 12455 * function in a nested property or even `browser().version` to get an 12456 * object property if the function called returns an object. 12457 * * `object` - use different data for the different data types requested by 12458 * DataTables ('filter', 'display', 'type' or 'sort'). The property names 12459 * of the object is the data type the property refers to and the value can 12460 * defined using an integer, string or function using the same rules as 12461 * `render` normally does. Note that an `_` option _must_ be specified. 12462 * This is the default value to use if you haven't specified a value for 12463 * the data type requested by DataTables. 12464 * * `function` - the function given will be executed whenever DataTables 12465 * needs to set or get the data for a cell in the column. The function 12466 * takes three parameters: 12467 * * Parameters: 12468 * * {array|object} The data source for the row (based on `data`) 12469 * * {string} The type call data requested - this will be 'filter', 12470 * 'display', 'type' or 'sort'. 12471 * * {array|object} The full data source for the row (not based on 12472 * `data`) 12473 * * Return: 12474 * * The return value from the function is what will be used for the 12475 * data requested. 12476 * 12477 * @type string|int|function|object|null 12478 * @default null Use the data source value. 12479 * 12480 * @name DataTable.defaults.column.render 12481 * @dtopt Columns 12482 * 12483 * @example 12484 * // Create a comma separated list from an array of objects 12485 * $(document).ready( function() { 12486 * $('#example').dataTable( { 12487 * "ajaxSource": "sources/deep.txt", 12488 * "columns": [ 12489 * { "data": "engine" }, 12490 * { "data": "browser" }, 12491 * { 12492 * "data": "platform", 12493 * "render": "[, ].name" 12494 * } 12495 * ] 12496 * } ); 12497 * } ); 12498 * 12499 * @example 12500 * // Execute a function to obtain data 12501 * $(document).ready( function() { 12502 * $('#example').dataTable( { 12503 * "columnDefs": [ { 12504 * "targets": [ 0 ], 12505 * "data": null, // Use the full data source object for the renderer's source 12506 * "render": "browserName()" 12507 * } ] 12508 * } ); 12509 * } ); 12510 * 12511 * @example 12512 * // As an object, extracting different data for the different types 12513 * // This would be used with a data source such as: 12514 * // { "phone": 5552368, "phone_filter": "5552368 555-2368", "phone_display": "555-2368" } 12515 * // Here the `phone` integer is used for sorting and type detection, while `phone_filter` 12516 * // (which has both forms) is used for filtering for if a user inputs either format, while 12517 * // the formatted phone number is the one that is shown in the table. 12518 * $(document).ready( function() { 12519 * $('#example').dataTable( { 12520 * "columnDefs": [ { 12521 * "targets": [ 0 ], 12522 * "data": null, // Use the full data source object for the renderer's source 12523 * "render": { 12524 * "_": "phone", 12525 * "filter": "phone_filter", 12526 * "display": "phone_display" 12527 * } 12528 * } ] 12529 * } ); 12530 * } ); 12531 * 12532 * @example 12533 * // Use as a function to create a link from the data source 12534 * $(document).ready( function() { 12535 * $('#example').dataTable( { 12536 * "columnDefs": [ { 12537 * "targets": [ 0 ], 12538 * "data": "download_link", 12539 * "render": function ( data, type, full ) { 12540 * return '<a href="'+data+'">Download</a>'; 12541 * } 12542 * } ] 12543 * } ); 12544 * } ); 12545 */ 12546 "mRender": null, 12547 12548 12549 /** 12550 * Change the cell type created for the column - either TD cells or TH cells. This 12551 * can be useful as TH cells have semantic meaning in the table body, allowing them 12552 * to act as a header for a row (you may wish to add scope='row' to the TH elements). 12553 * @type string 12554 * @default td 12555 * 12556 * @name DataTable.defaults.column.cellType 12557 * @dtopt Columns 12558 * 12559 * @example 12560 * // Make the first column use TH cells 12561 * $(document).ready( function() { 12562 * $('#example').dataTable( { 12563 * "columnDefs": [ { 12564 * "targets": [ 0 ], 12565 * "cellType": "th" 12566 * } ] 12567 * } ); 12568 * } ); 12569 */ 12570 "sCellType": "td", 12571 12572 12573 /** 12574 * Class to give to each cell in this column. 12575 * @type string 12576 * @default <i>Empty string</i> 12577 * 12578 * @name DataTable.defaults.column.class 12579 * @dtopt Columns 12580 * 12581 * @example 12582 * // Using `columnDefs` 12583 * $(document).ready( function() { 12584 * $('#example').dataTable( { 12585 * "columnDefs": [ 12586 * { "class": "my_class", "targets": [ 0 ] } 12587 * ] 12588 * } ); 12589 * } ); 12590 * 12591 * @example 12592 * // Using `columns` 12593 * $(document).ready( function() { 12594 * $('#example').dataTable( { 12595 * "columns": [ 12596 * { "class": "my_class" }, 12597 * null, 12598 * null, 12599 * null, 12600 * null 12601 * ] 12602 * } ); 12603 * } ); 12604 */ 12605 "sClass": "", 12606 12607 /** 12608 * When DataTables calculates the column widths to assign to each column, 12609 * it finds the longest string in each column and then constructs a 12610 * temporary table and reads the widths from that. The problem with this 12611 * is that "mmm" is much wider then "iiii", but the latter is a longer 12612 * string - thus the calculation can go wrong (doing it properly and putting 12613 * it into an DOM object and measuring that is horribly(!) slow). Thus as 12614 * a "work around" we provide this option. It will append its value to the 12615 * text that is found to be the longest string for the column - i.e. padding. 12616 * Generally you shouldn't need this! 12617 * @type string 12618 * @default <i>Empty string<i> 12619 * 12620 * @name DataTable.defaults.column.contentPadding 12621 * @dtopt Columns 12622 * 12623 * @example 12624 * // Using `columns` 12625 * $(document).ready( function() { 12626 * $('#example').dataTable( { 12627 * "columns": [ 12628 * null, 12629 * null, 12630 * null, 12631 * { 12632 * "contentPadding": "mmm" 12633 * } 12634 * ] 12635 * } ); 12636 * } ); 12637 */ 12638 "sContentPadding": "", 12639 12640 12641 /** 12642 * Allows a default value to be given for a column's data, and will be used 12643 * whenever a null data source is encountered (this can be because `data` 12644 * is set to null, or because the data source itself is null). 12645 * @type string 12646 * @default null 12647 * 12648 * @name DataTable.defaults.column.defaultContent 12649 * @dtopt Columns 12650 * 12651 * @example 12652 * // Using `columnDefs` 12653 * $(document).ready( function() { 12654 * $('#example').dataTable( { 12655 * "columnDefs": [ 12656 * { 12657 * "data": null, 12658 * "defaultContent": "Edit", 12659 * "targets": [ -1 ] 12660 * } 12661 * ] 12662 * } ); 12663 * } ); 12664 * 12665 * @example 12666 * // Using `columns` 12667 * $(document).ready( function() { 12668 * $('#example').dataTable( { 12669 * "columns": [ 12670 * null, 12671 * null, 12672 * null, 12673 * { 12674 * "data": null, 12675 * "defaultContent": "Edit" 12676 * } 12677 * ] 12678 * } ); 12679 * } ); 12680 */ 12681 "sDefaultContent": null, 12682 12683 12684 /** 12685 * This parameter is only used in DataTables' server-side processing. It can 12686 * be exceptionally useful to know what columns are being displayed on the 12687 * client side, and to map these to database fields. When defined, the names 12688 * also allow DataTables to reorder information from the server if it comes 12689 * back in an unexpected order (i.e. if you switch your columns around on the 12690 * client-side, your server-side code does not also need updating). 12691 * @type string 12692 * @default <i>Empty string</i> 12693 * 12694 * @name DataTable.defaults.column.name 12695 * @dtopt Columns 12696 * 12697 * @example 12698 * // Using `columnDefs` 12699 * $(document).ready( function() { 12700 * $('#example').dataTable( { 12701 * "columnDefs": [ 12702 * { "name": "engine", "targets": [ 0 ] }, 12703 * { "name": "browser", "targets": [ 1 ] }, 12704 * { "name": "platform", "targets": [ 2 ] }, 12705 * { "name": "version", "targets": [ 3 ] }, 12706 * { "name": "grade", "targets": [ 4 ] } 12707 * ] 12708 * } ); 12709 * } ); 12710 * 12711 * @example 12712 * // Using `columns` 12713 * $(document).ready( function() { 12714 * $('#example').dataTable( { 12715 * "columns": [ 12716 * { "name": "engine" }, 12717 * { "name": "browser" }, 12718 * { "name": "platform" }, 12719 * { "name": "version" }, 12720 * { "name": "grade" } 12721 * ] 12722 * } ); 12723 * } ); 12724 */ 12725 "sName": "", 12726 12727 12728 /** 12729 * Defines a data source type for the ordering which can be used to read 12730 * real-time information from the table (updating the internally cached 12731 * version) prior to ordering. This allows ordering to occur on user 12732 * editable elements such as form inputs. 12733 * @type string 12734 * @default std 12735 * 12736 * @name DataTable.defaults.column.orderDataType 12737 * @dtopt Columns 12738 * 12739 * @example 12740 * // Using `columnDefs` 12741 * $(document).ready( function() { 12742 * $('#example').dataTable( { 12743 * "columnDefs": [ 12744 * { "orderDataType": "dom-text", "targets": [ 2, 3 ] }, 12745 * { "type": "numeric", "targets": [ 3 ] }, 12746 * { "orderDataType": "dom-select", "targets": [ 4 ] }, 12747 * { "orderDataType": "dom-checkbox", "targets": [ 5 ] } 12748 * ] 12749 * } ); 12750 * } ); 12751 * 12752 * @example 12753 * // Using `columns` 12754 * $(document).ready( function() { 12755 * $('#example').dataTable( { 12756 * "columns": [ 12757 * null, 12758 * null, 12759 * { "orderDataType": "dom-text" }, 12760 * { "orderDataType": "dom-text", "type": "numeric" }, 12761 * { "orderDataType": "dom-select" }, 12762 * { "orderDataType": "dom-checkbox" } 12763 * ] 12764 * } ); 12765 * } ); 12766 */ 12767 "sSortDataType": "std", 12768 12769 12770 /** 12771 * The title of this column. 12772 * @type string 12773 * @default null <i>Derived from the 'TH' value for this column in the 12774 * original HTML table.</i> 12775 * 12776 * @name DataTable.defaults.column.title 12777 * @dtopt Columns 12778 * 12779 * @example 12780 * // Using `columnDefs` 12781 * $(document).ready( function() { 12782 * $('#example').dataTable( { 12783 * "columnDefs": [ 12784 * { "title": "My column title", "targets": [ 0 ] } 12785 * ] 12786 * } ); 12787 * } ); 12788 * 12789 * @example 12790 * // Using `columns` 12791 * $(document).ready( function() { 12792 * $('#example').dataTable( { 12793 * "columns": [ 12794 * { "title": "My column title" }, 12795 * null, 12796 * null, 12797 * null, 12798 * null 12799 * ] 12800 * } ); 12801 * } ); 12802 */ 12803 "sTitle": null, 12804 12805 12806 /** 12807 * The type allows you to specify how the data for this column will be 12808 * ordered. Four types (string, numeric, date and html (which will strip 12809 * HTML tags before ordering)) are currently available. Note that only date 12810 * formats understood by Javascript's Date() object will be accepted as type 12811 * date. For example: "Mar 26, 2008 5:03 PM". May take the values: 'string', 12812 * 'numeric', 'date' or 'html' (by default). Further types can be adding 12813 * through plug-ins. 12814 * @type string 12815 * @default null <i>Auto-detected from raw data</i> 12816 * 12817 * @name DataTable.defaults.column.type 12818 * @dtopt Columns 12819 * 12820 * @example 12821 * // Using `columnDefs` 12822 * $(document).ready( function() { 12823 * $('#example').dataTable( { 12824 * "columnDefs": [ 12825 * { "type": "html", "targets": [ 0 ] } 12826 * ] 12827 * } ); 12828 * } ); 12829 * 12830 * @example 12831 * // Using `columns` 12832 * $(document).ready( function() { 12833 * $('#example').dataTable( { 12834 * "columns": [ 12835 * { "type": "html" }, 12836 * null, 12837 * null, 12838 * null, 12839 * null 12840 * ] 12841 * } ); 12842 * } ); 12843 */ 12844 "sType": null, 12845 12846 12847 /** 12848 * Defining the width of the column, this parameter may take any CSS value 12849 * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not 12850 * been given a specific width through this interface ensuring that the table 12851 * remains readable. 12852 * @type string 12853 * @default null <i>Automatic</i> 12854 * 12855 * @name DataTable.defaults.column.width 12856 * @dtopt Columns 12857 * 12858 * @example 12859 * // Using `columnDefs` 12860 * $(document).ready( function() { 12861 * $('#example').dataTable( { 12862 * "columnDefs": [ 12863 * { "width": "20%", "targets": [ 0 ] } 12864 * ] 12865 * } ); 12866 * } ); 12867 * 12868 * @example 12869 * // Using `columns` 12870 * $(document).ready( function() { 12871 * $('#example').dataTable( { 12872 * "columns": [ 12873 * { "width": "20%" }, 12874 * null, 12875 * null, 12876 * null, 12877 * null 12878 * ] 12879 * } ); 12880 * } ); 12881 */ 12882 "sWidth": null 12883 }; 12884 12885 _fnHungarianMap( DataTable.defaults.column ); 12886 12887 12888 12889 /** 12890 * DataTables settings object - this holds all the information needed for a 12891 * given table, including configuration, data and current application of the 12892 * table options. DataTables does not have a single instance for each DataTable 12893 * with the settings attached to that instance, but rather instances of the 12894 * DataTable "class" are created on-the-fly as needed (typically by a 12895 * $().dataTable() call) and the settings object is then applied to that 12896 * instance. 12897 * 12898 * Note that this object is related to {@link DataTable.defaults} but this 12899 * one is the internal data store for DataTables's cache of columns. It should 12900 * NOT be manipulated outside of DataTables. Any configuration should be done 12901 * through the initialisation options. 12902 * @namespace 12903 * @todo Really should attach the settings object to individual instances so we 12904 * don't need to create new instances on each $().dataTable() call (if the 12905 * table already exists). It would also save passing oSettings around and 12906 * into every single function. However, this is a very significant 12907 * architecture change for DataTables and will almost certainly break 12908 * backwards compatibility with older installations. This is something that 12909 * will be done in 2.0. 12910 */ 12911 DataTable.models.oSettings = { 12912 /** 12913 * Primary features of DataTables and their enablement state. 12914 * @namespace 12915 */ 12916 "oFeatures": { 12917 12918 /** 12919 * Flag to say if DataTables should automatically try to calculate the 12920 * optimum table and columns widths (true) or not (false). 12921 * Note that this parameter will be set by the initialisation routine. To 12922 * set a default use {@link DataTable.defaults}. 12923 * @type boolean 12924 */ 12925 "bAutoWidth": null, 12926 12927 /** 12928 * Delay the creation of TR and TD elements until they are actually 12929 * needed by a driven page draw. This can give a significant speed 12930 * increase for Ajax source and Javascript source data, but makes no 12931 * difference at all f
12931ro
vendor: 14,836 bytes, lines 12931-13508
12931 DOM and server-side processing tables. 12932 * Note that this parameter will be set by the initialisation routine. To 12933 * set a default use {@link DataTable.defaults}. 12934 * @type boolean 12935 */ 12936 "bDeferRender": null, 12937 12938 /** 12939 * Enable filtering on the table or not. Note that if this is disabled 12940 * then there is no filtering at all on the table, including fnFilter. 12941 * To just remove the filtering input use sDom and remove the 'f' option. 12942 * Note that this parameter will be set by the initialisation routine. To 12943 * set a default use {@link DataTable.defaults}. 12944 * @type boolean 12945 */ 12946 "bFilter": null, 12947 12948 /** 12949 * Table information element (the 'Showing x of y records' div) enable 12950 * flag. 12951 * Note that this parameter will be set by the initialisation routine. To 12952 * set a default use {@link DataTable.defaults}. 12953 * @type boolean 12954 */ 12955 "bInfo": null, 12956 12957 /** 12958 * Present a user control allowing the end user to change the page size 12959 * when pagination is enabled. 12960 * Note that this parameter will be set by the initialisation routine. To 12961 * set a default use {@link DataTable.defaults}. 12962 * @type boolean 12963 */ 12964 "bLengthChange": null, 12965 12966 /** 12967 * Pagination enabled or not. Note that if this is disabled then length 12968 * changing must also be disabled. 12969 * Note that this parameter will be set by the initialisation routine. To 12970 * set a default use {@link DataTable.defaults}. 12971 * @type boolean 12972 */ 12973 "bPaginate": null, 12974 12975 /** 12976 * Processing indicator enable flag whenever DataTables is enacting a 12977 * user request - typically an Ajax request for server-side processing. 12978 * Note that this parameter will be set by the initialisation routine. To 12979 * set a default use {@link DataTable.defaults}. 12980 * @type boolean 12981 */ 12982 "bProcessing": null, 12983 12984 /** 12985 * Server-side processing enabled flag - when enabled DataTables will 12986 * get all data from the server for every draw - there is no filtering, 12987 * sorting or paging done on the client-side. 12988 * Note that this parameter will be set by the initialisation routine. To 12989 * set a default use {@link DataTable.defaults}. 12990 * @type boolean 12991 */ 12992 "bServerSide": null, 12993 12994 /** 12995 * Sorting enablement flag. 12996 * Note that this parameter will be set by the initialisation routine. To 12997 * set a default use {@link DataTable.defaults}. 12998 * @type boolean 12999 */ 13000 "bSort": null, 13001 13002 /** 13003 * Multi-column sorting 13004 * Note that this parameter will be set by the initialisation routine. To 13005 * set a default use {@link DataTable.defaults}. 13006 * @type boolean 13007 */ 13008 "bSortMulti": null, 13009 13010 /** 13011 * Apply a class to the columns which are being sorted to provide a 13012 * visual highlight or not. This can slow things down when enabled since 13013 * there is a lot of DOM interaction. 13014 * Note that this parameter will be set by the initialisation routine. To 13015 * set a default use {@link DataTable.defaults}. 13016 * @type boolean 13017 */ 13018 "bSortClasses": null, 13019 13020 /** 13021 * State saving enablement flag. 13022 * Note that this parameter will be set by the initialisation routine. To 13023 * set a default use {@link DataTable.defaults}. 13024 * @type boolean 13025 */ 13026 "bStateSave": null 13027 }, 13028 13029 13030 /** 13031 * Scrolling settings for a table. 13032 * @namespace 13033 */ 13034 "oScroll": { 13035 /** 13036 * When the table is shorter in height than sScrollY, collapse the 13037 * table container down to the height of the table (when true). 13038 * Note that this parameter will be set by the initialisation routine. To 13039 * set a default use {@link DataTable.defaults}. 13040 * @type boolean 13041 */ 13042 "bCollapse": null, 13043 13044 /** 13045 * Width of the scrollbar for the web-browser's platform. Calculated 13046 * during table initialisation. 13047 * @type int 13048 * @default 0 13049 */ 13050 "iBarWidth": 0, 13051 13052 /** 13053 * Viewport width for horizontal scrolling. Horizontal scrolling is 13054 * disabled if an empty string. 13055 * Note that this parameter will be set by the initialisation routine. To 13056 * set a default use {@link DataTable.defaults}. 13057 * @type string 13058 */ 13059 "sX": null, 13060 13061 /** 13062 * Width to expand the table to when using x-scrolling. Typically you 13063 * should not need to use this. 13064 * Note that this parameter will be set by the initialisation routine. To 13065 * set a default use {@link DataTable.defaults}. 13066 * @type string 13067 * @deprecated 13068 */ 13069 "sXInner": null, 13070 13071 /** 13072 * Viewport height for vertical scrolling. Vertical scrolling is disabled 13073 * if an empty string. 13074 * Note that this parameter will be set by the initialisation routine. To 13075 * set a default use {@link DataTable.defaults}. 13076 * @type string 13077 */ 13078 "sY": null 13079 }, 13080 13081 /** 13082 * Language information for the table. 13083 * @namespace 13084 * @extends DataTable.defaults.oLanguage 13085 */ 13086 "oLanguage": { 13087 /** 13088 * Information callback function. See 13089 * {@link DataTable.defaults.fnInfoCallback} 13090 * @type function 13091 * @default null 13092 */ 13093 "fnInfoCallback": null 13094 }, 13095 13096 /** 13097 * Browser support parameters 13098 * @namespace 13099 */ 13100 "oBrowser": { 13101 /** 13102 * Indicate if the browser incorrectly calculates width:100% inside a 13103 * scrolling element (IE6/7) 13104 * @type boolean 13105 * @default false 13106 */ 13107 "bScrollOversize": false, 13108 13109 /** 13110 * Determine if the vertical scrollbar is on the right or left of the 13111 * scrolling container - needed for rtl language layout, although not 13112 * all browsers move the scrollbar (Safari). 13113 * @type boolean 13114 * @default false 13115 */ 13116 "bScrollbarLeft": false, 13117 13118 /** 13119 * Flag for if `getBoundingClientRect` is fully supported or not 13120 * @type boolean 13121 * @default false 13122 */ 13123 "bBounding": false, 13124 13125 /** 13126 * Browser scrollbar width 13127 * @type integer 13128 * @default 0 13129 */ 13130 "barWidth": 0 13131 }, 13132 13133 13134 "ajax": null, 13135 13136 13137 /** 13138 * Array referencing the nodes which are used for the features. The 13139 * parameters of this object match what is allowed by sDom - i.e. 13140 * <ul> 13141 * <li>'l' - Length changing</li> 13142 * <li>'f' - Filtering input</li> 13143 * <li>'t' - The table!</li> 13144 * <li>'i' - Information</li> 13145 * <li>'p' - Pagination</li> 13146 * <li>'r' - pRocessing</li> 13147 * </ul> 13148 * @type array 13149 * @default [] 13150 */ 13151 "aanFeatures": [], 13152 13153 /** 13154 * Store data information - see {@link DataTable.models.oRow} for detailed 13155 * information. 13156 * @type array 13157 * @default [] 13158 */ 13159 "aoData": [], 13160 13161 /** 13162 * Array of indexes which are in the current display (after filtering etc) 13163 * @type array 13164 * @default [] 13165 */ 13166 "aiDisplay": [], 13167 13168 /** 13169 * Array of indexes for display - no filtering 13170 * @type array 13171 * @default [] 13172 */ 13173 "aiDisplayMaster": [], 13174 13175 /** 13176 * Map of row ids to data indexes 13177 * @type object 13178 * @default {} 13179 */ 13180 "aIds": {}, 13181 13182 /** 13183 * Store information about each column that is in use 13184 * @type array 13185 * @default [] 13186 */ 13187 "aoColumns": [], 13188 13189 /** 13190 * Store information about the table's header 13191 * @type array 13192 * @default [] 13193 */ 13194 "aoHeader": [], 13195 13196 /** 13197 * Store information about the table's footer 13198 * @type array 13199 * @default [] 13200 */ 13201 "aoFooter": [], 13202 13203 /** 13204 * Store the applied global search information in case we want to force a 13205 * research or compare the old search to a new one. 13206 * Note that this parameter will be set by the initialisation routine. To 13207 * set a default use {@link DataTable.defaults}. 13208 * @namespace 13209 * @extends DataTable.models.oSearch 13210 */ 13211 "oPreviousSearch": {}, 13212 13213 /** 13214 * Store the applied search for each column - see 13215 * {@link DataTable.models.oSearch} for the format that is used for the 13216 * filtering information for each column. 13217 * @type array 13218 * @default [] 13219 */ 13220 "aoPreSearchCols": [], 13221 13222 /** 13223 * Sorting that is applied to the table. Note that the inner arrays are 13224 * used in the following manner: 13225 * <ul> 13226 * <li>Index 0 - column number</li> 13227 * <li>Index 1 - current sorting direction</li> 13228 * </ul> 13229 * Note that this parameter will be set by the initialisation routine. To 13230 * set a default use {@link DataTable.defaults}. 13231 * @type array 13232 * @todo These inner arrays should really be objects 13233 */ 13234 "aaSorting": null, 13235 13236 /** 13237 * Sorting that is always applied to the table (i.e. prefixed in front of 13238 * aaSorting). 13239 * Note that this parameter will be set by the initialisation routine. To 13240 * set a default use {@link DataTable.defaults}. 13241 * @type array 13242 * @default [] 13243 */ 13244 "aaSortingFixed": [], 13245 13246 /** 13247 * Classes to use for the striping of a table. 13248 * Note that this parameter will be set by the initialisation routine. To 13249 * set a default use {@link DataTable.defaults}. 13250 * @type array 13251 * @default [] 13252 */ 13253 "asStripeClasses": null, 13254 13255 /** 13256 * If restoring a table - we should restore its striping classes as well 13257 * @type array 13258 * @default [] 13259 */ 13260 "asDestroyStripes": [], 13261 13262 /** 13263 * If restoring a table - we should restore its width 13264 * @type int 13265 * @default 0 13266 */ 13267 "sDestroyWidth": 0, 13268 13269 /** 13270 * Callback functions array for every time a row is inserted (i.e. on a draw). 13271 * @type array 13272 * @default [] 13273 */ 13274 "aoRowCallback": [], 13275 13276 /** 13277 * Callback functions for the header on each draw. 13278 * @type array 13279 * @default [] 13280 */ 13281 "aoHeaderCallback": [], 13282 13283 /** 13284 * Callback function for the footer on each draw. 13285 * @type array 13286 * @default [] 13287 */ 13288 "aoFooterCallback": [], 13289 13290 /** 13291 * Array of callback functions for draw callback functions 13292 * @type array 13293 * @default [] 13294 */ 13295 "aoDrawCallback": [], 13296 13297 /** 13298 * Array of callback functions for row created function 13299 * @type array 13300 * @default [] 13301 */ 13302 "aoRowCreatedCallback": [], 13303 13304 /** 13305 * Callback functions for just before the table is redrawn. A return of 13306 * false will be used to cancel the draw. 13307 * @type array 13308 * @default [] 13309 */ 13310 "aoPreDrawCallback": [], 13311 13312 /** 13313 * Callback functions for when the table has been initialised. 13314 * @type array 13315 * @default [] 13316 */ 13317 "aoInitComplete": [], 13318 13319 13320 /** 13321 * Callbacks for modifying the settings to be stored for state saving, prior to 13322 * saving state. 13323 * @type array 13324 * @default [] 13325 */ 13326 "aoStateSaveParams": [], 13327 13328 /** 13329 * Callbacks for modifying the settings that have been stored for state saving 13330 * prior to using the stored values to restore the state. 13331 * @type array 13332 * @default [] 13333 */ 13334 "aoStateLoadParams": [], 13335 13336 /** 13337 * Callbacks for operating on the settings object once the saved state has been 13338 * loaded 13339 * @type array 13340 * @default [] 13341 */ 13342 "aoStateLoaded": [], 13343 13344 /** 13345 * Cache the table ID for quick access 13346 * @type string 13347 * @default <i>Empty string</i> 13348 */ 13349 "sTableId": "", 13350 13351 /** 13352 * The TABLE node for the main table 13353 * @type node 13354 * @default null 13355 */ 13356 "nTable": null, 13357 13358 /** 13359 * Permanent ref to the thead element 13360 * @type node 13361 * @default null 13362 */ 13363 "nTHead": null, 13364 13365 /** 13366 * Permanent ref to the tfoot element - if it exists 13367 * @type node 13368 * @default null 13369 */ 13370 "nTFoot": null, 13371 13372 /** 13373 * Permanent ref to the tbody element 13374 * @type node 13375 * @default null 13376 */ 13377 "nTBody": null, 13378 13379 /** 13380 * Cache the wrapper node (contains all DataTables controlled elements) 13381 * @type node 13382 * @default null 13383 */ 13384 "nTableWrapper": null, 13385 13386 /** 13387 * Indicate if when using server-side processing the loading of data 13388 * should be deferred until the second draw. 13389 * Note that this parameter will be set by the initialisation routine. To 13390 * set a default use {@link DataTable.defaults}. 13391 * @type boolean 13392 * @default false 13393 */ 13394 "bDeferLoading": false, 13395 13396 /** 13397 * Indicate if all required information has been read in 13398 * @type boolean 13399 * @default false 13400 */ 13401 "bInitialised": false, 13402 13403 /** 13404 * Information about open rows. Each object in the array has the parameters 13405 * 'nTr' and 'nParent' 13406 * @type array 13407 * @default [] 13408 */ 13409 "aoOpenRows": [], 13410 13411 /** 13412 * Dictate the positioning of DataTables' control elements - see 13413 * {@link DataTable.model.oInit.sDom}. 13414 * Note that this parameter will be set by the initialisation routine. To 13415 * set a default use {@link DataTable.defaults}. 13416 * @type string 13417 * @default null 13418 */ 13419 "sDom": null, 13420 13421 /** 13422 * Search delay (in mS) 13423 * @type integer 13424 * @default null 13425 */ 13426 "searchDelay": null, 13427 13428 /** 13429 * Which type of pagination should be used. 13430 * Note that this parameter will be set by the initialisation routine. To 13431 * set a default use {@link DataTable.defaults}. 13432 * @type string 13433 * @default two_button 13434 */ 13435 "sPaginationType": "two_button", 13436 13437 /** 13438 * The state duration (for `stateSave`) in seconds. 13439 * Note that this parameter will be set by the initialisation routine. To 13440 * set a default use {@link DataTable.defaults}. 13441 * @type int 13442 * @default 0 13443 */ 13444 "iStateDuration": 0, 13445 13446 /** 13447 * Array of callback functions for state saving. Each array element is an 13448 * object with the following parameters: 13449 * <ul> 13450 * <li>function:fn - function to call. Takes two parameters, oSettings 13451 * and the JSON string to save that has been thus far created. Returns 13452 * a JSON string to be inserted into a json object 13453 * (i.e. '"param": [ 0, 1, 2]')</li> 13454 * <li>string:sName - name of callback</li> 13455 * </ul> 13456 * @type array 13457 * @default [] 13458 */ 13459 "aoStateSave": [], 13460 13461 /** 13462 * Array of callback functions for state loading. Each array element is an 13463 * object with the following parameters: 13464 * <ul> 13465 * <li>function:fn - function to call. Takes two parameters, oSettings 13466 * and the object stored. May return false to cancel state loading</li> 13467 * <li>string:sName - name of callback</li> 13468 * </ul> 13469 * @type array 13470 * @default [] 13471 */ 13472 "aoStateLoad": [], 13473 13474 /** 13475 * State that was saved. Useful for back reference 13476 * @type object 13477 * @default null 13478 */ 13479 "oSavedState": null, 13480 13481 /** 13482 * State that was loaded. Useful for back reference 13483 * @type object 13484 * @default null 13485 */ 13486 "oLoadedState": null, 13487 13488 /** 13489 * Source url for AJAX data for the table. 13490 * Note that this parameter will be set by the initialisation routine. To 13491 * set a default use {@link DataTable.defaults}. 13492 * @type string 13493 * @default null 13494 */ 13495 "sAjaxSource": null, 13496 13497 /** 13498 * Property from a given object from which to read the table data from. This 13499 * can be an empty string (when not server-side processing), in which case 13500 * it is assumed an an array is given directly. 13501 * Note that this parameter will be set by the initialisation routine. To 13502 * set a default use {@link DataTable.defaults}. 13503 * @type string 13504 */ 13505 "sAjaxDataProp": null, 13506 13507 /** 13508 *
13508Note if draw should be blocked while getting data 13509 * @type boolean 13510 * @default true 13511 */ 13512 "bAjaxDataGet": true, 13513 13514 /** 13515 * The last jQuery XHR object that was used for server-side data gathering. 13516 * This can be used for working with the XHR information in one of the 13517 * callbacks 13518 * @type object 13519 * @default null 13520 */ 13521 "jqXHR": null, 13522 13523 /** 13524 * JSON returned from the server in the last Ajax request 13525 * @type object 13526 * @default undefined 13527 */ 13528 "json": undefined, 13529 13530 /** 13531 * Data submitted as part of the last Ajax request 13532 * @type object 13533 * @default undefined 13534 */ 13535 "oAjaxData": undefined, 13536 13537 /** 13538 * Function to get the server-side data. 13539 * Note that this parameter will be set by the initialisation routine. To 13540 * set a default use {@link DataTable.defaults}. 13541 * @type function 13542 */ 13543 "fnServerData": null, 13544 13545 /** 13546 * Functions which are called prior to sending an Ajax request so extra 13547 * parameters can easily be sent to the server 13548 * @type array 13549 * @default [] 13550 */ 13551 "aoServerParams": [], 13552 13553 /** 13554 * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if 13555 * required). 13556 * Note that this parameter will be set by the initialisation routine. To 13557 * set a default use {@link DataTable.defaults}. 13558 * @type string 13559 */ 13560 "sServerMethod": null, 13561 13562 /** 13563 * Format numbers for display. 13564 * Note that this parameter will be set by the initialisation routine. To 13565 * set a default use {@link DataTable.defaults}. 13566 * @type function 13567 */ 13568 "fnFormatNumber": null, 13569 13570 /** 13571 * List of options that can be used for the user selectable length menu. 13572 * Note that this parameter will be set by the initialisation routine. To 13573 * set a default use {@link DataTable.defaults}. 13574 * @type array 13575 * @default [] 13576 */ 13577 "aLengthMenu": null, 13578 13579 /** 13580 * Counter for the draws that the table does. Also used as a tracker for 13581 * server-side processing 13582 * @type int 13583 * @default 0 13584 */ 13585 "iDraw": 0, 13586 13587 /** 13588 * Indicate if a redraw is being done - useful for Ajax 13589 * @type boolean 13590 * @default false 13591 */ 13592 "bDrawing": false, 13593 13594 /** 13595 * Draw index (iDraw) of the last error when parsing the returned data 13596 * @type int 13597 * @default -1 13598 */ 13599 "iDrawError": -1, 13600 13601 /** 13602 * Paging display length 13603 * @type int 13604 * @default 10 13605 */ 13606 "_iDisplayLength": 10, 13607 13608 /** 13609 * Paging start point - aiDisplay index 13610 * @type int 13611 * @default 0 13612 */ 13613 "_iDisplayStart": 0, 13614 13615 /** 13616 * Server-side processing - number of records in the result set 13617 * (i.e. before filtering), Use fnRecordsTotal rather than 13618 * this property to get the value of the number of records, regardless of 13619 * the server-side processing setting. 13620 * @type int 13621 * @default 0 13622 * @private 13623 */ 13624 "_iRecordsTotal": 0, 13625 13626 /** 13627 * Server-side processing - number of records in the current display set 13628 * (i.e. after filtering). Use fnRecordsDisplay rather than 13629 * this property to get the value of the number of records, regardless of 13630 * the server-side processing setting. 13631 * @type boolean 13632 * @default 0 13633 * @private 13634 */ 13635 "_iRecordsDisplay": 0, 13636 13637 /** 13638 * The classes to use for the table 13639 * @type object 13640 * @default {} 13641 */
vendor: 4,830 bytes, lines 13642-13850
13642 "oClasses": {}, 13643 13644 /** 13645 * Flag attached to the settings object so you can check in the draw 13646 * callback if filtering has been done in the draw. Deprecated in favour of 13647 * events. 13648 * @type boolean 13649 * @default false 13650 * @deprecated 13651 */ 13652 "bFiltered": false, 13653 13654 /** 13655 * Flag attached to the settings object so you can check in the draw 13656 * callback if sorting has been done in the draw. Deprecated in favour of 13657 * events. 13658 * @type boolean 13659 * @default false 13660 * @deprecated 13661 */ 13662 "bSorted": false, 13663 13664 /** 13665 * Indicate that if multiple rows are in the header and there is more than 13666 * one unique cell per column, if the top one (true) or bottom one (false) 13667 * should be used for sorting / title by DataTables. 13668 * Note that this parameter will be set by the initialisation routine. To 13669 * set a default use {@link DataTable.defaults}. 13670 * @type boolean 13671 */ 13672 "bSortCellsTop": null, 13673 13674 /** 13675 * Initialisation object that is used for the table 13676 * @type object 13677 * @default null 13678 */ 13679 "oInit": null, 13680 13681 /** 13682 * Destroy callback functions - for plug-ins to attach themselves to the 13683 * destroy so they can clean up markup and events. 13684 * @type array 13685 * @default [] 13686 */ 13687 "aoDestroyCallback": [], 13688 13689 13690 /** 13691 * Get the number of records in the current record set, before filtering 13692 * @type function 13693 */ 13694 "fnRecordsTotal": function () 13695 { 13696 return _fnDataSource( this ) == 'ssp' ? 13697 this._iRecordsTotal * 1 : 13698 this.aiDisplayMaster.length; 13699 }, 13700 13701 /** 13702 * Get the number of records in the current record set, after filtering 13703 * @type function 13704 */ 13705 "fnRecordsDisplay": function () 13706 { 13707 return _fnDataSource( this ) == 'ssp' ? 13708 this._iRecordsDisplay * 1 : 13709 this.aiDisplay.length; 13710 }, 13711 13712 /** 13713 * Get the display end point - aiDisplay index 13714 * @type function 13715 */ 13716 "fnDisplayEnd": function () 13717 { 13718 var 13719 len = this._iDisplayLength, 13720 start = this._iDisplayStart, 13721 calc = start + len, 13722 records = this.aiDisplay.length, 13723 features = this.oFeatures, 13724 paginate = features.bPaginate; 13725 13726 if ( features.bServerSide ) { 13727 return paginate === false || len === -1 ? 13728 start + records : 13729 Math.min( start+len, this._iRecordsDisplay ); 13730 } 13731 else { 13732 return ! paginate || calc>records || len===-1 ? 13733 records : 13734 calc; 13735 } 13736 }, 13737 13738 /** 13739 * The DataTables object for this table 13740 * @type object 13741 * @default null 13742 */ 13743 "oInstance": null, 13744 13745 /** 13746 * Unique identifier for each instance of the DataTables object. If there 13747 * is an ID on the table node, then it takes that value, otherwise an 13748 * incrementing internal counter is used. 13749 * @type string 13750 * @default null 13751 */ 13752 "sInstance": null, 13753 13754 /** 13755 * tabindex attribute value that is added to DataTables control elements, allowing 13756 * keyboard navigation of the table and its controls. 13757 */ 13758 "iTabIndex": 0, 13759 13760 /** 13761 * DIV container for the footer scrolling table if scrolling 13762 */ 13763 "nScrollHead": null, 13764 13765 /** 13766 * DIV container for the footer scrolling table if scrolling 13767 */ 13768 "nScrollFoot": null, 13769 13770 /** 13771 * Last applied sort 13772 * @type array 13773 * @default [] 13774 */ 13775 "aLastSort": [], 13776 13777 /** 13778 * Stored plug-in instances 13779 * @type object 13780 * @default {} 13781 */ 13782 "oPlugins": {}, 13783 13784 /** 13785 * Function used to get a row's id from the row's data 13786 * @type function 13787 * @default null 13788 */ 13789 "rowIdFn": null, 13790 13791 /** 13792 * Data location where to store a row's id 13793 * @type string 13794 * @default null 13795 */ 13796 "rowId": null 13797 }; 13798 13799 /** 13800 * Extension object for DataTables that is used to provide all extension 13801 * options. 13802 * 13803 * Note that the `DataTable.ext` object is available through 13804 * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is 13805 * also aliased to `jQuery.fn.dataTableExt` for historic reasons. 13806 * @namespace 13807 * @extends DataTable.models.ext 13808 */ 13809 13810 13811 /** 13812 * DataTables extensions 13813 * 13814 * This namespace acts as a collection area for plug-ins that can be used to 13815 * extend DataTables capabilities. Indeed many of the build in methods 13816 * use this method to provide their own capabilities (sorting methods for 13817 * example). 13818 * 13819 * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy 13820 * reasons 13821 * 13822 * @namespace 13823 */ 13824 DataTable.ext = _ext = { 13825 /** 13826 * Buttons. For use with the Buttons extension for DataTables. This is 13827 * defined here so other extensions can define buttons regardless of load 13828 * order. It is _not_ used by DataTables core. 13829 * 13830 * @type object 13831 * @default {} 13832 */ 13833 buttons: {}, 13834 13835 13836 /** 13837 * Element class names 13838 * 13839 * @type object 13840 * @default {} 13841 */ 13842 classes: {}, 13843 13844 13845 /** 13846 * DataTables build type (expanded by the download builder) 13847 * 13848 * @type string 13849 */ 13850 build:"bs/dt-1.10.16/r-2.2.1
vendor: 10,712 bytes, lines 13850-14164
13850", 13851 13852 13853 /** 13854 * Error reporting. 13855 * 13856 * How should DataTables report an error. Can take the value 'alert', 13857 * 'throw', 'none' or a function. 13858 * 13859 * @type string|function 13860 * @default alert 13861 */ 13862 errMode: "alert", 13863 13864 13865 /** 13866 * Feature plug-ins. 13867 * 13868 * This is an array of objects which describe the feature plug-ins that are 13869 * available to DataTables. These feature plug-ins are then available for 13870 * use through the `dom` initialisation option. 13871 * 13872 * Each feature plug-in is described by an object which must have the 13873 * following properties: 13874 * 13875 * * `fnInit` - function that is used to initialise the plug-in, 13876 * * `cFeature` - a character so the feature can be enabled by the `dom` 13877 * instillation option. This is case sensitive. 13878 * 13879 * The `fnInit` function has the following input parameters: 13880 * 13881 * 1. `{object}` DataTables settings object: see 13882 * {@link DataTable.models.oSettings} 13883 * 13884 * And the following return is expected: 13885 * 13886 * * {node|null} The element which contains your feature. Note that the 13887 * return may also be void if your plug-in does not require to inject any 13888 * DOM elements into DataTables control (`dom`) - for example this might 13889 * be useful when developing a plug-in which allows table control via 13890 * keyboard entry 13891 * 13892 * @type array 13893 * 13894 * @example 13895 * $.fn.dataTable.ext.features.push( { 13896 * "fnInit": function( oSettings ) { 13897 * return new TableTools( { "oDTSettings": oSettings } ); 13898 * }, 13899 * "cFeature": "T" 13900 * } ); 13901 */ 13902 feature: [], 13903 13904 13905 /** 13906 * Row searching. 13907 * 13908 * This method of searching is complimentary to the default type based 13909 * searching, and a lot more comprehensive as it allows you complete control 13910 * over the searching logic. Each element in this array is a function 13911 * (parameters described below) that is called for every row in the table, 13912 * and your logic decides if it should be included in the searching data set 13913 * or not. 13914 * 13915 * Searching functions have the following input parameters: 13916 * 13917 * 1. `{object}` DataTables settings object: see 13918 * {@link DataTable.models.oSettings} 13919 * 2. `{array|object}` Data for the row to be processed (same as the 13920 * original format that was passed in as the data source, or an array 13921 * from a DOM data source 13922 * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which 13923 * can be useful to retrieve the `TR` element if you need DOM interaction. 13924 * 13925 * And the following return is expected: 13926 * 13927 * * {boolean} Include the row in the searched result set (true) or not 13928 * (false) 13929 * 13930 * Note that as with the main search ability in DataTables, technically this 13931 * is "filtering", since it is subtractive. However, for consistency in 13932 * naming we call it searching here. 13933 * 13934 * @type array 13935 * @default [] 13936 * 13937 * @example 13938 * // The following example shows custom search being applied to the 13939 * // fourth column (i.e. the data[3] index) based on two input values 13940 * // from the end-user, matching the data in a certain range. 13941 * $.fn.dataTable.ext.search.push( 13942 * function( settings, data, dataIndex ) { 13943 * var min = document.getElementById('min').value * 1; 13944 * var max = document.getElementById('max').value * 1; 13945 * var version = data[3] == "-" ? 0 : data[3]*1; 13946 * 13947 * if ( min == "" && max == "" ) { 13948 * return true; 13949 * } 13950 * else if ( min == "" && version < max ) { 13951 * return true; 13952 * } 13953 * else if ( min < version && "" == max ) { 13954 * return true; 13955 * } 13956 * else if ( min < version && version < max ) { 13957 * return true; 13958 * } 13959 * return false; 13960 * } 13961 * ); 13962 */ 13963 search: [], 13964 13965 13966 /** 13967 * Selector extensions 13968 * 13969 * The `selector` option can be used to extend the options available for the 13970 * selector modifier options (`selector-modifier` object data type) that 13971 * each of the three built in selector types offer (row, column and cell + 13972 * their plural counterparts). For example the Select extension uses this 13973 * mechanism to provide an option to select only rows, columns and cells 13974 * that have been marked as selected by the end user (`{selected: true}`), 13975 * which can be used in conjunction with the existing built in selector 13976 * options. 13977 * 13978 * Each property is an array to which functions can be pushed. The functions 13979 * take three attributes: 13980 * 13981 * * Settings object for the host table 13982 * * Options object (`selector-modifier` object type) 13983 * * Array of selected item indexes 13984 * 13985 * The return is an array of the resulting item indexes after the custom 13986 * selector has been applied. 13987 * 13988 * @type object 13989 */ 13990 selector: { 13991 cell: [], 13992 column: [], 13993 row: [] 13994 }, 13995 13996 13997 /** 13998 * Internal functions, exposed for used in plug-ins. 13999 * 14000 * Please note that you should not need to use the internal methods for 14001 * anything other than a plug-in (and even then, try to avoid if possible). 14002 * The internal function may change between releases. 14003 * 14004 * @type object 14005 * @default {} 14006 */ 14007 internal: {}, 14008 14009 14010 /** 14011 * Legacy configuration options. Enable and disable legacy options that 14012 * are available in DataTables. 14013 * 14014 * @type object 14015 */ 14016 legacy: { 14017 /** 14018 * Enable / disable DataTables 1.9 compatible server-side processing 14019 * requests 14020 * 14021 * @type boolean 14022 * @default null 14023 */ 14024 ajax: null 14025 }, 14026 14027 14028 /** 14029 * Pagination plug-in methods. 14030 * 14031 * Each entry in this object is a function and defines which buttons should 14032 * be shown by the pagination rendering method that is used for the table: 14033 * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the 14034 * buttons are displayed in the document, while the functions here tell it 14035 * what buttons to display. This is done by returning an array of button 14036 * descriptions (what each button will do). 14037 * 14038 * Pagination types (the four built in options and any additional plug-in 14039 * options defined here) can be used through the `paginationType` 14040 * initialisation parameter. 14041 * 14042 * The functions defined take two parameters: 14043 * 14044 * 1. `{int} page` The current page index 14045 * 2. `{int} pages` The number of pages in the table 14046 * 14047 * Each function is expected to return an array where each element of the 14048 * array can be one of: 14049 * 14050 * * `first` - Jump to first page when activated 14051 * * `last` - Jump to last page when activated 14052 * * `previous` - Show previous page when activated 14053 * * `next` - Show next page when activated 14054 * * `{int}` - Show page of the index given 14055 * * `{array}` - A nested array containing the above elements to add a 14056 * containing 'DIV' element (might be useful for styling). 14057 * 14058 * Note that DataTables v1.9- used this object slightly differently whereby 14059 * an object with two functions would be defined for each plug-in. That 14060 * ability is still supported by DataTables 1.10+ to provide backwards 14061 * compatibility, but this option of use is now decremented and no longer 14062 * documented in DataTables 1.10+. 14063 * 14064 * @type object 14065 * @default {} 14066 * 14067 * @example 14068 * // Show previous, next and current page buttons only 14069 * $.fn.dataTableExt.oPagination.current = function ( page, pages ) { 14070 * return [ 'previous', page, 'next' ]; 14071 * }; 14072 */ 14073 pager: {}, 14074 14075 14076 renderer: { 14077 pageButton: {}, 14078 header: {} 14079 }, 14080 14081 14082 /** 14083 * Ordering plug-ins - custom data source 14084 * 14085 * The extension options for ordering of data available here is complimentary 14086 * to the default type based ordering that DataTables typically uses. It 14087 * allows much greater control over the the data that is being used to 14088 * order a column, but is necessarily therefore more complex. 14089 * 14090 * This type of ordering is useful if you want to do ordering based on data 14091 * live from the DOM (for example the contents of an 'input' element) rather 14092 * than just the static string that DataTables knows of. 14093 * 14094 * The way these plug-ins work is that you create an array of the values you 14095 * wish to be ordering for the column in question and then return that 14096 * array. The data in the array much be in the index order of the rows in 14097 * the table (not the currently ordering order!). Which order data gathering 14098 * function is run here depends on the `dt-init columns.orderDataType` 14099 * parameter that is used for the column (if any). 14100 * 14101 * The functions defined take two parameters: 14102 * 14103 * 1. `{object}` DataTables settings object: see 14104 * {@link DataTable.models.oSettings} 14105 * 2. `{int}` Target column index 14106 * 14107 * Each function is expected to return an array: 14108 * 14109 * * `{array}` Data for the column to be ordering upon 14110 * 14111 * @type array 14112 * 14113 * @example 14114 * // Ordering using `input` node values 14115 * $.fn.dataTable.ext.order['dom-text'] = function ( settings, col ) 14116 * { 14117 * return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) { 14118 * return $('input', td).val(); 14119 * } ); 14120 * } 14121 */ 14122 order: {}, 14123 14124 14125 /** 14126 * Type based plug-ins. 14127 * 14128 * Each column in DataTables has a type assigned to it, either by automatic 14129 * detection or by direct assignment using the `type` option for the column. 14130 * The type of a column will effect how it is ordering and search (plug-ins 14131 * can also make use of the column type if required). 14132 * 14133 * @namespace 14134 */ 14135 type: { 14136 /** 14137 * Type detection functions. 14138 * 14139 * The functions defined in this object are used to automatically detect 14140 * a column's type, making initialisation of DataTables super easy, even 14141 * when complex data is in the table. 14142 * 14143 * The functions defined take two parameters: 14144 * 14145 * 1. `{*}` Data from the column cell to be analysed 14146 * 2. `{settings}` DataTables settings object. This can be used to 14147 * perform context specific type detection - for example detection 14148 * based on language settings such as using a comma for a decimal 14149 * place. Generally speaking the options from the settings will not 14150 * be required 14151 * 14152 * Each function is expected to return: 14153 * 14154 * * `{string|null}` Data type detected, or null if unknown (and thus 14155 * pass it on to the other type detection functions. 14156 * 14157 * @type array 14158 * 14159 * @example 14160 * // Currency type detection plug-in: 14161 * $.fn.dataTable.ext.type.detect.push( 14162 * function ( data, settings ) { 14163 * // Check the numeric part 14164 * if ( !
14164$.isNumeric( data.substring(1) ) ) { 14165 * return null; 14166 * } 14167 * 14168 * // Check prefixed by currency 14169 * if ( data.charAt(0) == '$' || data.charAt(0) == '£' ) { 14170 * return 'currency'; 14171 * } 14172 * return null; 14173 * } 14174 * ); 14175 */ 14176 detect: [], 14177 14178 14179 /** 14180 * Type based search formatting. 14181 * 14182 * The type based searching functions can be used to pre-format the 14183 * data to be search on. For example, it can be used to strip HTML 14184 * tags or to de-format telephone numbers for numeric only searching. 14185 * 14186 * Note that is a search is not defined for a column of a given type, 14187 * no search formatting will be performed. 14188 * 14189 * Pre-processing of searching data plug-ins - When you assign the sType 14190 * for a column (or have it automatically detected for you by DataTables 14191 * or a type detection plug-in), you will typically be using this for 14192 * custom sorting, but it can also be used to provide custom searching 14193 * by allowing you to pre-processing the data and returning the data in 14194 * the format that should be searched upon. This is done by adding 14195 * functions this object with a parameter name which matches the sType 14196 * for that target column. This is the corollary of <i>afnSortData</i> 14197 * for searching data. 14198 * 14199 * The functions defined take a single parameter: 14200 * 14201 * 1. `{*}` Data from the column cell to be prepared for searching 14202 *
14203 * Each function is expected to return: 14204 * 14205 * * `{string|null}` Formatted string that will be used for the searching. 14206 * 14207 * @type object 14208 * @default {} 14209 * 14210 * @example 14211 * $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) { 14212 * return d.replace(/\n/g," ").replace( /<.*?>/g, "" ); 14213 * } 14214 */ 14215 search: {}, 14216 14217 14218 /** 14219 * Type based ordering. 14220 * 14221 * The column type tells DataTables what ordering to apply to the table 14222 * when a column is sorted upon. The order for each type that is defined, 14223 * is defined by the functions available in this object. 14224 * 14225 * Each ordering option can be described by three properties added to 14226 * this object: 14227 * 14228 * * `{type}-pre` - Pre-formatting function 14229 * * `{type}-asc` - Ascending order function 14230 * * `{type}-desc` - Descending order function 14231 * 14232 * All three can be used together, only `{type}-pre` or only 14233 * `{type}-asc` and `{type}-desc` together. It is generally recommended 14234 * that only `{type}-pre` is used, as this provides the optimal 14235 * implementation in terms of speed, although the others are provided 14236 * for compatibility with existing Javascript sort functions. 14237 * 14238 * `{type}-pre`: Functions defined take a single parameter: 14239 * 14240 * 1. `{*}` Data from the column cell to be prepared for ordering 14241 * 14242 * And return: 14243 * 14244 * * `{*}` Data to be sorted upon 14245 * 14246 * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort 14247 * functions, taking two parameters: 14248 * 14249 * 1. `{*}` Data to compare to the second parameter 14250 * 2. `{*}` Data to compare to the first parameter 14251 * 14252 * And returning: 14253 * 14254 * * `{*}` Ordering match: <0 if first parameter should be sorted lower 14255 * than the second parameter, ===0 if the two parameters are equal and 14256 * >0 if the first parameter should be sorted height than the second 14257 * parameter. 14258 * 14259 * @type object 14260 * @default {} 14261 * 14262 * @example 14263 * // Numeric ordering of formatted numbers with a pre-formatter 14264 * $.extend( $.fn.dataTable.ext.type.order, { 14265 * "string-pre": function(x) { 14266 * a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" ); 14267 * return parseFloat( a ); 14268 * } 14269 * } ); 14270 * 14271 * @example 14272 * // Case-sensitive string ordering, with no pre-formatting method 14273 * $.extend( $.fn.dataTable.ext.order, { 14274 * "string-case-asc": function(x,y) { 14275 * return ((x < y) ? -1 : ((x > y) ? 1 : 0)); 14276 * }, 14277 * "string-case-desc": function(x,y) { 14278 * return ((x < y) ? 1 : ((x > y) ? -1 : 0)); 14279 * } 14280 * } ); 14281 */ 14282 order: {} 14283 }, 14284 14285 /** 14286 * Unique DataTables instance counter 14287 * 14288 * @type int 14289 * @private 14290 */ 14291 _unique: 0, 14292 14293 14294 // 14295 // Depreciated 14296 // The following properties are retained for backwards compatiblity only. 14297 // The should not be used in new projects and will be removed in a future 14298 // version 14299 // 14300 14301 /** 14302 * Version check function. 14303 * @type function 14304 * @depreciated Since 1.10 14305 */ 14306 fnVersionCheck: DataTable.fnVersionCheck, 14307 14308 14309 /** 14310 * Index for what 'this' index API functions should use 14311 * @type int 14312 * @deprecated Since v1.10 14313 */ 14314 iApiIndex: 0, 14315 14316 14317 /** 14318 * jQuery UI class container 14319 * @type object 14320 * @deprecated Since v1.10 14321 */ 14322 oJUIClasses: {}, 14323 14324 14325 /** 14326 * Software version 14327 * @type string 14328 * @deprecated Since v1.10 14329 */ 14330 sVersion: DataTable.version 14331 }; 14332 14333 14334 // 14335 // Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts 14336 // 14337 $.extend( _ext, { 14338 afnFiltering: _ext.search, 14339 aTypes: _ext.type.detect, 14340 ofnSearch: _ext.type.search, 14341 oSort: _ext.type.order, 14342 afnSortData: _ext.order, 14343 aoFeatures: _ext.feature, 14344 oApi: _ext.internal, 14345 oStdClasses: _ext.classes, 14346 oPagination: _ext.pager 14347 } ); 14348 14349 14350 $.extend( DataTable.ext.classes, { 14351 "sTable": "dataTable", 14352 "sNoFooter": "no-footer", 14353 14354 /* Paging buttons */ 14355 "sPageButton": "paginate_button", 14356 "sPageButtonActive": "current", 14357 "sPageButtonDisabled": "disabled", 14358 14359 /* Striping classes */ 14360 "sStripeOdd": "odd", 14361 "sStripeEven": "even", 14362 14363 /* Empty row */ 14364 "sRowEmpty": "dataTables_empty", 14365 14366 /* Features */ 14367 "sWrapper": "dataTables_wrapper", 14368 "sFilter": "dataTables_filter", 14369 "sInfo": "dataTables_info", 14370 "sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */ 14371 "sLength": "dataTables_length", 14372 "sProcessing": "dataTables_processing", 14373 14374 /* Sorting */ 14375 "sSortAsc": "sorting_asc", 14376 "sSortDesc": "sorting_desc", 14377 "sSortable": "sorting", /* Sortable in both directions */ 14378 "sSortableAsc": "sorting_asc_disabled", 14379 "sSortableDesc": "sorting_desc_disabled", 14380 "sSortableNone": "sorting_disabled", 14381 "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */ 14382 14383 /* Filtering */ 14384 "sFilterInput": "", 14385 14386 /* Page length */ 14387 "sLengthSelect": "", 14388 14389 /* Scrolling */ 14390 "sScrollWrapper": "dataTables_scroll", 14391 "sScrollHead": "dataTables_scrollHead", 14392 "sScrollHeadInner": "dataTables_scrollHeadInner", 14393 "sScrollBody": "dataTables_scrollBody", 14394 "sScrollFoot": "dataTables_scrollFoot", 14395 "sScrollFootInner": "dataTables_scrollFootInner", 14396 14397 /* Misc */ 14398 "sHeaderTH": "", 14399 "sFooterTH": "", 14400 14401 // Deprecated 14402 "sSortJUIAsc": "", 14403 "sSortJUIDesc": "", 14404 "sSortJUI": "", 14405 "sSortJUIAscAllowed": "", 14406 "sSortJUIDescAllowed": "", 14407 "sSortJUIWrapper": "", 14408 "sSortIcon": "", 14409 "sJUIHeader": "", 14410 "sJUIFooter": "" 14411 } ); 14412 14413 14414 var extPagination = DataTable.ext.pager; 14415 14416 function _numbers ( page, pages ) { 14417 var 14418 numbers = [], 14419 buttons = extPagination.numbers_length, 14420 half = Math.floor( buttons / 2 ), 14421 i = 1; 14422 14423 if ( pages <= buttons ) { 14424 numbers = _range( 0, pages ); 14425 } 14426 else if ( page <= half ) { 14427 numbers = _range( 0, buttons-2 ); 14428 numbers.push( 'ellipsis' ); 14429 numbers.push( pages-1 ); 14430 } 14431 else if ( page >= pages - 1 - half ) { 14432 numbers = _range( pages-(buttons-2), pages ); 14433 numbers.splice( 0, 0, 'ellipsis' );
14433 // no unshift in ie6 14434 numbers.splice( 0, 0, 0 ); 14435 } 14436 else { 14437 numbers = _range( page-half+2, page+half-1 ); 14438 numbers.push( 'ellipsis' ); 14439 numbers.push( pages-1 ); 14440 numbers.splice( 0, 0, 'ellipsis' ); 14441 numbers.splice( 0, 0, 0 ); 14442 } 14443 14444 numbers.DT_el = 'span'; 14445 return numbers; 14446 } 14447 14448 14449 $.extend( extPagination, { 14450 simple: function ( page, pages ) { 14451 return [ 'previous', 'next' ]; 14452 }, 14453 14454 full: function ( page, pages ) { 14455 return [ 'first', 'previous', 'next', 'last' ]; 14456 }, 14457 14458 numbers: function ( page, pages ) { 14459 return [ _numbers(page, pages) ]; 14460 }, 14461 14462 simple_numbers: function ( page, pages ) { 14463 return [ 'previous', _numbers(page, pages), 'next' ]; 14464 }, 14465 14466 full_numbers: function ( page, pages ) { 14467 return [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ]; 14468 }, 14469 14470 first_last_numbers: function (page, pages) { 14471 return ['first', _numbers(page, pages), 'last']; 14472 }, 14473 14474 // For testing and plug-ins to use 14475 _numbers: _numbers, 14476 14477 // Number of number buttons (including ellipsis) to show. _Must be odd!_ 14478 numbers_length: 7 14479 } ); 14480 14481 14482 $.extend( true, DataTable.ext.renderer, { 14483 pageButton: { 14484 _: function ( settings, host, idx, buttons, page, pages ) { 14485 var classes = settings.oClasses; 14486 var lang = settings.oLanguage.oPaginate; 14487 var aria = settings.oLanguage.oAria.paginate || {}; 14488 var btnDisplay, btnClass, counter=0; 14489 14490 var attach = function( container, buttons ) { 14491 var i, ien, node, button; 14492 var clickHandler = function ( e ) { 14493 _fnPageChange( settings, e.data.action, true ); 14494 }; 14495 14496 for ( i=0, ien=buttons.length ; i<ien ; i++ ) { 14497 button = buttons[i]; 14498 14499 if ( $.isArray( button ) ) { 14500 var inner = $( '<'+(button.DT_el || 'div')+'/>' ) 14501 .appendTo( container ); 14502 attach( inner, button ); 14503 } 14504 else { 14505 btnDisplay = null; 14506 btnClass = ''; 14507 14508 switch ( button ) { 14509 case 'ellipsis': 14510 container.append('<span class="ellipsis">…</span>'); 14511 break; 14512 14513 case 'first': 14514 btnDisplay = lang.sFirst; 14515 btnClass = button + (page > 0 ? 14516 '' : ' '+classes.sPageButtonDisabled); 14517 break; 14518 14519 case 'previous': 14520 btnDisplay = lang.sPrevious; 14521 btnClass = button + (page > 0 ? 14522 '' : ' '+classes.sPageButtonDisabled); 14523 break; 14524 14525 case 'next': 14526 btnDisplay = lang.sNext; 14527 btnClass = button + (page < pages-1 ? 14528 '' : ' '+classes.sPageButtonDisabled); 14529 break; 14530 14531 case 'last': 14532 btnDisplay = lang.sLast; 14533 btnClass = button + (page < pages-1 ? 14534 '' : ' '+classes.sPageButtonDisabled); 14535 break; 14536 14537 default: 14538 btnDisplay = button + 1; 14539 btnClass = page === button ? 14540 classes.sPageButtonActive : ''; 14541 break; 14542 } 14543 14544 if ( btnDisplay !== null ) { 14545 node = $('<a>', { 14546 'class': classes.sPageButton+' '+btnClass, 14547 'aria-controls': settings.sTableId, 14548 'aria-label': aria[ button ], 14549 'data-dt-idx': counter, 14550 'tabindex': settings.iTabIndex, 14551 'id': idx === 0 && typeof button === 'string' ? 14552 settings.sTableId +'_'+ button : 14553 null 14554 } ) 14555 .html( btnDisplay ) 14556 .appendTo( container ); 14557 14558 _fnBindAction( 14559 node, {action: button}, clickHandler 14560 ); 14561 14562 counter++; 14563 } 14564 } 14565 } 14566 }; 14567 14568 // IE9 throws an 'unknown error' if document.activeElement is used 14569 // inside an iframe or frame. Try / catch the error. Not good for 14570 // accessibility, but neither are frames. 14571 var activeEl; 14572 14573 try { 14574 // Because this approach is destroying and recreating the paging 14575 // elements, focus is lost on the select button which is bad for 14576 // accessibility. So we want to restore focus once the draw has 14577 // completed 14578 activeEl = $(host).find(document.activeElement).data('dt-idx'); 14579 } 14580 catch (e) {} 14581 14582 attach( $(host).empty(), buttons ); 14583 14584 if ( activeEl !== undefined ) { 14585 $(host).find( '[data-dt-idx='+activeEl+']' ).focus(); 14586 } 14587 } 14588 } 14589 } ); 14590 14591 14592 14593 // Built in type detection. See model.ext.aTypes for information about 14594 // what is required from this methods. 14595 $.extend( DataTable.ext.type.detect, [
vendor: 18,159 bytes, lines 14596-15190
14596 // Plain numbers - first since V8 detects some plain numbers as dates 14597 // e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...). 14598 function ( d, settings ) 14599 { 14600 var decimal = settings.oLanguage.sDecimal; 14601 return _isNumber( d, decimal ) ? 'num'+decimal : null; 14602 }, 14603 14604 // Dates (only those recognised by the browser's Date.parse) 14605 function ( d, settings ) 14606 { 14607 // V8 tries _very_ hard to make a string passed into `Date.parse()` 14608 // valid, so we need to use a regex to restrict date formats. Use a 14609 // plug-in for anything other than ISO8601 style strings 14610 if ( d && !(d instanceof Date) && ! _re_date.test(d) ) { 14611 return null; 14612 } 14613 var parsed = Date.parse(d); 14614 return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null; 14615 }, 14616 14617 // Formatted numbers 14618 function ( d, settings ) 14619 { 14620 var decimal = settings.oLanguage.sDecimal; 14621 return _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null; 14622 }, 14623 14624 // HTML numeric 14625 function ( d, settings ) 14626 { 14627 var decimal = settings.oLanguage.sDecimal; 14628 return _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null; 14629 }, 14630 14631 // HTML numeric, formatted 14632 function ( d, settings ) 14633 { 14634 var decimal = settings.oLanguage.sDecimal; 14635 return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null; 14636 }, 14637 14638 // HTML (this is strict checking - there must be html) 14639 function ( d, settings ) 14640 { 14641 return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ? 14642 'html' : null; 14643 } 14644 ] ); 14645 14646 14647 14648 // Filter formatting functions. See model.ext.ofnSearch for information about 14649 // what is required from these methods. 14650 // 14651 // Note that additional search methods are added for the html numbers and 14652 // html formatted numbers by `_addNumericSort()` when we know what the decimal 14653 // place is 14654 14655 14656 $.extend( DataTable.ext.type.search, { 14657 html: function ( data ) { 14658 return _empty(data) ? 14659 data : 14660 typeof data === 'string' ? 14661 data 14662 .replace( _re_new_lines, " " ) 14663 .replace( _re_html, "" ) : 14664 ''; 14665 }, 14666 14667 string: function ( data ) { 14668 return _empty(data) ? 14669 data : 14670 typeof data === 'string' ? 14671 data.replace( _re_new_lines, " " ) : 14672 data; 14673 } 14674 } ); 14675 14676 14677 14678 var __numericReplace = function ( d, decimalPlace, re1, re2 ) { 14679 if ( d !== 0 && (!d || d === '-') ) { 14680 return -Infinity; 14681 } 14682 14683 // If a decimal place other than `.` is used, it needs to be given to the 14684 // function so we can detect it and replace with a `.` which is the only 14685 // decimal place Javascript recognises - it is not locale aware. 14686 if ( decimalPlace ) { 14687 d = _numToDecimal( d, decimalPlace ); 14688 } 14689 14690 if ( d.replace ) { 14691 if ( re1 ) { 14692 d = d.replace( re1, '' ); 14693 } 14694 14695 if ( re2 ) { 14696 d = d.replace( re2, '' ); 14697 } 14698 } 14699 14700 return d * 1; 14701 }; 14702 14703 14704 // Add the numeric 'deformatting' functions for sorting and search. This is done 14705 // in a function to provide an easy ability for the language options to add 14706 // additional methods if a non-period decimal place is used. 14707 function _addNumericSort ( decimalPlace ) { 14708 $.each( 14709 { 14710 // Plain numbers 14711 "num": function ( d ) { 14712 return __numericReplace( d, decimalPlace ); 14713 }, 14714 14715 // Formatted numbers 14716 "num-fmt": function ( d ) { 14717 return __numericReplace( d, decimalPlace, _re_formatted_numeric ); 14718 }, 14719 14720 // HTML numeric 14721 "html-num": function ( d ) { 14722 return __numericReplace( d, decimalPlace, _re_html ); 14723 }, 14724 14725 // HTML numeric, formatted 14726 "html-num-fmt": function ( d ) { 14727 return __numericReplace( d, decimalPlace, _re_html, _re_formatted_numeric ); 14728 } 14729 }, 14730 function ( key, fn ) { 14731 // Add the ordering method 14732 _ext.type.order[ key+decimalPlace+'-pre' ] = fn; 14733 14734 // For HTML types add a search formatter that will strip the HTML 14735 if ( key.match(/^html\-/) ) { 14736 _ext.type.search[ key+decimalPlace ] = _ext.type.search.html; 14737 } 14738 } 14739 ); 14740 } 14741 14742 14743 // Default sort methods 14744 $.extend( _ext.type.order, { 14745 // Dates 14746 "date-pre": function ( d ) { 14747 return Date.parse( d ) || -Infinity; 14748 }, 14749 14750 // html 14751 "html-pre": function ( a ) { 14752 return _empty(a) ? 14753 '' : 14754 a.replace ? 14755 a.replace( /<.*?>/g, "" ).toLowerCase() : 14756 a+''; 14757 }, 14758 14759 // string 14760 "string-pre": function ( a ) { 14761 // This is a little complex, but faster than always calling toString, 14762 // http://jsperf.com/tostring-v-check 14763 return _empty(a) ? 14764 '' : 14765 typeof a === 'string' ? 14766 a.toLowerCase() : 14767 ! a.toString ? 14768 '' : 14769 a.toString(); 14770 }, 14771 14772 // string-asc and -desc are retained only for compatibility with the old 14773 // sort methods 14774 "string-asc": function ( x, y ) { 14775 return ((x < y) ? -1 : ((x > y) ? 1 : 0)); 14776 }, 14777 14778 "string-desc": function ( x, y ) { 14779 return ((x < y) ? 1 : ((x > y) ? -1 : 0)); 14780 } 14781 } ); 14782 14783 14784 // Numeric sorting types - order doesn't matter here 14785 _addNumericSort( '' ); 14786 14787 14788 $.extend( true, DataTable.ext.renderer, { 14789 header: { 14790 _: function ( settings, cell, column, classes ) { 14791 // No additional mark-up required 14792 // Attach a sort listener to update on sort - note that using the 14793 // `DT` namespace will allow the event to be removed automatically 14794 // on destroy, while the `dt` namespaced event is the one we are 14795 // listening for 14796 $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) { 14797 if ( settings !== ctx ) { // need to check this this is the host 14798 return; // table, not a nested one 14799 } 14800 14801 var colIdx = column.idx; 14802 14803 cell 14804 .removeClass( 14805 column.sSortingClass +' '+ 14806 classes.sSortAsc +' '+ 14807 classes.sSortDesc 14808 ) 14809 .addClass( columns[ colIdx ] == 'asc' ? 14810 classes.sSortAsc : columns[ colIdx ] == 'desc' ? 14811 classes.sSortDesc : 14812 column.sSortingClass 14813 ); 14814 } ); 14815 }, 14816 14817 jqueryui: function ( settings, cell, column, classes ) { 14818 $('<div/>') 14819 .addClass( classes.sSortJUIWrapper ) 14820 .append( cell.contents() ) 14821 .append( $('<span/>') 14822 .addClass( classes.sSortIcon+' '+column.sSortingClassJUI ) 14823 ) 14824 .appendTo( cell ); 14825 14826 // Attach a sort listener to update on sort 14827 $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) { 14828 if ( settings !== ctx ) { 14829 return; 14830 } 14831 14832 var colIdx = column.idx; 14833 14834 cell 14835 .removeClass( classes.sSortAsc +" "+classes.sSortDesc ) 14836 .addClass( columns[ colIdx ] == 'asc' ? 14837 classes.sSortAsc : columns[ colIdx ] == 'desc' ? 14838 classes.sSortDesc : 14839 column.sSortingClass 14840 ); 14841 14842 cell 14843 .find( 'span.'+classes.sSortIcon ) 14844 .removeClass( 14845 classes.sSortJUIAsc +" "+ 14846 classes.sSortJUIDesc +" "+ 14847 classes.sSortJUI +" "+ 14848 classes.sSortJUIAscAllowed +" "+ 14849 classes.sSortJUIDescAllowed 14850 ) 14851 .addClass( columns[ colIdx ] == 'asc' ? 14852 classes.sSortJUIAsc : columns[ colIdx ] == 'desc' ? 14853 classes.sSortJUIDesc : 14854 column.sSortingClassJUI 14855 ); 14856 } ); 14857 } 14858 } 14859 } ); 14860 14861 /* 14862 * Public helper functions. These aren't used internally by DataTables, or 14863 * called by any of the options passed into DataTables, but they can be used 14864 * externally by developers working with DataTables. They are helper functions 14865 * to make working with DataTables a little bit easier. 14866 */ 14867 14868 var __htmlEscapeEntities = function ( d ) { 14869 return typeof d === 'string' ? 14870 d.replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"') : 14871 d; 14872 }; 14873 14874 /** 14875 * Helpers for `columns.render`. 14876 * 14877 * The options defined here can be used with the `columns.render` initialisation 14878 * option to provide a display renderer. The following functions are defined: 14879 * 14880 * * `number` - Will format numeric data (defined by `columns.data`) for 14881 * display, retaining the original unformatted data for sorting and filtering. 14882 * It takes 5 parameters: 14883 * * `string` - Thousands grouping separator 14884 * * `string` - Decimal point indicator 14885 * * `integer` - Number of decimal points to show 14886 * * `string` (optional) - Prefix. 14887 * * `string` (optional) - Postfix (/suffix). 14888 * * `text` - Escape HTML to help prevent XSS attacks. It has no optional 14889 * parameters. 14890 * 14891 * @example 14892 * // Column definition using the number renderer 14893 * { 14894 * data: "salary", 14895 * render: $.fn.dataTable.render.number( '\'', '.', 0, '$' ) 14896 * } 14897 * 14898 * @namespace 14899 */ 14900 DataTable.render = { 14901 number: function ( thousands, decimal, precision, prefix, postfix ) { 14902 return { 14903 display: function ( d ) { 14904 if ( typeof d !== 'number' && typeof d !== 'string' ) { 14905 return d; 14906 } 14907 14908 var negative = d < 0 ? '-' : ''; 14909 var flo = parseFloat( d ); 14910 14911 // If NaN then there isn't much formatting that we can do - just 14912 // return immediately, escaping any HTML (this was supposed to 14913 // be a number after all) 14914 if ( isNaN( flo ) ) { 14915 return __htmlEscapeEntities( d ); 14916 } 14917 14918 flo = flo.toFixed( precision ); 14919 d = Math.abs( flo ); 14920 14921 var intPart = parseInt( d, 10 ); 14922 var floatPart = precision ? 14923 decimal+(d - intPart).toFixed( precision ).substring( 2 ): 14924 ''; 14925 14926 return negative + (prefix||'') + 14927 intPart.toString().replace( 14928 /\B(?=(\d{3})+(?!\d))/g, thousands 14929 ) + 14930 floatPart + 14931 (postfix||''); 14932 } 14933 }; 14934 }, 14935 14936 text: function () { 14937 return { 14938 display: __htmlEscapeEntities 14939 }; 14940 } 14941 }; 14942 14943 14944 /* 14945 * This is really a good bit rubbish this method of exposing the internal methods 14946 * publicly... - To be fixed in 2.0 using methods on the prototype 14947 */ 14948 14949 14950 /** 14951 * Create a wrapper function for exporting an internal functions to an external API. 14952 * @param {string} fn API function name 14953 * @returns {function} wrapped function 14954 * @memberof DataTable#internal 14955 */ 14956 function _fnExternApiFunc (fn) 14957 { 14958 return function() { 14959 var args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat( 14960 Array.prototype.slice.call(arguments) 14961 ); 14962 return DataTable.ext.internal[fn].apply( this, args ); 14963 }; 14964 } 14965 14966 14967 /** 14968 * Reference to internal functions for use by plug-in developers. Note that 14969 * these methods are references to internal functions and are considered to be 14970 * private. If you use these methods, be aware that they are liable to change 14971 * between versions. 14972 * @namespace 14973 */ 14974 $.extend( DataTable.ext.internal, { 14975 _fnExternApiFunc: _fnExternApiFunc, 14976 _fnBuildAjax: _fnBuildAjax, 14977 _fnAjaxUpdate: _fnAjaxUpdate, 14978 _fnAjaxParameters: _fnAjaxParameters, 14979 _fnAjaxUpdateDraw: _fnAjaxUpdateDraw, 14980 _fnAjaxDataSrc: _fnAjaxDataSrc, 14981 _fnAddColumn: _fnAddColumn, 14982 _fnColumnOptions: _fnColumnOptions, 14983 _fnAdjustColumnSizing: _fnAdjustColumnSizing, 14984 _fnVisibleToColumnIndex: _fnVisibleToColumnIndex, 14985 _fnColumnIndexToVisible: _fnColumnIndexToVisible, 14986 _fnVisbleColumns: _fnVisbleColumns, 14987 _fnGetColumns: _fnGetColumns, 14988 _fnColumnTypes: _fnColumnTypes, 14989 _fnApplyColumnDefs: _fnApplyColumnDefs, 14990 _fnHungarianMap: _fnHungarianMap, 14991 _fnCamelToHungarian: _fnCamelToHungarian, 14992 _fnLanguageCompat: _fnLanguageCompat, 14993 _fnBrowserDetect: _fnBrowserDetect, 14994 _fnAddData: _fnAddData, 14995 _fnAddTr: _fnAddTr, 14996 _fnNodeToDataIndex: _fnNodeToDataIndex, 14997 _fnNodeToColumnIndex: _fnNodeToColumnIndex, 14998 _fnGetCellData: _fnGetCellData, 14999 _fnSetCellData: _fnSetCellData, 15000 _fnSplitObjNotation: _fnSplitObjNotation, 15001 _fnGetObjectDataFn: _fnGetObjectDataFn, 15002 _fnSetObjectDataFn: _fnSetObjectDataFn, 15003 _fnGetDataMaster: _fnGetDataMaster, 15004 _fnClearTable: _fnClearTable, 15005 _fnDeleteIndex: _fnDeleteIndex, 15006 _fnInvalidate: _fnInvalidate, 15007 _fnGetRowElements: _fnGetRowElements, 15008 _fnCreateTr: _fnCreateTr, 15009 _fnBuildHead: _fnBuildHead, 15010 _fnDrawHead: _fnDrawHead, 15011 _fnDraw: _fnDraw, 15012 _fnReDraw: _fnReDraw, 15013 _fnAddOptionsHtml: _fnAddOptionsHtml, 15014 _fnDetectHeader: _fnDetectHeader, 15015 _fnGetUniqueThs: _fnGetUniqueThs, 15016 _fnFeatureHtmlFilter: _fnFeatureHtmlFilter, 15017 _fnFilterComplete: _fnFilterComplete, 15018 _fnFilterCustom: _fnFilterCustom, 15019 _fnFilterColumn: _fnFilterColumn, 15020 _fnFilter: _fnFilter, 15021 _fnFilterCreateSearch: _fnFilterCreateSearch, 15022 _fnEscapeRegex: _fnEscapeRegex, 15023 _fnFilterData: _fnFilterData, 15024 _fnFeatureHtmlInfo: _fnFeatureHtmlInfo, 15025 _fnUpdateInfo: _fnUpdateInfo, 15026 _fnInfoMacros: _fnInfoMacros, 15027 _fnInitialise: _fnInitialise, 15028 _fnInitComplete: _fnInitComplete, 15029 _fnLengthChange: _fnLengthChange, 15030 _fnFeatureHtmlLength: _fnFeatureHtmlLength, 15031 _fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate, 15032 _fnPageChange: _fnPageChange, 15033 _fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing, 15034 _fnProcessingDisplay: _fnProcessingDisplay, 15035 _fnFeatureHtmlTable: _fnFeatureHtmlTable, 15036 _fnScrollDraw: _fnScrollDraw, 15037 _fnApplyToChildren: _fnApplyToChildren, 15038 _fnCalculateColumnWidths: _fnCalculateColumnWidths, 15039 _fnThrottle: _fnThrottle, 15040 _fnConvertToWidth: _fnConvertToWidth, 15041 _fnGetWidestNode: _fnGetWidestNode, 15042 _fnGetMaxLenString: _fnGetMaxLenString, 15043 _fnStringToCss: _fnStringToCss, 15044 _fnSortFlatten: _fnSortFlatten, 15045 _fnSort: _fnSort, 15046 _fnSortAria: _fnSortAria, 15047 _fnSortListener: _fnSortListener, 15048 _fnSortAttachListener: _fnSortAttachListener, 15049 _fnSortingClasses: _fnSortingClasses, 15050 _fnSortData: _fnSortData, 15051 _fnSaveState: _fnSaveState, 15052 _fnLoadState: _fnLoadState, 15053 _fnSettingsFromNode: _fnSettingsFromNode, 15054 _fnLog: _fnLog, 15055 _fnMap: _fnMap, 15056 _fnBindAction: _fnBindAction, 15057 _fnCallbackReg: _fnCallbackReg, 15058 _fnCallbackFire: _fnCallbackFire, 15059 _fnLengthOverflow: _fnLengthOverflow, 15060 _fnRenderer: _fnRenderer, 15061 _fnDataSource: _fnDataSource, 15062 _fnRowAttributes: _fnRowAttributes, 15063 _fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant 15064 // in 1.10, so this dead-end function is 15065 // added to prevent errors 15066 } ); 15067 15068 15069 // jQuery access 15070 $.fn.dataTable = DataTable; 15071 15072 // Provide access to the host jQuery object (circular reference) 15073 DataTable.$ = $; 15074 15075 // Legacy aliases 15076 $.fn.dataTableSettings = DataTable.settings; 15077 $.fn.dataTableExt = DataTable.ext; 15078 15079 // With a capital `D` we return a DataTables API instance rather than a 15080 // jQuery object 15081 $.fn.DataTable = function ( opts ) { 15082 return $(this).dataTable( opts ).api(); 15083 }; 15084 15085 // All properties that are available to $.fn.dataTable should also be 15086 // available on $.fn.DataTable 15087 $.each( DataTable, function ( prop, val ) { 15088 $.fn.DataTable[ prop ] = val; 15089 } ); 15090 15091 15092 // Information about events fired by DataTables - for documentation. 15093 /** 15094 * Draw event, fired whenever the table is redrawn on the page, at the same 15095 * point as fnDrawCallback. This may be useful for binding events or 15096 * performing calculations when the table is altered at all. 15097 * @name DataTable#draw.dt 15098 * @event 15099 * @param {event} e jQuery event object 15100 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 15101 */ 15102 15103 /** 15104 * Search event, fired when the searching applied to the table (using the 15105 * built-in global search, or column filters) is altered. 15106 * @name DataTable#search.dt 15107 * @event 15108 * @param {event} e jQuery event object 15109 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 15110 */ 15111 15112 /** 15113 * Page change event, fired when the paging of the table is altered. 15114 * @name DataTable#page.dt 15115 * @event 15116 * @param {event} e jQuery event object 15117 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 15118 */ 15119 15120 /** 15121 * Order event, fired when the ordering applied to the table is altered. 15122 * @name DataTable#order.dt 15123 * @event 15124 * @param {event} e jQuery event object 15125 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 15126 */ 15127 15128 /** 15129 * DataTables initialisation complete event, fired when the table is fully 15130 * drawn, including Ajax data loaded, if Ajax data is required. 15131 * @name DataTable#init.dt 15132 * @event 15133 * @param {event} e jQuery event object 15134 * @param {object} oSettings DataTables settings object 15135 * @param {object} json The JSON object request from the server - only 15136 * present if client-side Ajax sourced data is used</li></ol> 15137 */ 15138 15139 /** 15140 * State save event, fired when the table has changed state a new state save 15141 * is required. This event allows modification of the state saving object 15142 * prior to actually doing the save, including addition or other state 15143 * properties (for plug-ins) or modification of a DataTables core property. 15144 * @name DataTable#stateSaveParams.dt 15145 * @event 15146 * @param {event} e jQuery event object 15147 * @param {object} oSettings DataTables settings object 15148 * @param {object} json The state information to be saved 15149 */ 15150 15151 /** 15152 * State load event, fired when the table is loading state from the stored 15153 * data, but prior to the settings object being modified by the saved state 15154 * - allowing modification of the saved state is required or loading of 15155 * state for a plug-in. 15156 * @name DataTable#stateLoadParams.dt 15157 * @event 15158 * @param {event} e jQuery event object 15159 * @param {object} oSettings DataTables settings object 15160 * @param {object} json The saved state information 15161 */ 15162 15163 /** 15164 * State loaded event, fired when state has been loaded from stored data and 15165 * the settings object has been modified by the loaded data. 15166 * @name DataTable#stateLoaded.dt 15167 * @event 15168 * @param {event} e jQuery event object 15169 * @param {object} oSettings DataTables settings object 15170 * @param {object} json The saved state information 15171 */ 15172 15173 /** 15174 * Processing event, fired when DataTables is doing some kind of processing 15175 * (be it, order, searcg or anything else). It can be used to indicate to 15176 * the end user that there is something happening, or that something has 15177 * finished. 15178 * @name DataTable#processing.dt 15179 * @event 15180 * @param {event} e jQuery event object 15181 * @param {object} oSettings DataTables settings object 15182 * @param {boolean} bShow Flag for if DataTables is doing processing or not 15183 */ 15184 15185 /** 15186 * Ajax (XHR) event, fired whenever an Ajax request is completed from a 15187 * request to made to the server for new data. This event is called before 15188 * DataTables processed the returned data, so it can also be used to pre- 15189 * process the data returned from the server, if needed. 15190 *
15191 * Note that this trigger is called in `fnServerData`, if you override 15192 * `fnServerData` and which to use this event, you need to trigger it in you 15193 * success function. 15194 * @name DataTable#xhr.dt 15195 * @event 15196 * @param {event} e jQuery event object 15197 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 15198 * @param {object} json JSON returned from the server 15199 * 15200 * @example 15201 * // Use a custom property returned from the server in another DOM element 15202 * $('#table').dataTable().on('xhr.dt', function (e, settings, json) { 15203 * $('#status').html( json.status ); 15204 * } ); 15205 * 15206 * @example 15207 * // Pre-process the data returned from the server 15208 * $('#table').dataTable().on('xhr.dt', function (e, settings, json) { 15209 * for ( var i=0, ien=json.aaData.length ; i<ien ; i++ ) { 15210 * json.aaData[i].sum = json.aaData[i].one + json.aaData[i].two; 15211 * } 15212 * // Note no return - manipulate the data directly in the JSON object. 15213 * } ); 15214 */ 15215 15216 /** 15217 * Destroy event, fired when the DataTable is destroyed by calling fnDestroy 15218 * or passing the bDestroy:true parameter in the initialisation object. This 15219 * can be used to remove bound events, added DOM nodes, etc. 15220 * @name DataTable#destroy.dt 15221 * @event 15222 * @param {event} e jQuery event object 15223 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 15224 */ 15225 15226 /** 15227 * Page length change event, fired when number of records to show on each 15228 * page (the length) is changed. 15229 * @name DataTable#length.dt 15230 * @event 15231 * @param {event} e jQuery event object 15232 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 15233 * @param {integer} len New length 15234 */ 15235 15236 /** 15237 * Column sizing has changed. 15238 * @name DataTable#column-sizing.dt 15239 * @event 15240 * @param {event} e jQuery event object 15241 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 15242 */ 15243 15244 /** 15245 * Column visibility has changed. 15246 * @name DataTable#column-visibility.dt 15247 * @event 15248 * @param {event} e jQuery event object 15249 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 15250 * @param {int} column Column index 15251 * @param {bool} vis `false` if column now hidden, or `true` if visible 15252 */ 15253 15254 return $.fn.dataTable; 15255})); 15256 15257 15258/*! DataTables Bootstrap 3 integration 15259 * ©2011-2015 SpryMedia Ltd - datatables.net/license 15260 */ 15261 15262/** 15263 * DataTables integration for Bootstrap 3. This requires Bootstrap 3 and 15264 * DataTables 1.10 or newer. 15265 * 15266 * This file sets the defaults and adds options to DataTables to style its 15267 * controls using Bootstrap. See http://datatables.net/manual/styling/bootstrap 15268 * for further information. 15269 */ 15270(function( factory ){ 15271 if ( typeof define === 'function' && define.amd ) { 15272 // AMD 15273 define( ['jquery', 'datatables.net'], function ( $ ) { 15274 return factory( $, window, document ); 15275 } ); 15276 } 15277 else if ( typeof exports === 'object' ) { 15278 // CommonJS 15279 module.exports = function (root, $) { 15280 if ( ! root ) { 15281 root = window; 15282 } 15283 15284 if ( ! $ || ! $.fn.dataTable ) { 15285 // Require DataTables, which attaches to jQuery, including 15286 // jQuery if needed and have a $ property so we can access the 15287 // jQuery object that is used 15288 $ = require('datatables.net')(root, $).$; 15289 } 15290 15291 return factory( $, root, root.document ); 15292 }; 15293 } 15294 else { 15295 // Browser 15296 factory( jQuery, window, document ); 15297 } 15298}(function( $, window, document, undefined ) { 15299'use strict'; 15300var DataTable = $.fn.dataTable; 15301 15302 15303/* Set the defaults for DataTables initialisation */ 15304$.extend( true, DataTable.defaults, { 15305 dom: 15306 "<'row'<'col-sm-6'l><'col-sm-6'f>>" + 15307 "<'row'<'col-sm-12'tr>>" + 15308 "<'row'<'col-sm-5'i><'col-sm-7'p>>", 15309 renderer: 'bootstrap' 15310} ); 15311 15312 15313/* Default class modification */ 15314$.extend( DataTable.ext.classes, { 15315 sWrapper: "dataTables_wrapper form-inline dt-bootstrap", 15316 sFilterInput: "form-control input-sm", 15317 sLengthSelect: "form-control input-sm", 15318 sProcessing: "dataTables_processing panel panel-default" 15319} ); 15320 15321 15322/* Bootstrap paging button renderer */ 15323DataTable.ext.renderer.pageButton.bootstrap = function ( settings, host, idx, buttons, page, pages ) { 15324 var api = new DataTable.Api( settings ); 15325 var classes = settings.oClasses; 15326 var lang = settings.oLanguage.oPaginate; 15327 var aria = settings.oLanguage.oAria.paginate || {}; 15328 var btnDisplay, btnClass, counter=0; 15329 15330 var attach = function( container, buttons ) { 15331 var i, ien, node, button; 15332 var clickHandler = function ( e ) { 15333 e.preventDefault(); 15334 if ( !$(e.currentTarget).hasClass('disabled') && api.page() != e.data.action ) { 15335 api.page( e.data.action ).draw( 'page' ); 15336 } 15337 }; 15338 15339 for ( i=0, ien=buttons.length ; i<ien ; i++ ) { 15340 button = buttons[i]; 15341 15342 if ( $.isArray( button ) ) { 15343 attach( container, button ); 15344 } 15345 else { 15346 btnDisplay = ''; 15347 btnClass = ''; 15348 15349 switch ( button ) { 15350 case 'ellipsis': 15351 btnDisplay = '…'; 15352 btnClass = 'disabled'; 15353 break; 15354 15355 case 'first': 15356 btnDisplay = lang.sFirst; 15357 btnClass = button + (page > 0 ? 15358 '' : ' disabled'); 15359 break; 15360 15361 case 'previous': 15362 btnDisplay = lang.sPrevious; 15363 btnClass = button + (page > 0 ? 15364 '' : ' disabled'); 15365 break; 15366 15367 case 'next': 15368 btnDisplay = lang.sNext; 15369 btnClass = button + (page < pages-1 ? 15370 '' : ' disabled'); 15371 break; 15372 15373 case 'last': 15374 btnDisplay = lang.sLast; 15375 btnClass = button + (page < pages-1 ? 15376 '' : ' disabled'); 15377 break; 15378 15379 default: 15380 btnDisplay = button + 1; 15381 btnClass = page === button ? 15382 'active' : ''; 15383 break; 15384 } 15385 15386 if ( btnDisplay ) { 15387 node = $('<li>', { 15388 'class': classes.sPageButton+' '+btnClass, 15389 'id': idx === 0 && typeof button === 'string' ? 15390 settings.sTableId +'_'+ button : 15391 null 15392 } ) 15393 .append( $('<a>', { 15394 'href': '#', 15395 'aria-controls': settings.sTableId, 15396 'aria-label': aria[ button ], 15397 'data-dt-idx': counter, 15398 'tabindex': settings.iTabIndex 15399 } ) 15400 .html( btnDisplay ) 15401 ) 15402 .appendTo( container ); 15403 15404 settings.oApi._fnBindAction( 15405 node, {action: button}, clickHandler 15406 ); 15407 15408 counter++; 15409 } 15410 } 15411 } 15412 }; 15413 15414 // IE9 throws an 'unknown error' if document.activeElement is used 15415 // inside an iframe or frame. 15416 var activeEl; 15417 15418 try { 15419 // Because this approach is destroying and recreating the paging 15420 // elements, focus is lost on the select button which is bad for 15421 // accessibility. So we want to restore focus once the draw has 15422 // completed 15423 activeEl = $(host).find(document.activeElement).data('dt-idx'); 15424 } 15425 catch (e) {} 15426 15427 attach( 15428 $(host).empty().html('<ul class="pagination"/>').children('ul'), 15429 buttons 15430 ); 15431 15432 if ( activeEl !== undefined ) { 15433 $(host).find( '[data-dt-idx='+activeEl+']' ).focus(); 15434 } 15435}; 15436 15437 15438return DataTable; 15439})); 15440 15441 15442/*! Responsive 2.2.1 15443 * 2014-2017 SpryMedia Ltd - datatables.net/license 15444 */ 15445 15446/** 15447 * @summary Responsive 15448 * @description Responsive tables plug-in for DataTables 15449 * @version 2.2.1 15450 * @file dataTables.responsive.js 15451 * @author SpryMedia Ltd (www.sprymedia.co.uk) 15452 * @contact www.sprymedia.co.uk/contact 15453 * @copyright Copyright 2014-2017 SpryMedia Ltd. 15454 * 15455 * This source file is free software, available under the following license:
15456 * MIT license - http://datatables.net/license/mit 15457 * 15458 * This source file is distributed in the hope that it will be useful, but 15459 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15460 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. 15461 * 15462 * For details please refer to: http://www.datatables.net 15463 */ 15464(function( factory ){ 15465 if ( typeof define === 'function' && define.amd ) { 15466 // AMD 15467 define( ['jquery', 'datatables.net'], function ( $ ) { 15468 return factory( $, window, document ); 15469 } ); 15470 } 15471 else if ( typeof exports === 'object' ) { 15472 // CommonJS 15473 module.exports = function (root, $) { 15474 if ( ! root ) { 15475 root = window; 15476 } 15477 15478 if ( ! $ || ! $.fn.dataTable ) { 15479 $ = require('datatables.net')(root, $).$; 15480 } 15481 15482 return factory( $, root, root.document ); 15483 }; 15484 } 15485 else { 15486 // Browser 15487 factory( jQuery, window, document ); 15488 } 15489}(function( $, window, document, undefined ) { 15490'use strict'; 15491var DataTable = $.fn.dataTable; 15492 15493 15494/** 15495 * Responsive is a plug-in for the DataTables library that makes use of 15496 * DataTables' ability to change the visibility of columns, changing the 15497 * visibility of columns so the displayed columns fit into the table container. 15498 * The end result is that complex tables will be dynamically adjusted to fit 15499 * into the viewport, be it on a desktop, tablet or mobile browser. 15500 * 15501 * Responsive for DataTables has two modes of operation, which can used 15502 * individually or combined: 15503 * 15504 * * Class name based control - columns assigned class names that match the 15505 * breakpoint logic can be shown / hidden as required for each breakpoint. 15506 * * Automatic control - columns are automatically hidden when there is no 15507 * room left to display them. Columns removed from the right. 15508 * 15509 * In additional to column visibility control, Responsive also has built into 15510 * options to use DataTables' child row display to show / hide the information 15511 * from the table that has been hidden. There are also two modes of operation 15512 * for this child row display: 15513 * 15514 * * Inline - when the control element that the user can use to show / hide 15515 * child rows is displayed inside the first column of the table. 15516 * * Column - where a whole column is dedicated to be the show / hide control. 15517 * 15518 * Initialisation of Responsive is performed by: 15519 * 15520 * * Adding the class `responsive` or `dt-responsive` to the table. In this case 15521 * Responsive will automatically be initialised with the default configuration 15522 * options when the DataTable is created. 15523 * * Using the `responsive` option in the DataTables configuration options. This 15524 * can also be used to specify the configuration options, or simply set to 15525 * `true` to use the defaults. 15526 * 15527 * @class 15528 * @param {object} settings DataTables settings object for the host table 15529 * @param {object} [opts] Configuration options 15530 * @requires jQuery 1.7+ 15531 * @requires DataTables 1.10.3+ 15532 * 15533 * @example 15534 * $('#example').DataTable( { 15535 * responsive: true 15536 * } ); 15537 * } ); 15538 */ 15539var Responsive = function ( settings, opts ) { 15540 // Sanity check that we are using DataTables 1.10 or newer 15541 if ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.10' ) ) { 15542 throw 'DataTables Responsive requires DataTables 1.10.10 or newer'; 15543 } 15544 15545 this.s = { 15546 dt: new DataTable.Api( settings ), 15547 columns: [], 15548 current: [] 15549 }; 15550 15551 // Check if responsive has already been initialised on this table 15552 if ( this.s.dt.settings()[0].responsive ) { 15553 return; 15554 } 15555 15556 // details is an object, but for simplicity the user can give it as a string 15557 // or a boolean 15558 if ( opts && typeof opts.details === 'string' ) { 15559 opts.details = { type: opts.details }; 15560 } 15561 else if ( opts && opts.details === false ) { 15562 opts.details = { type: false }; 15563 } 15564 else if ( opts && opts.details === true ) { 15565 opts.details = { type: 'inline' }; 15566 } 15567 15568 this.c = $.extend( true, {}, Responsive.defaults, DataTable.defaults.responsive, opts ); 15569 settings.responsive = this; 15570 this._constructor(); 15571}; 15572 15573$.extend( Responsive.prototype, { 15574 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 15575 * Constructor 15576 */ 15577 15578 /** 15579 * Initialise the Responsive instance 15580 * 15581 * @private 15582 */ 15583 _constructor: function () 15584 { 15585 var that = this; 15586 var dt = this.s.dt; 15587 var dtPrivateSettings = dt.settings()[0]; 15588 var oldWindowWidth = $(window).width(); 15589 15590 dt.settings()[0]._responsive = this; 15591 15592 // Use DataTables' throttle function to avoid processor thrashing on 15593 // resize 15594 $(window).on( 'resize.dtr orientationchange.dtr', DataTable.util.throttle( function () { 15595 // iOS has a bug whereby resize can fire when only scrolling 15596 // See: http://stackoverflow.com/questions/8898412 15597 var width = $(window).width(); 15598 15599 if ( width !== oldWindowWidth ) { 15600 that._resize(); 15601 oldWindowWidth = width; 15602 } 15603 } ) ); 15604 15605 // DataTables doesn't currently trigger an event when a row is added, so 15606 // we need to hook into its private API to enforce the hidden rows when 15607 // new data is added 15608 dtPrivateSettings.oApi._fnCallbackReg( dtPrivateSettings, 'aoRowCreatedCallback', function (tr, data, idx) { 15609 if ( $.inArray( false, that.s.current ) !== -1 ) { 15610 $('>td, >th', tr).each( function ( i ) { 15611 var idx = dt.column.index( 'toData', i ); 15612 15613 if ( that.s.current[idx] === false ) { 15614 $(this).css('display', 'none'); 15615 } 15616 } ); 15617 } 15618 } ); 15619 15620 // Destroy event handler 15621 dt.on( 'destroy.dtr', function () { 15622 dt.off( '.dtr' ); 15623 $( dt.table().body() ).off( '.dtr' ); 15624 $(window).off( 'resize.dtr orientationchange.dtr' ); 15625 15626 // Restore the columns that we've hidden
15627 $.each( that.s.current, function ( i, val ) { 15628 if ( val === false ) { 15629 that._setColumnVis( i, true ); 15630 } 15631 } ); 15632 } ); 15633 15634 // Reorder the breakpoints array here in case they have been added out 15635 // of order 15636 this.c.breakpoints.sort( function (a, b) { 15637 return a.width < b.width ? 1 : 15638 a.width > b.width ? -1 : 0; 15639 } ); 15640 15641 this._classLogic(); 15642 this._resizeAuto(); 15643 15644 // Details handler 15645 var details = this.c.details; 15646 15647 if ( details.type !== false ) { 15648 that._detailsInit(); 15649 15650 // DataTables will trigger this event on every column it shows and 15651 // hides individually 15652 dt.on( 'column-visibility.dtr', function (e, ctx, col, vis, recalc) { 15653 if ( recalc ) { 15654 that._classLogic(); 15655 that._resizeAuto(); 15656 that._resize(); 15657 } 15658 } ); 15659 15660 // Redraw the details box on each draw which will happen if the data 15661 // has changed. This is used until DataTables implements a native 15662 // `updated` event for rows 15663 dt.on( 'draw.dtr', function () { 15664 that._redrawChildren(); 15665 } ); 15666 15667 $(dt.table().node()).addClass( 'dtr-'+details.type ); 15668 } 15669 15670 dt.on( 'column-reorder.dtr', function (e, settings, details) { 15671 that._classLogic(); 15672 that._resizeAuto(); 15673 that._resize(); 15674 } ); 15675 15676 // Change in column sizes means we need to calc 15677 dt.on( 'column-sizing.dtr', function () { 15678 that._resizeAuto(); 15679 that._resize(); 15680 }); 15681 15682 // On Ajax reload we want to reopen any child rows which are displayed 15683 // by responsive 15684 dt.on( 'preXhr.dtr', function () { 15685 var rowIds = []; 15686 dt.rows().every( function () { 15687 if ( this.child.isShown() ) { 15688 rowIds.push( this.id(true) ); 15689 } 15690 } ); 15691 15692 dt.one( 'draw.dtr', function () { 15693 that._resizeAuto(); 15694 that._resize(); 15695 15696 dt.rows( rowIds ).every( function () { 15697 that._detailsDisplay( this, false ); 15698 } ); 15699 } ); 15700 }); 15701 15702 dt.on( 'init.dtr', function (e, settings, details) { 15703 that._resizeAuto(); 15704 that._resize(); 15705 15706 // If columns were hidden, then DataTables needs to adjust the 15707 // column sizing 15708 if ( $.inArray( false, that.s.current ) ) { 15709 dt.columns.adjust(); 15710 } 15711 } ); 15712 15713 // First pass - draw the table for the current viewport size 15714 this._resize(); 15715 }, 15716 15717 15718 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 15719 * Private methods 15720 */ 15721 15722 /** 15723 * Calculate the visibility for the columns in a table for a given 15724 * breakpoint. The result is pre-determined based on the class logic if 15725 * class names are used to control all columns, but the width of the table 15726 * is also used if there are columns which are to be automatically shown 15727 * and hidden. 15728 * 15729 * @param {string} breakpoint Breakpoint name to use for the calculation 15730 * @return {array} Array of boolean values initiating the visibility of each 15731 * column. 15732 * @private 15733 */ 15734 _columnsVisiblity: function ( breakpoint ) 15735 { 15736 var dt = this.s.dt; 15737 var columns = this.s.columns; 15738 var i, ien; 15739 15740 // Create an array that defines the column ordering based first on the 15741 // column's priority, and secondly the column index. This allows the 15742 // columns to be removed from the right if the priority matches 15743 var order = columns 15744 .map( function ( col, idx ) { 15745 return { 15746 columnIdx: idx, 15747 priority: col.priority 15748 }; 15749 } ) 15750 .sort( function ( a, b ) { 15751 if ( a.priority !== b.priority ) { 15752 return a.priority - b.priority; 15753 } 15754 return a.columnIdx - b.columnIdx; 15755 } ); 15756 15757 // Class logic - determine which columns are in this breakpoint based 15758 // on the classes. If no class control (i.e. `auto`) then `-` is used 15759 // to indicate this to the rest of the function 15760 var display = $.map( columns, function ( col ) { 15761 return col.auto && col.minWidth === null ? 15762 false : 15763 col.auto === true ? 15764 '-' : 15765 $.inArray( breakpoint, col.includeIn ) !== -1; 15766 } ); 15767 15768 // Auto column control - first pass: how much width is taken by the 15769 // ones that must be included from the non-auto columns 15770 var requiredWidth = 0; 15771 for ( i=0, ien=display.length ; i<ien ; i++ ) { 15772 if ( display[i] === true ) { 15773 requiredWidth += columns[i].minWidth; 15774 } 15775 } 15776 15777 // Second pass, use up any remaining width for other columns. For 15778 // scrolling tables we need to subtract the width of the scrollbar. It
15779 // may not be requires which makes this sub-optimal, but it would 15780 // require another full redraw to make complete use of those extra few 15781 // pixels 15782 var scrolling = dt.settings()[0].oScroll; 15783 var bar = scrolling.sY || scrolling.sX ? scrolling.iBarWidth : 0; 15784 var widthAvailable = dt.table().container().offsetWidth - bar; 15785 var usedWidth = widthAvailable - requiredWidth; 15786 15787 // Control column needs to always be included. This makes it sub- 15788 // optimal in terms of using the available with, but to stop layout 15789 // thrashing or overflow. Also we need to account for the control column 15790 // width first so we know how much width is available for the other 15791 // columns, since the control column might not be the first one shown 15792 for ( i=0, ien=display.length ; i<ien ; i++ ) { 15793 if ( columns[i].control ) { 15794 usedWidth -= columns[i].minWidth; 15795 } 15796 } 15797 15798 // Allow columns to be shown (counting by priority and then right to 15799 // left) until we run out of room 15800 var empty = false; 15801 for ( i=0, ien=order.length ; i<ien ; i++ ) { 15802 var colIdx = order[i].columnIdx; 15803 15804 if ( display[colIdx] === '-' && ! columns[colIdx].control && columns[colIdx].minWidth ) { 15805 // Once we've found a column that won't fit we don't let any 15806 // others display either, or columns might disappear in the 15807 // middle of the table 15808 if ( empty || usedWidth - columns[colIdx].minWidth < 0 ) { 15809 empty = true; 15810 display[colIdx] = false; 15811 } 15812 else { 15813 display[colIdx] = true; 15814 } 15815 15816 usedWidth -= columns[colIdx].minWidth; 15817 } 15818 } 15819 15820 // Determine if the 'control' column should be shown (if there is one). 15821 // This is the case when there is a hidden column (that is not the 15822 // control column). The two loops look inefficient here, but they are 15823 // trivial and will fly through. We need to know the outcome from the 15824 // first , before the action in the second can be taken 15825 var showControl = false; 15826 15827 for ( i=0, ien=columns.length ; i<ien ; i++ ) { 15828 if ( ! columns[i].control && ! columns[i].never && ! display[i] ) { 15829 showControl = true; 15830 break; 15831 } 15832 } 15833 15834 for ( i=0, ien=columns.length ; i<ien ; i++ ) { 15835 if ( columns[i].control ) { 15836 display[i] = showControl; 15837 } 15838 } 15839 15840 // Finally we need to make sure that there is at least one column that 15841 // is visible 15842 if ( $.inArray( true, display ) === -1 ) { 15843 display[0] = true; 15844 } 15845
15846 return display; 15847 }, 15848 15849 15850 /** 15851 * Create the internal `columns` array with information about the columns 15852 * for the table. This includes determining which breakpoints the column 15853 * will appear in, based upon class names in the column, which makes up the 15854 * vast majority of this method. 15855 * 15856 * @private 15857 */ 15858 _classLogic: function () 15859 { 15860 var that = this; 15861 var calc = {}; 15862 var breakpoints = this.c.breakpoints; 15863 var dt = this.s.dt; 15864 var columns = dt.columns().eq(0).map( function (i) { 15865 var column = this.column(i); 15866 var className = column.header().className; 15867 var priority = dt.settings()[0].aoColumns[i].responsivePriority; 15868 15869 if ( priority === undefined ) { 15870 var dataPriority = $(column.header()).data('priority'); 15871 15872 priority = dataPriority !== undefined ? 15873 dataPriority * 1 : 15874 10000; 15875 } 15876 15877 return { 15878 className: className, 15879 includeIn: [], 15880 auto: false, 15881 control: false, 15882 never: className.match(/\bnever\b/) ? true : false, 15883 priority: priority 15884 }; 15885 } ); 15886 15887 // Simply add a breakpoint to `includeIn` array, ensuring that there are 15888 // no duplicates 15889 var add = function ( colIdx, name ) { 15890 var includeIn = columns[ colIdx ].includeIn; 15891 15892 if ( $.inArray( name, includeIn ) === -1 ) { 15893 includeIn.push( name ); 15894 } 15895 }; 15896 15897 var column = function ( colIdx, name, operator, matched ) { 15898 var size, i, ien; 15899 15900 if ( ! operator ) { 15901 columns[ colIdx ].includeIn.push( name ); 15902 } 15903 else if ( operator === 'max-' ) { 15904 // Add this breakpoint and all smaller 15905 size = that._find( name ).width; 15906 15907 for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) { 15908 if ( breakpoints[i].width <= size ) { 15909 add( colIdx, breakpoints[i].name ); 15910 } 15911 } 15912 } 15913 else if ( operator === 'min-' ) { 15914 // Add this breakpoint and all larger 15915 size = that._find( name ).width; 15916 15917 for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) { 15918 if ( breakpoints[i].width >= size ) { 15919 add( colIdx, breakpoints[i].name ); 15920 } 15921 } 15922 } 15923 else if ( operator === 'not-' ) { 15924 // Add all but this breakpoint 15925 for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) { 15926 if ( breakpoints[i].name.indexOf( matched ) === -1 ) { 15927 add( colIdx, breakpoints[i].name ); 15928 } 15929 } 15930 } 15931 }; 15932 15933 // Loop over each column and determine if it has a responsive control 15934 // class 15935 columns.each( function ( col, i ) { 15936 var classNames = col.className.split(' '); 15937 var hasClass = false; 15938 15939 // Split the class name up so multiple rules can be applied if needed 15940 for ( var k=0, ken=classNames.length ; k<ken ; k++ ) { 15941 var className = $.trim( classNames[k] ); 15942 15943 if ( className === 'all' ) { 15944 // Include in all 15945 hasClass = true; 15946 col.includeIn = $.map( breakpoints, function (a) { 15947 return a.name; 15948 } ); 15949 return; 15950 } 15951 else if ( className === 'none' || col.never ) { 15952 // Include in none (default) and no auto 15953 hasClass = true; 15954 return; 15955 } 15956 else if ( className === 'control' ) { 15957 // Special column that is only visible, when one of the other 15958 // columns is hidden. This is used for the details control 15959 hasClass = true; 15960 col.control = true; 15961 return; 15962 } 15963 15964 $.each( breakpoints, function ( j, breakpoint ) { 15965 // Does this column have a class that matches this breakpoint? 15966 var brokenPoint = breakpoint.name.split('-'); 15967 var re = new RegExp( '(min\\-|max\\-|not\\-)?('+brokenPoint[0]+')(\\-[_a-zA-Z0-9])?' ); 15968 var match = className.match( re ); 15969 15970 if ( match ) { 15971 hasClass = true; 15972 15973 if ( match[2] === brokenPoint[0] && match[3] === '-'+brokenPoint[1] ) { 15974 // Class name matches breakpoint name fully 15975 column( i, breakpoint.name, match[1], match[2]+match[3] ); 15976 } 15977 else if ( match[2] === brokenPoint[0] && ! match[3] ) { 15978 // Class name matched primary breakpoint name with no qualifier 15979 column( i, breakpoint.name, match[1], match[2] ); 15980 } 15981 } 15982 } ); 15983 } 15984 15985 // If there was no control class, then automatic sizing is used 15986 if ( ! hasClass ) { 15987 col.auto = true; 15988 } 15989 } ); 15990 15991 this.s.columns = columns; 15992 }, 15993 15994 15995 /** 15996 * Show the details for the child row 15997 * 15998 * @param {DataTables.Api} row API instance for the row 15999 * @param {boolean} update Update flag 16000 * @private 16001 */ 16002 _detailsDisplay: function ( row, update ) 16003 { 16004 var that = this; 16005 var dt = this.s.dt; 16006 var details = this.c.details; 16007 16008 if ( details && details.type !== false ) { 16009 var res = details.display( row, update, function () { 16010 return details.renderer( 16011 dt, row[0], that._detailsObj(row[0]) 16012 ); 16013 } ); 16014 16015 if ( res === true || res === false ) { 16016 $(dt.table().node()).triggerHandler( 'responsive-display.dt', [dt, row, res, update] ); 16017 } 16018 } 16019 }, 16020 16021 16022 /** 16023 * Initialisation for the details handler 16024 * 16025 * @private 16026 */ 16027 _detailsInit: function () 16028 { 16029 var that = this; 16030 var dt = this.s.dt; 16031 var details = this.c.details; 16032 16033 // The inline type always uses the first child as the target 16034 if ( details.type === 'inline' ) { 16035 details.target = 'td:first-child, th:first-child'; 16036 } 16037 16038 // Keyboard accessibility 16039 dt.on( 'draw.dtr', function () { 16040 that._tabIndexes(); 16041 } ); 16042 that._tabIndexes(); // Initial draw has already happened 16043 16044 $( dt.table().body() ).on( 'keyup.dtr', 'td, th', function (e) { 16045 if ( e.keyCode === 13 && $(this).data('dtr-keyboard') ) { 16046 $(this).click(); 16047 } 16048 } ); 16049 16050 // type.target can be a string jQuery selector or a column index 16051 var target = details.target; 16052 var selector = typeof target === 'string' ? target : 'td, th'; 16053 16054 // Click handler to show / hide the details rows when they are available 16055 $( dt.table().body() ) 16056 .on( 'click.dtr mousedown.dtr mouseup.dtr', selector, function (e) { 16057 // If the table is not collapsed (i.e. there is no hidden columns) 16058 // then take no action 16059 if ( ! $(dt.table().node()).hasClass('collapsed' ) ) { 16060 return; 16061 } 16062 16063 // Check that the row is actually a DataTable's controlled node 16064 if ( $.inArray( $(this).closest('tr').get(0), dt.rows().nodes().toArray() ) === -1 ) { 16065 return; 16066 } 16067 16068 // For column index, we determine if we should act or not in the 16069 // handler - otherwise it is already okay 16070 if ( typeof target === 'number' ) { 16071 var targetIdx = target < 0 ? 16072 dt.columns().eq(0).length + target : 16073 target; 16074 16075 if ( dt.cell( this ).index().column !== targetIdx ) { 16076 return; 16077 } 16078 } 16079
16080 // $().closest() includes itself in its check 16081 var row = dt.row( $(this).closest('tr') ); 16082 16083 // Check event type to do an action 16084 if ( e.type === 'click' ) { 16085 // The renderer is given as a function so the caller can execute it 16086 // only when they need (i.e. if hiding there is no point is running 16087 // the renderer) 16088 that._detailsDisplay( row, false ); 16089 } 16090 else if ( e.type === 'mousedown' ) { 16091 // For mouse users, prevent the focus ring from showing 16092 $(this).css('outline', 'none'); 16093 } 16094 else if ( e.type === 'mouseup' ) { 16095 // And then re-allow at the end of the click 16096 $(this).blur().css('outline', ''); 16097 } 16098 } ); 16099 }, 16100 16101 16102 /** 16103 * Get the details to pass to a renderer for a row 16104 * @param {int} rowIdx Row index 16105 * @private 16106 */ 16107 _detailsObj: function ( rowIdx ) 16108 { 16109 var that = this; 16110 var dt = this.s.dt; 16111 16112 return $.map( this.s.columns, function( col, i ) { 16113 // Never and control columns should not be passed to the renderer 16114 if ( col.never || col.control ) { 16115 return; 16116 } 16117 16118 return { 16119 title: dt.settings()[0].aoColumns[ i ].sTitle, 16120 data: dt.cell( rowIdx, i ).render( that.c.orthogonal ), 16121 hidden: dt.column( i ).visible() && !that.s.current[ i ], 16122 columnIndex: i, 16123 rowIndex: rowIdx 16124 }; 16125 } ); 16126 }, 16127 16128 16129 /** 16130 * Find a breakpoint object from a name 16131 * 16132 * @param {string} name Breakpoint name to find 16133 * @return {object} Breakpoint description object 16134 * @private 16135 */ 16136 _find: function ( name ) 16137 { 16138 var breakpoints = this.c.breakpoints; 16139 16140 for ( var i=0, ien=breakpoints.length ; i<ien ; i++ ) { 16141 if ( breakpoints[i].name === name ) { 16142 return breakpoints[i]; 16143 } 16144 } 16145 }, 16146 16147 16148 /** 16149 * Re-create the contents of the child rows as the display has changed in 16150 * some way. 16151 * 16152 * @private 16153 */ 16154 _redrawChildren: function () 16155 { 16156 var that = this; 16157 var dt = this.s.dt; 16158 16159 dt.rows( {page: 'current'} ).iterator( 'row', function ( settings, idx ) { 16160 var row = dt.row( idx ); 16161 16162 that._detailsDisplay( dt.row( idx ), true ); 16163 } ); 16164 }, 16165 16166 16167 /** 16168 * Alter the table display for a resized viewport. This involves first 16169 * determining what breakpoint the window currently is in, getting the 16170 * column visibilities to apply and then setting them. 16171 * 16172 * @private 16173 */ 16174 _resize: function () 16175 { 16176 var that = this; 16177 var dt = this.s.dt; 16178 var width = $(window).width(); 16179 var breakpoints = this.c.breakpoints; 16180 var breakpoint = breakpoints[0].name; 16181 var columns = this.s.columns; 16182 var i, ien; 16183 var oldVis = this.s.current.slice(); 16184 16185 // Determine what breakpoint we are currently at 16186 for ( i=breakpoints.length-1 ; i>=0 ; i-- ) { 16187 if ( width <= breakpoints[i].width ) { 16188 breakpoint = breakpoints[i].name; 16189 break; 16190 } 16191 } 16192 16193 // Show the columns for that break point 16194 var columnsVis = this._columnsVisiblity( breakpoint ); 16195 this.s.current = columnsVis; 16196 16197 // Set the class before the column visibility is changed so event 16198 // listeners know what the state is. Need to determine if there are 16199 // any columns that are not visible but can be shown 16200 var collapsedClass = false; 16201 for ( i=0, ien=columns.length ; i<ien ; i++ ) { 16202 if ( columnsVis[i] === false && ! columns[i].never && ! columns[i].control ) { 16203 collapsedClass = true; 16204 break; 16205 } 16206 } 16207 16208 $( dt.table().node() ).toggleClass( 'collapsed', collapsedClass ); 16209 16210 var changed = false; 16211 var visible = 0; 16212 16213 dt.columns().eq(0).each( function ( colIdx, i ) { 16214 if ( columnsVis[i] === true ) { 16215 visible++; 16216 } 16217 16218 if ( columnsVis[i] !== oldVis[i] ) { 16219 changed = true; 16220 that._setColumnVis( colIdx, columnsVis[i] ); 16221 } 16222 } ); 16223 16224 if ( changed ) { 16225 this._redrawChildren(); 16226 16227 // Inform listeners of the change 16228 $(dt.table().node()).trigger( 'responsive-resize.dt', [dt, this.s.current] ); 16229 16230 // If no records, update the "No records" display element 16231 if ( dt.page.info().recordsDisplay === 0 ) { 16232 $('td', dt.table().body()).eq(0).attr('colspan', visible); 16233 } 16234 } 16235 }, 16236 16237 16238 /** 16239 * Determine the width of each column in the table so the auto column hiding 16240 * has that information to work with. This method is never going to be 100% 16241 * perfect since column widths can change slightly per page, but without 16242 * seriously compromising performance this is quite effective. 16243 * 16244 * @private 16245 */ 16246 _resizeAuto: function () 16247 { 16248 var dt = this.s.dt; 16249 var columns = this.s.columns; 16250 16251 // Are we allowed to do auto sizing? 16252 if ( ! this.c.auto ) { 16253 return; 16254 } 16255 16256 // Are there any columns that actually need auto-sizing, or do they all 16257 // have classes defined 16258 if ( $.inArray( true, $.map( columns, function (c) { return c.auto; }
16258 ) ) === -1 ) { 16259 return; 16260 } 16261 16262 // Need to restore all children. They will be reinstated by a re-render 16263 if ( ! $.isEmptyObject( _childNodeStore ) ) { 16264 $.each( _childNodeStore, function ( key ) { 16265 var idx = key.split('-'); 16266 16267 _childNodesRestore( dt, idx[0]*1, idx[1]*1 ); 16268 } ); 16269 } 16270 16271 // Clone the table with the current data in it 16272 var tableWidth = dt.table().node().offsetWidth; 16273 var columnWidths = dt.columns; 16274 var clonedTable = dt.table().node().cloneNode( false ); 16275 var clonedHeader = $( dt.table().header().cloneNode( false ) ).appendTo( clonedTable ); 16276 var clonedBody = $( dt.table().body() ).clone( false, false ).empty().appendTo( clonedTable ); // use jQuery because of IE8 16277 16278 // Header 16279 var headerCells = dt.columns() 16280 .header() 16281 .filter( function (idx) { 16282 return dt.column(idx).visible(); 16283 } ) 16284 .to$() 16285 .clone( false ) 16286 .css( 'display', 'table-cell' ) 16287 .css( 'min-width', 0 ); 16288 16289 // Body rows - we don't need to take account of DataTables' column 16290 // visibility since we implement our own here (hence the `display` set) 16291 $(clonedBody) 16292 .append( $(dt.rows( { page: 'current' } ).nodes()).clone( false ) ) 16293 .find( 'th, td' ).css( 'display', '' ); 16294 16295 // Footer 16296 var footer = dt.table().footer(); 16297 if ( footer ) { 16298 var clonedFooter = $( footer.cloneNode( false ) ).appendTo( clonedTable ); 16299 var footerCells = dt.columns() 16300 .footer() 16301 .filter( function (idx) { 16302 return dt.column(idx).visible(); 16303 } ) 16304 .to$() 16305 .clone( false ) 16306 .css( 'display', 'table-cell' ); 16307 16308 $('<tr/>') 16309 .append( footerCells ) 16310 .appendTo( clonedFooter ); 16311 } 16312 16313 $('<tr/>') 16314 .append( headerCells ) 16315 .appendTo( clonedHeader ); 16316 16317 // In the inline case extra padding is applied to the first column to 16318 // give space for the show / hide icon. We need to use this in the 16319 // calculation 16320 if ( this.c.details.type === 'inline' ) { 16321 $(clonedTable).addClass( 'dtr-inline collapsed' ); 16322 } 16323 16324 // It is unsafe to insert elements with the same name into the DOM 16325 // multiple times. For example, cloning and inserting a checked radio 16326 // clears the chcecked state of the original radio. 16327 $( clonedTable ).find( '[name]' ).removeAttr( 'name' ); 16328 16329 var inserted = $('<div/>') 16330 .css( { 16331 width: 1, 16332 height: 1, 16333 overflow: 'hidden', 16334 clear: 'both' 16335 } ) 16336 .append( clonedTable ); 16337 16338 inserted.insertBefore( dt.table().node() ); 16339 16340 // The cloned header now contains the smallest that each column can be 16341 headerCells.each( function (i) { 16342 var idx = dt.column.index( 'fromVisible', i ); 16343 columns[ idx ].minWidth = this.offsetWidth || 0; 16344 } ); 16345 16346 inserted.remove(); 16347 }, 16348 16349 /** 16350 * Set a column's visibility. 16351 * 16352 * We don't use DataTables' column visibility controls in order to ensure 16353 * that column visibility can Responsive can no-exist. Since only IE8+ is 16354 * supported (and all evergreen browsers of course) the control of the 16355 * display attribute works well. 16356 * 16357 * @param {integer} col Column index 16358 * @param {boolean} showHide Show or hide (true or false) 16359 * @private 16360 */ 16361 _setColumnVis: function ( col, showHide ) 16362 { 16363 var dt = this.s.dt; 16364 var display = showHide ? '' : 'none'; // empty string will remove the attr 16365 16366 $( dt.column( col ).header() ).css( 'display', display ); 16367 $( dt.column( col ).footer() ).css( 'display', display ); 16368 dt.column( col ).nodes().to$().css( 'display', display ); 16369 16370 // If the are child nodes stored, we might need to reinsert them 16371 if ( ! $.isEmptyObject( _childNodeStore ) ) { 16372 dt.cells( null, col ).indexes().each( function (idx) { 16373 _childNodesRestore( dt, idx.row, idx.column ); 16374 } ); 16375 } 16376 }, 16377 16378 16379 /** 16380 * Update the cell tab indexes for keyboard accessibility. This is called on 16381 * every table draw - that is potentially inefficient, but also the least 16382 * complex option given that column visibility can change on the fly. Its a 16383 * shame user-focus was removed from CSS 3 UI, as it would have solved this 16384 * issue with a single CSS statement. 16385 * 16386 * @private 16387 */ 16388 _tabIndexes: function () 16389 { 16390 var dt = this.s.dt; 16391 var cells = dt.cells( { page: 'current' } ).nodes().to$(); 16392 var ctx = dt.settings()[0]; 16393 var target = this.c.details.target; 16394 16395 cells.filter( '[data-dtr-keyboard]' ).removeData( '[data-dtr-keyboard]' ); 16396 16397 var selector = typeof target === 'number' ? 16398 ':eq('+target+')' : 16399 target; 16400 16401 // This is a bit of a hack - we need to limit the selected nodes to just 16402 // those of this table 16403 if ( selector === 'td:first-child, th:first-child' ) { 16404 selector = '>td:first-child, >th:first-child'; 16405 } 16406 16407 $( selector, dt.rows( { page: 'current' } ).nodes() ) 16408 .attr( 'tabIndex', ctx.iTabIndex ) 16409 .data( 'dtr-keyboard', 1 ); 16410 } 16411} ); 16412 16413 16414/** 16415 * List of default breakpoints. Each item in the array is an object with two 16416 * properties: 16417 * 16418 * * `name` - the breakpoint name. 16419 * * `width` - the breakpoint width 16420 * 16421 * @name Responsive.breakpoints 16422 * @static 16423 */ 16424Responsive.breakpoints = [ 16425 { name: 'desktop', width: Infinity }, 16426 { name: 'tablet-l', width: 1024 }, 16427 { name: 'tablet-p', width: 768 }, 16428 { name: 'mobile-l', width: 480 }, 16429 { name: 'mobile-p', width: 320 } 16430]; 16431 16432 16433/** 16434 * Display methods - functions which define how the hidden data should be shown 16435 * in the table. 16436 * 16437 * @namespace 16438 * @name Responsive.defaults 16439 * @static 16440 */ 16441Responsive.display = { 16442 childRow: function ( row, update, render ) { 16443 if ( update ) { 16444 if ( $(row.node()).hasClass('parent') ) { 16445 row.child( render(), 'child' ).show(); 16446 16447 return true; 16448 } 16449 } 16450 else { 16451 if ( ! row.child.isShown() ) { 16452 row.child( render(), 'child' ).show(); 16453 $( row.node() ).addClass( 'parent' ); 16454 16455 return true; 16456 } 16457 else { 16458 row.child( false ); 16459 $( row.node() ).removeClass( 'parent' ); 16460 16461 return false;
16462 } 16463 } 16464 }, 16465 16466 childRowImmediate: function ( row, update, render ) { 16467 if ( (! update && row.child.isShown()) || ! row.responsive.hasHidden() ) { 16468 // User interaction and the row is show, or nothing to show 16469 row.child( false ); 16470 $( row.node() ).removeClass( 'parent' ); 16471 16472 return false; 16473 } 16474 else { 16475 // Display 16476 row.child( render(), 'child' ).show(); 16477 $( row.node() ).addClass( 'parent' ); 16478 16479 return true; 16480 } 16481 }, 16482 16483 // This is a wrapper so the modal options for Bootstrap and jQuery UI can 16484 // have options passed into them. This specific one doesn't need to be a 16485 // function but it is for consistency in the `modal` name 16486 modal: function ( options ) { 16487 return function ( row, update, render ) { 16488 if ( ! update ) { 16489 // Show a modal 16490 var close = function () { 16491 modal.remove(); // will tidy events for us 16492 $(document).off( 'keypress.dtr' ); 16493 }; 16494 16495 var modal = $('<div class="dtr-modal"/>') 16496 .append( $('<div class="dtr-modal-display"/>') 16497 .append( $('<div class="dtr-modal-content"/>') 16498 .append( render() ) 16499 ) 16500 .append( $('<div class="dtr-modal-close">×</div>' ) 16501 .click( function () { 16502 close(); 16503 } ) 16504 ) 16505 ) 16506 .append( $('<div class="dtr-modal-background"/>') 16507 .click( function () { 16508 close(); 16509 } ) 16510 ) 16511 .appendTo( 'body' ); 16512 16513 $(document).on( 'keyup.dtr', function (e) { 16514 if ( e.keyCode === 27 ) { 16515 e.stopPropagation(); 16516 16517 close(); 16518 } 16519 } ); 16520 } 16521 else { 16522 $('div.dtr-modal-content') 16523 .empty() 16524 .append( render() ); 16525 } 16526 16527 if ( options && options.header ) { 16528 $('div.dtr-modal-content').prepend( 16529 '<h2>'+options.header( row )+'</h2>' 16530 ); 16531 } 16532 }; 16533 } 16534}; 16535 16536 16537var _childNodeStore = {}; 16538 16539function _childNodes( dt, row, col ) { 16540 var name = row+'-'+col; 16541 16542 if ( _childNodeStore[ name ] ) { 16543 return _childNodeStore[ name ]; 16544 } 16545 16546 // https://jsperf.com/childnodes-array-slice-vs-loop 16547 var nodes = []; 16548 var children = dt.cell( row, col ).node().childNodes; 16549 for ( var i=0, ien=children.length ; i<ien ; i++ ) { 16550 nodes.push( children[i] ); 16551 } 16552 16553 _childNodeStore[ name ] = nodes; 16554 16555 return nodes; 16556} 16557 16558function _childNodesRestore( dt, row, col ) { 16559 var name = row+'-'+col; 16560 16561 if ( ! _childNodeStore[ name ] ) { 16562 return; 16563 } 16564 16565 var node = dt.cell( row, col ).node(); 16566 var store = _childNodeStore[ name ]; 16567 var parent = store[0].parentNode; 16568 var parentChildren = parent.childNodes; 16569 var a = []; 16570 16571 for ( var i=0, ien=parentChildren.length ; i<ien ; i++ ) { 16572 a.push( parentChildren[i] ); 16573 } 16574 16575 for ( var j=0, jen=a.length ; j<jen ; j++ ) { 16576 node.appendChild( a[j] ); 16577 } 16578 16579 _childNodeStore[ name ] = undefined; 16580} 16581 16582 16583/** 16584 * Display methods - functions which define how the hidden data should be shown 16585 * in the table. 16586 * 16587 * @namespace 16588 * @name Responsive.defaults 16589 * @static 16590 */ 16591Responsive.renderer = { 16592 listHiddenNodes: function () { 16593 return function ( api, rowIdx, columns ) { 16594 var ul = $('<ul data-dtr-index="'+rowIdx+'" class="dtr-details"/>'); 16595 var found = false; 16596 16597 var data = $.each( columns, function ( i, col ) { 16598 if ( col.hidden ) { 16599 $( 16600 '<li data-dtr-index="'+col.columnIndex+'" data-dt-row="'+col.rowIndex+'" data-dt-column="'+col.columnIndex+'">'+ 16601 '<span class="dtr-title">'+ 16602 col.title+ 16603 '</span> '+ 16604 '</li>' 16605 ) 16606 .append( $('<span class="dtr-data"/>').append( _childNodes( api, col.rowIndex, col.columnIndex ) ) )// api.cell( col.rowIndex, col.columnIndex ).node().childNodes ) ) 16607 .appendTo( ul ); 16608 16609 found = true; 16610 } 16611 } ); 16612 16613 return found ? 16614 ul : 16615 false; 16616 }; 16617 }, 16618 16619 listHidden: function () { 16620 return function ( api, rowIdx, columns ) { 16621 var data = $.map( columns, function ( col ) { 16622 return col.hidden ? 16623 '<li data-dtr-index="'+col.columnIndex+'" data-dt-row="'+col.rowIndex+'" data-dt-column="'+col.columnIndex+'">'+ 16624 '<span class="dtr-title">'+ 16625 col.title+ 16626 '</span> '+ 16627 '<span class="dtr-data">'+ 16628 col.data+ 16629 '</span>'+ 16630 '</li>' : 16631 ''; 16632 } ).join(''); 16633 16634 return data ? 16635 $('<ul data-dtr-index="'+rowIdx+'" class="dtr-details"/>').append( data ) : 16636 false; 16637 } 16638 }, 16639 16640 tableAll: function ( options ) { 16641 options = $.extend( { 16642 tableClass: '' 16643 }, options ); 16644 16645 return function ( api, rowIdx, columns ) { 16646 var data = $.map( columns, function ( col ) { 16647 return '<tr data-dt-row="'+col.rowIndex+'" data-dt-column="'+col.columnIndex+'">'+ 16648 '<td>'+col.title+':'+'</td> '+ 16649 '<td>'+col.data+'</td>'+ 16650 '</tr>'; 16651 } ).join(''); 16652 16653 return $('<table class="'+options.tableClass+' dtr-details" width="100%"/>').append( data ); 16654 } 16655 } 16656}; 16657 16658/** 16659 * Responsive default settings for initialisation 16660 * 16661 * @namespace 16662 * @name Responsive.defaults 16663 * @static 16664 */ 16665Responsive.defaults = { 16666 /** 16667 * List of breakpoints for the instance. Note that this means that each 16668 * instance can have its own breakpoints. Additionally, the breakpoints 16669 * cannot be changed once an instance has been creased. 16670 * 16671 * @type {Array} 16672 * @default Takes the value of `Responsive.breakpoints` 16673 */ 16674 breakpoints: Responsive.breakpoints, 16675 16676 /** 16677 * Enable / disable auto hiding calculations. It can help to increase 16678 * performance slightly if you disable this option, but all columns would 16679 * need to have breakpoint classes assigned to them 16680 * 16681 * @type {Boolean} 16682 * @default `true` 16683 */ 16684 auto: true, 16685 16686 /** 16687 * Details control. If given as a string value, the `type` property of the 16688 * default object is set to that value, and the defaults used for the rest 16689 * of the object - this is for ease of implementation. 16690 *
16691 * The object consists of the following properties: 16692 * 16693 * * `display` - A function that is used to show and hide the hidden details 16694 * * `renderer` - function that is called for display of the child row data. 16695 * The default function will show the data from the hidden columns 16696 * * `target` - Used as the selector for what objects to attach the child 16697 * open / close to 16698 * * `type` - `false` to disable the details display, `inline` or `column` 16699 * for the two control types 16700 * 16701 * @type {Object|string} 16702 */ 16703 details: { 16704 display: Responsive.display.childRow, 16705 16706 renderer: Responsive.renderer.listHidden(), 16707 16708 target: 0, 16709 16710 type: 'inline' 16711 }, 16712 16713 /** 16714 * Orthogonal data request option. This is used to define the data type 16715 * requested when Responsive gets the data to show in the child row. 16716 * 16717 * @type {String} 16718 */ 16719 orthogonal: 'display' 16720}; 16721 16722 16723/* 16724 * API 16725 */ 16726var Api = $.fn.dataTable.Api; 16727 16728// Doesn't do anything - work around for a bug in DT... Not documented 16729Api.register( 'responsive()', function () { 16730 return this; 16731} ); 16732 16733Api.register( 'responsive.index()', function ( li ) { 16734 li = $(li); 16735 16736 return { 16737 column: li.data('dtr-index'), 16738 row: li.parent().data('dtr-index') 16739 }; 16740} ); 16741 16742Api.register( 'responsive.rebuild()', function () { 16743 return this.iterator( 'table', function ( ctx ) { 16744 if ( ctx._responsive ) { 16745 ctx._responsive._classLogic(); 16746 } 16747 } ); 16748} ); 16749 16750Api.register( 'responsive.recalc()', function () { 16751 return this.iterator( 'table', function ( ctx ) { 16752 if ( ctx._responsive ) { 16753 ctx._responsive._resizeAuto(); 16754 ctx._responsive._resize(); 16755 } 16756 } ); 16757} ); 16758 16759Api.register( 'responsive.hasHidden()', function () { 16760 var ctx = this.context[0]; 16761 16762 return ctx._responsive ? 16763 $.inArray( false, ctx._responsive.s.current ) !== -1 : 16764 false; 16765} ); 16766 16767Api.registerPlural( 'columns().responsiveHidden()', 'column().responsiveHidden()', function () { 16768 return this.iterator( 'column', function ( settings, column ) { 16769 return settings._responsive ? 16770 settings._responsive.s.current[ column ] : 16771 false; 16772 }, 1 ); 16773} ); 16774 16775 16776/** 16777 * Version information 16778 * 16779 * @name Responsive.version 16780 * @static 16781 */ 16782Responsive.version = '2.2.1'; 16783 16784 16785$.fn.dataTable.Responsive = Responsive; 16786$.fn.DataTable.Responsive = Responsive; 16787 16788// Attach a listener to the document which listens for DataTables initialisation 16789// events so we can automatically initialise 16790$(document).on( 'preInit.dt.dtr', function (e, settings, json) { 16791 if ( e.namespace !== 'dt' ) { 16792 return; 16793 } 16794 16795 if ( $(settings.nTable).hasClass( 'responsive' ) || 16796 $(settings.nTable).hasClass( 'dt-responsive' ) || 16797 settings.oInit.responsive || 16798 DataTable.defaults.responsive 16799 ) { 16800 var init = settings.oInit.responsive; 16801 16802 if ( init !== false ) { 16803 new Responsive( settings, $.isPlainObject( init ) ? init : {} ); 16804 } 16805 } 16806} ); 16807 16808 16809return Responsive; 16810})); 16811 16812
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.