vendor: 3,603 bytes, lines 1-89
1/******/ (function(modules) { // webpackBootstrap 2/******/ // The module cache 3/******/ var installedModules = {}; 4/******/ 5/******/ // The require function 6/******/ function __webpack_require__(moduleId) { 7/******/ 8/******/ // Check if module is in cache 9/******/ if(installedModules[moduleId]) { 10/******/ return installedModules[moduleId].exports; 11/******/ } 12/******/ // Create a new module (and put it into the cache) 13/******/ var module = installedModules[moduleId] = { 14/******/ i: moduleId, 15/******/ l: false, 16/******/ exports: {} 17/******/ }; 18/******/ 19/******/ // Execute the module function 20/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 21/******/ 22/******/ // Flag the module as loaded 23/******/ module.l = true; 24/******/ 25/******/ // Return the exports of the module 26/******/ return module.exports; 27/******/ } 28/******/ 29/******/ 30/******/ // expose the modules object (__webpack_modules__) 31/******/ __webpack_require__.m = modules; 32/******/ 33/******/ // expose the module cache 34/******/ __webpack_require__.c = installedModules; 35/******/ 36/******/ // define getter function for harmony exports 37/******/ __webpack_require__.d = function(exports, name, getter) { 38/******/ if(!__webpack_require__.o(exports, name)) { 39/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); 40/******/ } 41/******/ }; 42/******/ 43/******/ // define __esModule on exports 44/******/ __webpack_require__.r = function(exports) { 45/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { 46/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); 47/******/ } 48/******/ Object.defineProperty(exports, '__esModule', { value: true }); 49/******/ }; 50/******/ 51/******/ // create a fake namespace object 52/******/ // mode & 1: value is a module id, require it 53/******/ // mode & 2: merge all properties of value into the ns 54/******/ // mode & 4: return value when already ns object 55/******/ // mode & 8|1: behave like require 56/******/ __webpack_require__.t = function(value, mode) { 57/******/ if(mode & 1) value = __webpack_require__(value); 58/******/ if(mode & 8) return value; 59/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; 60/******/ var ns = Object.create(null); 61/******/ __webpack_require__.r(ns); 62/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); 63/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); 64/******/ return ns; 65/******/ }; 66/******/ 67/******/ // getDefaultExport function for compatibility with non-harmony modules 68/******/ __webpack_require__.n = function(module) { 69/******/ var getter = module && module.__esModule ? 70/******/ function getDefault() { return module['default']; } : 71/******/ function getModuleExports() { return module; }; 72/******/ __webpack_require__.d(getter, 'a', getter); 73/******/ return getter; 74/******/ }; 75/******/ 76/******/ // Object.prototype.hasOwnProperty.call 77/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 78/******/ 79/******/ // __webpack_public_path__ 80/******/ __webpack_require__.p = ""; 81/******/ 82/******/ 83/******/ // Load entry module and return exports 84/******/ return __webpack_require__(__webpack_require__.s = 0); 85/******/ }) 86/************************************************************************/ 87/******/ ({ 88 89/***/ "./
89Frontend/JavaScript/src/public/main.js": 90/*!************************************************!*\ 91 !*** ./Frontend/JavaScript/src/public/main.js ***! 92 \************************************************/ 93/*! no static exports found */ 94/***/ (function(module, exports, __webpack_require__) { 95 96/** 97 * JS App main file. 98 * 99 * Main file, as an entry point, for the JS Application and to bootstrap it. 100 * 101 * @author: SIEN 102 * @since: 2020.04.7 103 * dt-helper.js 104 * 105 * JS helpers for datatables 106 */ 107var $ = __webpack_require__(/*! jquery */ "./node_modules/jquery/dist/jquery.js"); 108 109var Datatables = __webpack_require__(/*! datatables.net */ "./node_modules/datatables.net/js/jquery.dataTables.js"); 110 111__webpack_require__(/*! datatables.net-responsive */ "./node_modules/datatables.net-responsive/js/dataTables.responsive.js"); 112 113$(document).ready(function () { 114 $(".tx_newspapers").DataTable({ 115 order: [[0, "desc"]], 116 pagingType: "numbers", 117 bInfo: false, 118 stateSave: false, 119 sDom: '<"H"lfrp>t<"F"ip>', 120 language: { 121 processing: "Traitement en cours...", 122 search: "Rechercher :", 123 lengthMenu: "Afficher _MENU_ éléments", 124 info: "Affichage de l'élement _START_ à _END_ sur _TOTAL_ éléments", 125 infoEmpty: "Affichage de l'élement 0 à 0 sur 0 éléments", 126 infoFiltered: "(filtré de _MAX_ éléments au total)", 127 infoPostFix: "", 128 loadingRecords: "Chargement en cours...", 129 zeroRecords: "Aucun élément à afficher", 130 emptyTable: "Aucune donnée disponible dans le tableau", 131 paginate: { 132 first: "Premier", 133 previous: "Précédent", 134 next: "Suivant", 135 last: "Dernier" 136 }, 137 aria: { 138 sortAscending: ": activer pour trier la colonne par ordre croissant", 139 sortDescending: ": activer pour trier la colonne par ordre décroissant" 140 } 141 } 142 }); 143}); 144 145/***/ }), 146
147/***/ "./Frontend/SCSS/main.scss": 148/*!*********************************!*\ 149 !*** ./Frontend/SCSS/main.scss ***! 150 \*********************************/ 151/*! no static exports found */ 152/***/ (function(module, exports, __webpack_require__) { 153 154var api = __webpack_require__(/*! ../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js */ "./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js"); 155 var content = __webpack_require__(/*! !../../node_modules/mini-css-extract-plugin/dist/loader.js!../../node_modules/css-loader/dist/cjs.js??ref--6-2!../../node_modules/postcss-loader/src??ref--6-3!../../node_modules/sass-loader/dist/cjs.js??ref--6-4!./main.scss */ "./node_modules/mini-css-extract-plugin/dist/loader.js!./node_modules/css-loader/dist/cjs.js?!./node_modules/postcss-loader/src/index.js?!./node_modules/sass-loader/dist/cjs.js?!./Frontend/SCSS/main.scss"); 156 157 content = content.__esModule ? content.default : content; 158 159 if (typeof content === 'string') { 160 content = [[module.i, content, '']]; 161 } 162 163var options = {}; 164 165options.insert = "head"; 166options.singleton = false; 167 168var update = api(content, options); 169 170 171 172module.exports = content.locals || {}; 173 174/***/ }), 175
vendor: 41,064 bytes, lines 176-1644
176/***/ "./node_modules/datatables.net-responsive/js/dataTables.responsive.js": 177/*!****************************************************************************!*\ 178 !*** ./node_modules/datatables.net-responsive/js/dataTables.responsive.js ***! 179 \****************************************************************************/ 180/*! no static exports found */ 181/***/ (function(module, exports, __webpack_require__) { 182 183var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*! Responsive 2.2.7 184 * 2014-2021 SpryMedia Ltd - datatables.net/license 185 */ 186 187/** 188 * @summary Responsive 189 * @description Responsive tables plug-in for DataTables 190 * @version 2.2.7 191 * @file dataTables.responsive.js 192 * @author SpryMedia Ltd (www.sprymedia.co.uk) 193 * @contact www.sprymedia.co.uk/contact 194 * @copyright Copyright 2014-2021 SpryMedia Ltd. 195 * 196 * This source file is free software, available under the following license: 197 * MIT license - http://datatables.net/license/mit 198 * 199 * This source file is distributed in the hope that it will be useful, but 200 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 201 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. 202 * 203 * For details please refer to: http://www.datatables.net 204 */ 205(function( factory ){ 206 if ( true ) { 207 // AMD 208 !(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(/*! jquery */ "./node_modules/jquery/dist/jquery.js"), __webpack_require__(/*! datatables.net */ "./node_modules/datatables.net/js/jquery.dataTables.js")], __WEBPACK_AMD_DEFINE_RESULT__ = (function ( $ ) { 209 return factory( $, window, document ); 210 }).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), 211 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 212 } 213 else {} 214}(function( $, window, document, undefined ) { 215'use strict'; 216var DataTable = $.fn.dataTable; 217 218 219/** 220 * Responsive is a plug-in for the DataTables library that makes use of 221 * DataTables' ability to change the visibility of columns, changing the 222 * visibility of columns so the displayed columns fit into the table container. 223 * The end result is that complex tables will be dynamically adjusted to fit 224 * into the viewport, be it on a desktop, tablet or mobile browser. 225 * 226 * Responsive for DataTables has two modes of operation, which can used 227 * individually or combined: 228 * 229 * * Class name based control - columns assigned class names that match the 230 * breakpoint logic can be shown / hidden as required for each breakpoint. 231 * * Automatic control - columns are automatically hidden when there is no 232 * room left to display them. Columns removed from the right. 233 * 234 * In additional to column visibility control, Responsive also has built into 235 * options to use DataTables' child row display to show / hide the information 236 * from the table that has been hidden. There are also two modes of operation 237 * for this child row display: 238 * 239 * * Inline - when the control element that the user can use to show / hide 240 * child rows is displayed inside the first column of the table. 241 * * Column - where a whole column is dedicated to be the show / hide control. 242 * 243 * Initialisation of Responsive is performed by: 244 * 245 * * Adding the class `responsive` or `dt-responsive` to the table. In this case 246 * Responsive will automatically be initialised with the default configuration 247 * options when the DataTable is created. 248 * * Using the `responsive` option in the DataTables configuration options. This 249 * can also be used to specify the configuration options, or simply set to 250 * `true` to use the defaults. 251 * 252 * @class 253 * @param {object} settings DataTables settings object for the host table 254 * @param {object} [opts] Configuration options 255 * @requires jQuery 1.7+ 256 * @requires DataTables 1.10.3+ 257 * 258 * @example 259 * $('#example').DataTable( { 260 * responsive: true 261 * } ); 262 * } ); 263 */ 264var Responsive = function ( settings, opts ) { 265 // Sanity check that we are using DataTables 1.10 or newer 266 if ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.10' ) ) { 267 throw 'DataTables Responsive requires DataTables 1.10.10 or newer'; 268 } 269 270 this.s = { 271 dt: new DataTable.Api( settings ), 272 columns: [], 273 current: [] 274 }; 275 276 // Check if responsive has already been initialised on this table 277 if ( this.s.dt.settings()[0].responsive ) { 278 return; 279 } 280 281 // details is an object, but for simplicity the user can give it as a string 282 // or a boolean 283 if ( opts && typeof opts.details === 'string' ) { 284 opts.details = { type: opts.details }; 285 } 286 else if ( opts && opts.details === false ) { 287 opts.details = { type: false }; 288 } 289 else if ( opts && opts.details === true ) { 290 opts.details = { type: 'inline' }; 291 } 292 293 this.c = $.extend( true, {}, Responsive.defaults, DataTable.defaults.responsive, opts ); 294 settings.responsive = this; 295 this._constructor(); 296}; 297 298$.extend( Responsive.prototype, { 299 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 300 * Constructor 301 */ 302 303 /** 304 * Initialise the Responsive instance 305 * 306 * @private 307 */ 308 _constructor: function () 309 { 310 var that = this; 311 var dt = this.s.dt; 312 var dtPrivateSettings = dt.settings()[0]; 313 var oldWindowWidth = $(window).innerWidth(); 314 315 dt.settings()[0]._responsive = this; 316 317 // Use DataTables' throttle function to avoid processor thrashing on 318 // resize 319 $(window).on( 'resize.dtr orientationchange.dtr', DataTable.util.throttle( function () { 320 // iOS has a bug whereby resize can fire when only scrolling 321 // See: http://stackoverflow.com/questions/8898412 322 var width = $(window).innerWidth(); 323 324 if ( width !== oldWindowWidth ) { 325 that._resize(); 326 oldWindowWidth = width; 327 } 328 } ) ); 329 330 // DataTables doesn't currently trigger an event when a row is added, so 331 // we need to hook into its private API to enforce the hidden rows when 332 // new data is added 333 dtPrivateSettings.oApi._fnCallbackReg( dtPrivateSettings, 'aoRowCreatedCallback', function (tr, data, idx) { 334 if ( $.inArray( false, that.s.current ) !== -1 ) { 335 $('>td, >th', tr).each( function ( i ) { 336 var idx = dt.column.index( 'toData', i ); 337 338 if ( that.s.current[idx] === false ) { 339 $(this).css('display', 'none'); 340 } 341 } ); 342 } 343 } ); 344 345 // Destroy event handler 346 dt.on( 'destroy.dtr', function () { 347 dt.off( '.dtr' ); 348 $( dt.table().body() ).off( '.dtr' ); 349 $(window).off( 'resize.dtr orientationchange.dtr' ); 350 dt.cells('.dtr-control').nodes().to$().removeClass('dtr-control'); 351 352 // Restore the columns that we've hidden 353 $.each( that.s.current, function ( i, val ) { 354 if ( val === false ) { 355 that._setColumnVis( i, true ); 356 } 357 } ); 358 } ); 359 360 // Reorder the breakpoints array here in case they have been added out 361 // of order 362 this.c.breakpoints.sort( function (a, b) { 363 return a.width < b.width ? 1 : 364 a.width > b.width ? -1 : 0; 365 } ); 366 367 this._classLogic(); 368 this._resizeAuto(); 369 370 // Details handler 371 var details = this.c.details; 372 373 if ( details.type !== false ) { 374 that._detailsInit(); 375 376 // DataTables will trigger this event on every column it shows and 377 // hides individually 378 dt.on( 'column-visibility.dtr', function () { 379 // Use a small debounce to allow multiple columns to be set together 380 if ( that._timer ) { 381 clearTimeout( that._timer ); 382 } 383 384 that._timer = setTimeout( function () { 385 that._timer = null; 386 387 that._classLogic(); 388 that._resizeAuto(); 389 that._resize(true); 390 391 that._redrawChildren(); 392 }, 100 ); 393 } ); 394 395 // Redraw the details box on each draw which will happen if the data 396 // has changed. This is used until DataTables implements a native 397 // `updated` event for rows 398 dt.on( 'draw.dtr', function () { 399 that._redrawChildren(); 400 } ); 401 402 $(dt.table().node()).addClass( 'dtr-'+details.type ); 403 } 404 405 dt.on( 'column-reorder.dtr', function (e, settings, details) { 406 that._classLogic(); 407 that._resizeAuto(); 408 that._resize(true); 409 } ); 410 411 // Change in column sizes means we need to calc 412 dt.on( 'column-sizing.dtr', function () { 413 that._resizeAuto(); 414 that._resize(); 415 }); 416 417 // On Ajax reload we want to reopen any child rows which are displayed 418 // by responsive 419 dt.on( 'preXhr.dtr', function () { 420 var rowIds = []; 421 dt.rows().every( function () { 422 if ( this.child.isShown() ) { 423 rowIds.push( this.id(true) ); 424 } 425 } ); 426 427 dt.one( 'draw.dtr', function () { 428 that._resizeAuto(); 429 that._resize(); 430 431 dt.rows( rowIds ).every( function () { 432 that._detailsDisplay( this, false ); 433 } ); 434 } ); 435 }); 436 437 dt 438 .on( 'draw.dtr', function () { 439 that._controlClass(); 440 }) 441 .on( 'init.dtr', function (e, settings, details) { 442 if ( e.namespace !== 'dt' ) { 443 return; 444 } 445 446 that._resizeAuto(); 447 that._resize(); 448 449 // If columns were hidden, then DataTables needs to adjust the 450 // column sizing 451 if ( $.inArray( false, that.s.current ) ) { 452 dt.columns.adjust(); 453 } 454 } ); 455 456 // First pass - draw the table for the current viewport size 457 this._resize(); 458 }, 459 460 461 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 462 * Private methods 463 */ 464 465 /** 466 * Calculate the visibility for the columns in a table for a given 467 * breakpoint. The result is pre-determined based on the class logic if 468 * class names are used to control all columns, but the width of the table 469 * is also used if there are columns which are to be automatically shown 470 * and hidden. 471 * 472 * @param {string} breakpoint Breakpoint name to use for the calculation 473 * @return {array} Array of boolean values initiating the visibility of each 474 * column. 475 * @private 476 */ 477 _columnsVisiblity: function ( breakpoint ) 478 { 479 var dt = this.s.dt; 480 var columns = this.s.columns; 481 var i, ien; 482 483 // Create an array that defines the column ordering based first on the 484 // column's priority, and secondly the column index. This allows the 485 // columns to be removed from the right if the priority matches 486 var order = columns 487 .map( function ( col, idx ) { 488 return { 489 columnIdx: idx, 490 priority: col.priority 491 }; 492 } ) 493 .sort( function ( a, b ) { 494 if ( a.priority !== b.priority ) { 495 return a.priority - b.priority; 496 } 497 return a.columnIdx - b.columnIdx; 498 } ); 499 500 // Class logic - determine which columns are in this breakpoint based 501 // on the classes. If no class control (i.e. `auto`) then `-` is used 502 // to indicate this to the rest of the function 503 var display = $.map( columns, function ( col, i ) { 504 if ( dt.column(i).visible() === false ) { 505 return 'not-visible'; 506 } 507 return col.auto && col.minWidth === null ? 508 false : 509 col.auto === true ? 510 '-' : 511 $.inArray( breakpoint, col.includeIn ) !== -1; 512 } ); 513 514 // Auto column control - first pass: how much width is taken by the 515 // ones that must be included from the non-auto columns 516 var requiredWidth = 0; 517 for ( i=0, ien=display.length ; i<ien ; i++ ) { 518 if ( display[i] === true ) { 519 requiredWidth += columns[i].minWidth; 520 } 521 } 522 523 // Second pass, use up any remaining width for other columns. For 524 // scrolling tables we need to subtract the width of the scrollbar. It 525 // may not be requires which makes this sub-optimal, but it would 526 // require another full redraw to make complete use of those extra few 527 // pixels 528 var scrolling = dt.settings()[0].oScroll; 529 var bar = scrolling.sY || scrolling.sX ? scrolling.iBarWidth : 0; 530 var widthAvailable = dt.table().container().offsetWidth - bar; 531 var usedWidth = widthAvailable - requiredWidth; 532 533 // Control column needs to always be included. This makes it sub- 534 // optimal in terms of using the available with, but to stop layout 535 // thrashing or overflow. Also we need to account for the control column 536 // width first so we know how much width is available for the other 537 // columns, since the control column might not be the first one shown 538 for ( i=0, ien=display.length ; i<ien ; i++ ) { 539 if ( columns[i].control ) { 540 usedWidth -= columns[i].minWidth; 541 } 542 } 543 544 // Allow columns to be shown (counting by priority and then right to 545 // left) until we run out of room 546 var empty = false; 547 for ( i=0, ien=order.length ; i<ien ; i++ ) { 548 var colIdx = order[i].columnIdx; 549 550 if ( display[colIdx] === '-' && ! columns[colIdx].control && columns[colIdx].minWidth ) { 551 // Once we've found a column that won't fit we don't let any 552 // others display either, or columns might disappear in the 553 // middle of the table 554 if ( empty || usedWidth - columns[colIdx].minWidth < 0 ) { 555 empty = true; 556 display[colIdx] = false; 557 } 558 else { 559 display[colIdx] = true; 560 } 561 562 usedWidth -= columns[colIdx].minWidth; 563 } 564 } 565 566 // Determine if the 'control' column should be shown (if there is one). 567 // This is the case when there is a hidden column (that is not the 568 // control column). The two loops look inefficient here, but they are 569 // trivial and will fly through. We need to know the outcome from the 570 // first , before the action in the second can be taken 571 var showControl = false; 572 573 for ( i=0, ien=columns.length ; i<ien ; i++ ) { 574 if ( ! columns[i].control && ! columns[i].never && display[i] === false ) { 575 showControl = true; 576 break; 577 } 578 } 579 580 for ( i=0, ien=columns.length ; i<ien ; i++ ) { 581 if ( columns[i].control ) { 582 display[i] = showControl; 583 } 584 585 // Replace not visible string with false from the control column detection above 586 if ( display[i] === 'not-visible' ) { 587 display[i] = false; 588 } 589 } 590 591 // Finally we need to make sure that there is at least one column that 592 // is visible 593 if ( $.inArray( true, display ) === -1 ) { 594 display[0] = true; 595 } 596 597 return display; 598 }, 599 600 601 /** 602 * Create the internal `columns` array with information about the columns 603 * for the table. This includes determining which breakpoints the column 604 * will appear in, based upon class names in the column, which makes up the 605 * vast majority of this method. 606 * 607 * @private 608 */ 609 _classLogic: function () 610 { 611 var that = this; 612 var calc = {}; 613 var breakpoints = this.c.breakpoints; 614 var dt = this.s.dt; 615 var columns = dt.columns().eq(0).map( function (i) { 616 var column = this.column(i); 617 var className = column.header().className; 618 var priority = dt.settings()[0].aoColumns[i].responsivePriority; 619 var dataPriority = column.header().getAttribute('data-priority'); 620 621 if ( priority === undefined ) { 622 priority = dataPriority === undefined || dataPriority === null? 623 10000 : 624 dataPriority * 1; 625 } 626 627 return { 628 className: className, 629 includeIn: [], 630 auto: false, 631 control: false, 632 never: className.match(/\bnever\b/) ? true : false, 633 priority: priority 634 }; 635 } ); 636 637 // Simply add a breakpoint to `includeIn` array, ensuring that there are 638 // no duplicates 639 var add = function ( colIdx, name ) { 640 var includeIn = columns[ colIdx ].includeIn; 641 642 if ( $.inArray( name, includeIn ) === -1 ) { 643 includeIn.push( name ); 644 } 645 }; 646 647 var column = function ( colIdx, name, operator, matched ) { 648 var size, i, ien; 649 650 if ( ! operator ) { 651 columns[ colIdx ].includeIn.push( name ); 652 } 653 else if ( operator === 'max-' ) { 654 // Add this breakpoint and all smaller 655 size = that._find( name ).width; 656 657 for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) { 658 if ( breakpoints[i].width <= size ) { 659 add( colIdx, breakpoints[i].name ); 660 } 661 } 662 } 663 else if ( operator === 'min-' ) { 664 // Add this breakpoint and all larger 665 size = that._find( name ).width; 666 667 for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) { 668 if ( breakpoints[i].width >= size ) { 669 add( colIdx, breakpoints[i].name ); 670 } 671 } 672 } 673 else if ( operator === 'not-' ) { 674 // Add all but this breakpoint 675 for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) { 676 if ( breakpoints[i].name.indexOf( matched ) === -1 ) { 677 add( colIdx, breakpoints[i].name ); 678 } 679 } 680 } 681 }; 682 683 // Loop over each column and determine if it has a responsive control 684 // class 685 columns.each( function ( col, i ) { 686 var classNames = col.className.split(' '); 687 var hasClass = false; 688 689 // Split the class name up so multiple rules can be applied if needed 690 for ( var k=0, ken=classNames.length ; k<ken ; k++ ) { 691 var className = classNames[k].trim(); 692 693 if ( className === 'all' ) { 694 // Include in all 695 hasClass = true; 696 col.includeIn = $.map( breakpoints, function (a) { 697 return a.name; 698 } ); 699 return; 700 } 701 else if ( className === 'none' || col.never ) { 702 // Include in none (default) and no auto 703 hasClass = true; 704 return; 705 } 706 else if ( className === 'control' || className === 'dtr-control' ) { 707 // Special column that is only visible, when one of the other 708 // columns is hidden. This is used for the details control 709 hasClass = true; 710 col.control = true; 711 return; 712 } 713 714 $.each( breakpoints, function ( j, breakpoint ) { 715 // Does this column have a class that matches this breakpoint? 716 var brokenPoint = breakpoint.name.split('-'); 717 var re = new RegExp( '(min\\-|max\\-|not\\-)?('+brokenPoint[0]+')(\\-[_a-zA-Z0-9])?' ); 718 var match = className.match( re ); 719 720 if ( match ) { 721 hasClass = true; 722 723 if ( match[2] === brokenPoint[0] && match[3] === '-'+brokenPoint[1] ) { 724 // Class name matches breakpoint name fully 725 column( i, breakpoint.name, match[1], match[2]+match[3] ); 726 } 727 else if ( match[2] === brokenPoint[0] && ! match[3] ) { 728 // Class name matched primary breakpoint name with no qualifier 729 column( i, breakpoint.name, match[1], match[2] ); 730 } 731 } 732 } ); 733 } 734 735 // If there was no control class, then automatic sizing is used 736 if ( ! hasClass ) { 737 col.auto = true; 738 } 739 } ); 740 741 this.s.columns = columns; 742 }, 743 744 /** 745 * Update the cells to show the correct control class / button 746 * @private 747 */ 748 _controlClass: function () 749 { 750 if ( this.c.details.type === 'inline' ) { 751 var dt = this.s.dt; 752 var columnsVis = this.s.current; 753 var firstVisible = $.inArray(true, columnsVis); 754 755 // Remove from any cells which shouldn't have it 756 dt.cells( 757 null, 758 function(idx) { 759 return idx !== firstVisible; 760 }, 761 {page: 'current'} 762 ) 763 .nodes() 764 .to$() 765 .filter('.dtr-control') 766 .removeClass('dtr-control'); 767 768 dt.cells(null, firstVisible, {page: 'current'}) 769 .nodes() 770 .to$() 771 .addClass('dtr-control'); 772 } 773 }, 774 775 /** 776 * Show the details for the child row 777 * 778 * @param {DataTables.Api} row API instance for the row 779 * @param {boolean} update Update flag 780 * @private 781 */ 782 _detailsDisplay: function ( row, update ) 783 { 784 var that = this; 785 var dt = this.s.dt; 786 var details = this.c.details; 787 788 if ( details && details.type !== false ) { 789 var res = details.display( row, update, function () { 790 return details.renderer( 791 dt, row[0], that._detailsObj(row[0]) 792 ); 793 } ); 794 795 if ( res === true || res === false ) { 796 $(dt.table().node()).triggerHandler( 'responsive-display.dt', [dt, row, res, update] ); 797 } 798 } 799 }, 800 801 802 /** 803 * Initialisation for the details handler 804 * 805 * @private 806 */ 807 _detailsInit: function () 808 { 809 var that = this; 810 var dt = this.s.dt; 811 var details = this.c.details; 812 813 // The inline type always uses the first child as the target 814 if ( details.type === 'inline' ) { 815 details.target = 'td.dtr-control, th.dtr-control'; 816 } 817 818 // Keyboard accessibility 819 dt.on( 'draw.dtr', function () { 820 that._tabIndexes(); 821 } ); 822 that._tabIndexes(); // Initial draw has already happened 823 824 $( dt.table().body() ).on( 'keyup.dtr', 'td, th', function (e) { 825 if ( e.keyCode === 13 && $(this).data('dtr-keyboard') ) { 826 $(this).click(); 827 } 828 } ); 829 830 // type.target can be a string jQuery selector or a column index 831 var target = details.target; 832 var selector = typeof target === 'string' ? target : 'td, th'; 833 834 if ( target !== undefined || target !== null ) { 835 // Click handler to show / hide the details rows when they are available 836 $( dt.table().body() ) 837 .on( 'click.dtr mousedown.dtr mouseup.dtr', selector, function (e) { 838 // If the table is not collapsed (i.e. there is no hidden columns) 839 // then take no action 840 if ( ! $(dt.table().node()).hasClass('collapsed' ) ) { 841 return; 842 } 843 844 // Check that the row is actually a DataTable's controlled node 845 if ( $.inArray( $(this).closest('tr').get(0), dt.rows().nodes().toArray() ) === -1 ) { 846 return; 847 } 848 849 // For column index, we determine if we should act or not in the 850 // handler - otherwise it is already okay 851 if ( typeof target === 'number' ) { 852 var targetIdx = target < 0 ? 853 dt.columns().eq(0).length + target : 854 target; 855 856 if ( dt.cell( this ).index().column !== targetIdx ) { 857 return; 858 } 859 } 860 861 // $().closest() includes itself in its check 862 var row = dt.row( $(this).closest('tr') ); 863 864 // Check event type to do an action 865 if ( e.type === 'click' ) { 866 // The renderer is given as a function so the caller can execute it 867 // only when they need (i.e. if hiding there is no point is running 868 // the renderer) 869 that._detailsDisplay( row, false ); 870 } 871 else if ( e.type === 'mousedown' ) { 872 // For mouse users, prevent the focus ring from showing 873 $(this).css('outline', 'none'); 874 } 875 else if ( e.type === 'mouseup' ) { 876 // And then re-allow at the end of the click 877 $(this).trigger('blur').css('outline', ''); 878 } 879 } ); 880 } 881 }, 882 883 884 /** 885 * Get the details to pass to a renderer for a row 886 * @param {int} rowIdx Row index 887 * @private 888 */ 889 _detailsObj: function ( rowIdx ) 890 { 891 var that = this; 892 var dt = this.s.dt; 893 894 return $.map( this.s.columns, function( col, i ) { 895 // Never and control columns should not be passed to the renderer 896 if ( col.never || col.control ) { 897 return; 898 } 899 900 var dtCol = dt.settings()[0].aoColumns[ i ]; 901 902 return { 903 className: dtCol.sClass, 904 columnIndex: i, 905 data: dt.cell( rowIdx, i ).render( that.c.orthogonal ), 906 hidden: dt.column( i ).visible() && !that.s.current[ i ], 907 rowIndex: rowIdx, 908 title: dtCol.sTitle !== null ? 909 dtCol.sTitle : 910 $(dt.column(i).header()).text() 911 }; 912 } ); 913 }, 914 915 916 /** 917 * Find a breakpoint object from a name 918 * 919 * @param {string} name Breakpoint name to find 920 * @return {object} Breakpoint description object 921 * @private 922 */ 923 _find: function ( name ) 924 { 925 var breakpoints = this.c.breakpoints; 926 927 for ( var i=0, ien=breakpoints.length ; i<ien ; i++ ) { 928 if ( breakpoints[i].name === name ) { 929 return breakpoints[i]; 930 } 931 } 932 }, 933 934 935 /** 936 * Re-create the contents of the child rows as the display has changed in 937 * some way. 938 * 939 * @private 940 */ 941 _redrawChildren: function () 942 { 943 var that = this; 944 var dt = this.s.dt; 945 946 dt.rows( {page: 'current'} ).iterator( 'row', function ( settings, idx ) { 947 var row = dt.row( idx ); 948 949 that._detailsDisplay( dt.row( idx ), true ); 950 } ); 951 }, 952 953 954 /** 955 * Alter the table display for a resized viewport. This involves first 956 * determining what breakpoint the window currently is in, getting the 957 * column visibilities to apply and then setting them. 958 * 959 * @param {boolean} forceRedraw Force a redraw 960 * @private 961 */ 962 _resize: function (forceRedraw) 963 { 964 var that = this; 965 var dt = this.s.dt; 966 var width = $(window).innerWidth(); 967 var breakpoints = this.c.breakpoints; 968 var breakpoint = breakpoints[0].name; 969 var columns = this.s.columns; 970 var i, ien; 971 var oldVis = this.s.current.slice(); 972 973 // Determine what breakpoint we are currently at 974 for ( i=breakpoints.length-1 ; i>=0 ; i-- ) { 975 if ( width <= breakpoints[i].width ) { 976 breakpoint = breakpoints[i].name; 977 break; 978 } 979 } 980 981 // Show the columns for that break point 982 var columnsVis = this._columnsVisiblity( breakpoint ); 983 this.s.current = columnsVis; 984 985 // Set the class before the column visibility is changed so event 986 // listeners know what the state is. Need to determine if there are 987 // any columns that are not visible but can be shown 988 var collapsedClass = false; 989 990 for ( i=0, ien=columns.length ; i<ien ; i++ ) { 991 if ( columnsVis[i] === false && ! columns[i].never && ! columns[i].control && ! dt.column(i).visible() === false ) { 992 collapsedClass = true; 993 break; 994 } 995 } 996 997 $( dt.table().node() ).toggleClass( 'collapsed', collapsedClass ); 998 999 var changed = false; 1000 var visible = 0; 1001 1002 dt.columns().eq(0).each( function ( colIdx, i ) { 1003 if ( columnsVis[i] === true ) { 1004 visible++; 1005 } 1006 1007 if ( forceRedraw || columnsVis[i] !== oldVis[i] ) { 1008 changed = true; 1009 that._setColumnVis( colIdx, columnsVis[i] ); 1010 } 1011 } ); 1012 1013 if ( changed ) { 1014 this._redrawChildren(); 1015 1016 // Inform listeners of the change 1017 $(dt.table().node()).trigger( 'responsive-resize.dt', [dt, this.s.current] ); 1018 1019 // If no records, update the "No records" display element 1020 if ( dt.page.info().recordsDisplay === 0 ) { 1021 $('td', dt.table().body()).eq(0).attr('colspan', visible); 1022 } 1023 } 1024 1025 that._controlClass(); 1026 }, 1027 1028 1029 /** 1030 * Determine the width of each column in the table so the auto column hiding 1031 * has that information to work with. This method is never going to be 100% 1032 * perfect since column widths can change slightly per page, but without 1033 * seriously compromising performance this is quite effective. 1034 * 1035 * @private 1036 */ 1037 _resizeAuto: function () 1038 { 1039 var dt = this.s.dt; 1040 var columns = this.s.columns; 1041 1042 // Are we allowed to do auto sizing? 1043 if ( ! this.c.auto ) { 1044 return; 1045 } 1046 1047 // Are there any columns that actually need auto-sizing, or do they all 1048 // have classes defined 1049 if ( $.inArray( true, $.map( columns, function (c) { return c.auto; } ) ) === -1 ) { 1050 return; 1051 } 1052 1053 // Need to restore all children. They will be reinstated by a re-render 1054 if ( ! $.isEmptyObject( _childNodeStore ) ) { 1055 $.each( _childNodeStore, function ( key ) { 1056 var idx = key.split('-'); 1057 1058 _childNodesRestore( dt, idx[0]*1, idx[1]*1 ); 1059 } ); 1060 } 1061 1062 // Clone the table with the current data in it 1063 var tableWidth = dt.table().node().offsetWidth; 1064 var columnWidths = dt.columns; 1065 var clonedTable = dt.table().node().cloneNode( false ); 1066 var clonedHeader = $( dt.table().header().cloneNode( false ) ).appendTo( clonedTable ); 1067 var clonedBody = $( dt.table().body() ).clone( false, false ).empty().appendTo( clonedTable ); // use jQuery because of IE8 1068 1069 clonedTable.style.width = 'auto'; 1070 1071 // Header 1072 var headerCells = dt.columns() 1073 .header() 1074 .filter( function (idx) { 1075 return dt.column(idx).visible(); 1076 } ) 1077 .to$() 1078 .clone( false ) 1079 .css( 'display', 'table-cell' ) 1080 .css( 'width', 'auto' ) 1081 .css( 'min-width', 0 ); 1082 1083 // Body rows - we don't need to take account of DataTables' column 1084 // visibility since we implement our own here (hence the `display` set) 1085 $(clonedBody) 1086 .append( $(dt.rows( { page: 'current' } ).nodes()).clone( false ) ) 1087 .find( 'th, td' ).css( 'display', '' ); 1088 1089 // Footer 1090 var footer = dt.table().footer(); 1091 if ( footer ) { 1092 var clonedFooter = $( footer.cloneNode( false ) ).appendTo( clonedTable ); 1093 var footerCells = dt.columns() 1094 .footer() 1095 .filter( function (idx) { 1096 return dt.column(idx).visible(); 1097 } ) 1098 .to$() 1099 .clone( false ) 1100 .css( 'display', 'table-cell' ); 1101 1102 $('<tr/>') 1103 .append( footerCells ) 1104 .appendTo( clonedFooter ); 1105 } 1106 1107 $('<tr/>') 1108 .append( headerCells ) 1109 .appendTo( clonedHeader ); 1110 1111 // In the inline case extra padding is applied to the first column to 1112 // give space for the show / hide icon. We need to use this in the 1113 // calculation 1114 if ( this.c.details.type === 'inline' ) { 1115 $(clonedTable).addClass( 'dtr-inline collapsed' ); 1116 } 1117 1118 // It is unsafe to insert elements with the same name into the DOM 1119 // multiple times. For example, cloning and inserting a checked radio 1120 // clears the chcecked state of the original radio. 1121 $( clonedTable ).find( '[name]' ).removeAttr( 'name' ); 1122 1123 // A position absolute table would take the table out of the flow of 1124 // our container element, bypassing the height and width (Scroller) 1125 $( clonedTable ).css( 'position', 'relative' ) 1126 1127 var inserted = $('<div/>') 1128 .css( { 1129 width: 1, 1130 height: 1, 1131 overflow: 'hidden', 1132 clear: 'both' 1133 } ) 1134 .append( clonedTable ); 1135 1136 inserted.insertBefore( dt.table().node() ); 1137 1138 // The cloned header now contains the smallest that each column can be 1139 headerCells.each( function (i) { 1140 var idx = dt.column.index( 'fromVisible', i ); 1141 columns[ idx ].minWidth = this.offsetWidth || 0; 1142 } ); 1143 1144 inserted.remove(); 1145 }, 1146 1147 /** 1148 * Get the state of the current hidden columns - controlled by Responsive only 1149 */ 1150 _responsiveOnlyHidden: function () 1151 { 1152 var dt = this.s.dt; 1153 1154 return $.map( this.s.current, function (v, i) { 1155 // If the column is hidden by DataTables then it can't be hidden by 1156 // Responsive! 1157 if ( dt.column(i).visible() === false ) { 1158 return true; 1159 } 1160 return v; 1161 } ); 1162 }, 1163 1164 /** 1165 * Set a column's visibility. 1166 * 1167 * We don't use DataTables' column visibility controls in order to ensure 1168 * that column visibility can Responsive can no-exist. Since only IE8+ is 1169 * supported (and all evergreen browsers of course) the control of the 1170 * display attribute works well. 1171 * 1172 * @param {integer} col Column index 1173 * @param {boolean} showHide Show or hide (true or false) 1174 * @private 1175 */ 1176 _setColumnVis: function ( col, showHide ) 1177 { 1178 var dt = this.s.dt; 1179 var display = showHide ? '' : 'none'; // empty string will remove the attr 1180 1181 $( dt.column( col ).header() ).css( 'display', display ); 1182 $( dt.column( col ).footer() ).css( 'display', display ); 1183 dt.column( col ).nodes().to$().css( 'display', display ); 1184 1185 // If the are child nodes stored, we might need to reinsert them 1186 if ( ! $.isEmptyObject( _childNodeStore ) ) { 1187 dt.cells( null, col ).indexes().each( function (idx) { 1188 _childNodesRestore( dt, idx.row, idx.column ); 1189 } ); 1190 } 1191 }, 1192 1193 1194 /** 1195 * Update the cell tab indexes for keyboard accessibility. This is called on 1196 * every table draw - that is potentially inefficient, but also the least 1197 * complex option given that column visibility can change on the fly. Its a 1198 * shame user-focus was removed from CSS 3 UI, as it would have solved this 1199 * issue with a single CSS statement. 1200 * 1201 * @private 1202 */ 1203 _tabIndexes: function () 1204 { 1205 var dt = this.s.dt; 1206 var cells = dt.cells( { page: 'current' } ).nodes().to$(); 1207 var ctx = dt.settings()[0]; 1208 var target = this.c.details.target; 1209 1210 cells.filter( '[data-dtr-keyboard]' ).removeData( '[data-dtr-keyboard]' ); 1211 1212 if ( typeof target === 'number' ) { 1213 dt.cells( null, target, { page: 'current' } ).nodes().to$() 1214 .attr( 'tabIndex', ctx.iTabIndex ) 1215 .data( 'dtr-keyboard', 1 ); 1216 } 1217 else { 1218 // This is a bit of a hack - we need to limit the selected nodes to just 1219 // those of this table 1220 if ( target === 'td:first-child, th:first-child' ) { 1221 target = '>td:first-child, >th:first-child'; 1222 } 1223 1224 $( target, dt.rows( { page: 'current' } ).nodes() ) 1225 .attr( 'tabIndex', ctx.iTabIndex ) 1226 .data( 'dtr-keyboard', 1 ); 1227 } 1228 } 1229} ); 1230 1231 1232/** 1233 * List of default breakpoints. Each item in the array is an object with two 1234 * properties: 1235 * 1236 * * `name` - the breakpoint name. 1237 * * `width` - the breakpoint width 1238 * 1239 * @name Responsive.breakpoints 1240 * @static 1241 */ 1242Responsive.breakpoints = [ 1243 { name: 'desktop', width: Infinity }, 1244 { name: 'tablet-l', width: 1024 }, 1245 { name: 'tablet-p', width: 768 }, 1246 { name: 'mobile-l', width: 480 }, 1247 { name: 'mobile-p', width: 320 } 1248]; 1249 1250 1251/** 1252 * Display methods - functions which define how the hidden data should be shown 1253 * in the table. 1254 * 1255 * @namespace 1256 * @name Responsive.defaults 1257 * @static 1258 */ 1259Responsive.display = { 1260 childRow: function ( row, update, render ) { 1261 if ( update ) { 1262 if ( $(row.node()).hasClass('parent') ) { 1263 row.child( render(), 'child' ).show(); 1264 1265 return true; 1266 } 1267 } 1268 else { 1269 if ( ! row.child.isShown() ) { 1270 row.child( render(), 'child' ).show(); 1271 $( row.node() ).addClass( 'parent' ); 1272 1273 return true; 1274 } 1275 else { 1276 row.child( false ); 1277 $( row.node() ).removeClass( 'parent' ); 1278 1279 return false; 1280 } 1281 } 1282 }, 1283 1284 childRowImmediate: function ( row, update, render ) { 1285 if ( (! update && row.child.isShown()) || ! row.responsive.hasHidden() ) { 1286 // User interaction and the row is show, or nothing to show 1287 row.child( false ); 1288 $( row.node() ).removeClass( 'parent' ); 1289 1290 return false; 1291 } 1292 else { 1293 // Display 1294 row.child( render(), 'child' ).show(); 1295 $( row.node() ).addClass( 'parent' ); 1296 1297 return true; 1298 } 1299 }, 1300 1301 // This is a wrapper so the modal options for Bootstrap and jQuery UI can 1302 // have options passed into them. This specific one doesn't need to be a 1303 // function but it is for consistency in the `modal` name 1304 modal: function ( options ) { 1305 return function ( row, update, render ) { 1306 if ( ! update ) { 1307 // Show a modal 1308 var close = function () { 1309 modal.remove(); // will tidy events for us 1310 $(document).off( 'keypress.dtr' ); 1311 }; 1312 1313 var modal = $('<div class="dtr-modal"/>') 1314 .append( $('<div class="dtr-modal-display"/>') 1315 .append( $('<div class="dtr-modal-content"/>') 1316 .append( render() ) 1317 ) 1318 .append( $('<div class="dtr-modal-close">×</div>' ) 1319 .click( function () { 1320 close(); 1321 } ) 1322 ) 1323 ) 1324 .append( $('<div class="dtr-modal-background"/>') 1325 .click( function () { 1326 close(); 1327 } ) 1328 ) 1329 .appendTo( 'body' ); 1330 1331 $(document).on( 'keyup.dtr', function (e) { 1332 if ( e.keyCode === 27 ) { 1333 e.stopPropagation(); 1334 1335 close(); 1336 } 1337 } ); 1338 } 1339 else { 1340 $('div.dtr-modal-content') 1341 .empty() 1342 .append( render() ); 1343 } 1344 1345 if ( options && options.header ) { 1346 $('div.dtr-modal-content').prepend( 1347 '<h2>'+options.header( row )+'</h2>' 1348 ); 1349 } 1350 }; 1351 } 1352}; 1353 1354 1355var _childNodeStore = {}; 1356 1357function _childNodes( dt, row, col ) { 1358 var name = row+'-'+col; 1359 1360 if ( _childNodeStore[ name ] ) { 1361 return _childNodeStore[ name ]; 1362 } 1363 1364 // https://jsperf.com/childnodes-array-slice-vs-loop 1365 var nodes = []; 1366 var children = dt.cell( row, col ).node().childNodes; 1367 for ( var i=0, ien=children.length ; i<ien ; i++ ) { 1368 nodes.push( children[i] ); 1369 } 1370 1371 _childNodeStore[ name ] = nodes; 1372 1373 return nodes; 1374} 1375 1376function _childNodesRestore( dt, row, col ) { 1377 var name = row+'-'+col; 1378 1379 if ( ! _childNodeStore[ name ] ) { 1380 return; 1381 } 1382 1383 var node = dt.cell( row, col ).node(); 1384 var store = _childNodeStore[ name ]; 1385 var parent = store[0].parentNode; 1386 var parentChildren = parent.childNodes; 1387 var a = []; 1388 1389 for ( var i=0, ien=parentChildren.length ; i<ien ; i++ ) { 1390 a.push( parentChildren[i] ); 1391 } 1392 1393 for ( var j=0, jen=a.length ; j<jen ; j++ ) { 1394 node.appendChild( a[j] ); 1395 } 1396 1397 _childNodeStore[ name ] = undefined; 1398} 1399 1400 1401/** 1402 * Display methods - functions which define how the hidden data should be shown 1403 * in the table. 1404 * 1405 * @namespace 1406 * @name Responsive.defaults 1407 * @static 1408 */ 1409Responsive.renderer = { 1410 listHiddenNodes: function () { 1411 return function ( api, rowIdx, columns ) { 1412 var ul = $('<ul data-dtr-index="'+rowIdx+'" class="dtr-details"/>'); 1413 var found = false; 1414 1415 var data = $.each( columns, function ( i, col ) { 1416 if ( col.hidden ) { 1417 var klass = col.className ? 1418 'class="'+ col.className +'"' : 1419 ''; 1420 1421 $( 1422 '<li '+klass+' data-dtr-index="'+col.columnIndex+'" data-dt-row="'+col.rowIndex+'" data-dt-column="'+col.columnIndex+'">'+ 1423 '<span class="dtr-title">'+ 1424 col.title+ 1425 '</span> '+ 1426 '</li>' 1427 ) 1428 .append( $('<span class="dtr-data"/>').append( _childNodes( api, col.rowIndex, col.columnIndex ) ) )// api.cell( col.rowIndex, col.columnIndex ).node().childNodes ) ) 1429 .appendTo( ul ); 1430 1431 found = true; 1432 } 1433 } ); 1434 1435 return found ? 1436 ul : 1437 false; 1438 }; 1439 }, 1440 1441 listHidden: function () { 1442 return function ( api, rowIdx, columns ) { 1443 var data = $.map( columns, function ( col ) { 1444 var klass = col.className ? 1445 'class="'+ col.className +'"' : 1446 ''; 1447 1448 return col.hidden ? 1449 '<li '+klass+' data-dtr-index="'+col.columnIndex+'" data-dt-row="'+col.rowIndex+'" data-dt-column="'+col.columnIndex+'">'+ 1450 '<span class="dtr-title">'+ 1451 col.title+ 1452 '</span> '+ 1453 '<span class="dtr-data">'+ 1454 col.data+ 1455 '</span>'+ 1456 '</li>' : 1457 ''; 1458 } ).join(''); 1459 1460 return data ? 1461 $('<ul data-dtr-index="'+rowIdx+'" class="dtr-details"/>').append( data ) : 1462 false; 1463 } 1464 }, 1465 1466 tableAll: function ( options ) { 1467 options = $.extend( { 1468 tableClass: '' 1469 }, options ); 1470 1471 return function ( api, rowIdx, columns ) { 1472 var data = $.map( columns, function ( col ) { 1473 var klass = col.className ? 1474 'class="'+ col.className +'"' : 1475 ''; 1476 1477 return '<tr '+klass+' data-dt-row="'+col.rowIndex+'" data-dt-column="'+col.columnIndex+'">'+ 1478 '<td>'+col.title+':'+'</td> '+ 1479 '<td>'+col.data+'</td>'+ 1480 '</tr>'; 1481 } ).join(''); 1482 1483 return $('<table class="'+options.tableClass+' dtr-details" width="100%"/>').append( data ); 1484 } 1485 } 1486}; 1487 1488/** 1489 * Responsive default settings for initialisation 1490 * 1491 * @namespace 1492 * @name Responsive.defaults 1493 * @static 1494 */ 1495Responsive.defaults = { 1496 /** 1497 * List of breakpoints for the instance. Note that this means that each 1498 * instance can have its own breakpoints. Additionally, the breakpoints 1499 * cannot be changed once an instance has been creased. 1500 * 1501 * @type {Array} 1502 * @default Takes the value of `Responsive.breakpoints` 1503 */ 1504 breakpoints: Responsive.breakpoints, 1505 1506 /** 1507 * Enable / disable auto hiding calculations. It can help to increase 1508 * performance slightly if you disable this option, but all columns would 1509 * need to have breakpoint classes assigned to them 1510 * 1511 * @type {Boolean} 1512 * @default `true` 1513 */ 1514 auto: true, 1515 1516 /** 1517 * Details control. If given as a string value, the `type` property of the 1518 * default object is set to that value, and the defaults used for the rest 1519 * of the object - this is for ease of implementation. 1520 * 1521 * The object consists of the following properties: 1522 * 1523 * * `display` - A function that is used to show and hide the hidden details 1524 * * `renderer` - function that is called for display of the child row data. 1525 * The default function will show the data from the hidden columns 1526 * * `target` - Used as the selector for what objects to attach the child 1527 * open / close to 1528 * * `type` - `false` to disable the details display, `inline` or `column` 1529 * for the two control types 1530 * 1531 * @type {Object|string} 1532 */ 1533 details: { 1534 display: Responsive.display.childRow, 1535 1536 renderer: Responsive.renderer.listHidden(), 1537 1538 target: 0, 1539 1540 type: 'inline' 1541 }, 1542 1543 /** 1544 * Orthogonal data request option. This is used to define the data type 1545 * requested when Responsive gets the data to show in the child row. 1546 * 1547 * @type {String} 1548 */ 1549 orthogonal: 'display' 1550}; 1551 1552 1553/* 1554 * API 1555 */ 1556var Api = $.fn.dataTable.Api; 1557 1558// Doesn't do anything - work around for a bug in DT... Not documented 1559Api.register( 'responsive()', function () { 1560 return this; 1561} ); 1562 1563Api.register( 'responsive.index()', function ( li ) { 1564 li = $(li); 1565 1566 return { 1567 column: li.data('dtr-index'), 1568 row: li.parent().data('dtr-index') 1569 }; 1570} ); 1571 1572Api.register( 'responsive.rebuild()', function () { 1573 return this.iterator( 'table', function ( ctx ) { 1574 if ( ctx._responsive ) { 1575 ctx._responsive._classLogic(); 1576 } 1577 } ); 1578} ); 1579 1580Api.register( 'responsive.recalc()', function () { 1581 return this.iterator( 'table', function ( ctx ) { 1582 if ( ctx._responsive ) { 1583 ctx._responsive._resizeAuto(); 1584 ctx._responsive._resize(); 1585 } 1586 } ); 1587} ); 1588 1589Api.register( 'responsive.hasHidden()', function () { 1590 var ctx = this.context[0]; 1591 1592 return ctx._responsive ? 1593 $.inArray( false, ctx._responsive._responsiveOnlyHidden() ) !== -1 : 1594 false; 1595} ); 1596 1597Api.registerPlural( 'columns().responsiveHidden()', 'column().responsiveHidden()', function () { 1598 return this.iterator( 'column', function ( settings, column ) { 1599 return settings._responsive ? 1600 settings._responsive._responsiveOnlyHidden()[ column ] : 1601 false; 1602 }, 1 ); 1603} ); 1604 1605 1606/** 1607 * Version information 1608 * 1609 * @name Responsive.version 1610 * @static 1611 */ 1612Responsive.version = '2.2.7'; 1613 1614 1615$.fn.dataTable.Responsive = Responsive; 1616$.fn.DataTable.Responsive = Responsive; 1617 1618// Attach a listener to the document which listens for DataTables initialisation 1619// events so we can automatically initialise 1620$(document).on( 'preInit.dt.dtr', function (e, settings, json) { 1621 if ( e.namespace !== 'dt' ) { 1622 return; 1623 } 1624 1625 if ( $(settings.nTable).hasClass( 'responsive' ) || 1626 $(settings.nTable).hasClass( 'dt-responsive' ) || 1627 settings.oInit.responsive || 1628 DataTable.defaults.responsive 1629 ) { 1630 var init = settings.oInit.responsive; 1631 1632 if ( init !== false ) { 1633 new Responsive( settings, $.isPlainObject( init ) ? init : {} ); 1634 } 1635 } 1636} ); 1637 1638 1639return Responsive; 1640})); 1641 1642 1643/***/ }), 1644
vendor: 450,516 bytes, lines 1645-17022
1645/***/ "./node_modules/datatables.net/js/jquery.dataTables.js": 1646/*!*************************************************************!*\ 1647 !*** ./node_modules/datatables.net/js/jquery.dataTables.js ***! 1648 \*************************************************************/ 1649/*! no static exports found */ 1650/***/ (function(module, exports, __webpack_require__) { 1651 1652var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*! DataTables 1.10.24 1653 * ©2008-2021 SpryMedia Ltd - datatables.net/license 1654 */ 1655 1656/** 1657 * @summary DataTables 1658 * @description Paginate, search and order HTML tables 1659 * @version 1.10.24 1660 * @file jquery.dataTables.js 1661 * @author SpryMedia Ltd 1662 * @contact www.datatables.net 1663 * @copyright Copyright 2008-2021 SpryMedia Ltd. 1664 * 1665 * This source file is free software, available under the following license: 1666 * MIT license - http://datatables.net/license 1667 * 1668 * This source file is distributed in the hope that it will be useful, but 1669 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 1670 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. 1671 * 1672 * For details please refer to: http://www.datatables.net 1673 */ 1674 1675/*jslint evil: true, undef: true, browser: true */ 1676/*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*/ 1677 1678(function( factory ) { 1679 "use strict"; 1680 1681 if ( true ) { 1682 // AMD 1683 !(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(/*! jquery */ "./node_modules/jquery/dist/jquery.js")], __WEBPACK_AMD_DEFINE_RESULT__ = (function ( $ ) { 1684 return factory( $, window, document ); 1685 }).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), 1686 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 1687 } 1688 else {} 1689} 1690(function( $, window, document, undefined ) { 1691 "use strict"; 1692 1693 /** 1694 * DataTables is a plug-in for the jQuery Javascript library. It is a highly 1695 * flexible tool, based upon the foundations of progressive enhancement, 1696 * which will add advanced interaction controls to any HTML table. For a 1697 * full list of features please refer to 1698 * [DataTables.net](href="http://datatables.net). 1699 * 1700 * Note that the `DataTable` object is not a global variable but is aliased 1701 * to `jQuery.fn.DataTable` and `jQuery.fn.dataTable` through which it may 1702 * be accessed. 1703 * 1704 * @class 1705 * @param {object} [init={}] Configuration object for DataTables. Options 1706 * are defined by {@link DataTable.defaults} 1707 * @requires jQuery 1.7+ 1708 * 1709 * @example 1710 * // Basic initialisation 1711 * $(document).ready( function { 1712 * $('#example').dataTable(); 1713 * } ); 1714 * 1715 * @example 1716 * // Initialisation with configuration options - in this case, disable 1717 * // pagination and sorting. 1718 * $(document).ready( function { 1719 * $('#example').dataTable( { 1720 * "paginate": false, 1721 * "sort": false 1722 * } ); 1723 * } ); 1724 */ 1725 var DataTable = function ( options ) 1726 { 1727 /** 1728 * Perform a jQuery selector action on the table's TR elements (from the tbody) and 1729 * return the resulting jQuery object. 1730 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on 1731 * @param {object} [oOpts] Optional parameters for modifying the rows to be included 1732 * @param {string} [oOpts.filter=none] Select TR elements that meet the current filter 1733 * criterion ("applied") or all TR elements (i.e. no filter). 1734 * @param {string} [oOpts.order=current] Order of the TR elements in the processed array. 1735 * Can be either 'current', whereby the current sorting of the table is used, or 1736 * 'original' whereby the original order the data was read into the table is used. 1737 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page 1738 * ("current") or not ("all"). If 'current' is given, then order is assumed to be 1739 * 'current' and filter is 'applied', regardless of what they might be given as. 1740 * @returns {object} jQuery object, filtered by the given selector. 1741 * @dtopt API 1742 * @deprecated Since v1.10 1743 * 1744 * @example 1745 * $(document).ready(function() { 1746 * var oTable = $('#example').dataTable(); 1747 * 1748 * // Highlight every second row 1749 * oTable.$('tr:odd').css('backgroundColor', 'blue'); 1750 * } ); 1751 * 1752 * @example 1753 * $(document).ready(function() { 1754 * var oTable = $('#example').dataTable(); 1755 * 1756 * // Filter to rows with 'Webkit' in them, add a background colour and then 1757 * // remove the filter, thus highlighting the 'Webkit' rows only. 1758 * oTable.fnFilter('Webkit'); 1759 * oTable.$('tr', {"search": "applied"}).css('backgroundColor', 'blue'); 1760 * oTable.fnFilter(''); 1761 * } ); 1762 */ 1763 this.$ = function ( sSelector, oOpts ) 1764 { 1765 return this.api(true).$( sSelector, oOpts ); 1766 }; 1767 1768 1769 /** 1770 * Almost identical to $ in operation, but in this case returns the data for the matched 1771 * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes 1772 * rather than any descendants, so the data can be obtained for the row/cell. If matching 1773 * rows are found, the data returned is the original data array/object that was used to 1774 * create the row (or a generated array if from a DOM source). 1775 * 1776 * This method is often useful in-combination with $ where both functions are given the 1777 * same parameters and the array indexes will match identically. 1778 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on 1779 * @param {object} [oOpts] Optional parameters for modifying the rows to be included 1780 * @param {string} [oOpts.filter=none] Select elements that meet the current filter 1781 * criterion ("applied") or all elements (i.e. no filter). 1782 * @param {string} [oOpts.order=current] Order of the data in the processed array. 1783 * Can be either 'current', whereby the current sorting of the table is used, or 1784 * 'original' whereby the original order the data was read into the table is used. 1785 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page 1786 * ("current") or not ("all"). If 'current' is given, then order is assumed to be 1787 * 'current' and filter is 'applied', regardless of what they might be given as. 1788 * @returns {array} Data for the matched elements. If any elements, as a result of the 1789 * selector, were not TR, TD or TH elements in the DataTable, they will have a null 1790 * entry in the array. 1791 * @dtopt API 1792 * @deprecated Since v1.10 1793 * 1794 * @example 1795 * $(document).ready(function() { 1796 * var oTable = $('#example').dataTable(); 1797 * 1798 * // Get the data from the first row in the table 1799 * var data = oTable._('tr:first'); 1800 * 1801 * // Do something useful with the data 1802 * alert( "First cell is: "+data[0] ); 1803 * } ); 1804 * 1805 * @example 1806 * $(document).ready(function() { 1807 * var oTable = $('#example').dataTable(); 1808 * 1809 * // Filter to 'Webkit' and get all data for 1810 * oTable.fnFilter('Webkit'); 1811 * var data = oTable._('tr', {"search": "applied"}); 1812 * 1813 * // Do something with the data 1814 * alert( data.length+" rows matched the search" ); 1815 * } ); 1816 */ 1817 this._ = function ( sSelector, oOpts ) 1818 { 1819 return this.api(true).rows( sSelector, oOpts ).data(); 1820 }; 1821 1822 1823 /** 1824 * Create a DataTables Api instance, with the currently selected tables for 1825 * the Api's context. 1826 * @param {boolean} [traditional=false] Set the API instance's context to be 1827 * only the table referred to by the `DataTable.ext.iApiIndex` option, as was 1828 * used in the API presented by DataTables 1.9- (i.e. the traditional mode), 1829 * or if all tables captured in the jQuery object should be used. 1830 * @return {DataTables.Api} 1831 */ 1832 this.api = function ( traditional ) 1833 { 1834 return traditional ? 1835 new _Api( 1836 _fnSettingsFromNode( this[ _ext.iApiIndex ] ) 1837 ) : 1838 new _Api( this ); 1839 }; 1840 1841 1842 /** 1843 * Add a single new row or multiple rows of data to the table. Please note 1844 * that this is suitable for client-side processing only - if you are using 1845 * server-side processing (i.e. "bServerSide": true), then to add data, you 1846 * must add it to the data source, i.e. the server-side, through an Ajax call. 1847 * @param {array|object} data The data to be added to the table. This can be: 1848 * <ul> 1849 * <li>1D array of data - add a single row with the data provided</li> 1850 * <li>2D array of arrays - add multiple rows in a single call</li> 1851 * <li>object - data object when using <i>mData</i></li> 1852 * <li>array of objects - multiple data objects when using <i>mData</i></li> 1853 * </ul> 1854 * @param {bool} [redraw=true] redraw the table or not 1855 * @returns {array} An array of integers, representing the list of indexes in 1856 * <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to 1857 * the table. 1858 * @dtopt API 1859 * @deprecated Since v1.10 1860 * 1861 * @example 1862 * // Global var for counter 1863 * var giCount = 2; 1864 * 1865 * $(document).ready(function() { 1866 * $('#example').dataTable(); 1867 * } ); 1868 * 1869 * function fnClickAddRow() { 1870 * $('#example').dataTable().fnAddData( [ 1871 * giCount+".1", 1872 * giCount+".2", 1873 * giCount+".3", 1874 * giCount+".4" ] 1875 * ); 1876 * 1877 * giCount++; 1878 * } 1879 */ 1880 this.fnAddData = function( data, redraw ) 1881 { 1882 var api = this.api( true ); 1883 1884 /* Check if we want to add multiple rows or not */ 1885 var rows = Array.isArray(data) && ( Array.isArray(data[0]) || $.isPlainObject(data[0]) ) ? 1886 api.rows.add( data ) : 1887 api.row.add( data ); 1888 1889 if ( redraw === undefined || redraw ) { 1890 api.draw(); 1891 } 1892 1893 return rows.flatten().toArray(); 1894 }; 1895 1896 1897 /** 1898 * This function will make DataTables recalculate the column sizes, based on the data 1899 * contained in the table and the sizes applied to the columns (in the DOM, CSS or 1900 * through the sWidth parameter). This can be useful when the width of the table's 1901 * parent element changes (for example a window resize). 1902 * @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to 1903 * @dtopt API 1904 * @deprecated Since v1.10 1905 * 1906 * @example 1907 * $(document).ready(function() { 1908 * var oTable = $('#example').dataTable( { 1909 * "sScrollY": "200px", 1910 * "bPaginate": false 1911 * } ); 1912 * 1913 * $(window).on('resize', function () { 1914 * oTable.fnAdjustColumnSizing(); 1915 * } ); 1916 * } ); 1917 */ 1918 this.fnAdjustColumnSizing = function ( bRedraw ) 1919 { 1920 var api = this.api( true ).columns.adjust(); 1921 var settings = api.settings()[0]; 1922 var scroll = settings.oScroll; 1923 1924 if ( bRedraw === undefined || bRedraw ) { 1925 api.draw( false ); 1926 } 1927 else if ( scroll.sX !== "" || scroll.sY !== "" ) { 1928 /* If not redrawing, but scrolling, we want to apply the new column sizes anyway */ 1929 _fnScrollDraw( settings ); 1930 } 1931 }; 1932 1933 1934 /** 1935 * Quickly and simply clear a table 1936 * @param {bool} [bRedraw=true] redraw the table or not 1937 * @dtopt API 1938 * @deprecated Since v1.10 1939 * 1940 * @example 1941 * $(document).ready(function() { 1942 * var oTable = $('#example').dataTable(); 1943 * 1944 * // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...) 1945 * oTable.fnClearTable(); 1946 * } ); 1947 */ 1948 this.fnClearTable = function( bRedraw ) 1949 { 1950 var api = this.api( true ).clear(); 1951 1952 if ( bRedraw === undefined || bRedraw ) { 1953 api.draw(); 1954 } 1955 }; 1956 1957 1958 /** 1959 * The exact opposite of 'opening' a row, this function will close any rows which 1960 * are currently 'open'. 1961 * @param {node} nTr the table row to 'close' 1962 * @returns {int} 0 on success, or 1 if failed (can't find the row) 1963 * @dtopt API 1964 * @deprecated Since v1.10 1965 * 1966 * @example 1967 * $(document).ready(function() { 1968 * var oTable; 1969 * 1970 * // 'open' an information row when a row is clicked on 1971 * $('#example tbody tr').click( function () { 1972 * if ( oTable.fnIsOpen(this) ) { 1973 * oTable.fnClose( this ); 1974 * } else { 1975 * oTable.fnOpen( this, "Temporary row opened", "info_row" ); 1976 * } 1977 * } ); 1978 * 1979 * oTable = $('#example').dataTable(); 1980 * } ); 1981 */ 1982 this.fnClose = function( nTr ) 1983 { 1984 this.api( true ).row( nTr ).child.hide(); 1985 }; 1986 1987 1988 /** 1989 * Remove a row for the table 1990 * @param {mixed} target The index of the row from aoData to be deleted, or 1991 * the TR element you want to delete 1992 * @param {function|null} [callBack] Callback function 1993 * @param {bool} [redraw=true] Redraw the table or not 1994 * @returns {array} The row that was deleted 1995 * @dtopt API 1996 * @deprecated Since v1.10 1997 * 1998 * @example 1999 * $(document).ready(function() { 2000 * var oTable = $('#example').dataTable(); 2001 * 2002 * // Immediately remove the first row 2003 * oTable.fnDeleteRow( 0 ); 2004 * } ); 2005 */ 2006 this.fnDeleteRow = function( target, callback, redraw ) 2007 { 2008 var api = this.api( true ); 2009 var rows = api.rows( target ); 2010 var settings = rows.settings()[0]; 2011 var data = settings.aoData[ rows[0][0] ]; 2012 2013 rows.remove(); 2014 2015 if ( callback ) { 2016 callback.call( this, settings, data ); 2017 } 2018 2019 if ( redraw === undefined || redraw ) { 2020 api.draw(); 2021 } 2022 2023 return data; 2024 }; 2025 2026 2027 /** 2028 * Restore the table to it's original state in the DOM by removing all of DataTables 2029 * enhancements, alterations to the DOM structure of the table and event listeners. 2030 * @param {boolean} [remove=false] Completely remove the table from the DOM 2031 * @dtopt API 2032 * @deprecated Since v1.10 2033 * 2034 * @example 2035 * $(document).ready(function() { 2036 * // This example is fairly pointless in reality, but shows how fnDestroy can be used 2037 * var oTable = $('#example').dataTable(); 2038 * oTable.fnDestroy(); 2039 * } ); 2040 */ 2041 this.fnDestroy = function ( remove ) 2042 { 2043 this.api( true ).destroy( remove ); 2044 }; 2045 2046 2047 /** 2048 * Redraw the table 2049 * @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw. 2050 * @dtopt API 2051 * @deprecated Since v1.10 2052 * 2053 * @example 2054 * $(document).ready(function() { 2055 * var oTable = $('#example').dataTable(); 2056 * 2057 * // Re-draw the table - you wouldn't want to do it here, but it's an example :-) 2058 * oTable.fnDraw(); 2059 * } ); 2060 */ 2061 this.fnDraw = function( complete ) 2062 { 2063 // Note that this isn't an exact match to the old call to _fnDraw - it takes 2064 // into account the new data, but can hold position. 2065 this.api( true ).draw( complete ); 2066 }; 2067 2068 2069 /** 2070 * Filter the input based on data 2071 * @param {string} sInput String to filter the table on 2072 * @param {int|null} [iColumn] Column to limit filtering to 2073 * @param {bool} [bRegex=false] Treat as regular expression or not 2074 * @param {bool} [bSmart=true] Perform smart filtering or not 2075 * @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es) 2076 * @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false) 2077 * @dtopt API 2078 * @deprecated Since v1.10 2079 * 2080 * @example 2081 * $(document).ready(function() { 2082 * var oTable = $('#example').dataTable(); 2083 * 2084 * // Sometime later - filter... 2085 * oTable.fnFilter( 'test string' ); 2086 * } ); 2087 */ 2088 this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive ) 2089 { 2090 var api = this.api( true ); 2091 2092 if ( iColumn === null || iColumn === undefined ) { 2093 api.search( sInput, bRegex, bSmart, bCaseInsensitive ); 2094 } 2095 else { 2096 api.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive ); 2097 } 2098 2099 api.draw(); 2100 }; 2101 2102 2103 /** 2104 * Get the data for the whole table, an individual row or an individual cell based on the 2105 * provided parameters. 2106 * @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as 2107 * a TR node then the data source for the whole row will be returned. If given as a 2108 * TD/TH cell node then iCol will be automatically calculated and the data for the 2109 * cell returned. If given as an integer, then this is treated as the aoData internal 2110 * data index for the row (see fnGetPosition) and the data for that row used. 2111 * @param {int} [col] Optional column index that you want the data of. 2112 * @returns {array|object|string} If mRow is undefined, then the data for all rows is 2113 * returned. If mRow is defined, just data for that row, and is iCol is 2114 * defined, only data for the designated cell is returned. 2115 * @dtopt API 2116 * @deprecated Since v1.10 2117 * 2118 * @example 2119 * // Row data 2120 * $(document).ready(function() { 2121 * oTable = $('#example').dataTable(); 2122 * 2123 * oTable.$('tr').click( function () { 2124 * var data = oTable.fnGetData( this ); 2125 * // ... do something with the array / object of data for the row 2126 * } ); 2127 * } ); 2128 * 2129 * @example 2130 * // Individual cell data 2131 * $(document).ready(function() { 2132 * oTable = $('#example').dataTable(); 2133 * 2134 * oTable.$('td').click( function () { 2135 * var sData = oTable.fnGetData( this ); 2136 * alert( 'The cell clicked on had the value of '+sData ); 2137 * } ); 2138 * } ); 2139 */ 2140 this.fnGetData = function( src, col ) 2141 { 2142 var api = this.api( true ); 2143 2144 if ( src !== undefined ) { 2145 var type = src.nodeName ? src.nodeName.toLowerCase() : ''; 2146 2147 return col !== undefined || type == 'td' || type == 'th' ? 2148 api.cell( src, col ).data() : 2149 api.row( src ).data() || null; 2150 } 2151 2152 return api.data().toArray(); 2153 }; 2154 2155 2156 /** 2157 * Get an array of the TR nodes that are used in the table's body. Note that you will 2158 * typically want to use the '$' API method in preference to this as it is more 2159 * flexible. 2160 * @param {int} [iRow] Optional row index for the TR element you want 2161 * @returns {array|node} If iRow is undefined, returns an array of all TR elements 2162 * in the table's body, or iRow is defined, just the TR element requested. 2163 * @dtopt API 2164 * @deprecated Since v1.10 2165 * 2166 * @example 2167 * $(document).ready(function() { 2168 * var oTable = $('#example').dataTable(); 2169 * 2170 * // Get the nodes from the table 2171 * var nNodes = oTable.fnGetNodes( ); 2172 * } ); 2173 */ 2174 this.fnGetNodes = function( iRow ) 2175 { 2176 var api = this.api( true ); 2177 2178 return iRow !== undefined ? 2179 api.row( iRow ).node() : 2180 api.rows().nodes().flatten().toArray(); 2181 }; 2182 2183 2184 /** 2185 * Get the array indexes of a particular cell from it's DOM element 2186 * and column index including hidden columns 2187 * @param {node} node this can either be a TR, TD or TH in the table's body 2188 * @returns {int} If nNode is given as a TR, then a single index is returned, or 2189 * if given as a cell, an array of [row index, column index (visible), 2190 * column index (all)] is given. 2191 * @dtopt API 2192 * @deprecated Since v1.10 2193 * 2194 * @example 2195 * $(document).ready(function() { 2196 * $('#example tbody td').click( function () { 2197 * // Get the position of the current data from the node 2198 * var aPos = oTable.fnGetPosition( this ); 2199 * 2200 * // Get the data array for this row 2201 * var aData = oTable.fnGetData( aPos[0] ); 2202 * 2203 * // Update the data array and return the value 2204 * aData[ aPos[1] ] = 'clicked'; 2205 * this.innerHTML = 'clicked'; 2206 * } ); 2207 * 2208 * // Init DataTables 2209 * oTable = $('#example').dataTable(); 2210 * } ); 2211 */ 2212 this.fnGetPosition = function( node ) 2213 { 2214 var api = this.api( true ); 2215 var nodeName = node.nodeName.toUpperCase(); 2216 2217 if ( nodeName == 'TR' ) { 2218 return api.row( node ).index(); 2219 } 2220 else if ( nodeName == 'TD' || nodeName == 'TH' ) { 2221 var cell = api.cell( node ).index(); 2222 2223 return [ 2224 cell.row, 2225 cell.columnVisible, 2226 cell.column 2227 ]; 2228 } 2229 return null; 2230 }; 2231 2232 2233 /** 2234 * Check to see if a row is 'open' or not. 2235 * @param {node} nTr the table row to check 2236 * @returns {boolean} true if the row is currently open, false otherwise 2237 * @dtopt API 2238 * @deprecated Since v1.10 2239 * 2240 * @example 2241 * $(document).ready(function() { 2242 * var oTable; 2243 * 2244 * // 'open' an information row when a row is clicked on 2245 * $('#example tbody tr').click( function () { 2246 * if ( oTable.fnIsOpen(this) ) { 2247 * oTable.fnClose( this ); 2248 * } else { 2249 * oTable.fnOpen( this, "Temporary row opened", "info_row" ); 2250 * } 2251 * } ); 2252 * 2253 * oTable = $('#example').dataTable(); 2254 * } ); 2255 */ 2256 this.fnIsOpen = function( nTr ) 2257 { 2258 return this.api( true ).row( nTr ).child.isShown(); 2259 }; 2260 2261 2262 /** 2263 * This function will place a new row directly after a row which is currently 2264 * on display on the page, with the HTML contents that is passed into the 2265 * function. This can be used, for example, to ask for confirmation that a 2266 * particular record should be deleted. 2267 * @param {node} nTr The table row to 'open' 2268 * @param {string|node|jQuery} mHtml The HTML to put into the row 2269 * @param {string} sClass Class to give the new TD cell 2270 * @returns {node} The row opened. Note that if the table row passed in as the 2271 * first parameter, is not found in the table, this method will silently 2272 * return. 2273 * @dtopt API 2274 * @deprecated Since v1.10 2275 * 2276 * @example 2277 * $(document).ready(function() { 2278 * var oTable; 2279 * 2280 * // 'open' an information row when a row is clicked on 2281 * $('#example tbody tr').click( function () { 2282 * if ( oTable.fnIsOpen(this) ) { 2283 * oTable.fnClose( this ); 2284 * } else { 2285 * oTable.fnOpen( this, "Temporary row opened", "info_row" ); 2286 * } 2287 * } ); 2288 * 2289 * oTable = $('#example').dataTable(); 2290 * } ); 2291 */ 2292 this.fnOpen = function( nTr, mHtml, sClass ) 2293 { 2294 return this.api( true ) 2295 .row( nTr ) 2296 .child( mHtml, sClass ) 2297 .show() 2298 .child()[0]; 2299 }; 2300 2301 2302 /** 2303 * Change the pagination - provides the internal logic for pagination in a simple API 2304 * function. With this function you can have a DataTables table go to the next, 2305 * previous, first or last pages. 2306 * @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last" 2307 * or page number to jump to (integer), note that page 0 is the first page. 2308 * @param {bool} [bRedraw=true] Redraw the table or not 2309 * @dtopt API 2310 * @deprecated Since v1.10 2311 * 2312 * @example 2313 * $(document).ready(function() { 2314 * var oTable = $('#example').dataTable(); 2315 * oTable.fnPageChange( 'next' ); 2316 * } ); 2317 */ 2318 this.fnPageChange = function ( mAction, bRedraw ) 2319 { 2320 var api = this.api( true ).page( mAction ); 2321 2322 if ( bRedraw === undefined || bRedraw ) { 2323 api.draw(false); 2324 } 2325 }; 2326 2327 2328 /** 2329 * Show a particular column 2330 * @param {int} iCol The column whose display should be changed 2331 * @param {bool} bShow Show (true) or hide (false) the column 2332 * @param {bool} [bRedraw=true] Redraw the table or not 2333 * @dtopt API 2334 * @deprecated Since v1.10 2335 * 2336 * @example 2337 * $(document).ready(function() { 2338 * var oTable = $('#example').dataTable(); 2339 * 2340 * // Hide the second column after initialisation 2341 * oTable.fnSetColumnVis( 1, false ); 2342 * } ); 2343 */ 2344 this.fnSetColumnVis = function ( iCol, bShow, bRedraw ) 2345 { 2346 var api = this.api( true ).column( iCol ).visible( bShow ); 2347 2348 if ( bRedraw === undefined || bRedraw ) { 2349 api.columns.adjust().draw(); 2350 } 2351 }; 2352 2353 2354 /** 2355 * Get the settings for a particular table for external manipulation 2356 * @returns {object} DataTables settings object. See 2357 * {@link DataTable.models.oSettings} 2358 * @dtopt API 2359 * @deprecated Since v1.10 2360 * 2361 * @example 2362 * $(document).ready(function() { 2363 * var oTable = $('#example').dataTable(); 2364 * var oSettings = oTable.fnSettings(); 2365 * 2366 * // Show an example parameter from the settings 2367 * alert( oSettings._iDisplayStart ); 2368 * } ); 2369 */ 2370 this.fnSettings = function() 2371 { 2372 return _fnSettingsFromNode( this[_ext.iApiIndex] ); 2373 }; 2374 2375 2376 /** 2377 * Sort the table by a particular column 2378 * @param {int} iCol the data index to sort on. Note that this will not match the 2379 * 'display index' if you have hidden data entries 2380 * @dtopt API 2381 * @deprecated Since v1.10 2382 * 2383 * @example 2384 * $(document).ready(function() { 2385 * var oTable = $('#example').dataTable(); 2386 * 2387 * // Sort immediately with columns 0 and 1 2388 * oTable.fnSort( [ [0,'asc'], [1,'asc'] ] ); 2389 * } ); 2390 */ 2391 this.fnSort = function( aaSort ) 2392 { 2393 this.api( true ).order( aaSort ).draw(); 2394 }; 2395 2396 2397 /** 2398 * Attach a sort listener to an element for a given column 2399 * @param {node} nNode the element to attach the sort listener to 2400 * @param {int} iColumn the column that a click on this node will sort on 2401 * @param {function} [fnCallback] callback function when sort is run 2402 * @dtopt API 2403 * @deprecated Since v1.10 2404 * 2405 * @example 2406 * $(document).ready(function() { 2407 * var oTable = $('#example').dataTable(); 2408 * 2409 * // Sort on column 1, when 'sorter' is clicked on 2410 * oTable.fnSortListener( document.getElementById('sorter'), 1 ); 2411 * } ); 2412 */ 2413 this.fnSortListener = function( nNode, iColumn, fnCallback ) 2414 { 2415 this.api( true ).order.listener( nNode, iColumn, fnCallback ); 2416 }; 2417 2418 2419 /** 2420 * Update a table cell or row - this method will accept either a single value to 2421 * update the cell with, an array of values with one element for each column or 2422 * an object in the same format as the original data source. The function is 2423 * self-referencing in order to make the multi column updates easier. 2424 * @param {object|array|string} mData Data to update the cell/row with 2425 * @param {node|int} mRow TR element you want to update or the aoData index 2426 * @param {int} [iColumn] The column to update, give as null or undefined to 2427 * update a whole row. 2428 * @param {bool} [bRedraw=true] Redraw the table or not 2429 * @param {bool} [bAction=true] Perform pre-draw actions or not 2430 * @returns {int} 0 on success, 1 on error 2431 * @dtopt API 2432 * @deprecated Since v1.10 2433 * 2434 * @example 2435 * $(document).ready(function() { 2436 * var oTable = $('#example').dataTable(); 2437 * oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell 2438 * oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row 2439 * } ); 2440 */ 2441 this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction ) 2442 { 2443 var api = this.api( true ); 2444 2445 if ( iColumn === undefined || iColumn === null ) { 2446 api.row( mRow ).data( mData ); 2447 } 2448 else { 2449 api.cell( mRow, iColumn ).data( mData ); 2450 } 2451 2452 if ( bAction === undefined || bAction ) { 2453 api.columns.adjust(); 2454 } 2455 2456 if ( bRedraw === undefined || bRedraw ) { 2457 api.draw(); 2458 } 2459 return 0; 2460 }; 2461 2462 2463 /** 2464 * Provide a common method for plug-ins to check the version of DataTables being used, in order 2465 * to ensure compatibility. 2466 * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the 2467 * formats "X" and "X.Y" are also acceptable. 2468 * @returns {boolean} true if this version of DataTables is greater or equal to the required 2469 * version, or false if this version of DataTales is not suitable 2470 * @method 2471 * @dtopt API 2472 * @deprecated Since v1.10 2473 * 2474 * @example 2475 * $(document).ready(function() { 2476 * var oTable = $('#example').dataTable(); 2477 * alert( oTable.fnVersionCheck( '1.9.0' ) ); 2478 * } ); 2479 */ 2480 this.fnVersionCheck = _ext.fnVersionCheck; 2481 2482 2483 var _that = this; 2484 var emptyInit = options === undefined; 2485 var len = this.length; 2486 2487 if ( emptyInit ) { 2488 options = {}; 2489 } 2490 2491 this.oApi = this.internal = _ext.internal; 2492 2493 // Extend with old style plug-in API methods 2494 for ( var fn in DataTable.ext.internal ) { 2495 if ( fn ) { 2496 this[fn] = _fnExternApiFunc(fn); 2497 } 2498 } 2499 2500 this.each(function() { 2501 // For each initialisation we want to give it a clean initialisation 2502 // object that can be bashed around 2503 var o = {}; 2504 var oInit = len > 1 ? // optimisation for single table case 2505 _fnExtend( o, options, true ) : 2506 options; 2507 2508 /*global oInit,_that,emptyInit*/ 2509 var i=0, iLen, j, jLen, k, kLen; 2510 var sId = this.getAttribute( 'id' ); 2511 var bInitHandedOff = false; 2512 var defaults = DataTable.defaults; 2513 var $this = $(this); 2514 2515 2516 /* Sanity check */ 2517 if ( this.nodeName.toLowerCase() != 'table' ) 2518 { 2519 _fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 ); 2520 return; 2521 } 2522 2523 /* Backwards compatibility for the defaults */ 2524 _fnCompatOpts( defaults ); 2525 _fnCompatCols( defaults.column ); 2526 2527 /* Convert the camel-case defaults to Hungarian */ 2528 _fnCamelToHungarian( defaults, defaults, true ); 2529 _fnCamelToHungarian( defaults.column, defaults.column, true ); 2530 2531 /* Setting up the initialisation object */ 2532 _fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ), true ); 2533 2534 2535 2536 /* Check to see if we are re-initialising a table */ 2537 var allSettings = DataTable.settings; 2538 for ( i=0, iLen=allSettings.length ; i<iLen ; i++ ) 2539 { 2540 var s = allSettings[i]; 2541 2542 /* Base check on table node */ 2543 if ( 2544 s.nTable == this || 2545 (s.nTHead && s.nTHead.parentNode == this) || 2546 (s.nTFoot && s.nTFoot.parentNode == this) 2547 ) { 2548 var bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve; 2549 var bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy; 2550 2551 if ( emptyInit || bRetrieve ) 2552 { 2553 return s.oInstance; 2554 } 2555 else if ( bDestroy ) 2556 { 2557 s.oInstance.fnDestroy(); 2558 break; 2559 } 2560 else 2561 { 2562 _fnLog( s, 0, 'Cannot reinitialise DataTable', 3 ); 2563 return; 2564 } 2565 } 2566 2567 /* If the element we are initialising has the same ID as a table which was previously 2568 * initialised, but the table nodes don't match (from before) then we destroy the old 2569 * instance by simply deleting it. This is under the assumption that the table has been 2570 * destroyed by other methods. Anyone using non-id selectors will need to do this manually 2571 */ 2572 if ( s.sTableId == this.id ) 2573 { 2574 allSettings.splice( i, 1 ); 2575 break; 2576 } 2577 } 2578 2579 /* Ensure the table has an ID - required for accessibility */ 2580 if ( sId === null || sId === "" ) 2581 { 2582 sId = "DataTables_Table_"+(DataTable.ext._unique++); 2583 this.id = sId; 2584 } 2585 2586 /* Create the settings object for this table and set some of the default parameters */ 2587 var oSettings = $.extend( true, {}, DataTable.models.oSettings, { 2588 "sDestroyWidth": $this[0].style.width, 2589 "sInstance": sId, 2590 "sTableId": sId 2591 } ); 2592 oSettings.nTable = this; 2593 oSettings.oApi = _that.internal; 2594 oSettings.oInit = oInit; 2595 2596 allSettings.push( oSettings ); 2597 2598 // Need to add the instance after the instance after the settings object has been added 2599 // to the settings array, so we can self reference the table instance if more than one 2600 oSettings.oInstance = (_that.length===1) ? _that : $this.dataTable(); 2601 2602 // Backwards compatibility, before we apply all the defaults 2603 _fnCompatOpts( oInit ); 2604 _fnLanguageCompat( oInit.oLanguage ); 2605 2606 // If the length menu is given, but the init display length is not, use the length menu 2607 if ( oInit.aLengthMenu && ! oInit.iDisplayLength ) 2608 { 2609 oInit.iDisplayLength = Array.isArray( oInit.aLengthMenu[0] ) ? 2610 oInit.aLengthMenu[0][0] : oInit.aLengthMenu[0]; 2611 } 2612 2613 // Apply the defaults and init options to make a single init object will all 2614 // options defined from defaults and instance options. 2615 oInit = _fnExtend( $.extend( true, {}, defaults ), oInit ); 2616 2617 2618 // Map the initialisation options onto the settings object 2619 _fnMap( oSettings.oFeatures, oInit, [ 2620 "bPaginate", 2621 "bLengthChange", 2622 "bFilter", 2623 "bSort", 2624 "bSortMulti", 2625 "bInfo", 2626 "bProcessing", 2627 "bAutoWidth", 2628 "bSortClasses", 2629 "bServerSide", 2630 "bDeferRender" 2631 ] ); 2632 _fnMap( oSettings, oInit, [ 2633 "asStripeClasses", 2634 "ajax", 2635 "fnServerData", 2636 "fnFormatNumber", 2637 "sServerMethod", 2638 "aaSorting", 2639 "aaSortingFixed", 2640 "aLengthMenu", 2641 "sPaginationType", 2642 "sAjaxSource", 2643 "sAjaxDataProp", 2644 "iStateDuration", 2645 "sDom", 2646 "bSortCellsTop", 2647 "iTabIndex", 2648 "fnStateLoadCallback", 2649 "fnStateSaveCallback", 2650 "renderer", 2651 "searchDelay", 2652 "rowId", 2653 [ "iCookieDuration", "iStateDuration" ], // backwards compat 2654 [ "oSearch", "oPreviousSearch" ], 2655 [ "aoSearchCols", "aoPreSearchCols" ], 2656 [ "iDisplayLength", "_iDisplayLength" ] 2657 ] ); 2658 _fnMap( oSettings.oScroll, oInit, [ 2659 [ "sScrollX", "sX" ], 2660 [ "sScrollXInner", "sXInner" ], 2661 [ "sScrollY", "sY" ], 2662 [ "bScrollCollapse", "bCollapse" ] 2663 ] ); 2664 _fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" ); 2665 2666 /* Callback functions which are array driven */ 2667 _fnCallbackReg( oSettings, 'aoDrawCallback', oInit.fnDrawCallback, 'user' ); 2668 _fnCallbackReg( oSettings, 'aoServerParams', oInit.fnServerParams, 'user' ); 2669 _fnCallbackReg( oSettings, 'aoStateSaveParams', oInit.fnStateSaveParams, 'user' ); 2670 _fnCallbackReg( oSettings, 'aoStateLoadParams', oInit.fnStateLoadParams, 'user' ); 2671 _fnCallbackReg( oSettings, 'aoStateLoaded', oInit.fnStateLoaded, 'user' ); 2672 _fnCallbackReg( oSettings, 'aoRowCallback', oInit.fnRowCallback, 'user' ); 2673 _fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow, 'user' ); 2674 _fnCallbackReg( oSettings, 'aoHeaderCallback', oInit.fnHeaderCallback, 'user' ); 2675 _fnCallbackReg( oSettings, 'aoFooterCallback', oInit.fnFooterCallback, 'user' ); 2676 _fnCallbackReg( oSettings, 'aoInitComplete', oInit.fnInitComplete, 'user' ); 2677 _fnCallbackReg( oSettings, 'aoPreDrawCallback', oInit.fnPreDrawCallback, 'user' ); 2678 2679 oSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId ); 2680 2681 /* Browser support detection */ 2682 _fnBrowserDetect( oSettings ); 2683 2684 var oClasses = oSettings.oClasses; 2685 2686 $.extend( oClasses, DataTable.ext.classes, oInit.oClasses ); 2687 $this.addClass( oClasses.sTable ); 2688 2689 2690 if ( oSettings.iInitDisplayStart === undefined ) 2691 { 2692 /* Display start point, taking into account the save saving */ 2693 oSettings.iInitDisplayStart = oInit.iDisplayStart; 2694 oSettings._iDisplayStart = oInit.iDisplayStart; 2695 } 2696 2697 if ( oInit.iDeferLoading !== null ) 2698 { 2699 oSettings.bDeferLoading = true; 2700 var tmp = Array.isArray( oInit.iDeferLoading ); 2701 oSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading; 2702 oSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading; 2703 } 2704 2705 /* Language definitions */ 2706 var oLanguage = oSettings.oLanguage; 2707 $.extend( true, oLanguage, oInit.oLanguage ); 2708 2709 if ( oLanguage.sUrl ) 2710 { 2711 /* Get the language definitions from a file - because this Ajax call makes the language 2712 * get async to the remainder of this function we use bInitHandedOff to indicate that 2713 * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor 2714 */ 2715 $.ajax( { 2716 dataType: 'json', 2717 url: oLanguage.sUrl, 2718 success: function ( json ) { 2719 _fnLanguageCompat( json ); 2720 _fnCamelToHungarian( defaults.oLanguage, json ); 2721 $.extend( true, oLanguage, json ); 2722 2723 _fnCallbackFire( oSettings, null, 'i18n', [oSettings]); 2724 _fnInitialise( oSettings ); 2725 }, 2726 error: function () { 2727 // Error occurred loading language file, continue on as best we can 2728 _fnInitialise( oSettings ); 2729 } 2730 } ); 2731 bInitHandedOff = true; 2732 } 2733 else { 2734 _fnCallbackFire( oSettings, null, 'i18n', [oSettings]); 2735 } 2736 2737 /* 2738 * Stripes 2739 */ 2740 if ( oInit.asStripeClasses === null ) 2741 { 2742 oSettings.asStripeClasses =[ 2743 oClasses.sStripeOdd, 2744 oClasses.sStripeEven 2745 ]; 2746 } 2747 2748 /* Remove row stripe classes if they are already on the table row */ 2749 var stripeClasses = oSettings.asStripeClasses; 2750 var rowOne = $this.children('tbody').find('tr').eq(0); 2751 if ( $.inArray( true, $.map( stripeClasses, function(el, i) { 2752 return rowOne.hasClass(el); 2753 } ) ) !== -1 ) { 2754 $('tbody tr', this).removeClass( stripeClasses.join(' ') ); 2755 oSettings.asDestroyStripes = stripeClasses.slice(); 2756 } 2757 2758 /* 2759 * Columns 2760 * See if we should load columns automatically or use defined ones 2761 */ 2762 var anThs = []; 2763 var aoColumnsInit; 2764 var nThead = this.getElementsByTagName('thead'); 2765 if ( nThead.length !== 0 ) 2766 { 2767 _fnDetectHeader( oSettings.aoHeader, nThead[0] ); 2768 anThs = _fnGetUniqueThs( oSettings ); 2769 } 2770 2771 /* If not given a column array, generate one with nulls */ 2772 if ( oInit.aoColumns === null ) 2773 { 2774 aoColumnsInit = []; 2775 for ( i=0, iLen=anThs.length ; i<iLen ; i++ ) 2776 { 2777 aoColumnsInit.push( null ); 2778 } 2779 } 2780 else 2781 { 2782 aoColumnsInit = oInit.aoColumns; 2783 } 2784 2785 /* Add the columns */ 2786 for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ ) 2787 { 2788 _fnAddColumn( oSettings, anThs ? anThs[i] : null ); 2789 } 2790 2791 /* Apply the column definitions */ 2792 _fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) { 2793 _fnColumnOptions( oSettings, iCol, oDef ); 2794 } ); 2795 2796 /* HTML5 attribute detection - build an mData object automatically if the 2797 * attributes are found 2798 */ 2799 if ( rowOne.length ) { 2800 var a = function ( cell, name ) { 2801 return cell.getAttribute( 'data-'+name ) !== null ? name : null; 2802 }; 2803 2804 $( rowOne[0] ).children('th, td').each( function (i, cell) { 2805 var col = oSettings.aoColumns[i]; 2806 2807 if ( col.mData === i ) { 2808 var sort = a( cell, 'sort' ) || a( cell, 'order' ); 2809 var filter = a( cell, 'filter' ) || a( cell, 'search' ); 2810 2811 if ( sort !== null || filter !== null ) { 2812 col.mData = { 2813 _: i+'.display', 2814 sort: sort !== null ? i+'.@data-'+sort : undefined, 2815 type: sort !== null ? i+'.@data-'+sort : undefined, 2816 filter: filter !== null ? i+'.@data-'+filter : undefined 2817 }; 2818 2819 _fnColumnOptions( oSettings, i ); 2820 } 2821 } 2822 } ); 2823 } 2824 2825 var features = oSettings.oFeatures; 2826 var loadedInit = function () { 2827 /* 2828 * Sorting 2829 * @todo For modularisation (1.11) this needs to do into a sort start up handler 2830 */ 2831 2832 // If aaSorting is not defined, then we use the first indicator in asSorting 2833 // in case that has been altered, so the default sort reflects that option 2834 if ( oInit.aaSorting === undefined ) { 2835 var sorting = oSettings.aaSorting; 2836 for ( i=0, iLen=sorting.length ; i<iLen ; i++ ) { 2837 sorting[i][1] = oSettings.aoColumns[ i ].asSorting[0]; 2838 } 2839 } 2840 2841 /* Do a first pass on the sorting classes (allows any size changes to be taken into 2842 * account, and also will apply sorting disabled classes if disabled 2843 */ 2844 _fnSortingClasses( oSettings ); 2845 2846 if ( features.bSort ) { 2847 _fnCallbackReg( oSettings, 'aoDrawCallback', function () { 2848 if ( oSettings.bSorted ) { 2849 var aSort = _fnSortFlatten( oSettings ); 2850 var sortedColumns = {}; 2851 2852 $.each( aSort, function (i, val) { 2853 sortedColumns[ val.src ] = val.dir; 2854 } ); 2855 2856 _fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] ); 2857 _fnSortAria( oSettings ); 2858 } 2859 } ); 2860 } 2861 2862 _fnCallbackReg( oSettings, 'aoDrawCallback', function () { 2863 if ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) { 2864 _fnSortingClasses( oSettings ); 2865 } 2866 }, 'sc' ); 2867 2868 2869 /* 2870 * Final init 2871 * Cache the header, body and footer as required, creating them if needed 2872 */ 2873 2874 // Work around for Webkit bug 83867 - store the caption-side before removing from doc 2875 var captions = $this.children('caption').each( function () { 2876 this._captionSide = $(this).css('caption-side'); 2877 } ); 2878 2879 var thead = $this.children('thead'); 2880 if ( thead.length === 0 ) { 2881 thead = $('<thead/>').appendTo($this); 2882 } 2883 oSettings.nTHead = thead[0]; 2884 2885 var tbody = $this.children('tbody'); 2886 if ( tbody.length === 0 ) { 2887 tbody = $('<tbody/>').appendTo($this); 2888 } 2889 oSettings.nTBody = tbody[0]; 2890 2891 var tfoot = $this.children('tfoot'); 2892 if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") ) { 2893 // If we are a scrolling table, and no footer has been given, then we need to create 2894 // a tfoot element for the caption element to be appended to 2895 tfoot = $('<tfoot/>').appendTo($this); 2896 } 2897 2898 if ( tfoot.length === 0 || tfoot.children().length === 0 ) { 2899 $this.addClass( oClasses.sNoFooter ); 2900 } 2901 else if ( tfoot.length > 0 ) { 2902 oSettings.nTFoot = tfoot[0]; 2903 _fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot ); 2904 } 2905 2906 /* Check if there is data passing into the constructor */ 2907 if ( oInit.aaData ) { 2908 for ( i=0 ; i<oInit.aaData.length ; i++ ) { 2909 _fnAddData( oSettings, oInit.aaData[ i ] ); 2910 } 2911 } 2912 else if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' ) { 2913 /* Grab the data from the page - only do this when deferred loading or no Ajax 2914 * source since there is no point in reading the DOM data if we are then going 2915 * to replace it with Ajax data 2916 */ 2917 _fnAddTr( oSettings, $(oSettings.nTBody).children('tr') ); 2918 } 2919 2920 /* Copy the data index array */ 2921 oSettings.aiDisplay = oSettings.aiDisplayMaster.slice(); 2922 2923 /* Initialisation complete - table can be drawn */ 2924 oSettings.bInitialised = true; 2925 2926 /* Check if we need to initialise the table (it might not have been handed off to the 2927 * language processor) 2928 */ 2929 if ( bInitHandedOff === false ) { 2930 _fnInitialise( oSettings ); 2931 } 2932 }; 2933 2934 /* Must be done after everything which can be overridden by the state saving! */ 2935 if ( oInit.bStateSave ) 2936 { 2937 features.bStateSave = true; 2938 _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' ); 2939 _fnLoadState( oSettings, oInit, loadedInit ); 2940 } 2941 else { 2942 loadedInit(); 2943 } 2944 2945 } ); 2946 _that = null; 2947 return this; 2948 }; 2949 2950 2951 /* 2952 * It is useful to have variables which are scoped locally so only the 2953 * DataTables functions can access them and they don't leak into global space. 2954 * At the same time these functions are often useful over multiple files in the 2955 * core and API, so we list, or at least document, all variables which are used 2956 * by DataTables as private variables here. This also ensures that there is no 2957 * clashing of variable names and that they can easily referenced for reuse. 2958 */ 2959 2960 2961 // Defined else where 2962 // _selector_run 2963 // _selector_opts 2964 // _selector_first 2965 // _selector_row_indexes 2966 2967 var _ext; // DataTable.ext 2968 var _Api; // DataTable.Api 2969 var _api_register; // DataTable.Api.register 2970 var _api_registerPlural; // DataTable.Api.registerPlural 2971 2972 var _re_dic = {}; 2973 var _re_new_lines = /[\r\n\u2028]/g; 2974 var _re_html = /<.*?>/g; 2975 2976 // This is not strict ISO8601 - Date.parse() is quite lax, although 2977 // implementations differ between browsers. 2978 var _re_date = /^\d{2,4}[\.\/\-]\d{1,2}[\.\/\-]\d{1,2}([T ]{1}\d{1,2}[:\.]\d{2}([\.:]\d{2})?)?$/; 2979 2980 // Escape regular expression special characters 2981 var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' ); 2982 2983 // http://en.wikipedia.org/wiki/Foreign_exchange_market 2984 // - \u20BD - Russian ruble. 2985 // - \u20a9 - South Korean Won 2986 // - \u20BA - Turkish Lira 2987 // - \u20B9 - Indian Rupee 2988 // - R - Brazil (R$) and South Africa 2989 // - fr - Swiss Franc 2990 // - kr - Swedish krona, Norwegian krone and Danish krone 2991 // - \u2009 is thin space and \u202F is narrow no-break space, both used in many 2992 // - É - Bitcoin 2993 // - Î - Ethereum 2994 // standards as thousands separators. 2995 var _re_formatted_numeric = /['\u00A0,$£â¬Â¥%\u2009\u202F\u20BD\u20a9\u20BArfkÉÎ]/gi; 2996 2997 2998 var _empty = function ( d ) { 2999 return !d || d === true || d === '-' ? true : false; 3000 }; 3001 3002 3003 var _intVal = function ( s ) { 3004 var integer = parseInt( s, 10 ); 3005 return !isNaN(integer) && isFinite(s) ? integer : null; 3006 }; 3007 3008 // Convert from a formatted number with characters other than `.` as the 3009 // decimal place, to a Javascript number 3010 var _numToDecimal = function ( num, decimalPoint ) { 3011 // Cache created regular expressions for speed as this function is called often 3012 if ( ! _re_dic[ decimalPoint ] ) { 3013 _re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' ); 3014 } 3015 return typeof num === 'string' && decimalPoint !== '.' ? 3016 num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) : 3017 num; 3018 }; 3019 3020 3021 var _isNumber = function ( d, decimalPoint, formatted ) { 3022 var strType = typeof d === 'string'; 3023 3024 // If empty return immediately so there must be a number if it is a 3025 // formatted string (this stops the string "k", or "kr", etc being detected 3026 // as a formatted number for currency 3027 if ( _empty( d ) ) { 3028 return true; 3029 } 3030 3031 if ( decimalPoint && strType ) { 3032 d = _numToDecimal( d, decimalPoint ); 3033 } 3034 3035 if ( formatted && strType ) { 3036 d = d.replace( _re_formatted_numeric, '' ); 3037 } 3038 3039 return !isNaN( parseFloat(d) ) && isFinite( d ); 3040 }; 3041 3042 3043 // A string without HTML in it can be considered to be HTML still 3044 var _isHtml = function ( d ) { 3045 return _empty( d ) || typeof d === 'string'; 3046 }; 3047 3048 3049 var _htmlNumeric = function ( d, decimalPoint, formatted ) { 3050 if ( _empty( d ) ) { 3051 return true; 3052 } 3053 3054 var html = _isHtml( d ); 3055 return ! html ? 3056 null : 3057 _isNumber( _stripHtml( d ), decimalPoint, formatted ) ? 3058 true : 3059 null; 3060 }; 3061 3062 3063 var _pluck = function ( a, prop, prop2 ) { 3064 var out = []; 3065 var i=0, ien=a.length; 3066 3067 // Could have the test in the loop for slightly smaller code, but speed 3068 // is essential here 3069 if ( prop2 !== undefined ) { 3070 for ( ; i<ien ; i++ ) { 3071 if ( a[i] && a[i][ prop ] ) { 3072 out.push( a[i][ prop ][ prop2 ] ); 3073 } 3074 } 3075 } 3076 else { 3077 for ( ; i<ien ; i++ ) { 3078 if ( a[i] ) { 3079 out.push( a[i][ prop ] ); 3080 } 3081 } 3082 } 3083 3084 return out; 3085 }; 3086 3087 3088 // Basically the same as _pluck, but rather than looping over `a` we use `order` 3089 // as the indexes to pick from `a` 3090 var _pluck_order = function ( a, order, prop, prop2 ) 3091 { 3092 var out = []; 3093 var i=0, ien=order.length; 3094 3095 // Could have the test in the loop for slightly smaller code, but speed 3096 // is essential here 3097 if ( prop2 !== undefined ) { 3098 for ( ; i<ien ; i++ ) { 3099 if ( a[ order[i] ][ prop ] ) { 3100 out.push( a[ order[i] ][ prop ][ prop2 ] ); 3101 } 3102 } 3103 } 3104 else { 3105 for ( ; i<ien ; i++ ) { 3106 out.push( a[ order[i] ][ prop ] ); 3107 } 3108 } 3109 3110 return out; 3111 }; 3112 3113 3114 var _range = function ( len, start ) 3115 { 3116 var out = []; 3117 var end; 3118 3119 if ( start === undefined ) { 3120 start = 0; 3121 end = len; 3122 } 3123 else { 3124 end = start; 3125 start = len; 3126 } 3127 3128 for ( var i=start ; i<end ; i++ ) { 3129 out.push( i ); 3130 } 3131 3132 return out; 3133 }; 3134 3135 3136 var _removeEmpty = function ( a ) 3137 { 3138 var out = []; 3139 3140 for ( var i=0, ien=a.length ; i<ien ; i++ ) { 3141 if ( a[i] ) { // careful - will remove all falsy values! 3142 out.push( a[i] ); 3143 } 3144 } 3145 3146 return out; 3147 }; 3148 3149 3150 var _stripHtml = function ( d ) { 3151 return d.replace( _re_html, '' ); 3152 }; 3153 3154 3155 /** 3156 * Determine if all values in the array are unique. This means we can short 3157 * cut the _unique method at the cost of a single loop. A sorted array is used 3158 * to easily check the values. 3159 * 3160 * @param {array} src Source array 3161 * @return {boolean} true if all unique, false otherwise 3162 * @ignore 3163 */ 3164 var _areAllUnique = function ( src ) { 3165 if ( src.length < 2 ) { 3166 return true; 3167 } 3168 3169 var sorted = src.slice().sort(); 3170 var last = sorted[0]; 3171 3172 for ( var i=1, ien=sorted.length ; i<ien ; i++ ) { 3173 if ( sorted[i] === last ) { 3174 return false; 3175 } 3176 3177 last = sorted[i]; 3178 } 3179 3180 return true; 3181 }; 3182 3183 3184 /** 3185 * Find the unique elements in a source array. 3186 * 3187 * @param {array} src Source array 3188 * @return {array} Array of unique items 3189 * @ignore 3190 */ 3191 var _unique = function ( src ) 3192 { 3193 if ( _areAllUnique( src ) ) { 3194 return src.slice(); 3195 } 3196 3197 // A faster unique method is to use object keys to identify used values, 3198 // but this doesn't work with arrays or objects, which we must also 3199 // consider. See jsperf.com/compare-array-unique-versions/4 for more 3200 // information. 3201 var 3202 out = [], 3203 val, 3204 i, ien=src.length, 3205 j, k=0; 3206 3207 again: for ( i=0 ; i<ien ; i++ ) { 3208 val = src[i]; 3209 3210 for ( j=0 ; j<k ; j++ ) { 3211 if ( out[j] === val ) { 3212 continue again; 3213 } 3214 } 3215 3216 out.push( val ); 3217 k++; 3218 } 3219 3220 return out; 3221 }; 3222 3223 // Surprisingly this is faster than [].concat.apply 3224 // https://jsperf.com/flatten-an-array-loop-vs-reduce/2 3225 var _flatten = function (out, val) { 3226 if (Array.isArray(val)) { 3227 for (var i=0 ; i<val.length ; i++) { 3228 _flatten(out, val[i]); 3229 } 3230 } 3231 else { 3232 out.push(val); 3233 } 3234 3235 return out; 3236 } 3237 3238 // Array.isArray polyfill. 3239 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray 3240 if (! Array.isArray) { 3241 Array.isArray = function(arg) { 3242 return Object.prototype.toString.call(arg) === '[object Array]'; 3243 }; 3244 } 3245 3246 // .trim() polyfill 3247 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/trim 3248 if (!String.prototype.trim) { 3249 String.prototype.trim = function () { 3250 return this.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ''); 3251 }; 3252 } 3253 3254 /** 3255 * DataTables utility methods 3256 * 3257 * This namespace provides helper methods that DataTables uses internally to 3258 * create a DataTable, but which are not exclusively used only for DataTables. 3259 * These methods can be used by extension authors to save the duplication of 3260 * code. 3261 * 3262 * @namespace 3263 */ 3264 DataTable.util = { 3265 /** 3266 * Throttle the calls to a function. Arguments and context are maintained 3267 * for the throttled function. 3268 * 3269 * @param {function} fn Function to be called 3270 * @param {integer} freq Call frequency in mS 3271 * @return {function} Wrapped function 3272 */ 3273 throttle: function ( fn, freq ) { 3274 var 3275 frequency = freq !== undefined ? freq : 200, 3276 last, 3277 timer; 3278 3279 return function () { 3280 var 3281 that = this, 3282 now = +new Date(), 3283 args = arguments; 3284 3285 if ( last && now < last + frequency ) { 3286 clearTimeout( timer ); 3287 3288 timer = setTimeout( function () { 3289 last = undefined; 3290 fn.apply( that, args ); 3291 }, frequency ); 3292 } 3293 else { 3294 last = now; 3295 fn.apply( that, args ); 3296 } 3297 }; 3298 }, 3299 3300 3301 /** 3302 * Escape a string such that it can be used in a regular expression 3303 * 3304 * @param {string} val string to escape 3305 * @returns {string} escaped string 3306 */ 3307 escapeRegex: function ( val ) { 3308 return val.replace( _re_escape_regex, '\\$1' ); 3309 } 3310 }; 3311 3312 3313 3314 /** 3315 * Create a mapping object that allows camel case parameters to be looked up 3316 * for their Hungarian counterparts. The mapping is stored in a private 3317 * parameter called `_hungarianMap` which can be accessed on the source object. 3318 * @param {object} o 3319 * @memberof DataTable#oApi 3320 */ 3321 function _fnHungarianMap ( o ) 3322 { 3323 var 3324 hungarian = 'a aa ai ao as b fn i m o s ', 3325 match, 3326 newKey, 3327 map = {}; 3328 3329 $.each( o, function (key, val) { 3330 match = key.match(/^([^A-Z]+?)([A-Z])/); 3331 3332 if ( match && hungarian.indexOf(match[1]+' ') !== -1 ) 3333 { 3334 newKey = key.replace( match[0], match[2].toLowerCase() ); 3335 map[ newKey ] = key; 3336 3337 if ( match[1] === 'o' ) 3338 { 3339 _fnHungarianMap( o[key] ); 3340 } 3341 } 3342 } ); 3343 3344 o._hungarianMap = map; 3345 } 3346 3347 3348 /** 3349 * Convert from camel case parameters to Hungarian, based on a Hungarian map 3350 * created by _fnHungarianMap. 3351 * @param {object} src The model object which holds all parameters that can be 3352 * mapped. 3353 * @param {object} user The object to convert from camel case to Hungarian. 3354 * @param {boolean} force When set to `true`, properties which already have a 3355 * Hungarian value in the `user` object will be overwritten. Otherwise they 3356 * won't be. 3357 * @memberof DataTable#oApi 3358 */ 3359 function _fnCamelToHungarian ( src, user, force ) 3360 { 3361 if ( ! src._hungarianMap ) { 3362 _fnHungarianMap( src ); 3363 } 3364 3365 var hungarianKey; 3366 3367 $.each( user, function (key, val) { 3368 hungarianKey = src._hungarianMap[ key ]; 3369 3370 if ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) ) 3371 { 3372 // For objects, we need to buzz down into the object to copy parameters 3373 if ( hungarianKey.charAt(0) === 'o' ) 3374 { 3375 // Copy the camelCase options over to the hungarian 3376 if ( ! user[ hungarianKey ] ) { 3377 user[ hungarianKey ] = {}; 3378 } 3379 $.extend( true, user[hungarianKey], user[key] ); 3380 3381 _fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force ); 3382 } 3383 else { 3384 user[hungarianKey] = user[ key ]; 3385 } 3386 } 3387 } ); 3388 } 3389 3390 3391 /** 3392 * Language compatibility - when certain options are given, and others aren't, we 3393 * need to duplicate the values over, in order to provide backwards compatibility 3394 * with older language files. 3395 * @param {object} oSettings dataTables settings object 3396 * @memberof DataTable#oApi 3397 */ 3398 function _fnLanguageCompat( lang ) 3399 { 3400 // Note the use of the Hungarian notation for the parameters in this method as 3401 // this is called after the mapping of camelCase to Hungarian 3402 var defaults = DataTable.defaults.oLanguage; 3403 3404 // Default mapping 3405 var defaultDecimal = defaults.sDecimal; 3406 if ( defaultDecimal ) { 3407 _addNumericSort( defaultDecimal ); 3408 } 3409 3410 if ( lang ) { 3411 var zeroRecords = lang.sZeroRecords; 3412 3413 // Backwards compatibility - if there is no sEmptyTable given, then use the same as 3414 // sZeroRecords - assuming that is given. 3415 if ( ! lang.sEmptyTable && zeroRecords && 3416 defaults.sEmptyTable === "No data available in table" ) 3417 { 3418 _fnMap( lang, lang, 'sZeroRecords', 'sEmptyTable' ); 3419 } 3420 3421 // Likewise with loading records 3422 if ( ! lang.sLoadingRecords && zeroRecords && 3423 defaults.sLoadingRecords === "Loading..." ) 3424 { 3425 _fnMap( lang, lang, 'sZeroRecords', 'sLoadingRecords' ); 3426 } 3427 3428 // Old parameter name of the thousands separator mapped onto the new 3429 if ( lang.sInfoThousands ) { 3430 lang.sThousands = lang.sInfoThousands; 3431 } 3432 3433 var decimal = lang.sDecimal; 3434 if ( decimal && defaultDecimal !== decimal ) { 3435 _addNumericSort( decimal ); 3436 } 3437 } 3438 } 3439 3440 3441 /** 3442 * Map one parameter onto another 3443 * @param {object} o Object to map 3444 * @param {*} knew The new parameter name 3445 * @param {*} old The old parameter name 3446 */ 3447 var _fnCompatMap = function ( o, knew, old ) { 3448 if ( o[ knew ] !== undefined ) { 3449 o[ old ] = o[ knew ]; 3450 } 3451 }; 3452 3453 3454 /** 3455 * Provide backwards compatibility for the main DT options. Note that the new 3456 * options are mapped onto the old parameters, so this is an external interface 3457 * change only. 3458 * @param {object} init Object to map 3459 */ 3460 function _fnCompatOpts ( init ) 3461 { 3462 _fnCompatMap( init, 'ordering', 'bSort' ); 3463 _fnCompatMap( init, 'orderMulti', 'bSortMulti' ); 3464 _fnCompatMap( init, 'orderClasses', 'bSortClasses' ); 3465 _fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' ); 3466 _fnCompatMap( init, 'order', 'aaSorting' ); 3467 _fnCompatMap( init, 'orderFixed', 'aaSortingFixed' ); 3468 _fnCompatMap( init, 'paging', 'bPaginate' ); 3469 _fnCompatMap( init, 'pagingType', 'sPaginationType' ); 3470 _fnCompatMap( init, 'pageLength', 'iDisplayLength' ); 3471 _fnCompatMap( init, 'searching', 'bFilter' ); 3472 3473 // Boolean initialisation of x-scrolling 3474 if ( typeof init.sScrollX === 'boolean' ) { 3475 init.sScrollX = init.sScrollX ? '100%' : ''; 3476 } 3477 if ( typeof init.scrollX === 'boolean' ) { 3478 init.scrollX = init.scrollX ? '100%' : ''; 3479 } 3480 3481 // Column search objects are in an array, so it needs to be converted 3482 // element by element 3483 var searchCols = init.aoSearchCols; 3484 3485 if ( searchCols ) { 3486 for ( var i=0, ien=searchCols.length ; i<ien ; i++ ) { 3487 if ( searchCols[i] ) { 3488 _fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] ); 3489 } 3490 } 3491 } 3492 } 3493 3494 3495 /** 3496 * Provide backwards compatibility for column options. Note that the new options 3497 * are mapped onto the old parameters, so this is an external interface change 3498 * only. 3499 * @param {object} init Object to map 3500 */ 3501 function _fnCompatCols ( init ) 3502 { 3503 _fnCompatMap( init, 'orderable', 'bSortable' ); 3504 _fnCompatMap( init, 'orderData', 'aDataSort' ); 3505 _fnCompatMap( init, 'orderSequence', 'asSorting' ); 3506 _fnCompatMap( init, 'orderDataType', 'sortDataType' ); 3507 3508 // orderData can be given as an integer 3509 var dataSort = init.aDataSort; 3510 if ( typeof dataSort === 'number' && ! Array.isArray( dataSort ) ) { 3511 init.aDataSort = [ dataSort ]; 3512 } 3513 } 3514 3515 3516 /** 3517 * Browser feature detection for capabilities, quirks 3518 * @param {object} settings dataTables settings object 3519 * @memberof DataTable#oApi 3520 */ 3521 function _fnBrowserDetect( settings ) 3522 { 3523 // We don't need to do this every time DataTables is constructed, the values 3524 // calculated are specific to the browser and OS configuration which we 3525 // don't expect to change between initialisations 3526 if ( ! DataTable.__browser ) { 3527 var browser = {}; 3528 DataTable.__browser = browser; 3529 3530 // Scrolling feature / quirks detection 3531 var n = $('<div/>') 3532 .css( { 3533 position: 'fixed', 3534 top: 0, 3535 left: $(window).scrollLeft()*-1, // allow for scrolling 3536 height: 1, 3537 width: 1, 3538 overflow: 'hidden' 3539 } ) 3540 .append( 3541 $('<div/>') 3542 .css( { 3543 position: 'absolute', 3544 top: 1, 3545 left: 1, 3546 width: 100, 3547 overflow: 'scroll' 3548 } ) 3549 .append( 3550 $('<div/>') 3551 .css( { 3552 width: '100%', 3553 height: 10 3554 } ) 3555 ) 3556 ) 3557 .appendTo( 'body' ); 3558 3559 var outer = n.children(); 3560 var inner = outer.children(); 3561 3562 // Numbers below, in order, are: 3563 // inner.offsetWidth, inner.clientWidth, outer.offsetWidth, outer.clientWidth 3564 // 3565 // IE6 XP: 100 100 100 83 3566 // IE7 Vista: 100 100 100 83 3567 // IE 8+ Windows: 83 83 100 83 3568 // Evergreen Windows: 83 83 100 83 3569 // Evergreen Mac with scrollbars: 85 85 100 85 3570 // Evergreen Mac without scrollbars: 100 100 100 100 3571 3572 // Get scrollbar width 3573 browser.barWidth = outer[0].offsetWidth - outer[0].clientWidth; 3574 3575 // IE6/7 will oversize a width 100% element inside a scrolling element, to 3576 // include the width of the scrollbar, while other browsers ensure the inner 3577 // element is contained without forcing scrolling 3578 browser.bScrollOversize = inner[0].offsetWidth === 100 && outer[0].clientWidth !== 100; 3579 3580 // In rtl text layout, some browsers (most, but not all) will place the 3581 // scrollbar on the left, rather than the right. 3582 browser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1; 3583 3584 // IE8- don't provide height and width for getBoundingClientRect 3585 browser.bBounding = n[0].getBoundingClientRect().width ? true : false; 3586 3587 n.remove(); 3588 } 3589 3590 $.extend( settings.oBrowser, DataTable.__browser ); 3591 settings.oScroll.iBarWidth = DataTable.__browser.barWidth; 3592 } 3593 3594 3595 /** 3596 * Array.prototype reduce[Right] method, used for browsers which don't support 3597 * JS 1.6. Done this way to reduce code size, since we iterate either way 3598 * @param {object} settings dataTables settings object 3599 * @memberof DataTable#oApi 3600 */ 3601 function _fnReduce ( that, fn, init, start, end, inc ) 3602 { 3603 var 3604 i = start, 3605 value, 3606 isSet = false; 3607 3608 if ( init !== undefined ) { 3609 value = init; 3610 isSet = true; 3611 } 3612 3613 while ( i !== end ) { 3614 if ( ! that.hasOwnProperty(i) ) { 3615 continue; 3616 } 3617 3618 value = isSet ? 3619 fn( value, that[i], i, that ) : 3620 that[i]; 3621 3622 isSet = true; 3623 i += inc; 3624 } 3625 3626 return value; 3627 } 3628 3629 /** 3630 * Add a column to the list used for the table with default values 3631 * @param {object} oSettings dataTables settings object 3632 * @param {node} nTh The th element for this column 3633 * @memberof DataTable#oApi 3634 */ 3635 function _fnAddColumn( oSettings, nTh ) 3636 { 3637 // Add column to aoColumns array 3638 var oDefaults = DataTable.defaults.column; 3639 var iCol = oSettings.aoColumns.length; 3640 var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, { 3641 "nTh": nTh ? nTh : document.createElement('th'), 3642 "sTitle": oDefaults.sTitle ? oDefaults.sTitle : nTh ? nTh.innerHTML : '', 3643 "aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol], 3644 "mData": oDefaults.mData ? oDefaults.mData : iCol, 3645 idx: iCol 3646 } ); 3647 oSettings.aoColumns.push( oCol ); 3648 3649 // Add search object for column specific search. Note that the `searchCols[ iCol ]` 3650 // passed into extend can be undefined. This allows the user to give a default 3651 // with only some of the parameters defined, and also not give a default 3652 var searchCols = oSettings.aoPreSearchCols; 3653 searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] ); 3654 3655 // Use the default column options function to initialise classes etc 3656 _fnColumnOptions( oSettings, iCol, $(nTh).data() ); 3657 } 3658 3659 3660 /** 3661 * Apply options for a column 3662 * @param {object} oSettings dataTables settings object 3663 * @param {int} iCol column index to consider 3664 * @param {object} oOptions object with sType, bVisible and bSearchable etc 3665 * @memberof DataTable#oApi 3666 */ 3667 function _fnColumnOptions( oSettings, iCol, oOptions ) 3668 { 3669 var oCol = oSettings.aoColumns[ iCol ]; 3670 var oClasses = oSettings.oClasses; 3671 var th = $(oCol.nTh); 3672 3673 // Try to get width information from the DOM. We can't get it from CSS 3674 // as we'd need to parse the CSS stylesheet. `width` option can override 3675 if ( ! oCol.sWidthOrig ) { 3676 // Width attribute 3677 oCol.sWidthOrig = th.attr('width') || null; 3678 3679 // Style attribute 3680 var t = (th.attr('style') || '').match(/width:\s*(\d+[pxem%]+)/); 3681 if ( t ) { 3682 oCol.sWidthOrig = t[1]; 3683 } 3684 } 3685 3686 /* User specified column options */ 3687 if ( oOptions !== undefined && oOptions !== null ) 3688 { 3689 // Backwards compatibility 3690 _fnCompatCols( oOptions ); 3691 3692 // Map camel case parameters to their Hungarian counterparts 3693 _fnCamelToHungarian( DataTable.defaults.column, oOptions, true ); 3694 3695 /* Backwards compatibility for mDataProp */ 3696 if ( oOptions.mDataProp !== undefined && !oOptions.mData ) 3697 { 3698 oOptions.mData = oOptions.mDataProp; 3699 } 3700 3701 if ( oOptions.sType ) 3702 { 3703 oCol._sManualType = oOptions.sType; 3704 } 3705 3706 // `class` is a reserved word in Javascript, so we need to provide 3707 // the ability to use a valid name for the camel case input 3708 if ( oOptions.className && ! oOptions.sClass ) 3709 { 3710 oOptions.sClass = oOptions.className; 3711 } 3712 if ( oOptions.sClass ) { 3713 th.addClass( oOptions.sClass ); 3714 } 3715 3716 $.extend( oCol, oOptions ); 3717 _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" ); 3718 3719 /* iDataSort to be applied (backwards compatibility), but aDataSort will take 3720 * priority if defined 3721 */ 3722 if ( oOptions.iDataSort !== undefined ) 3723 { 3724 oCol.aDataSort = [ oOptions.iDataSort ]; 3725 } 3726 _fnMap( oCol, oOptions, "aDataSort" ); 3727 } 3728 3729 /* Cache the data get and set functions for speed */ 3730 var mDataSrc = oCol.mData; 3731 var mData = _fnGetObjectDataFn( mDataSrc ); 3732 var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null; 3733 3734 var attrTest = function( src ) { 3735 return typeof src === 'string' && src.indexOf('@') !== -1; 3736 }; 3737 oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && ( 3738 attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter) 3739 ); 3740 oCol._setter = null; 3741 3742 oCol.fnGetData = function (rowData, type, meta) { 3743 var innerData = mData( rowData, type, undefined, meta ); 3744 3745 return mRender && type ? 3746 mRender( innerData, type, rowData, meta ) : 3747 innerData; 3748 }; 3749 oCol.fnSetData = function ( rowData, val, meta ) { 3750 return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta ); 3751 }; 3752 3753 // Indicate if DataTables should read DOM data as an object or array 3754 // Used in _fnGetRowElements 3755 if ( typeof mDataSrc !== 'number' ) { 3756 oSettings._rowReadObject = true; 3757 } 3758 3759 /* Feature sorting overrides column specific when off */ 3760 if ( !oSettings.oFeatures.bSort ) 3761 { 3762 oCol.bSortable = false; 3763 th.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called 3764 } 3765 3766 /* Check that the class assignment is correct for sorting */ 3767 var bAsc = $.inArray('asc', oCol.asSorting) !== -1; 3768 var bDesc = $.inArray('desc', oCol.asSorting) !== -1; 3769 if ( !oCol.bSortable || (!bAsc && !bDesc) ) 3770 { 3771 oCol.sSortingClass = oClasses.sSortableNone; 3772 oCol.sSortingClassJUI = ""; 3773 } 3774 else if ( bAsc && !bDesc ) 3775 { 3776 oCol.sSortingClass = oClasses.sSortableAsc; 3777 oCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed; 3778 } 3779 else if ( !bAsc && bDesc ) 3780 { 3781 oCol.sSortingClass = oClasses.sSortableDesc; 3782 oCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed; 3783 } 3784 else 3785 { 3786 oCol.sSortingClass = oClasses.sSortable; 3787 oCol.sSortingClassJUI = oClasses.sSortJUI; 3788 } 3789 } 3790 3791 3792 /** 3793 * Adjust the table column widths for new data. Note: you would probably want to 3794 * do a redraw after calling this function! 3795 * @param {object} settings dataTables settings object 3796 * @memberof DataTable#oApi 3797 */ 3798 function _fnAdjustColumnSizing ( settings ) 3799 { 3800 /* Not interested in doing column width calculation if auto-width is disabled */ 3801 if ( settings.oFeatures.bAutoWidth !== false ) 3802 { 3803 var columns = settings.aoColumns; 3804 3805 _fnCalculateColumnWidths( settings ); 3806 for ( var i=0 , iLen=columns.length ; i<iLen ; i++ ) 3807 { 3808 columns[i].nTh.style.width = columns[i].sWidth; 3809 } 3810 } 3811 3812 var scroll = settings.oScroll; 3813 if ( scroll.sY !== '' || scroll.sX !== '') 3814 { 3815 _fnScrollDraw( settings ); 3816 } 3817 3818 _fnCallbackFire( settings, null, 'column-sizing', [settings] ); 3819 } 3820 3821 3822 /** 3823 * Covert the index of a visible column to the index in the data array (take account 3824 * of hidden columns) 3825 * @param {object} oSettings dataTables settings object 3826 * @param {int} iMatch Visible column index to lookup 3827 * @returns {int} i the data index 3828 * @memberof DataTable#oApi 3829 */ 3830 function _fnVisibleToColumnIndex( oSettings, iMatch ) 3831 { 3832 var aiVis = _fnGetColumns( oSettings, 'bVisible' ); 3833 3834 return typeof aiVis[iMatch] === 'number' ? 3835 aiVis[iMatch] : 3836 null; 3837 } 3838 3839 3840 /** 3841 * Covert the index of an index in the data array and convert it to the visible 3842 * column index (take account of hidden columns) 3843 * @param {int} iMatch Column index to lookup 3844 * @param {object} oSettings dataTables settings object 3845 * @returns {int} i the data index 3846 * @memberof DataTable#oApi 3847 */ 3848 function _fnColumnIndexToVisible( oSettings, iMatch ) 3849 { 3850 var aiVis = _fnGetColumns( oSettings, 'bVisible' ); 3851 var iPos = $.inArray( iMatch, aiVis ); 3852 3853 return iPos !== -1 ? iPos : null; 3854 } 3855 3856 3857 /** 3858 * Get the number of visible columns 3859 * @param {object} oSettings dataTables settings object 3860 * @returns {int} i the number of visible columns 3861 * @memberof DataTable#oApi 3862 */ 3863 function _fnVisbleColumns( oSettings ) 3864 { 3865 var vis = 0; 3866 3867 // No reduce in IE8, use a loop for now 3868 $.each( oSettings.aoColumns, function ( i, col ) { 3869 if ( col.bVisible && $(col.nTh).css('display') !== 'none' ) { 3870 vis++; 3871 } 3872 } ); 3873 3874 return vis; 3875 } 3876 3877 3878 /** 3879 * Get an array of column indexes that match a given property 3880 * @param {object} oSettings dataTables settings object 3881 * @param {string} sParam Parameter in aoColumns to look for - typically 3882 * bVisible or bSearchable 3883 * @returns {array} Array of indexes with matched properties 3884 * @memberof DataTable#oApi 3885 */ 3886 function _fnGetColumns( oSettings, sParam ) 3887 { 3888 var a = []; 3889 3890 $.map( oSettings.aoColumns, function(val, i) { 3891 if ( val[sParam] ) { 3892 a.push( i ); 3893 } 3894 } ); 3895 3896 return a; 3897 } 3898 3899 3900 /** 3901 * Calculate the 'type' of a column 3902 * @param {object} settings dataTables settings object 3903 * @memberof DataTable#oApi 3904 */ 3905 function _fnColumnTypes ( settings ) 3906 { 3907 var columns = settings.aoColumns; 3908 var data = settings.aoData; 3909 var types = DataTable.ext.type.detect; 3910 var i, ien, j, jen, k, ken; 3911 var col, cell, detectedType, cache; 3912 3913 // For each column, spin over the 3914 for ( i=0, ien=columns.length ; i<ien ; i++ ) { 3915 col = columns[i]; 3916 cache = []; 3917 3918 if ( ! col.sType && col._sManualType ) { 3919 col.sType = col._sManualType; 3920 } 3921 else if ( ! col.sType ) { 3922 for ( j=0, jen=types.length ; j<jen ; j++ ) { 3923 for ( k=0, ken=data.length ; k<ken ; k++ ) { 3924 // Use a cache array so we only need to get the type data 3925 // from the formatter once (when using multiple detectors) 3926 if ( cache[k] === undefined ) { 3927 cache[k] = _fnGetCellData( settings, k, i, 'type' ); 3928 } 3929 3930 detectedType = types[j]( cache[k], settings ); 3931 3932 // If null, then this type can't apply to this column, so 3933 // rather than testing all cells, break out. There is an 3934 // exception for the last type which is `html`. We need to 3935 // scan all rows since it is possible to mix string and HTML 3936 // types 3937 if ( ! detectedType && j !== types.length-1 ) { 3938 break; 3939 } 3940 3941 // Only a single match is needed for html type since it is 3942 // bottom of the pile and very similar to string 3943 if ( detectedType === 'html' ) { 3944 break; 3945 } 3946 } 3947 3948 // Type is valid for all data points in the column - use this 3949 // type 3950 if ( detectedType ) { 3951 col.sType = detectedType; 3952 break; 3953 } 3954 } 3955 3956 // Fall back - if no type was detected, always use string 3957 if ( ! col.sType ) { 3958 col.sType = 'string'; 3959 } 3960 } 3961 } 3962 } 3963 3964 3965 /** 3966 * Take the column definitions and static columns arrays and calculate how 3967 * they relate to column indexes. The callback function will then apply the 3968 * definition found for a column to a suitable configuration object. 3969 * @param {object} oSettings dataTables settings object 3970 * @param {array} aoColDefs The aoColumnDefs array that is to be applied 3971 * @param {array} aoCols The aoColumns array that defines columns individually 3972 * @param {function} fn Callback function - takes two parameters, the calculated 3973 * column index and the definition for that column. 3974 * @memberof DataTable#oApi 3975 */ 3976 function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn ) 3977 { 3978 var i, iLen, j, jLen, k, kLen, def; 3979 var columns = oSettings.aoColumns; 3980 3981 // Column definitions with aTargets 3982 if ( aoColDefs ) 3983 { 3984 /* Loop over the definitions array - loop in reverse so first instance has priority */ 3985 for ( i=aoColDefs.length-1 ; i>=0 ; i-- ) 3986 { 3987 def = aoColDefs[i]; 3988 3989 /* Each definition can target multiple columns, as it is an array */ 3990 var aTargets = def.targets !== undefined ? 3991 def.targets : 3992 def.aTargets; 3993 3994 if ( ! Array.isArray( aTargets ) ) 3995 { 3996 aTargets = [ aTargets ]; 3997 } 3998 3999 for ( j=0, jLen=aTargets.length ; j<jLen ; j++ ) 4000 { 4001 if ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 ) 4002 { 4003 /* Add columns that we don't yet know about */ 4004 while( columns.length <= aTargets[j] ) 4005 { 4006 _fnAddColumn( oSettings ); 4007 } 4008 4009 /* Integer, basic index */ 4010 fn( aTargets[j], def ); 4011 } 4012 else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 ) 4013 { 4014 /* Negative integer, right to left column counting */ 4015 fn( columns.length+aTargets[j], def ); 4016 } 4017 else if ( typeof aTargets[j] === 'string' ) 4018 { 4019 /* Class name matching on TH element */ 4020 for ( k=0, kLen=columns.length ; k<kLen ; k++ ) 4021 { 4022 if ( aTargets[j] == "_all" || 4023 $(columns[k].nTh).hasClass( aTargets[j] ) ) 4024 { 4025 fn( k, def ); 4026 } 4027 } 4028 } 4029 } 4030 } 4031 } 4032 4033 // Statically defined columns array 4034 if ( aoCols ) 4035 { 4036 for ( i=0, iLen=aoCols.length ; i<iLen ; i++ ) 4037 { 4038 fn( i, aoCols[i] ); 4039 } 4040 } 4041 } 4042 4043 /** 4044 * Add a data array to the table, creating DOM node etc. This is the parallel to 4045 * _fnGatherData, but for adding rows from a Javascript source, rather than a 4046 * DOM source. 4047 * @param {object} oSettings dataTables settings object 4048 * @param {array} aData data array to be added 4049 * @param {node} [nTr] TR element to add to the table - optional. If not given, 4050 * DataTables will create a row automatically 4051 * @param {array} [anTds] Array of TD|TH elements for the row - must be given 4052 * if nTr is. 4053 * @returns {int} >=0 if successful (index of new aoData entry), -1 if failed 4054 * @memberof DataTable#oApi 4055 */ 4056 function _fnAddData ( oSettings, aDataIn, nTr, anTds ) 4057 { 4058 /* Create the object for storing information about this new row */ 4059 var iRow = oSettings.aoData.length; 4060 var oData = $.extend( true, {}, DataTable.models.oRow, { 4061 src: nTr ? 'dom' : 'data', 4062 idx: iRow 4063 } ); 4064 4065 oData._aData = aDataIn; 4066 oSettings.aoData.push( oData ); 4067 4068 /* Create the cells */ 4069 var nTd, sThisType; 4070 var columns = oSettings.aoColumns; 4071 4072 // Invalidate the column types as the new data needs to be revalidated 4073 for ( var i=0, iLen=columns.length ; i<iLen ; i++ ) 4074 { 4075 columns[i].sType = null; 4076 } 4077 4078 /* Add to the display array */ 4079 oSettings.aiDisplayMaster.push( iRow ); 4080 4081 var id = oSettings.rowIdFn( aDataIn ); 4082 if ( id !== undefined ) { 4083 oSettings.aIds[ id ] = oData; 4084 } 4085 4086 /* Create the DOM information, or register it if already present */ 4087 if ( nTr || ! oSettings.oFeatures.bDeferRender ) 4088 { 4089 _fnCreateTr( oSettings, iRow, nTr, anTds ); 4090 } 4091 4092 return iRow; 4093 } 4094 4095 4096 /** 4097 * Add one or more TR elements to the table. Generally we'd expect to 4098 * use this for reading data from a DOM sourced table, but it could be 4099 * used for an TR element. Note that if a TR is given, it is used (i.e. 4100 * it is not cloned). 4101 * @param {object} settings dataTables settings object 4102 * @param {array|node|jQuery} trs The TR element(s) to add to the table 4103 * @returns {array} Array of indexes for the added rows 4104 * @memberof DataTable#oApi 4105 */ 4106 function _fnAddTr( settings, trs ) 4107 { 4108 var row; 4109 4110 // Allow an individual node to be passed in 4111 if ( ! (trs instanceof $) ) { 4112 trs = $(trs); 4113 } 4114 4115 return trs.map( function (i, el) { 4116 row = _fnGetRowElements( settings, el ); 4117 return _fnAddData( settings, row.data, el, row.cells ); 4118 } ); 4119 } 4120 4121 4122 /** 4123 * Take a TR element and convert it to an index in aoData 4124 * @param {object} oSettings dataTables settings object 4125 * @param {node} n the TR element to find 4126 * @returns {int} index if the node is found, null if not 4127 * @memberof DataTable#oApi 4128 */ 4129 function _fnNodeToDataIndex( oSettings, n ) 4130 { 4131 return (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null; 4132 } 4133 4134 4135 /** 4136 * Take a TD element and convert it into a column data index (not the visible index) 4137 * @param {object} oSettings dataTables settings object 4138 * @param {int} iRow The row number the TD/TH can be found in 4139 * @param {node} n The TD/TH element to find 4140 * @returns {int} index if the node is found, -1 if not 4141 * @memberof DataTable#oApi 4142 */ 4143 function _fnNodeToColumnIndex( oSettings, iRow, n ) 4144 { 4145 return $.inArray( n, oSettings.aoData[ iRow ].anCells ); 4146 } 4147 4148 4149 /** 4150 * Get the data for a given cell from the internal cache, taking into account data mapping 4151 * @param {object} settings dataTables settings object 4152 * @param {int} rowIdx aoData row id 4153 * @param {int} colIdx Column index 4154 * @param {string} type data get type ('display', 'type' 'filter' 'sort') 4155 * @returns {*} Cell data 4156 * @memberof DataTable#oApi 4157 */ 4158 function _fnGetCellData( settings, rowIdx, colIdx, type ) 4159 { 4160 var draw = settings.iDraw; 4161 var col = settings.aoColumns[colIdx]; 4162 var rowData = settings.aoData[rowIdx]._aData; 4163 var defaultContent = col.sDefaultContent; 4164 var cellData = col.fnGetData( rowData, type, { 4165 settings: settings, 4166 row: rowIdx, 4167 col: colIdx 4168 } ); 4169 4170 if ( cellData === undefined ) { 4171 if ( settings.iDrawError != draw && defaultContent === null ) { 4172 _fnLog( settings, 0, "Requested unknown parameter "+ 4173 (typeof col.mData=='function' ? '{function}' : "'"+col.mData+"'")+ 4174 " for row "+rowIdx+", column "+colIdx, 4 ); 4175 settings.iDrawError = draw; 4176 } 4177 return defaultContent; 4178 } 4179 4180 // When the data source is null and a specific data type is requested (i.e. 4181 // not the original data), we can use default column data 4182 if ( (cellData === rowData || cellData === null) && defaultContent !== null && type !== undefined ) { 4183 cellData = defaultContent; 4184 } 4185 else if ( typeof cellData === 'function' ) { 4186 // If the data source is a function, then we run it and use the return, 4187 // executing in the scope of the data object (for instances) 4188 return cellData.call( rowData ); 4189 } 4190 4191 if ( cellData === null && type == 'display' ) { 4192 return ''; 4193 } 4194 return cellData; 4195 } 4196 4197 4198 /** 4199 * Set the value for a specific cell, into the internal data cache 4200 * @param {object} settings dataTables settings object 4201 * @param {int} rowIdx aoData row id 4202 * @param {int} colIdx Column index 4203 * @param {*} val Value to set 4204 * @memberof DataTable#oApi 4205 */ 4206 function _fnSetCellData( settings, rowIdx, colIdx, val ) 4207 { 4208 var col = settings.aoColumns[colIdx]; 4209 var rowData = settings.aoData[rowIdx]._aData; 4210 4211 col.fnSetData( rowData, val, { 4212 settings: settings, 4213 row: rowIdx, 4214 col: colIdx 4215 } ); 4216 } 4217 4218 4219 // Private variable that is used to match action syntax in the data property object 4220 var __reArray = /\[.*?\]$/; 4221 var __reFn = /\(\)$/; 4222 4223 /** 4224 * Split string on periods, taking into account escaped periods 4225 * @param {string} str String to split 4226 * @return {array} Split string 4227 */ 4228 function _fnSplitObjNotation( str ) 4229 { 4230 return $.map( str.match(/(\\.|[^\.])+/g) || [''], function ( s ) { 4231 return s.replace(/\\\./g, '.'); 4232 } ); 4233 } 4234 4235 4236 /** 4237 * Return a function that can be used to get data from a source object, taking 4238 * into account the ability to use nested objects as a source 4239 * @param {string|int|function} mSource The data source for the object 4240 * @returns {function} Data get function 4241 * @memberof DataTable#oApi 4242 */ 4243 function _fnGetObjectDataFn( mSource ) 4244 { 4245 if ( $.isPlainObject( mSource ) ) 4246 { 4247 /* Build an object of get functions, and wrap them in a single call */ 4248 var o = {}; 4249 $.each( mSource, function (key, val) { 4250 if ( val ) { 4251 o[key] = _fnGetObjectDataFn( val ); 4252 } 4253 } ); 4254 4255 return function (data, type, row, meta) { 4256 var t = o[type] || o._; 4257 return t !== undefined ? 4258 t(data, type, row, meta) : 4259 data; 4260 }; 4261 } 4262 else if ( mSource === null ) 4263 { 4264 /* Give an empty string for rendering / sorting etc */ 4265 return function (data) { // type, row and meta also passed, but not used 4266 return data; 4267 }; 4268 } 4269 else if ( typeof mSource === 'function' ) 4270 { 4271 return function (data, type, row, meta) { 4272 return mSource( data, type, row, meta ); 4273 }; 4274 } 4275 else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 || 4276 mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) ) 4277 { 4278 /* If there is a . in the source string then the data source is in a 4279 * nested object so we loop over the data for each level to get the next 4280 * level down. On each loop we test for undefined, and if found immediately 4281 * return. This allows entire objects to be missing and sDefaultContent to 4282 * be used if defined, rather than throwing an error 4283 */ 4284 var fetchData = function (data, type, src) { 4285 var arrayNotation, funcNotation, out, innerSrc; 4286 4287 if ( src !== "" ) 4288 { 4289 var a = _fnSplitObjNotation( src ); 4290 4291 for ( var i=0, iLen=a.length ; i<iLen ; i++ ) 4292 { 4293 // Check if we are dealing with special notation 4294 arrayNotation = a[i].match(__reArray); 4295 funcNotation = a[i].match(__reFn); 4296 4297 if ( arrayNotation ) 4298 { 4299 // Array notation 4300 a[i] = a[i].replace(__reArray, ''); 4301 4302 // Condition allows simply [] to be passed in 4303 if ( a[i] !== "" ) { 4304 data = data[ a[i] ]; 4305 } 4306 out = []; 4307 4308 // Get the remainder of the nested object to get 4309 a.splice( 0, i+1 ); 4310 innerSrc = a.join('.'); 4311 4312 // Traverse each entry in the array getting the properties requested 4313 if ( Array.isArray( data ) ) { 4314 for ( var j=0, jLen=data.length ; j<jLen ; j++ ) { 4315 out.push( fetchData( data[j], type, innerSrc ) ); 4316 } 4317 } 4318 4319 // If a string is given in between the array notation indicators, that 4320 // is used to join the strings together, otherwise an array is returned 4321 var join = arrayNotation[0].substring(1, arrayNotation[0].length-1); 4322 data = (join==="") ? out : out.join(join); 4323 4324 // The inner call to fetchData has already traversed through the remainder 4325 // of the source requested, so we exit from the loop 4326 break; 4327 } 4328 else if ( funcNotation ) 4329 { 4330 // Function call 4331 a[i] = a[i].replace(__reFn, ''); 4332 data = data[ a[i] ](); 4333 continue; 4334 } 4335 4336 if ( data === null || data[ a[i] ] === undefined ) 4337 { 4338 return undefined; 4339 } 4340 data = data[ a[i] ]; 4341 } 4342 } 4343 4344 return data; 4345 }; 4346 4347 return function (data, type) { // row and meta also passed, but not used 4348 return fetchData( data, type, mSource ); 4349 }; 4350 } 4351 else 4352 { 4353 /* Array or flat object mapping */ 4354 return function (data, type) { // row and meta also passed, but not used 4355 return data[mSource]; 4356 }; 4357 } 4358 } 4359 4360 4361 /** 4362 * Return a function that can be used to set data from a source object, taking 4363 * into account the ability to use nested objects as a source 4364 * @param {string|int|function} mSource The data source for the object 4365 * @returns {function} Data set function 4366 * @memberof DataTable#oApi 4367 */ 4368 function _fnSetObjectDataFn( mSource ) 4369 { 4370 if ( $.isPlainObject( mSource ) ) 4371 { 4372 /* Unlike get, only the underscore (global) option is used for for 4373 * setting data since we don't know the type here. This is why an object 4374 * option is not documented for `mData` (which is read/write), but it is 4375 * for `mRender` which is read only. 4376 */ 4377 return _fnSetObjectDataFn( mSource._ ); 4378 } 4379 else if ( mSource === null ) 4380 { 4381 /* Nothing to do when the data source is null */ 4382 return function () {}; 4383 } 4384 else if ( typeof mSource === 'function' ) 4385 { 4386 return function (data, val, meta) { 4387 mSource( data, 'set', val, meta ); 4388 }; 4389 } 4390 else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 || 4391 mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) ) 4392 { 4393 /* Like the get, we need to get data from a nested object */ 4394 var setData = function (data, val, src) { 4395 var a = _fnSplitObjNotation( src ), b; 4396 var aLast = a[a.length-1]; 4397 var arrayNotation, funcNotation, o, innerSrc; 4398 4399 for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ ) 4400 { 4401 // Protect against prototype pollution 4402 if (a[i] === '__proto__' || a[i] === 'constructor') { 4403 throw new Error('Cannot set prototype values'); 4404 } 4405 4406 // Check if we are dealing with an array notation request 4407 arrayNotation = a[i].match(__reArray); 4408 funcNotation = a[i].match(__reFn); 4409 4410 if ( arrayNotation ) 4411 { 4412 a[i] = a[i].replace(__reArray, ''); 4413 data[ a[i] ] = []; 4414 4415 // Get the remainder of the nested object to set so we can recurse 4416 b = a.slice(); 4417 b.splice( 0, i+1 ); 4418 innerSrc = b.join('.'); 4419 4420 // Traverse each entry in the array setting the properties requested 4421 if ( Array.isArray( val ) ) 4422 { 4423 for ( var j=0, jLen=val.length ; j<jLen ; j++ ) 4424 { 4425 o = {}; 4426 setData( o, val[j], innerSrc ); 4427 data[ a[i] ].push( o ); 4428 } 4429 } 4430 else 4431 { 4432 // We've been asked to save data to an array, but it 4433 // isn't array data to be saved. Best that can be done 4434 // is to just save the value. 4435 data[ a[i] ] = val; 4436 } 4437 4438 // The inner call to setData has already traversed through the remainder 4439 // of the source and has set the data, thus we can exit here 4440 return; 4441 } 4442 else if ( funcNotation ) 4443 { 4444 // Function call 4445 a[i] = a[i].replace(__reFn, ''); 4446 data = data[ a[i] ]( val ); 4447 } 4448 4449 // If the nested object doesn't currently exist - since we are 4450 // trying to set the value - create it 4451 if ( data[ a[i] ] === null || data[ a[i] ] === undefined ) 4452 { 4453 data[ a[i] ] = {}; 4454 } 4455 data = data[ a[i] ]; 4456 } 4457 4458 // Last item in the input - i.e, the actual set 4459 if ( aLast.match(__reFn ) ) 4460 { 4461 // Function call 4462 data = data[ aLast.replace(__reFn, '') ]( val ); 4463 } 4464 else 4465 { 4466 // If array notation is used, we just want to strip it and use the property name 4467 // and assign the value. If it isn't used, then we get the result we want anyway 4468 data[ aLast.replace(__reArray, '') ] = val; 4469 } 4470 }; 4471 4472 return function (data, val) { // meta is also passed in, but not used 4473 return setData( data, val, mSource ); 4474 }; 4475 } 4476 else 4477 { 4478 /* Array or flat object mapping */ 4479 return function (data, val) { // meta is also passed in, but not used 4480 data[mSource] = val; 4481 }; 4482 } 4483 } 4484 4485 4486 /** 4487 * Return an array with the full table data 4488 * @param {object} oSettings dataTables settings object 4489 * @returns array {array} aData Master data array 4490 * @memberof DataTable#oApi 4491 */ 4492 function _fnGetDataMaster ( settings ) 4493 { 4494 return _pluck( settings.aoData, '_aData' ); 4495 } 4496 4497 4498 /** 4499 * Nuke the table 4500 * @param {object} oSettings dataTables settings object 4501 * @memberof DataTable#oApi 4502 */ 4503 function _fnClearTable( settings ) 4504 { 4505 settings.aoData.length = 0; 4506 settings.aiDisplayMaster.length = 0; 4507 settings.aiDisplay.length = 0; 4508 settings.aIds = {}; 4509 } 4510 4511 4512 /** 4513 * Take an array of integers (index array) and remove a target integer (value - not 4514 * the key!) 4515 * @param {array} a Index array to target 4516 * @param {int} iTarget value to find 4517 * @memberof DataTable#oApi 4518 */ 4519 function _fnDeleteIndex( a, iTarget, splice ) 4520 { 4521 var iTargetIndex = -1; 4522 4523 for ( var i=0, iLen=a.length ; i<iLen ; i++ ) 4524 { 4525 if ( a[i] == iTarget ) 4526 { 4527 iTargetIndex = i; 4528 } 4529 else if ( a[i] > iTarget ) 4530 { 4531 a[i]--; 4532 } 4533 } 4534 4535 if ( iTargetIndex != -1 && splice === undefined ) 4536 { 4537 a.splice( iTargetIndex, 1 ); 4538 } 4539 } 4540 4541 4542 /** 4543 * Mark cached data as invalid such that a re-read of the data will occur when 4544 * the cached data is next requested. Also update from the data source object. 4545 * 4546 * @param {object} settings DataTables settings object 4547 * @param {int} rowIdx Row index to invalidate 4548 * @param {string} [src] Source to invalidate from: undefined, 'auto', 'dom' 4549 * or 'data' 4550 * @param {int} [colIdx] Column index to invalidate. If undefined the whole 4551 * row will be invalidated 4552 * @memberof DataTable#oApi 4553 * 4554 * @todo For the modularisation of v1.11 this will need to become a callback, so 4555 * the sort and filter methods can subscribe to it. That will required 4556 * initialisation options for sorting, which is why it is not already baked in 4557 */ 4558 function _fnInvalidate( settings, rowIdx, src, colIdx ) 4559 { 4560 var row = settings.aoData[ rowIdx ]; 4561 var i, ien; 4562 var cellWrite = function ( cell, col ) { 4563 // This is very frustrating, but in IE if you just write directly 4564 // to innerHTML, and elements that are overwritten are GC'ed, 4565 // even if there is a reference to them elsewhere 4566 while ( cell.childNodes.length ) { 4567 cell.removeChild( cell.firstChild ); 4568 } 4569 4570 cell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' ); 4571 }; 4572 4573 // Are we reading last data from DOM or the data object? 4574 if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) { 4575 // Read the data from the DOM 4576 row._aData = _fnGetRowElements( 4577 settings, row, colIdx, colIdx === undefined ? undefined : row._aData 4578 ) 4579 .data; 4580 } 4581 else { 4582 // Reading from data object, update the DOM 4583 var cells = row.anCells; 4584 4585 if ( cells ) { 4586 if ( colIdx !== undefined ) { 4587 cellWrite( cells[colIdx], colIdx ); 4588 } 4589 else { 4590 for ( i=0, ien=cells.length ; i<ien ; i++ ) { 4591 cellWrite( cells[i], i ); 4592 } 4593 } 4594 } 4595 } 4596 4597 // For both row and cell invalidation, the cached data for sorting and 4598 // filtering is nulled out 4599 row._aSortData = null; 4600 row._aFilterData = null; 4601 4602 // Invalidate the type for a specific column (if given) or all columns since 4603 // the data might have changed 4604 var cols = settings.aoColumns; 4605 if ( colIdx !== undefined ) { 4606 cols[ colIdx ].sType = null; 4607 } 4608 else { 4609 for ( i=0, ien=cols.length ; i<ien ; i++ ) { 4610 cols[i].sType = null; 4611 } 4612 4613 // Update DataTables special `DT_*` attributes for the row 4614 _fnRowAttributes( settings, row ); 4615 } 4616 } 4617 4618 4619 /** 4620 * Build a data source object from an HTML row, reading the contents of the 4621 * cells that are in the row. 4622 * 4623 * @param {object} settings DataTables settings object 4624 * @param {node|object} TR element from which to read data or existing row 4625 * object from which to re-read the data from the cells 4626 * @param {int} [colIdx] Optional column index 4627 * @param {array|object} [d] Data source object. If `colIdx` is given then this 4628 * parameter should also be given and will be used to write the data into. 4629 * Only the column in question will be written 4630 * @returns {object} Object with two parameters: `data` the data read, in 4631 * document order, and `cells` and array of nodes (they can be useful to the 4632 * caller, so rather than needing a second traversal to get them, just return 4633 * them from here). 4634 * @memberof DataTable#oApi 4635 */ 4636 function _fnGetRowElements( settings, row, colIdx, d ) 4637 { 4638 var 4639 tds = [], 4640 td = row.firstChild, 4641 name, col, o, i=0, contents, 4642 columns = settings.aoColumns, 4643 objectRead = settings._rowReadObject; 4644 4645 // Allow the data object to be passed in, or construct 4646 d = d !== undefined ? 4647 d : 4648 objectRead ? 4649 {} : 4650 []; 4651 4652 var attr = function ( str, td ) { 4653 if ( typeof str === 'string' ) { 4654 var idx = str.indexOf('@'); 4655 4656 if ( idx !== -1 ) { 4657 var attr = str.substring( idx+1 ); 4658 var setter = _fnSetObjectDataFn( str ); 4659 setter( d, td.getAttribute( attr ) ); 4660 } 4661 } 4662 }; 4663 4664 // Read data from a cell and store into the data object 4665 var cellProcess = function ( cell ) { 4666 if ( colIdx === undefined || colIdx === i ) { 4667 col = columns[i]; 4668 contents = (cell.innerHTML).trim(); 4669 4670 if ( col && col._bAttrSrc ) { 4671 var setter = _fnSetObjectDataFn( col.mData._ ); 4672 setter( d, contents ); 4673 4674 attr( col.mData.sort, cell ); 4675 attr( col.mData.type, cell ); 4676 attr( col.mData.filter, cell ); 4677 } 4678 else { 4679 // Depending on the `data` option for the columns the data can 4680 // be read to either an object or an array. 4681 if ( objectRead ) { 4682 if ( ! col._setter ) { 4683 // Cache the setter function 4684 col._setter = _fnSetObjectDataFn( col.mData ); 4685 } 4686 col._setter( d, contents ); 4687 } 4688 else { 4689 d[i] = contents; 4690 } 4691 } 4692 } 4693 4694 i++; 4695 }; 4696 4697 if ( td ) { 4698 // `tr` element was passed in 4699 while ( td ) { 4700 name = td.nodeName.toUpperCase(); 4701 4702 if ( name == "TD" || name == "TH" ) { 4703 cellProcess( td ); 4704 tds.push( td ); 4705 } 4706 4707 td = td.nextSibling; 4708 } 4709 } 4710 else { 4711 // Existing row object passed in 4712 tds = row.anCells; 4713 4714 for ( var j=0, jen=tds.length ; j<jen ; j++ ) { 4715 cellProcess( tds[j] ); 4716 } 4717 } 4718 4719 // Read the ID from the DOM if present 4720 var rowNode = row.firstChild ? row : row.nTr; 4721 4722 if ( rowNode ) { 4723 var id = rowNode.getAttribute( 'id' ); 4724 4725 if ( id ) { 4726 _fnSetObjectDataFn( settings.rowId )( d, id ); 4727 } 4728 } 4729 4730 return { 4731 data: d, 4732 cells: tds 4733 }; 4734 } 4735 /** 4736 * Create a new TR element (and it's TD children) for a row 4737 * @param {object} oSettings dataTables settings object 4738 * @param {int} iRow Row to consider 4739 * @param {node} [nTrIn] TR element to add to the table - optional. If not given, 4740 * DataTables will create a row automatically 4741 * @param {array} [anTds] Array of TD|TH elements for the row - must be given 4742 * if nTr is. 4743 * @memberof DataTable#oApi 4744 */ 4745 function _fnCreateTr ( oSettings, iRow, nTrIn, anTds ) 4746 { 4747 var 4748 row = oSettings.aoData[iRow], 4749 rowData = row._aData, 4750 cells = [], 4751 nTr, nTd, oCol, 4752 i, iLen, create; 4753 4754 if ( row.nTr === null ) 4755 { 4756 nTr = nTrIn || document.createElement('tr'); 4757 4758 row.nTr = nTr; 4759 row.anCells = cells; 4760 4761 /* Use a private property on the node to allow reserve mapping from the node 4762 * to the aoData array for fast look up 4763 */ 4764 nTr._DT_RowIndex = iRow; 4765 4766 /* Special parameters can be given by the data source to be used on the row */ 4767 _fnRowAttributes( oSettings, row ); 4768 4769 /* Process each column */ 4770 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ ) 4771 { 4772 oCol = oSettings.aoColumns[i]; 4773 create = nTrIn ? false : true; 4774 4775 nTd = create ? document.createElement( oCol.sCellType ) : anTds[i]; 4776 nTd._DT_CellIndex = { 4777 row: iRow, 4778 column: i 4779 }; 4780 4781 cells.push( nTd ); 4782 4783 // Need to create the HTML if new, or if a rendering function is defined 4784 if ( create || ((oCol.mRender || oCol.mData !== i) && 4785 (!$.isPlainObject(oCol.mData) || oCol.mData._ !== i+'.display') 4786 )) { 4787 nTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' ); 4788 } 4789 4790 /* Add user defined class */ 4791 if ( oCol.sClass ) 4792 { 4793 nTd.className += ' '+oCol.sClass; 4794 } 4795 4796 // Visibility - add or remove as required 4797 if ( oCol.bVisible && ! nTrIn ) 4798 { 4799 nTr.appendChild( nTd ); 4800 } 4801 else if ( ! oCol.bVisible && nTrIn ) 4802 { 4803 nTd.parentNode.removeChild( nTd ); 4804 } 4805 4806 if ( oCol.fnCreatedCell ) 4807 { 4808 oCol.fnCreatedCell.call( oSettings.oInstance, 4809 nTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i 4810 ); 4811 } 4812 } 4813 4814 _fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [nTr, rowData, iRow, cells] ); 4815 } 4816 } 4817 4818 4819 /** 4820 * Add attributes to a row based on the special `DT_*` parameters in a data 4821 * source object. 4822 * @param {object} settings DataTables settings object 4823 * @param {object} DataTables row object for the row to be modified 4824 * @memberof DataTable#oApi 4825 */ 4826 function _fnRowAttributes( settings, row ) 4827 { 4828 var tr = row.nTr; 4829 var data = row._aData; 4830 4831 if ( tr ) { 4832 var id = settings.rowIdFn( data ); 4833 4834 if ( id ) { 4835 tr.id = id; 4836 } 4837 4838 if ( data.DT_RowClass ) { 4839 // Remove any classes added by DT_RowClass before 4840 var a = data.DT_RowClass.split(' '); 4841 row.__rowc = row.__rowc ? 4842 _unique( row.__rowc.concat( a ) ) : 4843 a; 4844 4845 $(tr) 4846 .removeClass( row.__rowc.join(' ') ) 4847 .addClass( data.DT_RowClass ); 4848 } 4849 4850 if ( data.DT_RowAttr ) { 4851 $(tr).attr( data.DT_RowAttr ); 4852 } 4853 4854 if ( data.DT_RowData ) { 4855 $(tr).data( data.DT_RowData ); 4856 } 4857 } 4858 } 4859 4860 4861 /** 4862 * Create the HTML header for the table 4863 * @param {object} oSettings dataTables settings object 4864 * @memberof DataTable#oApi 4865 */ 4866 function _fnBuildHead( oSettings ) 4867 { 4868 var i, ien, cell, row, column; 4869 var thead = oSettings.nTHead; 4870 var tfoot = oSettings.nTFoot; 4871 var createHeader = $('th, td', thead).length === 0; 4872 var classes = oSettings.oClasses; 4873 var columns = oSettings.aoColumns; 4874 4875 if ( createHeader ) { 4876 row = $('<tr/>').appendTo( thead ); 4877 } 4878 4879 for ( i=0, ien=columns.length ; i<ien ; i++ ) { 4880 column = columns[i]; 4881 cell = $( column.nTh ).addClass( column.sClass ); 4882 4883 if ( createHeader ) { 4884 cell.appendTo( row ); 4885 } 4886 4887 // 1.11 move into sorting 4888 if ( oSettings.oFeatures.bSort ) { 4889 cell.addClass( column.sSortingClass ); 4890 4891 if ( column.bSortable !== false ) { 4892 cell 4893 .attr( 'tabindex', oSettings.iTabIndex ) 4894 .attr( 'aria-controls', oSettings.sTableId ); 4895 4896 _fnSortAttachListener( oSettings, column.nTh, i ); 4897 } 4898 } 4899 4900 if ( column.sTitle != cell[0].innerHTML ) { 4901 cell.html( column.sTitle ); 4902 } 4903 4904 _fnRenderer( oSettings, 'header' )( 4905 oSettings, cell, column, classes 4906 ); 4907 } 4908 4909 if ( createHeader ) { 4910 _fnDetectHeader( oSettings.aoHeader, thead ); 4911 } 4912 4913 /* ARIA role for the rows */ 4914 $(thead).children('tr').attr('role', 'row'); 4915 4916 /* Deal with the footer - add classes if required */ 4917 $(thead).children('tr').children('th, td').addClass( classes.sHeaderTH ); 4918 $(tfoot).children('tr').children('th, td').addClass( classes.sFooterTH ); 4919 4920 // Cache the footer cells. Note that we only take the cells from the first 4921 // row in the footer. If there is more than one row the user wants to 4922 // interact with, they need to use the table().foot() method. Note also this 4923 // allows cells to be used for multiple columns using colspan 4924 if ( tfoot !== null ) { 4925 var cells = oSettings.aoFooter[0]; 4926 4927 for ( i=0, ien=cells.length ; i<ien ; i++ ) { 4928 column = columns[i]; 4929 column.nTf = cells[i].cell; 4930 4931 if ( column.sClass ) { 4932 $(column.nTf).addClass( column.sClass ); 4933 } 4934 } 4935 } 4936 } 4937 4938 4939 /** 4940 * Draw the header (or footer) element based on the column visibility states. The 4941 * methodology here is to use the layout array from _fnDetectHeader, modified for 4942 * the instantaneous column visibility, to construct the new layout. The grid is 4943 * traversed over cell at a time in a rows x columns grid fashion, although each 4944 * cell insert can cover multiple elements in the grid - which is tracks using the 4945 * aApplied array. Cell inserts in the grid will only occur where there isn't 4946 * already a cell in that position. 4947 * @param {object} oSettings dataTables settings object 4948 * @param array {objects} aoSource Layout array from _fnDetectHeader 4949 * @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc, 4950 * @memberof DataTable#oApi 4951 */ 4952 function _fnDrawHead( oSettings, aoSource, bIncludeHidden ) 4953 { 4954 var i, iLen, j, jLen, k, kLen, n, nLocalTr; 4955 var aoLocal = []; 4956 var aApplied = []; 4957 var iColumns = oSettings.aoColumns.length; 4958 var iRowspan, iColspan; 4959 4960 if ( ! aoSource ) 4961 { 4962 return; 4963 } 4964 4965 if ( bIncludeHidden === undefined ) 4966 { 4967 bIncludeHidden = false; 4968 } 4969 4970 /* Make a copy of the master layout array, but without the visible columns in it */ 4971 for ( i=0, iLen=aoSource.length ; i<iLen ; i++ ) 4972 { 4973 aoLocal[i] = aoSource[i].slice(); 4974 aoLocal[i].nTr = aoSource[i].nTr; 4975 4976 /* Remove any columns which are currently hidden */ 4977 for ( j=iColumns-1 ; j>=0 ; j-- ) 4978 { 4979 if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden ) 4980 { 4981 aoLocal[i].splice( j, 1 ); 4982 } 4983 } 4984 4985 /* Prep the applied array - it needs an element for each row */ 4986 aApplied.push( [] ); 4987 } 4988 4989 for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ ) 4990 { 4991 nLocalTr = aoLocal[i].nTr; 4992 4993 /* All cells are going to be replaced, so empty out the row */ 4994 if ( nLocalTr ) 4995 { 4996 while( (n = nLocalTr.firstChild) ) 4997 { 4998 nLocalTr.removeChild( n ); 4999 } 5000 } 5001 5002 for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ ) 5003 { 5004 iRowspan = 1; 5005 iColspan = 1; 5006 5007 /* Check to see if there is already a cell (row/colspan) covering our target 5008 * insert point. If there is, then there is nothing to do. 5009 */ 5010 if ( aApplied[i][j] === undefined ) 5011 { 5012 nLocalTr.appendChild( aoLocal[i][j].cell ); 5013 aApplied[i][j] = 1; 5014 5015 /* Expand the cell to cover as many rows as needed */ 5016 while ( aoLocal[i+iRowspan] !== undefined && 5017 aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell ) 5018 { 5019 aApplied[i+iRowspan][j] = 1; 5020 iRowspan++; 5021 } 5022 5023 /* Expand the cell to cover as many columns as needed */ 5024 while ( aoLocal[i][j+iColspan] !== undefined && 5025 aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell ) 5026 { 5027 /* Must update the applied array over the rows for the columns */ 5028 for ( k=0 ; k<iRowspan ; k++ ) 5029 { 5030 aApplied[i+k][j+iColspan] = 1; 5031 } 5032 iColspan++; 5033 } 5034 5035 /* Do the actual expansion in the DOM */ 5036 $(aoLocal[i][j].cell) 5037 .attr('rowspan', iRowspan) 5038 .attr('colspan', iColspan); 5039 } 5040 } 5041 } 5042 } 5043 5044 5045 /** 5046 * Insert the required TR nodes into the table for display 5047 * @param {object} oSettings dataTables settings object 5048 * @memberof DataTable#oApi 5049 */ 5050 function _fnDraw( oSettings ) 5051 { 5052 /* Provide a pre-callback function which can be used to cancel the draw is false is returned */ 5053 var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] ); 5054 if ( $.inArray( false, aPreDraw ) !== -1 ) 5055 { 5056 _fnProcessingDisplay( oSettings, false ); 5057 return; 5058 } 5059 5060 var i, iLen, n; 5061 var anRows = []; 5062 var iRowCount = 0; 5063 var asStripeClasses = oSettings.asStripeClasses; 5064 var iStripes = asStripeClasses.length; 5065 var iOpenRows = oSettings.aoOpenRows.length; 5066 var oLang = oSettings.oLanguage; 5067 var iInitDisplayStart = oSettings.iInitDisplayStart; 5068 var bServerSide = _fnDataSource( oSettings ) == 'ssp'; 5069 var aiDisplay = oSettings.aiDisplay; 5070 5071 oSettings.bDrawing = true; 5072 5073 /* Check and see if we have an initial draw position from state saving */ 5074 if ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 ) 5075 { 5076 oSettings._iDisplayStart = bServerSide ? 5077 iInitDisplayStart : 5078 iInitDisplayStart >= oSettings.fnRecordsDisplay() ? 5079 0 : 5080 iInitDisplayStart; 5081 5082 oSettings.iInitDisplayStart = -1; 5083 } 5084 5085 var iDisplayStart = oSettings._iDisplayStart; 5086 var iDisplayEnd = oSettings.fnDisplayEnd(); 5087 5088 /* Server-side processing draw intercept */ 5089 if ( oSettings.bDeferLoading ) 5090 { 5091 oSettings.bDeferLoading = false; 5092 oSettings.iDraw++; 5093 _fnProcessingDisplay( oSettings, false ); 5094 } 5095 else if ( !bServerSide ) 5096 { 5097 oSettings.iDraw++; 5098 } 5099 else if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) ) 5100 { 5101 return; 5102 } 5103 5104 if ( aiDisplay.length !== 0 ) 5105 { 5106 var iStart = bServerSide ? 0 : iDisplayStart; 5107 var iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd; 5108 5109 for ( var j=iStart ; j<iEnd ; j++ ) 5110 { 5111 var iDataIndex = aiDisplay[j]; 5112 var aoData = oSettings.aoData[ iDataIndex ]; 5113 if ( aoData.nTr === null ) 5114 { 5115 _fnCreateTr( oSettings, iDataIndex ); 5116 } 5117 5118 var nRow = aoData.nTr; 5119 5120 /* Remove the old striping classes and then add the new one */ 5121 if ( iStripes !== 0 ) 5122 { 5123 var sStripe = asStripeClasses[ iRowCount % iStripes ]; 5124 if ( aoData._sRowStripe != sStripe ) 5125 { 5126 $(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe ); 5127 aoData._sRowStripe = sStripe; 5128 } 5129 } 5130 5131 // Row callback functions - might want to manipulate the row 5132 // iRowCount and j are not currently documented. Are they at all 5133 // useful? 5134 _fnCallbackFire( oSettings, 'aoRowCallback', null, 5135 [nRow, aoData._aData, iRowCount, j, iDataIndex] ); 5136 5137 anRows.push( nRow ); 5138 iRowCount++; 5139 } 5140 } 5141 else 5142 { 5143 /* Table is empty - create a row with an empty message in it */ 5144 var sZero = oLang.sZeroRecords; 5145 if ( oSettings.iDraw == 1 && _fnDataSource( oSettings ) == 'ajax' ) 5146 { 5147 sZero = oLang.sLoadingRecords; 5148 } 5149 else if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 ) 5150 { 5151 sZero = oLang.sEmptyTable; 5152 } 5153 5154 anRows[ 0 ] = $( '<tr/>', { 'class': iStripes ? asStripeClasses[0] : '' } ) 5155 .append( $('<td />', { 5156 'valign': 'top', 5157 'colSpan': _fnVisbleColumns( oSettings ), 5158 'class': oSettings.oClasses.sRowEmpty 5159 } ).html( sZero ) )[0]; 5160 } 5161 5162 /* Header and footer callbacks */ 5163 _fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0], 5164 _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] ); 5165 5166 _fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0], 5167 _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] ); 5168 5169 var body = $(oSettings.nTBody); 5170 5171 body.children().detach(); 5172 body.append( $(anRows) ); 5173 5174 /* Call all required callback functions for the end of a draw */ 5175 _fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] ); 5176 5177 /* Draw is complete, sorting and filtering must be as well */ 5178 oSettings.bSorted = false; 5179 oSettings.bFiltered = false; 5180 oSettings.bDrawing = false; 5181 } 5182 5183 5184 /** 5185 * Redraw the table - taking account of the various features which are enabled 5186 * @param {object} oSettings dataTables settings object 5187 * @param {boolean} [holdPosition] Keep the current paging position. By default 5188 * the paging is reset to the first page 5189 * @memberof DataTable#oApi 5190 */ 5191 function _fnReDraw( settings, holdPosition ) 5192 { 5193 var 5194 features = settings.oFeatures, 5195 sort = features.bSort, 5196 filter = features.bFilter; 5197 5198 if ( sort ) { 5199 _fnSort( settings ); 5200 } 5201 5202 if ( filter ) { 5203 _fnFilterComplete( settings, settings.oPreviousSearch ); 5204 } 5205 else { 5206 // No filtering, so we want to just use the display master 5207 settings.aiDisplay = settings.aiDisplayMaster.slice(); 5208 } 5209 5210 if ( holdPosition !== true ) { 5211 settings._iDisplayStart = 0; 5212 } 5213 5214 // Let any modules know about the draw hold position state (used by 5215 // scrolling internally) 5216 settings._drawHold = holdPosition; 5217 5218 _fnDraw( settings ); 5219 5220 settings._drawHold = false; 5221 } 5222 5223 5224 /** 5225 * Add the options to the page HTML for the table 5226 * @param {object} oSettings dataTables settings object 5227 * @memberof DataTable#oApi 5228 */ 5229 function _fnAddOptionsHtml ( oSettings ) 5230 { 5231 var classes = oSettings.oClasses; 5232 var table = $(oSettings.nTable); 5233 var holding = $('<div/>').insertBefore( table ); // Holding element for speed 5234 var features = oSettings.oFeatures; 5235 5236 // All DataTables are wrapped in a div 5237 var insert = $('<div/>', { 5238 id: oSettings.sTableId+'_wrapper', 5239 'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter) 5240 } ); 5241 5242 oSettings.nHolding = holding[0]; 5243 oSettings.nTableWrapper = insert[0]; 5244 oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling; 5245 5246 /* Loop over the user set positioning and place the elements as needed */ 5247 var aDom = oSettings.sDom.split(''); 5248 var featureNode, cOption, nNewNode, cNext, sAttr, j; 5249 for ( var i=0 ; i<aDom.length ; i++ ) 5250 { 5251 featureNode = null; 5252 cOption = aDom[i]; 5253 5254 if ( cOption == '<' ) 5255 { 5256 /* New container div */ 5257 nNewNode = $('<div/>')[0]; 5258 5259 /* Check to see if we should append an id and/or a class name to the container */ 5260 cNext = aDom[i+1]; 5261 if ( cNext == "'" || cNext == '"' ) 5262 { 5263 sAttr = ""; 5264 j = 2; 5265 while ( aDom[i+j] != cNext ) 5266 { 5267 sAttr += aDom[i+j]; 5268 j++; 5269 } 5270 5271 /* Replace jQuery UI constants @todo depreciated */ 5272 if ( sAttr == "H" ) 5273 { 5274 sAttr = classes.sJUIHeader; 5275 } 5276 else if ( sAttr == "F" ) 5277 { 5278 sAttr = classes.sJUIFooter; 5279 } 5280 5281 /* The attribute can be in the format of "#id.class", "#id" or "class" This logic 5282 * breaks the string into parts and applies them as needed 5283 */ 5284 if ( sAttr.indexOf('.') != -1 ) 5285 { 5286 var aSplit = sAttr.split('.'); 5287 nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1); 5288 nNewNode.className = aSplit[1]; 5289 } 5290 else if ( sAttr.charAt(0) == "#" ) 5291 { 5292 nNewNode.id = sAttr.substr(1, sAttr.length-1); 5293 } 5294 else 5295 { 5296 nNewNode.className = sAttr; 5297 } 5298 5299 i += j; /* Move along the position array */ 5300 } 5301 5302 insert.append( nNewNode ); 5303 insert = $(nNewNode); 5304 } 5305 else if ( cOption == '>' ) 5306 { 5307 /* End container div */ 5308 insert = insert.parent(); 5309 } 5310 // @todo Move options into their own plugins? 5311 else if ( cOption == 'l' && features.bPaginate && features.bLengthChange ) 5312 { 5313 /* Length */ 5314 featureNode = _fnFeatureHtmlLength( oSettings ); 5315 } 5316 else if ( cOption == 'f' && features.bFilter ) 5317 { 5318 /* Filter */ 5319 featureNode = _fnFeatureHtmlFilter( oSettings ); 5320 } 5321 else if ( cOption == 'r' && features.bProcessing ) 5322 { 5323 /* pRocessing */ 5324 featureNode = _fnFeatureHtmlProcessing( oSettings ); 5325 } 5326 else if ( cOption == 't' ) 5327 { 5328 /* Table */ 5329 featureNode = _fnFeatureHtmlTable( oSettings ); 5330 } 5331 else if ( cOption == 'i' && features.bInfo ) 5332 { 5333 /* Info */ 5334 featureNode = _fnFeatureHtmlInfo( oSettings ); 5335 } 5336 else if ( cOption == 'p' && features.bPaginate ) 5337 { 5338 /* Pagination */ 5339 featureNode = _fnFeatureHtmlPaginate( oSettings ); 5340 } 5341 else if ( DataTable.ext.feature.length !== 0 ) 5342 { 5343 /* Plug-in features */ 5344 var aoFeatures = DataTable.ext.feature; 5345 for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ ) 5346 { 5347 if ( cOption == aoFeatures[k].cFeature ) 5348 { 5349 featureNode = aoFeatures[k].fnInit( oSettings ); 5350 break; 5351 } 5352 } 5353 } 5354 5355 /* Add to the 2D features array */ 5356 if ( featureNode ) 5357 { 5358 var aanFeatures = oSettings.aanFeatures; 5359 5360 if ( ! aanFeatures[cOption] ) 5361 { 5362 aanFeatures[cOption] = []; 5363 } 5364 5365 aanFeatures[cOption].push( featureNode ); 5366 insert.append( featureNode ); 5367 } 5368 } 5369 5370 /* Built our DOM structure - replace the holding div with what we want */ 5371 holding.replaceWith( insert ); 5372 oSettings.nHolding = null; 5373 } 5374 5375 5376 /** 5377 * Use the DOM source to create up an array of header cells. The idea here is to 5378 * create a layout grid (array) of rows x columns, which contains a reference 5379 * to the cell that that point in the grid (regardless of col/rowspan), such that 5380 * any column / row could be removed and the new grid constructed 5381 * @param array {object} aLayout Array to store the calculated layout in 5382 * @param {node} nThead The header/footer element for the table 5383 * @memberof DataTable#oApi 5384 */ 5385 function _fnDetectHeader ( aLayout, nThead ) 5386 { 5387 var nTrs = $(nThead).children('tr'); 5388 var nTr, nCell; 5389 var i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan; 5390 var bUnique; 5391 var fnShiftCol = function ( a, i, j ) { 5392 var k = a[i]; 5393 while ( k[j] ) { 5394 j++; 5395 } 5396 return j; 5397 }; 5398 5399 aLayout.splice( 0, aLayout.length ); 5400 5401 /* We know how many rows there are in the layout - so prep it */ 5402 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ ) 5403 { 5404 aLayout.push( [] ); 5405 } 5406 5407 /* Calculate a layout array */ 5408 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ ) 5409 { 5410 nTr = nTrs[i]; 5411 iColumn = 0; 5412 5413 /* For every cell in the row... */ 5414 nCell = nTr.firstChild; 5415 while ( nCell ) { 5416 if ( nCell.nodeName.toUpperCase() == "TD" || 5417 nCell.nodeName.toUpperCase() == "TH" ) 5418 { 5419 /* Get the col and rowspan attributes from the DOM and sanitise them */ 5420 iColspan = nCell.getAttribute('colspan') * 1; 5421 iRowspan = nCell.getAttribute('rowspan') * 1; 5422 iColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan; 5423 iRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan; 5424 5425 /* There might be colspan cells already in this row, so shift our target 5426 * accordingly 5427 */ 5428 iColShifted = fnShiftCol( aLayout, i, iColumn ); 5429 5430 /* Cache calculation for unique columns */ 5431 bUnique = iColspan === 1 ? true : false; 5432 5433 /* If there is col / rowspan, copy the information into the layout grid */ 5434 for ( l=0 ; l<iColspan ; l++ ) 5435 { 5436 for ( k=0 ; k<iRowspan ; k++ ) 5437 { 5438 aLayout[i+k][iColShifted+l] = { 5439 "cell": nCell, 5440 "unique": bUnique 5441 }; 5442 aLayout[i+k].nTr = nTr; 5443 } 5444 } 5445 } 5446 nCell = nCell.nextSibling; 5447 } 5448 } 5449 } 5450 5451 5452 /** 5453 * Get an array of unique th elements, one for each column 5454 * @param {object} oSettings dataTables settings object 5455 * @param {node} nHeader automatically detect the layout from this node - optional 5456 * @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional 5457 * @returns array {node} aReturn list of unique th's 5458 * @memberof DataTable#oApi 5459 */ 5460 function _fnGetUniqueThs ( oSettings, nHeader, aLayout ) 5461 { 5462 var aReturn = []; 5463 if ( !aLayout ) 5464 { 5465 aLayout = oSettings.aoHeader; 5466 if ( nHeader ) 5467 { 5468 aLayout = []; 5469 _fnDetectHeader( aLayout, nHeader ); 5470 } 5471 } 5472 5473 for ( var i=0, iLen=aLayout.length ; i<iLen ; i++ ) 5474 { 5475 for ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ ) 5476 { 5477 if ( aLayout[i][j].unique && 5478 (!aReturn[j] || !oSettings.bSortCellsTop) ) 5479 { 5480 aReturn[j] = aLayout[i][j].cell; 5481 } 5482 } 5483 } 5484 5485 return aReturn; 5486 } 5487 5488 /** 5489 * Create an Ajax call based on the table's settings, taking into account that 5490 * parameters can have multiple forms, and backwards compatibility. 5491 * 5492 * @param {object} oSettings dataTables settings object 5493 * @param {array} data Data to send to the server, required by 5494 * DataTables - may be augmented by developer callbacks 5495 * @param {function} fn Callback function to run when data is obtained 5496 */ 5497 function _fnBuildAjax( oSettings, data, fn ) 5498 { 5499 // Compatibility with 1.9-, allow fnServerData and event to manipulate 5500 _fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] ); 5501 5502 // Convert to object based for 1.10+ if using the old array scheme which can 5503 // come from server-side processing or serverParams 5504 if ( data && Array.isArray(data) ) { 5505 var tmp = {}; 5506 var rbracket = /(.*?)\[\]$/; 5507 5508 $.each( data, function (key, val) { 5509 var match = val.name.match(rbracket); 5510 5511 if ( match ) { 5512 // Support for arrays 5513 var name = match[0]; 5514 5515 if ( ! tmp[ name ] ) { 5516 tmp[ name ] = []; 5517 } 5518 tmp[ name ].push( val.value ); 5519 } 5520 else { 5521 tmp[val.name] = val.value; 5522 } 5523 } ); 5524 data = tmp; 5525 } 5526 5527 var ajaxData; 5528 var ajax = oSettings.ajax; 5529 var instance = oSettings.oInstance; 5530 var callback = function ( json ) { 5531 _fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR] ); 5532 fn( json ); 5533 }; 5534 5535 if ( $.isPlainObject( ajax ) && ajax.data ) 5536 { 5537 ajaxData = ajax.data; 5538 5539 var newData = typeof ajaxData === 'function' ? 5540 ajaxData( data, oSettings ) : // fn can manipulate data or return 5541 ajaxData; // an object object or array to merge 5542 5543 // If the function returned something, use that alone 5544 data = typeof ajaxData === 'function' && newData ? 5545 newData : 5546 $.extend( true, data, newData ); 5547 5548 // Remove the data property as we've resolved it already and don't want 5549 // jQuery to do it again (it is restored at the end of the function) 5550 delete ajax.data; 5551 } 5552 5553 var baseAjax = { 5554 "data": data, 5555 "success": function (json) { 5556 var error = json.error || json.sError; 5557 if ( error ) { 5558 _fnLog( oSettings, 0, error ); 5559 } 5560 5561 oSettings.json = json; 5562 callback( json ); 5563 }, 5564 "dataType": "json", 5565 "cache": false, 5566 "type": oSettings.sServerMethod, 5567 "error": function (xhr, error, thrown) { 5568 var ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR] ); 5569 5570 if ( $.inArray( true, ret ) === -1 ) { 5571 if ( error == "parsererror" ) { 5572 _fnLog( oSettings, 0, 'Invalid JSON response', 1 ); 5573 } 5574 else if ( xhr.readyState === 4 ) { 5575 _fnLog( oSettings, 0, 'Ajax error', 7 ); 5576 } 5577 } 5578 5579 _fnProcessingDisplay( oSettings, false ); 5580 } 5581 }; 5582 5583 // Store the data submitted for the API 5584 oSettings.oAjaxData = data; 5585 5586 // Allow plug-ins and external processes to modify the data 5587 _fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data] ); 5588 5589 if ( oSettings.fnServerData ) 5590 { 5591 // DataTables 1.9- compatibility 5592 oSettings.fnServerData.call( instance, 5593 oSettings.sAjaxSource, 5594 $.map( data, function (val, key) { // Need to convert back to 1.9 trad format 5595 return { name: key, value: val }; 5596 } ), 5597 callback, 5598 oSettings 5599 ); 5600 } 5601 else if ( oSettings.sAjaxSource || typeof ajax === 'string' ) 5602 { 5603 // DataTables 1.9- compatibility 5604 oSettings.jqXHR = $.ajax( $.extend( baseAjax, { 5605 url: ajax || oSettings.sAjaxSource 5606 } ) ); 5607 } 5608 else if ( typeof ajax === 'function' ) 5609 { 5610 // Is a function - let the caller define what needs to be done 5611 oSettings.jqXHR = ajax.call( instance, data, callback, oSettings ); 5612 } 5613 else 5614 { 5615 // Object to extend the base settings 5616 oSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) ); 5617 5618 // Restore for next time around 5619 ajax.data = ajaxData; 5620 } 5621 } 5622 5623 5624 /** 5625 * Update the table using an Ajax call 5626 * @param {object} settings dataTables settings object 5627 * @returns {boolean} Block the table drawing or not 5628 * @memberof DataTable#oApi 5629 */ 5630 function _fnAjaxUpdate( settings ) 5631 { 5632 if ( settings.bAjaxDataGet ) { 5633 settings.iDraw++; 5634 _fnProcessingDisplay( settings, true ); 5635 5636 _fnBuildAjax( 5637 settings, 5638 _fnAjaxParameters( settings ), 5639 function(json) { 5640 _fnAjaxUpdateDraw( settings, json ); 5641 } 5642 ); 5643 5644 return false; 5645 } 5646 return true; 5647 } 5648 5649 5650 /** 5651 * Build up the parameters in an object needed for a server-side processing 5652 * request. Note that this is basically done twice, is different ways - a modern 5653 * method which is used by default in DataTables 1.10 which uses objects and 5654 * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if 5655 * the sAjaxSource option is used in the initialisation, or the legacyAjax 5656 * option is set. 5657 * @param {object} oSettings dataTables settings object 5658 * @returns {bool} block the table drawing or not 5659 * @memberof DataTable#oApi 5660 */ 5661 function _fnAjaxParameters( settings ) 5662 { 5663 var 5664 columns = settings.aoColumns, 5665 columnCount = columns.length, 5666 features = settings.oFeatures, 5667 preSearch = settings.oPreviousSearch, 5668 preColSearch = settings.aoPreSearchCols, 5669 i, data = [], dataProp, column, columnSearch, 5670 sort = _fnSortFlatten( settings ), 5671 displayStart = settings._iDisplayStart, 5672 displayLength = features.bPaginate !== false ? 5673 settings._iDisplayLength : 5674 -1; 5675 5676 var param = function ( name, value ) { 5677 data.push( { 'name': name, 'value': value } ); 5678 }; 5679 5680 // DataTables 1.9- compatible method 5681 param( 'sEcho', settings.iDraw ); 5682 param( 'iColumns', columnCount ); 5683 param( 'sColumns', _pluck( columns, 'sName' ).join(',') ); 5684 param( 'iDisplayStart', displayStart ); 5685 param( 'iDisplayLength', displayLength ); 5686 5687 // DataTables 1.10+ method 5688 var d = { 5689 draw: settings.iDraw, 5690 columns: [], 5691 order: [], 5692 start: displayStart, 5693 length: displayLength, 5694 search: { 5695 value: preSearch.sSearch, 5696 regex: preSearch.bRegex 5697 } 5698 }; 5699 5700 for ( i=0 ; i<columnCount ; i++ ) { 5701 column = columns[i]; 5702 columnSearch = preColSearch[i]; 5703 dataProp = typeof column.mData=="function" ? 'function' : column.mData ; 5704 5705 d.columns.push( { 5706 data: dataProp, 5707 name: column.sName, 5708 searchable: column.bSearchable, 5709 orderable: column.bSortable, 5710 search: { 5711 value: columnSearch.sSearch, 5712 regex: columnSearch.bRegex 5713 } 5714 } ); 5715 5716 param( "mDataProp_"+i, dataProp ); 5717 5718 if ( features.bFilter ) { 5719 param( 'sSearch_'+i, columnSearch.sSearch ); 5720 param( 'bRegex_'+i, columnSearch.bRegex ); 5721 param( 'bSearchable_'+i, column.bSearchable ); 5722 } 5723 5724 if ( features.bSort ) { 5725 param( 'bSortable_'+i, column.bSortable ); 5726 } 5727 } 5728 5729 if ( features.bFilter ) { 5730 param( 'sSearch', preSearch.sSearch ); 5731 param( 'bRegex', preSearch.bRegex ); 5732 } 5733 5734 if ( features.bSort ) { 5735 $.each( sort, function ( i, val ) { 5736 d.order.push( { column: val.col, dir: val.dir } ); 5737 5738 param( 'iSortCol_'+i, val.col ); 5739 param( 'sSortDir_'+i, val.dir ); 5740 } ); 5741 5742 param( 'iSortingCols', sort.length ); 5743 } 5744 5745 // If the legacy.ajax parameter is null, then we automatically decide which 5746 // form to use, based on sAjaxSource 5747 var legacy = DataTable.ext.legacy.ajax; 5748 if ( legacy === null ) { 5749 return settings.sAjaxSource ? data : d; 5750 } 5751 5752 // Otherwise, if legacy has been specified then we use that to decide on the 5753 // form 5754 return legacy ? data : d; 5755 } 5756 5757 5758 /** 5759 * Data the data from the server (nuking the old) and redraw the table 5760 * @param {object} oSettings dataTables settings object 5761 * @param {object} json json data return from the server. 5762 * @param {string} json.sEcho Tracking flag for DataTables to match requests 5763 * @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering 5764 * @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering 5765 * @param {array} json.aaData The data to display on this page 5766 * @param {string} [json.sColumns] Column ordering (sName, comma separated) 5767 * @memberof DataTable#oApi 5768 */ 5769 function _fnAjaxUpdateDraw ( settings, json ) 5770 { 5771 // v1.10 uses camelCase variables, while 1.9 uses Hungarian notation. 5772 // Support both 5773 var compat = function ( old, modern ) { 5774 return json[old] !== undefined ? json[old] : json[modern]; 5775 }; 5776 5777 var data = _fnAjaxDataSrc( settings, json ); 5778 var draw = compat( 'sEcho', 'draw' ); 5779 var recordsTotal = compat( 'iTotalRecords', 'recordsTotal' ); 5780 var recordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' ); 5781 5782 if ( draw !== undefined ) { 5783 // Protect against out of sequence returns 5784 if ( draw*1 < settings.iDraw ) { 5785 return; 5786 } 5787 settings.iDraw = draw * 1; 5788 } 5789 5790 _fnClearTable( settings ); 5791 settings._iRecordsTotal = parseInt(recordsTotal, 10); 5792 settings._iRecordsDisplay = parseInt(recordsFiltered, 10); 5793 5794 for ( var i=0, ien=data.length ; i<ien ; i++ ) { 5795 _fnAddData( settings, data[i] ); 5796 } 5797 settings.aiDisplay = settings.aiDisplayMaster.slice(); 5798 5799 settings.bAjaxDataGet = false; 5800 _fnDraw( settings ); 5801 5802 if ( ! settings._bInitComplete ) { 5803 _fnInitComplete( settings, json ); 5804 } 5805 5806 settings.bAjaxDataGet = true; 5807 _fnProcessingDisplay( settings, false ); 5808 } 5809 5810 5811 /** 5812 * Get the data from the JSON data source to use for drawing a table. Using 5813 * `_fnGetObjectDataFn` allows the data to be sourced from a property of the 5814 * source object, or from a processing function. 5815 * @param {object} oSettings dataTables settings object 5816 * @param {object} json Data source object / array from the server 5817 * @return {array} Array of data to use 5818 */ 5819 function _fnAjaxDataSrc ( oSettings, json ) 5820 { 5821 var dataSrc = $.isPlainObject( oSettings.ajax ) && oSettings.ajax.dataSrc !== undefined ? 5822 oSettings.ajax.dataSrc : 5823 oSettings.sAjaxDataProp; // Compatibility with 1.9-. 5824 5825 // Compatibility with 1.9-. In order to read from aaData, check if the 5826 // default has been changed, if not, check for aaData 5827 if ( dataSrc === 'data' ) { 5828 return json.aaData || json[dataSrc]; 5829 } 5830 5831 return dataSrc !== "" ? 5832 _fnGetObjectDataFn( dataSrc )( json ) : 5833 json; 5834 } 5835 5836 /** 5837 * Generate the node required for filtering text 5838 * @returns {node} Filter control element 5839 * @param {object} oSettings dataTables settings object 5840 * @memberof DataTable#oApi 5841 */ 5842 function _fnFeatureHtmlFilter ( settings ) 5843 { 5844 var classes = settings.oClasses; 5845 var tableId = settings.sTableId; 5846 var language = settings.oLanguage; 5847 var previousSearch = settings.oPreviousSearch; 5848 var features = settings.aanFeatures; 5849 var input = '<input type="search" class="'+classes.sFilterInput+'"/>'; 5850 5851 var str = language.sSearch; 5852 str = str.match(/_INPUT_/) ? 5853 str.replace('_INPUT_', input) : 5854 str+input; 5855 5856 var filter = $('<div/>', { 5857 'id': ! features.f ? tableId+'_filter' : null, 5858 'class': classes.sFilter 5859 } ) 5860 .append( $('<label/>' ).append( str ) ); 5861 5862 var searchFn = function() { 5863 /* Update all other filter input elements for the new display */ 5864 var n = features.f; 5865 var val = !this.value ? "" : this.value; // mental IE8 fix :-( 5866 5867 /* Now do the filter */ 5868 if ( val != previousSearch.sSearch ) { 5869 _fnFilterComplete( settings, { 5870 "sSearch": val, 5871 "bRegex": previousSearch.bRegex, 5872 "bSmart": previousSearch.bSmart , 5873 "bCaseInsensitive": previousSearch.bCaseInsensitive 5874 } ); 5875 5876 // Need to redraw, without resorting 5877 settings._iDisplayStart = 0; 5878 _fnDraw( settings ); 5879 } 5880 }; 5881 5882 var searchDelay = settings.searchDelay !== null ? 5883 settings.searchDelay : 5884 _fnDataSource( settings ) === 'ssp' ? 5885 400 : 5886 0; 5887 5888 var jqFilter = $('input', filter) 5889 .val( previousSearch.sSearch ) 5890 .attr( 'placeholder', language.sSearchPlaceholder ) 5891 .on( 5892 'keyup.DT search.DT input.DT paste.DT cut.DT', 5893 searchDelay ? 5894 _fnThrottle( searchFn, searchDelay ) : 5895 searchFn 5896 ) 5897 .on( 'mouseup', function(e) { 5898 // Edge fix! Edge 17 does not trigger anything other than mouse events when clicking 5899 // on the clear icon (Edge bug 17584515). This is safe in other browsers as `searchFn` 5900 // checks the value to see if it has changed. In other browsers it won't have. 5901 setTimeout( function () { 5902 searchFn.call(jqFilter[0]); 5903 }, 10); 5904 } ) 5905 .on( 'keypress.DT', function(e) { 5906 /* Prevent form submission */ 5907 if ( e.keyCode == 13 ) { 5908 return false; 5909 } 5910 } ) 5911 .attr('aria-controls', tableId); 5912 5913 // Update the input elements whenever the table is filtered 5914 $(settings.nTable).on( 'search.dt.DT', function ( ev, s ) { 5915 if ( settings === s ) { 5916 // IE9 throws an 'unknown error' if document.activeElement is used 5917 // inside an iframe or frame... 5918 try { 5919 if ( jqFilter[0] !== document.activeElement ) { 5920 jqFilter.val( previousSearch.sSearch ); 5921 } 5922 } 5923 catch ( e ) {} 5924 } 5925 } ); 5926 5927 return filter[0]; 5928 } 5929 5930 5931 /** 5932 * Filter the table using both the global filter and column based filtering 5933 * @param {object} oSettings dataTables settings object 5934 * @param {object} oSearch search information 5935 * @param {int} [iForce] force a research of the master array (1) or not (undefined or 0) 5936 * @memberof DataTable#oApi 5937 */ 5938 function _fnFilterComplete ( oSettings, oInput, iForce ) 5939 { 5940 var oPrevSearch = oSettings.oPreviousSearch; 5941 var aoPrevSearch = oSettings.aoPreSearchCols; 5942 var fnSaveFilter = function ( oFilter ) { 5943 /* Save the filtering values */ 5944 oPrevSearch.sSearch = oFilter.sSearch; 5945 oPrevSearch.bRegex = oFilter.bRegex; 5946 oPrevSearch.bSmart = oFilter.bSmart; 5947 oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive; 5948 }; 5949 var fnRegex = function ( o ) { 5950 // Backwards compatibility with the bEscapeRegex option 5951 return o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex; 5952 }; 5953 5954 // Resolve any column types that are unknown due to addition or invalidation 5955 // @todo As per sort - can this be moved into an event handler? 5956 _fnColumnTypes( oSettings ); 5957 5958 /* In server-side processing all filtering is done by the server, so no point hanging around here */ 5959 if ( _fnDataSource( oSettings ) != 'ssp' ) 5960 { 5961 /* Global filter */ 5962 _fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive ); 5963 fnSaveFilter( oInput ); 5964 5965 /* Now do the individual column filter */ 5966 for ( var i=0 ; i<aoPrevSearch.length ; i++ ) 5967 { 5968 _fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, fnRegex(aoPrevSearch[i]), 5969 aoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive ); 5970 } 5971 5972 /* Custom filtering */ 5973 _fnFilterCustom( oSettings ); 5974 } 5975 else 5976 { 5977 fnSaveFilter( oInput ); 5978 } 5979 5980 /* Tell the draw function we have been filtering */ 5981 oSettings.bFiltered = true; 5982 _fnCallbackFire( oSettings, null, 'search', [oSettings] ); 5983 } 5984 5985 5986 /** 5987 * Apply custom filtering functions 5988 * @param {object} oSettings dataTables settings object 5989 * @memberof DataTable#oApi 5990 */ 5991 function _fnFilterCustom( settings ) 5992 { 5993 var filters = DataTable.ext.search; 5994 var displayRows = settings.aiDisplay; 5995 var row, rowIdx; 5996 5997 for ( var i=0, ien=filters.length ; i<ien ; i++ ) { 5998 var rows = []; 5999 6000 // Loop over each row and see if it should be included 6001 for ( var j=0, jen=displayRows.length ; j<jen ; j++ ) { 6002 rowIdx = displayRows[ j ]; 6003 row = settings.aoData[ rowIdx ]; 6004 6005 if ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) { 6006 rows.push( rowIdx ); 6007 } 6008 } 6009 6010 // So the array reference doesn't break set the results into the 6011 // existing array 6012 displayRows.length = 0; 6013 $.merge( displayRows, rows ); 6014 } 6015 } 6016 6017 6018 /** 6019 * Filter the table on a per-column basis 6020 * @param {object} oSettings dataTables settings object 6021 * @param {string} sInput string to filter on 6022 * @param {int} iColumn column to filter 6023 * @param {bool} bRegex treat search string as a regular expression or not 6024 * @param {bool} bSmart use smart filtering or not 6025 * @param {bool} bCaseInsensitive Do case insenstive matching or not 6026 * @memberof DataTable#oApi 6027 */ 6028 function _fnFilterColumn ( settings, searchStr, colIdx, regex, smart, caseInsensitive ) 6029 { 6030 if ( searchStr === '' ) { 6031 return; 6032 } 6033 6034 var data; 6035 var out = []; 6036 var display = settings.aiDisplay; 6037 var rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive ); 6038 6039 for ( var i=0 ; i<display.length ; i++ ) { 6040 data = settings.aoData[ display[i] ]._aFilterData[ colIdx ]; 6041 6042 if ( rpSearch.test( data ) ) { 6043 out.push( display[i] ); 6044 } 6045 } 6046 6047 settings.aiDisplay = out; 6048 } 6049 6050 6051 /** 6052 * Filter the data table based on user input and draw the table 6053 * @param {object} settings dataTables settings object 6054 * @param {string} input string to filter on 6055 * @param {int} force optional - force a research of the master array (1) or not (undefined or 0) 6056 * @param {bool} regex treat as a regular expression or not 6057 * @param {bool} smart perform smart filtering or not 6058 * @param {bool} caseInsensitive Do case insenstive matching or not 6059 * @memberof DataTable#oApi 6060 */ 6061 function _fnFilter( settings, input, force, regex, smart, caseInsensitive ) 6062 { 6063 var rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive ); 6064 var prevSearch = settings.oPreviousSearch.sSearch; 6065 var displayMaster = settings.aiDisplayMaster; 6066 var display, invalidated, i; 6067 var filtered = []; 6068 6069 // Need to take account of custom filtering functions - always filter 6070 if ( DataTable.ext.search.length !== 0 ) { 6071 force = true; 6072 } 6073 6074 // Check if any of the rows were invalidated 6075 invalidated = _fnFilterData( settings ); 6076 6077 // If the input is blank - we just want the full data set 6078 if ( input.length <= 0 ) { 6079 settings.aiDisplay = displayMaster.slice(); 6080 } 6081 else { 6082 // New search - start from the master array 6083 if ( invalidated || 6084 force || 6085 regex || 6086 prevSearch.length > input.length || 6087 input.indexOf(prevSearch) !== 0 || 6088 settings.bSorted // On resort, the display master needs to be 6089 // re-filtered since indexes will have changed 6090 ) { 6091 settings.aiDisplay = displayMaster.slice(); 6092 } 6093 6094 // Search the display array 6095 display = settings.aiDisplay; 6096 6097 for ( i=0 ; i<display.length ; i++ ) { 6098 if ( rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) { 6099 filtered.push( display[i] ); 6100 } 6101 } 6102 6103 settings.aiDisplay = filtered; 6104 } 6105 } 6106 6107 6108 /** 6109 * Build a regular expression object suitable for searching a table 6110 * @param {string} sSearch string to search for 6111 * @param {bool} bRegex treat as a regular expression or not 6112 * @param {bool} bSmart perform smart filtering or not 6113 * @param {bool} bCaseInsensitive Do case insensitive matching or not 6114 * @returns {RegExp} constructed object 6115 * @memberof DataTable#oApi 6116 */ 6117 function _fnFilterCreateSearch( search, regex, smart, caseInsensitive ) 6118 { 6119 search = regex ? 6120 search : 6121 _fnEscapeRegex( search ); 6122 6123 if ( smart ) { 6124 /* For smart filtering we want to allow the search to work regardless of 6125 * word order. We also want double quoted text to be preserved, so word 6126 * order is important - a la google. So this is what we want to 6127 * generate: 6128 * 6129 * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$ 6130 */ 6131 var a = $.map( search.match( /"[^"]+"|[^ ]+/g ) || [''], function ( word ) { 6132 if ( word.charAt(0) === '"' ) { 6133 var m = word.match( /^"(.*)"$/ ); 6134 word = m ? m[1] : word; 6135 } 6136 6137 return word.replace('"', ''); 6138 } ); 6139 6140 search = '^(?=.*?'+a.join( ')(?=.*?' )+').*$'; 6141 } 6142 6143 return new RegExp( search, caseInsensitive ? 'i' : '' ); 6144 } 6145 6146 6147 /** 6148 * Escape a string such that it can be used in a regular expression 6149 * @param {string} sVal string to escape 6150 * @returns {string} escaped string 6151 * @memberof DataTable#oApi 6152 */ 6153 var _fnEscapeRegex = DataTable.util.escapeRegex; 6154 6155 var __filter_div = $('<div>')[0]; 6156 var __filter_div_textContent = __filter_div.textContent !== undefined; 6157 6158 // Update the filtering data for each row if needed (by invalidation or first run) 6159 function _fnFilterData ( settings ) 6160 { 6161 var columns = settings.aoColumns; 6162 var column; 6163 var i, j, ien, jen, filterData, cellData, row; 6164 var fomatters = DataTable.ext.type.search; 6165 var wasInvalidated = false; 6166 6167 for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) { 6168 row = settings.aoData[i]; 6169 6170 if ( ! row._aFilterData ) { 6171 filterData = []; 6172 6173 for ( j=0, jen=columns.length ; j<jen ; j++ ) { 6174 column = columns[j]; 6175 6176 if ( column.bSearchable ) { 6177 cellData = _fnGetCellData( settings, i, j, 'filter' ); 6178 6179 if ( fomatters[ column.sType ] ) { 6180 cellData = fomatters[ column.sType ]( cellData ); 6181 } 6182 6183 // Search in DataTables 1.10 is string based. In 1.11 this 6184 // should be altered to also allow strict type checking. 6185 if ( cellData === null ) { 6186 cellData = ''; 6187 } 6188 6189 if ( typeof cellData !== 'string' && cellData.toString ) { 6190 cellData = cellData.toString(); 6191 } 6192 } 6193 else { 6194 cellData = ''; 6195 } 6196 6197 // If it looks like there is an HTML entity in the string, 6198 // attempt to decode it so sorting works as expected. Note that 6199 // we could use a single line of jQuery to do this, but the DOM 6200 // method used here is much faster http://jsperf.com/html-decode 6201 if ( cellData.indexOf && cellData.indexOf('&') !== -1 ) { 6202 __filter_div.innerHTML = cellData; 6203 cellData = __filter_div_textContent ? 6204 __filter_div.textContent : 6205 __filter_div.innerText; 6206 } 6207 6208 if ( cellData.replace ) { 6209 cellData = cellData.replace(/[\r\n\u2028]/g, ''); 6210 } 6211 6212 filterData.push( cellData ); 6213 } 6214 6215 row._aFilterData = filterData; 6216 row._sFilterRow = filterData.join(' '); 6217 wasInvalidated = true; 6218 } 6219 } 6220 6221 return wasInvalidated; 6222 } 6223 6224 6225 /** 6226 * Convert from the internal Hungarian notation to camelCase for external 6227 * interaction 6228 * @param {object} obj Object to convert 6229 * @returns {object} Inverted object 6230 * @memberof DataTable#oApi 6231 */ 6232 function _fnSearchToCamel ( obj ) 6233 { 6234 return { 6235 search: obj.sSearch, 6236 smart: obj.bSmart, 6237 regex: obj.bRegex, 6238 caseInsensitive: obj.bCaseInsensitive 6239 }; 6240 } 6241 6242 6243 6244 /** 6245 * Convert from camelCase notation to the internal Hungarian. We could use the 6246 * Hungarian convert function here, but this is cleaner 6247 * @param {object} obj Object to convert 6248 * @returns {object} Inverted object 6249 * @memberof DataTable#oApi 6250 */ 6251 function _fnSearchToHung ( obj ) 6252 { 6253 return { 6254 sSearch: obj.search, 6255 bSmart: obj.smart, 6256 bRegex: obj.regex, 6257 bCaseInsensitive: obj.caseInsensitive 6258 }; 6259 } 6260 6261 /** 6262 * Generate the node required for the info display 6263 * @param {object} oSettings dataTables settings object 6264 * @returns {node} Information element 6265 * @memberof DataTable#oApi 6266 */ 6267 function _fnFeatureHtmlInfo ( settings ) 6268 { 6269 var 6270 tid = settings.sTableId, 6271 nodes = settings.aanFeatures.i, 6272 n = $('<div/>', { 6273 'class': settings.oClasses.sInfo, 6274 'id': ! nodes ? tid+'_info' : null 6275 } ); 6276 6277 if ( ! nodes ) { 6278 // Update display on each draw 6279 settings.aoDrawCallback.push( { 6280 "fn": _fnUpdateInfo, 6281 "sName": "information" 6282 } ); 6283 6284 n 6285 .attr( 'role', 'status' ) 6286 .attr( 'aria-live', 'polite' ); 6287 6288 // Table is described by our info div 6289 $(settings.nTable).attr( 'aria-describedby', tid+'_info' ); 6290 } 6291 6292 return n[0]; 6293 } 6294 6295 6296 /** 6297 * Update the information elements in the display 6298 * @param {object} settings dataTables settings object 6299 * @memberof DataTable#oApi 6300 */ 6301 function _fnUpdateInfo ( settings ) 6302 { 6303 /* Show information about the table */ 6304 var nodes = settings.aanFeatures.i; 6305 if ( nodes.length === 0 ) { 6306 return; 6307 } 6308 6309 var 6310 lang = settings.oLanguage, 6311 start = settings._iDisplayStart+1, 6312 end = settings.fnDisplayEnd(), 6313 max = settings.fnRecordsTotal(), 6314 total = settings.fnRecordsDisplay(), 6315 out = total ? 6316 lang.sInfo : 6317 lang.sInfoEmpty; 6318 6319 if ( total !== max ) { 6320 /* Record set after filtering */ 6321 out += ' ' + lang.sInfoFiltered; 6322 } 6323 6324 // Convert the macros 6325 out += lang.sInfoPostFix; 6326 out = _fnInfoMacros( settings, out ); 6327 6328 var callback = lang.fnInfoCallback; 6329 if ( callback !== null ) { 6330 out = callback.call( settings.oInstance, 6331 settings, start, end, max, total, out 6332 ); 6333 } 6334 6335 $(nodes).html( out ); 6336 } 6337 6338 6339 function _fnInfoMacros ( settings, str ) 6340 { 6341 // When infinite scrolling, we are always starting at 1. _iDisplayStart is used only 6342 // internally 6343 var 6344 formatter = settings.fnFormatNumber, 6345 start = settings._iDisplayStart+1, 6346 len = settings._iDisplayLength, 6347 vis = settings.fnRecordsDisplay(), 6348 all = len === -1; 6349 6350 return str. 6351 replace(/_START_/g, formatter.call( settings, start ) ). 6352 replace(/_END_/g, formatter.call( settings, settings.fnDisplayEnd() ) ). 6353 replace(/_MAX_/g, formatter.call( settings, settings.fnRecordsTotal() ) ). 6354 replace(/_TOTAL_/g, formatter.call( settings, vis ) ). 6355 replace(/_PAGE_/g, formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ). 6356 replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) ); 6357 } 6358 6359 6360 6361 /** 6362 * Draw the table for the first time, adding all required features 6363 * @param {object} settings dataTables settings object 6364 * @memberof DataTable#oApi 6365 */ 6366 function _fnInitialise ( settings ) 6367 { 6368 var i, iLen, iAjaxStart=settings.iInitDisplayStart; 6369 var columns = settings.aoColumns, column; 6370 var features = settings.oFeatures; 6371 var deferLoading = settings.bDeferLoading; // value modified by the draw 6372 6373 /* Ensure that the table data is fully initialised */ 6374 if ( ! settings.bInitialised ) { 6375 setTimeout( function(){ _fnInitialise( settings ); }, 200 ); 6376 return; 6377 } 6378 6379 /* Show the display HTML options */ 6380 _fnAddOptionsHtml( settings ); 6381 6382 /* Build and draw the header / footer for the table */ 6383 _fnBuildHead( settings ); 6384 _fnDrawHead( settings, settings.aoHeader ); 6385 _fnDrawHead( settings, settings.aoFooter ); 6386 6387 /* Okay to show that something is going on now */ 6388 _fnProcessingDisplay( settings, true ); 6389 6390 /* Calculate sizes for columns */ 6391 if ( features.bAutoWidth ) { 6392 _fnCalculateColumnWidths( settings ); 6393 } 6394 6395 for ( i=0, iLen=columns.length ; i<iLen ; i++ ) { 6396 column = columns[i]; 6397 6398 if ( column.sWidth ) { 6399 column.nTh.style.width = _fnStringToCss( column.sWidth ); 6400 } 6401 } 6402 6403 _fnCallbackFire( settings, null, 'preInit', [settings] ); 6404 6405 // If there is default sorting required - let's do it. The sort function 6406 // will do the drawing for us. Otherwise we draw the table regardless of the 6407 // Ajax source - this allows the table to look initialised for Ajax sourcing 6408 // data (show 'loading' message possibly) 6409 _fnReDraw( settings ); 6410 6411 // Server-side processing init complete is done by _fnAjaxUpdateDraw 6412 var dataSrc = _fnDataSource( settings ); 6413 if ( dataSrc != 'ssp' || deferLoading ) { 6414 // if there is an ajax source load the data 6415 if ( dataSrc == 'ajax' ) { 6416 _fnBuildAjax( settings, [], function(json) { 6417 var aData = _fnAjaxDataSrc( settings, json ); 6418 6419 // Got the data - add it to the table 6420 for ( i=0 ; i<aData.length ; i++ ) { 6421 _fnAddData( settings, aData[i] ); 6422 } 6423 6424 // Reset the init display for cookie saving. We've already done 6425 // a filter, and therefore cleared it before. So we need to make 6426 // it appear 'fresh' 6427 settings.iInitDisplayStart = iAjaxStart; 6428 6429 _fnReDraw( settings ); 6430 6431 _fnProcessingDisplay( settings, false ); 6432 _fnInitComplete( settings, json ); 6433 }, settings ); 6434 } 6435 else { 6436 _fnProcessingDisplay( settings, false ); 6437 _fnInitComplete( settings ); 6438 } 6439 } 6440 } 6441 6442 6443 /** 6444 * Draw the table for the first time, adding all required features 6445 * @param {object} oSettings dataTables settings object 6446 * @param {object} [json] JSON from the server that completed the table, if using Ajax source 6447 * with client-side processing (optional) 6448 * @memberof DataTable#oApi 6449 */ 6450 function _fnInitComplete ( settings, json ) 6451 { 6452 settings._bInitComplete = true; 6453 6454 // When data was added after the initialisation (data or Ajax) we need to 6455 // calculate the column sizing 6456 if ( json || settings.oInit.aaData ) { 6457 _fnAdjustColumnSizing( settings ); 6458 } 6459 6460 _fnCallbackFire( settings, null, 'plugin-init', [settings, json] ); 6461 _fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] ); 6462 } 6463 6464 6465 function _fnLengthChange ( settings, val ) 6466 { 6467 var len = parseInt( val, 10 ); 6468 settings._iDisplayLength = len; 6469 6470 _fnLengthOverflow( settings ); 6471 6472 // Fire length change event 6473 _fnCallbackFire( settings, null, 'length', [settings, len] ); 6474 } 6475 6476 6477 /** 6478 * Generate the node required for user display length changing 6479 * @param {object} settings dataTables settings object 6480 * @returns {node} Display length feature node 6481 * @memberof DataTable#oApi 6482 */ 6483 function _fnFeatureHtmlLength ( settings ) 6484 { 6485 var 6486 classes = settings.oClasses, 6487 tableId = settings.sTableId, 6488 menu = settings.aLengthMenu, 6489 d2 = Array.isArray( menu[0] ), 6490 lengths = d2 ? menu[0] : menu, 6491 language = d2 ? menu[1] : menu; 6492 6493 var select = $('<select/>', { 6494 'name': tableId+'_length', 6495 'aria-controls': tableId, 6496 'class': classes.sLengthSelect 6497 } ); 6498 6499 for ( var i=0, ien=lengths.length ; i<ien ; i++ ) { 6500 select[0][ i ] = new Option( 6501 typeof language[i] === 'number' ? 6502 settings.fnFormatNumber( language[i] ) : 6503 language[i], 6504 lengths[i] 6505 ); 6506 } 6507 6508 var div = $('<div><label/></div>').addClass( classes.sLength ); 6509 if ( ! settings.aanFeatures.l ) { 6510 div[0].id = tableId+'_length'; 6511 } 6512 6513 div.children().append( 6514 settings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML ) 6515 ); 6516 6517 // Can't use `select` variable as user might provide their own and the 6518 // reference is broken by the use of outerHTML 6519 $('select', div) 6520 .val( settings._iDisplayLength ) 6521 .on( 'change.DT', function(e) { 6522 _fnLengthChange( settings, $(this).val() ); 6523 _fnDraw( settings ); 6524 } ); 6525 6526 // Update node value whenever anything changes the table's length 6527 $(settings.nTable).on( 'length.dt.DT', function (e, s, len) { 6528 if ( settings === s ) { 6529 $('select', div).val( len ); 6530 } 6531 } ); 6532 6533 return div[0]; 6534 } 6535 6536 6537 6538 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 6539 * Note that most of the paging logic is done in 6540 * DataTable.ext.pager 6541 */ 6542 6543 /** 6544 * Generate the node required for default pagination 6545 * @param {object} oSettings dataTables settings object 6546 * @returns {node} Pagination feature node 6547 * @memberof DataTable#oApi 6548 */ 6549 function _fnFeatureHtmlPaginate ( settings ) 6550 { 6551 var 6552 type = settings.sPaginationType, 6553 plugin = DataTable.ext.pager[ type ], 6554 modern = typeof plugin === 'function', 6555 redraw = function( settings ) { 6556 _fnDraw( settings ); 6557 }, 6558 node = $('<div/>').addClass( settings.oClasses.sPaging + type )[0], 6559 features = settings.aanFeatures; 6560 6561 if ( ! modern ) { 6562 plugin.fnInit( settings, node, redraw ); 6563 } 6564 6565 /* Add a draw callback for the pagination on first instance, to update the paging display */ 6566 if ( ! features.p ) 6567 { 6568 node.id = settings.sTableId+'_paginate'; 6569 6570 settings.aoDrawCallback.push( { 6571 "fn": function( settings ) { 6572 if ( modern ) { 6573 var 6574 start = settings._iDisplayStart, 6575 len = settings._iDisplayLength, 6576 visRecords = settings.fnRecordsDisplay(), 6577 all = len === -1, 6578 page = all ? 0 : Math.ceil( start / len ), 6579 pages = all ? 1 : Math.ceil( visRecords / len ), 6580 buttons = plugin(page, pages), 6581 i, ien; 6582 6583 for ( i=0, ien=features.p.length ; i<ien ; i++ ) { 6584 _fnRenderer( settings, 'pageButton' )( 6585 settings, features.p[i], i, buttons, page, pages 6586 ); 6587 } 6588 } 6589 else { 6590 plugin.fnUpdate( settings, redraw ); 6591 } 6592 }, 6593 "sName": "pagination" 6594 } ); 6595 } 6596 6597 return node; 6598 } 6599 6600 6601 /** 6602 * Alter the display settings to change the page 6603 * @param {object} settings DataTables settings object 6604 * @param {string|int} action Paging action to take: "first", "previous", 6605 * "next" or "last" or page number to jump to (integer) 6606 * @param [bool] redraw Automatically draw the update or not 6607 * @returns {bool} true page has changed, false - no change 6608 * @memberof DataTable#oApi 6609 */ 6610 function _fnPageChange ( settings, action, redraw ) 6611 { 6612 var 6613 start = settings._iDisplayStart, 6614 len = settings._iDisplayLength, 6615 records = settings.fnRecordsDisplay(); 6616 6617 if ( records === 0 || len === -1 ) 6618 { 6619 start = 0; 6620 } 6621 else if ( typeof action === "number" ) 6622 { 6623 start = action * len; 6624 6625 if ( start > records ) 6626 { 6627 start = 0; 6628 } 6629 } 6630 else if ( action == "first" ) 6631 { 6632 start = 0; 6633 } 6634 else if ( action == "previous" ) 6635 { 6636 start = len >= 0 ? 6637 start - len : 6638 0; 6639 6640 if ( start < 0 ) 6641 { 6642 start = 0; 6643 } 6644 } 6645 else if ( action == "next" ) 6646 { 6647 if ( start + len < records ) 6648 { 6649 start += len; 6650 } 6651 } 6652 else if ( action == "last" ) 6653 { 6654 start = Math.floor( (records-1) / len) * len; 6655 } 6656 else 6657 { 6658 _fnLog( settings, 0, "Unknown paging action: "+action, 5 ); 6659 } 6660 6661 var changed = settings._iDisplayStart !== start; 6662 settings._iDisplayStart = start; 6663 6664 if ( changed ) { 6665 _fnCallbackFire( settings, null, 'page', [settings] ); 6666 6667 if ( redraw ) { 6668 _fnDraw( settings ); 6669 } 6670 } 6671 6672 return changed; 6673 } 6674 6675 6676 6677 /** 6678 * Generate the node required for the processing node 6679 * @param {object} settings dataTables settings object 6680 * @returns {node} Processing element 6681 * @memberof DataTable#oApi 6682 */ 6683 function _fnFeatureHtmlProcessing ( settings ) 6684 { 6685 return $('<div/>', { 6686 'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null, 6687 'class': settings.oClasses.sProcessing 6688 } ) 6689 .html( settings.oLanguage.sProcessing ) 6690 .insertBefore( settings.nTable )[0]; 6691 } 6692 6693 6694 /** 6695 * Display or hide the processing indicator 6696 * @param {object} settings dataTables settings object 6697 * @param {bool} show Show the processing indicator (true) or not (false) 6698 * @memberof DataTable#oApi 6699 */ 6700 function _fnProcessingDisplay ( settings, show ) 6701 { 6702 if ( settings.oFeatures.bProcessing ) { 6703 $(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' ); 6704 } 6705 6706 _fnCallbackFire( settings, null, 'processing', [settings, show] ); 6707 } 6708 6709 /** 6710 * Add any control elements for the table - specifically scrolling 6711 * @param {object} settings dataTables settings object 6712 * @returns {node} Node to add to the DOM 6713 * @memberof DataTable#oApi 6714 */ 6715 function _fnFeatureHtmlTable ( settings ) 6716 { 6717 var table = $(settings.nTable); 6718 6719 // Add the ARIA grid role to the table 6720 table.attr( 'role', 'grid' ); 6721 6722 // Scrolling from here on in 6723 var scroll = settings.oScroll; 6724 6725 if ( scroll.sX === '' && scroll.sY === '' ) { 6726 return settings.nTable; 6727 } 6728 6729 var scrollX = scroll.sX; 6730 var scrollY = scroll.sY; 6731 var classes = settings.oClasses; 6732 var caption = table.children('caption'); 6733 var captionSide = caption.length ? caption[0]._captionSide : null; 6734 var headerClone = $( table[0].cloneNode(false) ); 6735 var footerClone = $( table[0].cloneNode(false) ); 6736 var footer = table.children('tfoot'); 6737 var _div = '<div/>'; 6738 var size = function ( s ) { 6739 return !s ? null : _fnStringToCss( s ); 6740 }; 6741 6742 if ( ! footer.length ) { 6743 footer = null; 6744 } 6745 6746 /* 6747 * The HTML structure that we want to generate in this function is: 6748 * div - scroller 6749 * div - scroll head 6750 * div - scroll head inner 6751 * table - scroll head table 6752 * thead - thead 6753 * div - scroll body 6754 * table - table (master table) 6755 * thead - thead clone for sizing 6756 * tbody - tbody 6757 * div - scroll foot 6758 * div - scroll foot inner 6759 * table - scroll foot table 6760 * tfoot - tfoot 6761 */ 6762 var scroller = $( _div, { 'class': classes.sScrollWrapper } ) 6763 .append( 6764 $(_div, { 'class': classes.sScrollHead } ) 6765 .css( { 6766 overflow: 'hidden', 6767 position: 'relative', 6768 border: 0, 6769 width: scrollX ? size(scrollX) : '100%' 6770 } ) 6771 .append( 6772 $(_div, { 'class': classes.sScrollHeadInner } ) 6773 .css( { 6774 'box-sizing': 'content-box', 6775 width: scroll.sXInner || '100%' 6776 } ) 6777 .append( 6778 headerClone 6779 .removeAttr('id') 6780 .css( 'margin-left', 0 ) 6781 .append( captionSide === 'top' ? caption : null ) 6782 .append( 6783 table.children('thead') 6784 ) 6785 ) 6786 ) 6787 ) 6788 .append( 6789 $(_div, { 'class': classes.sScrollBody } ) 6790 .css( { 6791 position: 'relative', 6792 overflow: 'auto', 6793 width: size( scrollX ) 6794 } ) 6795 .append( table ) 6796 ); 6797 6798 if ( footer ) { 6799 scroller.append( 6800 $(_div, { 'class': classes.sScrollFoot } ) 6801 .css( { 6802 overflow: 'hidden', 6803 border: 0, 6804 width: scrollX ? size(scrollX) : '100%' 6805 } ) 6806 .append( 6807 $(_div, { 'class': classes.sScrollFootInner } ) 6808 .append( 6809 footerClone 6810 .removeAttr('id') 6811 .css( 'margin-left', 0 ) 6812 .append( captionSide === 'bottom' ? caption : null ) 6813 .append( 6814 table.children('tfoot') 6815 ) 6816 ) 6817 ) 6818 ); 6819 } 6820 6821 var children = scroller.children(); 6822 var scrollHead = children[0]; 6823 var scrollBody = children[1]; 6824 var scrollFoot = footer ? children[2] : null; 6825 6826 // When the body is scrolled, then we also want to scroll the headers 6827 if ( scrollX ) { 6828 $(scrollBody).on( 'scroll.DT', function (e) { 6829 var scrollLeft = this.scrollLeft; 6830 6831 scrollHead.scrollLeft = scrollLeft; 6832 6833 if ( footer ) { 6834 scrollFoot.scrollLeft = scrollLeft; 6835 } 6836 } ); 6837 } 6838 6839 $(scrollBody).css('max-height', scrollY); 6840 if (! scroll.bCollapse) { 6841 $(scrollBody).css('height', scrollY); 6842 } 6843 6844 settings.nScrollHead = scrollHead; 6845 settings.nScrollBody = scrollBody; 6846 settings.nScrollFoot = scrollFoot; 6847 6848 // On redraw - align columns 6849 settings.aoDrawCallback.push( { 6850 "fn": _fnScrollDraw, 6851 "sName": "scrolling" 6852 } ); 6853 6854 return scroller[0]; 6855 } 6856 6857 6858 6859 /** 6860 * Update the header, footer and body tables for resizing - i.e. column 6861 * alignment. 6862 * 6863 * Welcome to the most horrible function DataTables. The process that this 6864 * function follows is basically: 6865 * 1. Re-create the table inside the scrolling div 6866 * 2. Take live measurements from the DOM 6867 * 3. Apply the measurements to align the columns 6868 * 4. Clean up 6869 * 6870 * @param {object} settings dataTables settings object 6871 * @memberof DataTable#oApi 6872 */ 6873 function _fnScrollDraw ( settings ) 6874 { 6875 // Given that this is such a monster function, a lot of variables are use 6876 // to try and keep the minimised size as small as possible 6877 var 6878 scroll = settings.oScroll, 6879 scrollX = scroll.sX, 6880 scrollXInner = scroll.sXInner, 6881 scrollY = scroll.sY, 6882 barWidth = scroll.iBarWidth, 6883 divHeader = $(settings.nScrollHead), 6884 divHeaderStyle = divHeader[0].style, 6885 divHeaderInner = divHeader.children('div'), 6886 divHeaderInnerStyle = divHeaderInner[0].style, 6887 divHeaderTable = divHeaderInner.children('table'), 6888 divBodyEl = settings.nScrollBody, 6889 divBody = $(divBodyEl), 6890 divBodyStyle = divBodyEl.style, 6891 divFooter = $(settings.nScrollFoot), 6892 divFooterInner = divFooter.children('div'), 6893 divFooterTable = divFooterInner.children('table'), 6894 header = $(settings.nTHead), 6895 table = $(settings.nTable), 6896 tableEl = table[0], 6897 tableStyle = tableEl.style, 6898 footer = settings.nTFoot ? $(settings.nTFoot) : null, 6899 browser = settings.oBrowser, 6900 ie67 = browser.bScrollOversize, 6901 dtHeaderCells = _pluck( settings.aoColumns, 'nTh' ), 6902 headerTrgEls, footerTrgEls, 6903 headerSrcEls, footerSrcEls, 6904 headerCopy, footerCopy, 6905 headerWidths=[], footerWidths=[], 6906 headerContent=[], footerContent=[], 6907 idx, correction, sanityWidth, 6908 zeroOut = function(nSizer) { 6909 var style = nSizer.style; 6910 style.paddingTop = "0"; 6911 style.paddingBottom = "0"; 6912 style.borderTopWidth = "0"; 6913 style.borderBottomWidth = "0"; 6914 style.height = 0; 6915 }; 6916 6917 // If the scrollbar visibility has changed from the last draw, we need to 6918 // adjust the column sizes as the table width will have changed to account 6919 // for the scrollbar 6920 var scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight; 6921 6922 if ( settings.scrollBarVis !== scrollBarVis && settings.scrollBarVis !== undefined ) { 6923 settings.scrollBarVis = scrollBarVis; 6924 _fnAdjustColumnSizing( settings ); 6925 return; // adjust column sizing will call this function again 6926 } 6927 else { 6928 settings.scrollBarVis = scrollBarVis; 6929 } 6930 6931 /* 6932 * 1. Re-create the table inside the scrolling div 6933 */ 6934 6935 // Remove the old minimised thead and tfoot elements in the inner table 6936 table.children('thead, tfoot').remove(); 6937 6938 if ( footer ) { 6939 footerCopy = footer.clone().prependTo( table ); 6940 footerTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized 6941 footerSrcEls = footerCopy.find('tr'); 6942 } 6943 6944 // Clone the current header and footer elements and then place it into the inner table 6945 headerCopy = header.clone().prependTo( table ); 6946 headerTrgEls = header.find('tr'); // original header is in its own table 6947 headerSrcEls = headerCopy.find('tr'); 6948 headerCopy.find('th, td').removeAttr('tabindex'); 6949 6950 6951 /* 6952 * 2. Take live measurements from the DOM - do not alter the DOM itself! 6953 */ 6954 6955 // Remove old sizing and apply the calculated column widths 6956 // Get the unique column headers in the newly created (cloned) header. We want to apply the 6957 // calculated sizes to this header 6958 if ( ! scrollX ) 6959 { 6960 divBodyStyle.width = '100%'; 6961 divHeader[0].style.width = '100%'; 6962 } 6963 6964 $.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) { 6965 idx = _fnVisibleToColumnIndex( settings, i ); 6966 el.style.width = settings.aoColumns[idx].sWidth; 6967 } ); 6968 6969 if ( footer ) { 6970 _fnApplyToChildren( function(n) { 6971 n.style.width = ""; 6972 }, footerSrcEls ); 6973 } 6974 6975 // Size the table as a whole 6976 sanityWidth = table.outerWidth(); 6977 if ( scrollX === "" ) { 6978 // No x scrolling 6979 tableStyle.width = "100%"; 6980 6981 // IE7 will make the width of the table when 100% include the scrollbar 6982 // - which is shouldn't. When there is a scrollbar we need to take this 6983 // into account. 6984 if ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight || 6985 divBody.css('overflow-y') == "scroll") 6986 ) { 6987 tableStyle.width = _fnStringToCss( table.outerWidth() - barWidth); 6988 } 6989 6990 // Recalculate the sanity width 6991 sanityWidth = table.outerWidth(); 6992 } 6993 else if ( scrollXInner !== "" ) { 6994 // legacy x scroll inner has been given - use it 6995 tableStyle.width = _fnStringToCss(scrollXInner); 6996 6997 // Recalculate the sanity width 6998 sanityWidth = table.outerWidth(); 6999 } 7000 7001 // Hidden header should have zero height, so remove padding and borders. Then 7002 // set the width based on the real headers 7003 7004 // Apply all styles in one pass 7005 _fnApplyToChildren( zeroOut, headerSrcEls ); 7006 7007 // Read all widths in next pass 7008 _fnApplyToChildren( function(nSizer) { 7009 headerContent.push( nSizer.innerHTML ); 7010 headerWidths.push( _fnStringToCss( $(nSizer).css('width') ) ); 7011 }, headerSrcEls ); 7012 7013 // Apply all widths in final pass 7014 _fnApplyToChildren( function(nToSize, i) { 7015 // Only apply widths to the DataTables detected header cells - this 7016 // prevents complex headers from having contradictory sizes applied 7017 if ( $.inArray( nToSize, dtHeaderCells ) !== -1 ) { 7018 nToSize.style.width = headerWidths[i]; 7019 } 7020 }, headerTrgEls ); 7021 7022 $(headerSrcEls).height(0); 7023 7024 /* Same again with the footer if we have one */ 7025 if ( footer ) 7026 { 7027 _fnApplyToChildren( zeroOut, footerSrcEls ); 7028 7029 _fnApplyToChildren( function(nSizer) { 7030 footerContent.push( nSizer.innerHTML ); 7031 footerWidths.push( _fnStringToCss( $(nSizer).css('width') ) ); 7032 }, footerSrcEls ); 7033 7034 _fnApplyToChildren( function(nToSize, i) { 7035 nToSize.style.width = footerWidths[i]; 7036 }, footerTrgEls ); 7037 7038 $(footerSrcEls).height(0); 7039 } 7040 7041 7042 /* 7043 * 3. Apply the measurements 7044 */ 7045 7046 // "Hide" the header and footer that we used for the sizing. We need to keep 7047 // the content of the cell so that the width applied to the header and body 7048 // both match, but we want to hide it completely. We want to also fix their 7049 // width to what they currently are 7050 _fnApplyToChildren( function(nSizer, i) { 7051 nSizer.innerHTML = '<div class="dataTables_sizing">'+headerContent[i]+'</div>'; 7052 nSizer.childNodes[0].style.height = "0"; 7053 nSizer.childNodes[0].style.overflow = "hidden"; 7054 nSizer.style.width = headerWidths[i]; 7055 }, headerSrcEls ); 7056 7057 if ( footer ) 7058 { 7059 _fnApplyToChildren( function(nSizer, i) { 7060 nSizer.innerHTML = '<div class="dataTables_sizing">'+footerContent[i]+'</div>'; 7061 nSizer.childNodes[0].style.height = "0"; 7062 nSizer.childNodes[0].style.overflow = "hidden"; 7063 nSizer.style.width = footerWidths[i]; 7064 }, footerSrcEls ); 7065 } 7066 7067 // Sanity check that the table is of a sensible width. If not then we are going to get 7068 // misalignment - try to prevent this by not allowing the table to shrink below its min width 7069 if ( table.outerWidth() < sanityWidth ) 7070 { 7071 // The min width depends upon if we have a vertical scrollbar visible or not */ 7072 correction = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight || 7073 divBody.css('overflow-y') == "scroll")) ? 7074 sanityWidth+barWidth : 7075 sanityWidth; 7076 7077 // IE6/7 are a law unto themselves... 7078 if ( ie67 && (divBodyEl.scrollHeight > 7079 divBodyEl.offsetHeight || divBody.css('overflow-y') == "scroll") 7080 ) { 7081 tableStyle.width = _fnStringToCss( correction-barWidth ); 7082 } 7083 7084 // And give the user a warning that we've stopped the table getting too small 7085 if ( scrollX === "" || scrollXInner !== "" ) { 7086 _fnLog( settings, 1, 'Possible column misalignment', 6 ); 7087 } 7088 } 7089 else 7090 { 7091 correction = '100%'; 7092 } 7093 7094 // Apply to the container elements 7095 divBodyStyle.width = _fnStringToCss( correction ); 7096 divHeaderStyle.width = _fnStringToCss( correction ); 7097 7098 if ( footer ) { 7099 settings.nScrollFoot.style.width = _fnStringToCss( correction ); 7100 } 7101 7102 7103 /* 7104 * 4. Clean up 7105 */ 7106 if ( ! scrollY ) { 7107 /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting 7108 * the scrollbar height from the visible display, rather than adding it on. We need to 7109 * set the height in order to sort this. Don't want to do it in any other browsers. 7110 */ 7111 if ( ie67 ) { 7112 divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth ); 7113 } 7114 } 7115 7116 /* Finally set the width's of the header and footer tables */ 7117 var iOuterWidth = table.outerWidth(); 7118 divHeaderTable[0].style.width = _fnStringToCss( iOuterWidth ); 7119 divHeaderInnerStyle.width = _fnStringToCss( iOuterWidth ); 7120 7121 // Figure out if there are scrollbar present - if so then we need a the header and footer to 7122 // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar) 7123 var bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll"; 7124 var padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' ); 7125 divHeaderInnerStyle[ padding ] = bScrolling ? barWidth+"px" : "0px"; 7126 7127 if ( footer ) { 7128 divFooterTable[0].style.width = _fnStringToCss( iOuterWidth ); 7129 divFooterInner[0].style.width = _fnStringToCss( iOuterWidth ); 7130 divFooterInner[0].style[padding] = bScrolling ? barWidth+"px" : "0px"; 7131 } 7132 7133 // Correct DOM ordering for colgroup - comes before the thead 7134 table.children('colgroup').insertBefore( table.children('thead') ); 7135 7136 /* Adjust the position of the header in case we loose the y-scrollbar */ 7137 divBody.trigger('scroll'); 7138 7139 // If sorting or filtering has occurred, jump the scrolling back to the top 7140 // only if we aren't holding the position 7141 if ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) { 7142 divBodyEl.scrollTop = 0; 7143 } 7144 } 7145 7146 7147 7148 /** 7149 * Apply a given function to the display child nodes of an element array (typically 7150 * TD children of TR rows 7151 * @param {function} fn Method to apply to the objects 7152 * @param array {nodes} an1 List of elements to look through for display children 7153 * @param array {nodes} an2 Another list (identical structure to the first) - optional 7154 * @memberof DataTable#oApi 7155 */ 7156 function _fnApplyToChildren( fn, an1, an2 ) 7157 { 7158 var index=0, i=0, iLen=an1.length; 7159 var nNode1, nNode2; 7160 7161 while ( i < iLen ) { 7162 nNode1 = an1[i].firstChild; 7163 nNode2 = an2 ? an2[i].firstChild : null; 7164 7165 while ( nNode1 ) { 7166 if ( nNode1.nodeType === 1 ) { 7167 if ( an2 ) { 7168 fn( nNode1, nNode2, index ); 7169 } 7170 else { 7171 fn( nNode1, index ); 7172 } 7173 7174 index++; 7175 } 7176 7177 nNode1 = nNode1.nextSibling; 7178 nNode2 = an2 ? nNode2.nextSibling : null; 7179 } 7180 7181 i++; 7182 } 7183 } 7184 7185 7186 7187 var __re_html_remove = /<.*?>/g; 7188 7189 7190 /** 7191 * Calculate the width of columns for the table 7192 * @param {object} oSettings dataTables settings object 7193 * @memberof DataTable#oApi 7194 */ 7195 function _fnCalculateColumnWidths ( oSettings ) 7196 { 7197 var 7198 table = oSettings.nTable, 7199 columns = oSettings.aoColumns, 7200 scroll = oSettings.oScroll, 7201 scrollY = scroll.sY, 7202 scrollX = scroll.sX, 7203 scrollXInner = scroll.sXInner, 7204 columnCount = columns.length, 7205 visibleColumns = _fnGetColumns( oSettings, 'bVisible' ), 7206 headerCells = $('th', oSettings.nTHead), 7207 tableWidthAttr = table.getAttribute('width'), // from DOM element 7208 tableContainer = table.parentNode, 7209 userInputs = false, 7210 i, column, columnIdx, width, outerWidth, 7211 browser = oSettings.oBrowser, 7212 ie67 = browser.bScrollOversize; 7213 7214 var styleWidth = table.style.width; 7215 if ( styleWidth && styleWidth.indexOf('%') !== -1 ) { 7216 tableWidthAttr = styleWidth; 7217 } 7218 7219 /* Convert any user input sizes into pixel sizes */ 7220 for ( i=0 ; i<visibleColumns.length ; i++ ) { 7221 column = columns[ visibleColumns[i] ]; 7222 7223 if ( column.sWidth !== null ) { 7224 column.sWidth = _fnConvertToWidth( column.sWidthOrig, tableContainer ); 7225 7226 userInputs = true; 7227 } 7228 } 7229 7230 /* If the number of columns in the DOM equals the number that we have to 7231 * process in DataTables, then we can use the offsets that are created by 7232 * the web- browser. No custom sizes can be set in order for this to happen, 7233 * nor scrolling used 7234 */ 7235 if ( ie67 || ! userInputs && ! scrollX && ! scrollY && 7236 columnCount == _fnVisbleColumns( oSettings ) && 7237 columnCount == headerCells.length 7238 ) { 7239 for ( i=0 ; i<columnCount ; i++ ) { 7240 var colIdx = _fnVisibleToColumnIndex( oSettings, i ); 7241 7242 if ( colIdx !== null ) { 7243 columns[ colIdx ].sWidth = _fnStringToCss( headerCells.eq(i).width() ); 7244 } 7245 } 7246 } 7247 else 7248 { 7249 // Otherwise construct a single row, worst case, table with the widest 7250 // node in the data, assign any user defined widths, then insert it into 7251 // the DOM and allow the browser to do all the hard work of calculating 7252 // table widths 7253 var tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table 7254 .css( 'visibility', 'hidden' ) 7255 .removeAttr( 'id' ); 7256 7257 // Clean up the table body 7258 tmpTable.find('tbody tr').remove(); 7259 var tr = $('<tr/>').appendTo( tmpTable.find('tbody') ); 7260 7261 // Clone the table header and footer - we can't use the header / footer 7262 // from the cloned table, since if scrolling is active, the table's 7263 // real header and footer are contained in different table tags 7264 tmpTable.find('thead, tfoot').remove(); 7265 tmpTable 7266 .append( $(oSettings.nTHead).clone() ) 7267 .append( $(oSettings.nTFoot).clone() ); 7268 7269 // Remove any assigned widths from the footer (from scrolling) 7270 tmpTable.find('tfoot th, tfoot td').css('width', ''); 7271 7272 // Apply custom sizing to the cloned header 7273 headerCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] ); 7274 7275 for ( i=0 ; i<visibleColumns.length ; i++ ) { 7276 column = columns[ visibleColumns[i] ]; 7277 7278 headerCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ? 7279 _fnStringToCss( column.sWidthOrig ) : 7280 ''; 7281 7282 // For scrollX we need to force the column width otherwise the 7283 // browser will collapse it. If this width is smaller than the 7284 // width the column requires, then it will have no effect 7285 if ( column.sWidthOrig && scrollX ) { 7286 $( headerCells[i] ).append( $('<div/>').css( { 7287 width: column.sWidthOrig, 7288 margin: 0, 7289 padding: 0, 7290 border: 0, 7291 height: 1 7292 } ) ); 7293 } 7294 } 7295 7296 // Find the widest cell for each column and put it into the table 7297 if ( oSettings.aoData.length ) { 7298 for ( i=0 ; i<visibleColumns.length ; i++ ) { 7299 columnIdx = visibleColumns[i]; 7300 column = columns[ columnIdx ]; 7301 7302 $( _fnGetWidestNode( oSettings, columnIdx ) ) 7303 .clone( false ) 7304 .append( column.sContentPadding ) 7305 .appendTo( tr ); 7306 } 7307 } 7308 7309 // Tidy the temporary table - remove name attributes so there aren't 7310 // duplicated in the dom (radio elements for example) 7311 $('[name]', tmpTable).removeAttr('name'); 7312 7313 // Table has been built, attach to the document so we can work with it. 7314 // A holding element is used, positioned at the top of the container 7315 // with minimal height, so it has no effect on if the container scrolls 7316 // or not. Otherwise it might trigger scrolling when it actually isn't 7317 // needed 7318 var holder = $('<div/>').css( scrollX || scrollY ? 7319 { 7320 position: 'absolute', 7321 top: 0, 7322 left: 0, 7323 height: 1, 7324 right: 0, 7325 overflow: 'hidden' 7326 } : 7327 {} 7328 ) 7329 .append( tmpTable ) 7330 .appendTo( tableContainer ); 7331 7332 // When scrolling (X or Y) we want to set the width of the table as 7333 // appropriate. However, when not scrolling leave the table width as it 7334 // is. This results in slightly different, but I think correct behaviour 7335 if ( scrollX && scrollXInner ) { 7336 tmpTable.width( scrollXInner ); 7337 } 7338 else if ( scrollX ) { 7339 tmpTable.css( 'width', 'auto' ); 7340 tmpTable.removeAttr('width'); 7341 7342 // If there is no width attribute or style, then allow the table to 7343 // collapse 7344 if ( tmpTable.width() < tableContainer.clientWidth && tableWidthAttr ) { 7345 tmpTable.width( tableContainer.clientWidth ); 7346 } 7347 } 7348 else if ( scrollY ) { 7349 tmpTable.width( tableContainer.clientWidth ); 7350 } 7351 else if ( tableWidthAttr ) { 7352 tmpTable.width( tableWidthAttr ); 7353 } 7354 7355 // Get the width of each column in the constructed table - we need to 7356 // know the inner width (so it can be assigned to the other table's 7357 // cells) and the outer width so we can calculate the full width of the 7358 // table. This is safe since DataTables requires a unique cell for each 7359 // column, but if ever a header can span multiple columns, this will 7360 // need to be modified. 7361 var total = 0; 7362 for ( i=0 ; i<visibleColumns.length ; i++ ) { 7363 var cell = $(headerCells[i]); 7364 var border = cell.outerWidth() - cell.width(); 7365 7366 // Use getBounding... where possible (not IE8-) because it can give 7367 // sub-pixel accuracy, which we then want to round up! 7368 var bounding = browser.bBounding ? 7369 Math.ceil( headerCells[i].getBoundingClientRect().width ) : 7370 cell.outerWidth(); 7371 7372 // Total is tracked to remove any sub-pixel errors as the outerWidth 7373 // of the table might not equal the total given here (IE!). 7374 total += bounding; 7375 7376 // Width for each column to use 7377 columns[ visibleColumns[i] ].sWidth = _fnStringToCss( bounding - border ); 7378 } 7379 7380 table.style.width = _fnStringToCss( total ); 7381 7382 // Finished with the table - ditch it 7383 holder.remove(); 7384 } 7385 7386 // If there is a width attr, we want to attach an event listener which 7387 // allows the table sizing to automatically adjust when the window is 7388 // resized. Use the width attr rather than CSS, since we can't know if the 7389 // CSS is a relative value or absolute - DOM read is always px. 7390 if ( tableWidthAttr ) { 7391 table.style.width = _fnStringToCss( tableWidthAttr ); 7392 } 7393 7394 if ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) { 7395 var bindResize = function () { 7396 $(window).on('resize.DT-'+oSettings.sInstance, _fnThrottle( function () { 7397 _fnAdjustColumnSizing( oSettings ); 7398 } ) ); 7399 }; 7400 7401 // IE6/7 will crash if we bind a resize event handler on page load. 7402 // To be removed in 1.11 which drops IE6/7 support 7403 if ( ie67 ) { 7404 setTimeout( bindResize, 1000 ); 7405 } 7406 else { 7407 bindResize(); 7408 } 7409 7410 oSettings._reszEvt = true; 7411 } 7412 } 7413 7414 7415 /** 7416 * Throttle the calls to a function. Arguments and context are maintained for 7417 * the throttled function 7418 * @param {function} fn Function to be called 7419 * @param {int} [freq=200] call frequency in mS 7420 * @returns {function} wrapped function 7421 * @memberof DataTable#oApi 7422 */ 7423 var _fnThrottle = DataTable.util.throttle; 7424 7425 7426 /** 7427 * Convert a CSS unit width to pixels (e.g. 2em) 7428 * @param {string} width width to be converted 7429 * @param {node} parent parent to get the with for (required for relative widths) - optional 7430 * @returns {int} width in pixels 7431 * @memberof DataTable#oApi 7432 */ 7433 function _fnConvertToWidth ( width, parent ) 7434 { 7435 if ( ! width ) { 7436 return 0; 7437 } 7438 7439 var n = $('<div/>') 7440 .css( 'width', _fnStringToCss( width ) ) 7441 .appendTo( parent || document.body ); 7442 7443 var val = n[0].offsetWidth; 7444 n.remove(); 7445 7446 return val; 7447 } 7448 7449 7450 /** 7451 * Get the widest node 7452 * @param {object} settings dataTables settings object 7453 * @param {int} colIdx column of interest 7454 * @returns {node} widest table node 7455 * @memberof DataTable#oApi 7456 */ 7457 function _fnGetWidestNode( settings, colIdx ) 7458 { 7459 var idx = _fnGetMaxLenString( settings, colIdx ); 7460 if ( idx < 0 ) { 7461 return null; 7462 } 7463 7464 var data = settings.aoData[ idx ]; 7465 return ! data.nTr ? // Might not have been created when deferred rendering 7466 $('<td/>').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] : 7467 data.anCells[ colIdx ]; 7468 } 7469 7470 7471 /** 7472 * Get the maximum strlen for each data column 7473 * @param {object} settings dataTables settings object 7474 * @param {int} colIdx column of interest 7475 * @returns {string} max string length for each column 7476 * @memberof DataTable#oApi 7477 */ 7478 function _fnGetMaxLenString( settings, colIdx ) 7479 { 7480 var s, max=-1, maxIdx = -1; 7481 7482 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) { 7483 s = _fnGetCellData( settings, i, colIdx, 'display' )+''; 7484 s = s.replace( __re_html_remove, '' ); 7485 s = s.replace( / /g, ' ' ); 7486 7487 if ( s.length > max ) { 7488 max = s.length; 7489 maxIdx = i; 7490 } 7491 } 7492 7493 return maxIdx; 7494 } 7495 7496 7497 /** 7498 * Append a CSS unit (only if required) to a string 7499 * @param {string} value to css-ify 7500 * @returns {string} value with css unit 7501 * @memberof DataTable#oApi 7502 */ 7503 function _fnStringToCss( s ) 7504 { 7505 if ( s === null ) { 7506 return '0px'; 7507 } 7508 7509 if ( typeof s == 'number' ) { 7510 return s < 0 ? 7511 '0px' : 7512 s+'px'; 7513 } 7514 7515 // Check it has a unit character already 7516 return s.match(/\d$/) ? 7517 s+'px' : 7518 s; 7519 } 7520 7521 7522 7523 function _fnSortFlatten ( settings ) 7524 { 7525 var 7526 i, iLen, k, kLen, 7527 aSort = [], 7528 aiOrig = [], 7529 aoColumns = settings.aoColumns, 7530 aDataSort, iCol, sType, srcCol, 7531 fixed = settings.aaSortingFixed, 7532 fixedObj = $.isPlainObject( fixed ), 7533 nestedSort = [], 7534 add = function ( a ) { 7535 if ( a.length && ! Array.isArray( a[0] ) ) { 7536 // 1D array 7537 nestedSort.push( a ); 7538 } 7539 else { 7540 // 2D array 7541 $.merge( nestedSort, a ); 7542 } 7543 }; 7544 7545 // Build the sort array, with pre-fix and post-fix options if they have been 7546 // specified 7547 if ( Array.isArray( fixed ) ) { 7548 add( fixed ); 7549 } 7550 7551 if ( fixedObj && fixed.pre ) { 7552 add( fixed.pre ); 7553 } 7554 7555 add( settings.aaSorting ); 7556 7557 if (fixedObj && fixed.post ) { 7558 add( fixed.post ); 7559 } 7560 7561 for ( i=0 ; i<nestedSort.length ; i++ ) 7562 { 7563 srcCol = nestedSort[i][0]; 7564 aDataSort = aoColumns[ srcCol ].aDataSort; 7565 7566 for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ ) 7567 { 7568 iCol = aDataSort[k]; 7569 sType = aoColumns[ iCol ].sType || 'string'; 7570 7571 if ( nestedSort[i]._idx === undefined ) { 7572 nestedSort[i]._idx = $.inArray( nestedSort[i][1], aoColumns[iCol].asSorting ); 7573 } 7574 7575 aSort.push( { 7576 src: srcCol, 7577 col: iCol, 7578 dir: nestedSort[i][1], 7579 index: nestedSort[i]._idx, 7580 type: sType, 7581 formatter: DataTable.ext.type.order[ sType+"-pre" ] 7582 } ); 7583 } 7584 } 7585 7586 return aSort; 7587 } 7588 7589 /** 7590 * Change the order of the table 7591 * @param {object} oSettings dataTables settings object 7592 * @memberof DataTable#oApi 7593 * @todo This really needs split up! 7594 */ 7595 function _fnSort ( oSettings ) 7596 { 7597 var 7598 i, ien, iLen, j, jLen, k, kLen, 7599 sDataType, nTh, 7600 aiOrig = [], 7601 oExtSort = DataTable.ext.type.order, 7602 aoData = oSettings.aoData, 7603 aoColumns = oSettings.aoColumns, 7604 aDataSort, data, iCol, sType, oSort, 7605 formatters = 0, 7606 sortCol, 7607 displayMaster = oSettings.aiDisplayMaster, 7608 aSort; 7609 7610 // Resolve any column types that are unknown due to addition or invalidation 7611 // @todo Can this be moved into a 'data-ready' handler which is called when 7612 // data is going to be used in the table? 7613 _fnColumnTypes( oSettings ); 7614 7615 aSort = _fnSortFlatten( oSettings ); 7616 7617 for ( i=0, ien=aSort.length ; i<ien ; i++ ) { 7618 sortCol = aSort[i]; 7619 7620 // Track if we can use the fast sort algorithm 7621 if ( sortCol.formatter ) { 7622 formatters++; 7623 } 7624 7625 // Load the data needed for the sort, for each cell 7626 _fnSortData( oSettings, sortCol.col ); 7627 } 7628 7629 /* No sorting required if server-side or no sorting array */ 7630 if ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 ) 7631 { 7632 // Create a value - key array of the current row positions such that we can use their 7633 // current position during the sort, if values match, in order to perform stable sorting 7634 for ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) { 7635 aiOrig[ displayMaster[i] ] = i; 7636 } 7637 7638 /* Do the sort - here we want multi-column sorting based on a given data source (column) 7639 * and sorting function (from oSort) in a certain direction. It's reasonably complex to 7640 * follow on it's own, but this is what we want (example two column sorting): 7641 * fnLocalSorting = function(a,b){ 7642 * var iTest; 7643 * iTest = oSort['string-asc']('data11', 'data12'); 7644 * if (iTest !== 0) 7645 * return iTest; 7646 * iTest = oSort['numeric-desc']('data21', 'data22'); 7647 * if (iTest !== 0) 7648 * return iTest; 7649 * return oSort['numeric-asc']( aiOrig[a], aiOrig[b] ); 7650 * } 7651 * Basically we have a test for each sorting column, if the data in that column is equal, 7652 * test the next column. If all columns match, then we use a numeric sort on the row 7653 * positions in the original data array to provide a stable sort. 7654 * 7655 * Note - I know it seems excessive to have two sorting methods, but the first is around 7656 * 15% faster, so the second is only maintained for backwards compatibility with sorting 7657 * methods which do not have a pre-sort formatting function. 7658 */ 7659 if ( formatters === aSort.length ) { 7660 // All sort types have formatting functions 7661 displayMaster.sort( function ( a, b ) { 7662 var 7663 x, y, k, test, sort, 7664 len=aSort.length, 7665 dataA = aoData[a]._aSortData, 7666 dataB = aoData[b]._aSortData; 7667 7668 for ( k=0 ; k<len ; k++ ) { 7669 sort = aSort[k]; 7670 7671 x = dataA[ sort.col ]; 7672 y = dataB[ sort.col ]; 7673 7674 test = x<y ? -1 : x>y ? 1 : 0; 7675 if ( test !== 0 ) { 7676 return sort.dir === 'asc' ? test : -test; 7677 } 7678 } 7679 7680 x = aiOrig[a]; 7681 y = aiOrig[b]; 7682 return x<y ? -1 : x>y ? 1 : 0; 7683 } ); 7684 } 7685 else { 7686 // Depreciated - remove in 1.11 (providing a plug-in option) 7687 // Not all sort types have formatting methods, so we have to call their sorting 7688 // methods. 7689 displayMaster.sort( function ( a, b ) { 7690 var 7691 x, y, k, l, test, sort, fn, 7692 len=aSort.length, 7693 dataA = aoData[a]._aSortData, 7694 dataB = aoData[b]._aSortData; 7695 7696 for ( k=0 ; k<len ; k++ ) { 7697 sort = aSort[k]; 7698 7699 x = dataA[ sort.col ]; 7700 y = dataB[ sort.col ]; 7701 7702 fn = oExtSort[ sort.type+"-"+sort.dir ] || oExtSort[ "string-"+sort.dir ]; 7703 test = fn( x, y ); 7704 if ( test !== 0 ) { 7705 return test; 7706 } 7707 } 7708 7709 x = aiOrig[a]; 7710 y = aiOrig[b]; 7711 return x<y ? -1 : x>y ? 1 : 0; 7712 } ); 7713 } 7714 } 7715 7716 /* Tell the draw function that we have sorted the data */ 7717 oSettings.bSorted = true; 7718 } 7719 7720 7721 function _fnSortAria ( settings ) 7722 { 7723 var label; 7724 var nextSort; 7725 var columns = settings.aoColumns; 7726 var aSort = _fnSortFlatten( settings ); 7727 var oAria = settings.oLanguage.oAria; 7728 7729 // ARIA attributes - need to loop all columns, to update all (removing old 7730 // attributes as needed) 7731 for ( var i=0, iLen=columns.length ; i<iLen ; i++ ) 7732 { 7733 var col = columns[i]; 7734 var asSorting = col.asSorting; 7735 var sTitle = col.sTitle.replace( /<.*?>/g, "" ); 7736 var th = col.nTh; 7737 7738 // IE7 is throwing an error when setting these properties with jQuery's 7739 // attr() and removeAttr() methods... 7740 th.removeAttribute('aria-sort'); 7741 7742 /* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */ 7743 if ( col.bSortable ) { 7744 if ( aSort.length > 0 && aSort[0].col == i ) { 7745 th.setAttribute('aria-sort', aSort[0].dir=="asc" ? "ascending" : "descending" ); 7746 nextSort = asSorting[ aSort[0].index+1 ] || asSorting[0]; 7747 } 7748 else { 7749 nextSort = asSorting[0]; 7750 } 7751 7752 label = sTitle + ( nextSort === "asc" ? 7753 oAria.sSortAscending : 7754 oAria.sSortDescending 7755 ); 7756 } 7757 else { 7758 label = sTitle; 7759 } 7760 7761 th.setAttribute('aria-label', label); 7762 } 7763 } 7764 7765 7766 /** 7767 * Function to run on user sort request 7768 * @param {object} settings dataTables settings object 7769 * @param {node} attachTo node to attach the handler to 7770 * @param {int} colIdx column sorting index 7771 * @param {boolean} [append=false] Append the requested sort to the existing 7772 * sort if true (i.e. multi-column sort) 7773 * @param {function} [callback] callback function 7774 * @memberof DataTable#oApi 7775 */ 7776 function _fnSortListener ( settings, colIdx, append, callback ) 7777 { 7778 var col = settings.aoColumns[ colIdx ]; 7779 var sorting = settings.aaSorting; 7780 var asSorting = col.asSorting; 7781 var nextSortIdx; 7782 var next = function ( a, overflow ) { 7783 var idx = a._idx; 7784 if ( idx === undefined ) { 7785 idx = $.inArray( a[1], asSorting ); 7786 } 7787 7788 return idx+1 < asSorting.length ? 7789 idx+1 : 7790 overflow ? 7791 null : 7792 0; 7793 }; 7794 7795 // Convert to 2D array if needed 7796 if ( typeof sorting[0] === 'number' ) { 7797 sorting = settings.aaSorting = [ sorting ]; 7798 } 7799 7800 // If appending the sort then we are multi-column sorting 7801 if ( append && settings.oFeatures.bSortMulti ) { 7802 // Are we already doing some kind of sort on this column? 7803 var sortIdx = $.inArray( colIdx, _pluck(sorting, '0') ); 7804 7805 if ( sortIdx !== -1 ) { 7806 // Yes, modify the sort 7807 nextSortIdx = next( sorting[sortIdx], true ); 7808 7809 if ( nextSortIdx === null && sorting.length === 1 ) { 7810 nextSortIdx = 0; // can't remove sorting completely 7811 } 7812 7813 if ( nextSortIdx === null ) { 7814 sorting.splice( sortIdx, 1 ); 7815 } 7816 else { 7817 sorting[sortIdx][1] = asSorting[ nextSortIdx ]; 7818 sorting[sortIdx]._idx = nextSortIdx; 7819 } 7820 } 7821 else { 7822 // No sort on this column yet 7823 sorting.push( [ colIdx, asSorting[0], 0 ] ); 7824 sorting[sorting.length-1]._idx = 0; 7825 } 7826 } 7827 else if ( sorting.length && sorting[0][0] == colIdx ) { 7828 // Single column - already sorting on this column, modify the sort 7829 nextSortIdx = next( sorting[0] ); 7830 7831 sorting.length = 1; 7832 sorting[0][1] = asSorting[ nextSortIdx ]; 7833 sorting[0]._idx = nextSortIdx; 7834 } 7835 else { 7836 // Single column - sort only on this column 7837 sorting.length = 0; 7838 sorting.push( [ colIdx, asSorting[0] ] ); 7839 sorting[0]._idx = 0; 7840 } 7841 7842 // Run the sort by calling a full redraw 7843 _fnReDraw( settings ); 7844 7845 // callback used for async user interaction 7846 if ( typeof callback == 'function' ) { 7847 callback( settings ); 7848 } 7849 } 7850 7851 7852 /** 7853 * Attach a sort handler (click) to a node 7854 * @param {object} settings dataTables settings object 7855 * @param {node} attachTo node to attach the handler to 7856 * @param {int} colIdx column sorting index 7857 * @param {function} [callback] callback function 7858 * @memberof DataTable#oApi 7859 */ 7860 function _fnSortAttachListener ( settings, attachTo, colIdx, callback ) 7861 { 7862 var col = settings.aoColumns[ colIdx ]; 7863 7864 _fnBindAction( attachTo, {}, function (e) { 7865 /* If the column is not sortable - don't to anything */ 7866 if ( col.bSortable === false ) { 7867 return; 7868 } 7869 7870 // If processing is enabled use a timeout to allow the processing 7871 // display to be shown - otherwise to it synchronously 7872 if ( settings.oFeatures.bProcessing ) { 7873 _fnProcessingDisplay( settings, true ); 7874 7875 setTimeout( function() { 7876 _fnSortListener( settings, colIdx, e.shiftKey, callback ); 7877 7878 // In server-side processing, the draw callback will remove the 7879 // processing display 7880 if ( _fnDataSource( settings ) !== 'ssp' ) { 7881 _fnProcessingDisplay( settings, false ); 7882 } 7883 }, 0 ); 7884 } 7885 else { 7886 _fnSortListener( settings, colIdx, e.shiftKey, callback ); 7887 } 7888 } ); 7889 } 7890 7891 7892 /** 7893 * Set the sorting classes on table's body, Note: it is safe to call this function 7894 * when bSort and bSortClasses are false 7895 * @param {object} oSettings dataTables settings object 7896 * @memberof DataTable#oApi 7897 */ 7898 function _fnSortingClasses( settings ) 7899 { 7900 var oldSort = settings.aLastSort; 7901 var sortClass = settings.oClasses.sSortColumn; 7902 var sort = _fnSortFlatten( settings ); 7903 var features = settings.oFeatures; 7904 var i, ien, colIdx; 7905 7906 if ( features.bSort && features.bSortClasses ) { 7907 // Remove old sorting classes 7908 for ( i=0, ien=oldSort.length ; i<ien ; i++ ) { 7909 colIdx = oldSort[i].src; 7910 7911 // Remove column sorting 7912 $( _pluck( settings.aoData, 'anCells', colIdx ) ) 7913 .removeClass( sortClass + (i<2 ? i+1 : 3) ); 7914 } 7915 7916 // Add new column sorting 7917 for ( i=0, ien=sort.length ; i<ien ; i++ ) { 7918 colIdx = sort[i].src; 7919 7920 $( _pluck( settings.aoData, 'anCells', colIdx ) ) 7921 .addClass( sortClass + (i<2 ? i+1 : 3) ); 7922 } 7923 } 7924 7925 settings.aLastSort = sort; 7926 } 7927 7928 7929 // Get the data to sort a column, be it from cache, fresh (populating the 7930 // cache), or from a sort formatter 7931 function _fnSortData( settings, idx ) 7932 { 7933 // Custom sorting function - provided by the sort data type 7934 var column = settings.aoColumns[ idx ]; 7935 var customSort = DataTable.ext.order[ column.sSortDataType ]; 7936 var customData; 7937 7938 if ( customSort ) { 7939 customData = customSort.call( settings.oInstance, settings, idx, 7940 _fnColumnIndexToVisible( settings, idx ) 7941 ); 7942 } 7943 7944 // Use / populate cache 7945 var row, cellData; 7946 var formatter = DataTable.ext.type.order[ column.sType+"-pre" ]; 7947 7948 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) { 7949 row = settings.aoData[i]; 7950 7951 if ( ! row._aSortData ) { 7952 row._aSortData = []; 7953 } 7954 7955 if ( ! row._aSortData[idx] || customSort ) { 7956 cellData = customSort ? 7957 customData[i] : // If there was a custom sort function, use data from there 7958 _fnGetCellData( settings, i, idx, 'sort' ); 7959 7960 row._aSortData[ idx ] = formatter ? 7961 formatter( cellData ) : 7962 cellData; 7963 } 7964 } 7965 } 7966 7967 7968 7969 /** 7970 * Save the state of a table 7971 * @param {object} oSettings dataTables settings object 7972 * @memberof DataTable#oApi 7973 */ 7974 function _fnSaveState ( settings ) 7975 { 7976 if ( !settings.oFeatures.bStateSave || settings.bDestroying ) 7977 { 7978 return; 7979 } 7980 7981 /* Store the interesting variables */ 7982 var state = { 7983 time: +new Date(), 7984 start: settings._iDisplayStart, 7985 length: settings._iDisplayLength, 7986 order: $.extend( true, [], settings.aaSorting ), 7987 search: _fnSearchToCamel( settings.oPreviousSearch ), 7988 columns: $.map( settings.aoColumns, function ( col, i ) { 7989 return { 7990 visible: col.bVisible, 7991 search: _fnSearchToCamel( settings.aoPreSearchCols[i] ) 7992 }; 7993 } ) 7994 }; 7995 7996 _fnCallbackFire( settings, "aoStateSaveParams", 'stateSaveParams', [settings, state] ); 7997 7998 settings.oSavedState = state; 7999 settings.fnStateSaveCallback.call( settings.oInstance, settings, state ); 8000 } 8001 8002 8003 /** 8004 * Attempt to load a saved table state 8005 * @param {object} oSettings dataTables settings object 8006 * @param {object} oInit DataTables init object so we can override settings 8007 * @param {function} callback Callback to execute when the state has been loaded 8008 * @memberof DataTable#oApi 8009 */ 8010 function _fnLoadState ( settings, oInit, callback ) 8011 { 8012 var i, ien; 8013 var columns = settings.aoColumns; 8014 var loaded = function ( s ) { 8015 if ( ! s || ! s.time ) { 8016 callback(); 8017 return; 8018 } 8019 8020 // Allow custom and plug-in manipulation functions to alter the saved data set and 8021 // cancelling of loading by returning false 8022 var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, s] ); 8023 if ( $.inArray( false, abStateLoad ) !== -1 ) { 8024 callback(); 8025 return; 8026 } 8027 8028 // Reject old data 8029 var duration = settings.iStateDuration; 8030 if ( duration > 0 && s.time < +new Date() - (duration*1000) ) { 8031 callback(); 8032 return; 8033 } 8034 8035 // Number of columns have changed - all bets are off, no restore of settings 8036 if ( s.columns && columns.length !== s.columns.length ) { 8037 callback(); 8038 return; 8039 } 8040 8041 // Store the saved state so it might be accessed at any time 8042 settings.oLoadedState = $.extend( true, {}, s ); 8043 8044 // Restore key features - todo - for 1.11 this needs to be done by 8045 // subscribed events 8046 if ( s.start !== undefined ) { 8047 settings._iDisplayStart = s.start; 8048 settings.iInitDisplayStart = s.start; 8049 } 8050 if ( s.length !== undefined ) { 8051 settings._iDisplayLength = s.length; 8052 } 8053 8054 // Order 8055 if ( s.order !== undefined ) { 8056 settings.aaSorting = []; 8057 $.each( s.order, function ( i, col ) { 8058 settings.aaSorting.push( col[0] >= columns.length ? 8059 [ 0, col[1] ] : 8060 col 8061 ); 8062 } ); 8063 } 8064 8065 // Search 8066 if ( s.search !== undefined ) { 8067 $.extend( settings.oPreviousSearch, _fnSearchToHung( s.search ) ); 8068 } 8069 8070 // Columns 8071 // 8072 if ( s.columns ) { 8073 for ( i=0, ien=s.columns.length ; i<ien ; i++ ) { 8074 var col = s.columns[i]; 8075 8076 // Visibility 8077 if ( col.visible !== undefined ) { 8078 columns[i].bVisible = col.visible; 8079 } 8080 8081 // Search 8082 if ( col.search !== undefined ) { 8083 $.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) ); 8084 } 8085 } 8086 } 8087 8088 _fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, s] ); 8089 callback(); 8090 }; 8091 8092 if ( ! settings.oFeatures.bStateSave ) { 8093 callback(); 8094 return; 8095 } 8096 8097 var state = settings.fnStateLoadCallback.call( settings.oInstance, settings, loaded ); 8098 8099 if ( state !== undefined ) { 8100 loaded( state ); 8101 } 8102 // otherwise, wait for the loaded callback to be executed 8103 } 8104 8105 8106 /** 8107 * Return the settings object for a particular table 8108 * @param {node} table table we are using as a dataTable 8109 * @returns {object} Settings object - or null if not found 8110 * @memberof DataTable#oApi 8111 */ 8112 function _fnSettingsFromNode ( table ) 8113 { 8114 var settings = DataTable.settings; 8115 var idx = $.inArray( table, _pluck( settings, 'nTable' ) ); 8116 8117 return idx !== -1 ? 8118 settings[ idx ] : 8119 null; 8120 } 8121 8122 8123 /** 8124 * Log an error message 8125 * @param {object} settings dataTables settings object 8126 * @param {int} level log error messages, or display them to the user 8127 * @param {string} msg error message 8128 * @param {int} tn Technical note id to get more information about the error. 8129 * @memberof DataTable#oApi 8130 */ 8131 function _fnLog( settings, level, msg, tn ) 8132 { 8133 msg = 'DataTables warning: '+ 8134 (settings ? 'table id='+settings.sTableId+' - ' : '')+msg; 8135 8136 if ( tn ) { 8137 msg += '. For more information about this error, please see '+ 8138 'http://datatables.net/tn/'+tn; 8139 } 8140 8141 if ( ! level ) { 8142 // Backwards compatibility pre 1.10 8143 var ext = DataTable.ext; 8144 var type = ext.sErrMode || ext.errMode; 8145 8146 if ( settings ) { 8147 _fnCallbackFire( settings, null, 'error', [ settings, tn, msg ] ); 8148 } 8149 8150 if ( type == 'alert' ) { 8151 alert( msg ); 8152 } 8153 else if ( type == 'throw' ) { 8154 throw new Error(msg); 8155 } 8156 else if ( typeof type == 'function' ) { 8157 type( settings, tn, msg ); 8158 } 8159 } 8160 else if ( window.console && console.log ) { 8161 console.log( msg ); 8162 } 8163 } 8164 8165 8166 /** 8167 * See if a property is defined on one object, if so assign it to the other object 8168 * @param {object} ret target object 8169 * @param {object} src source object 8170 * @param {string} name property 8171 * @param {string} [mappedName] name to map too - optional, name used if not given 8172 * @memberof DataTable#oApi 8173 */ 8174 function _fnMap( ret, src, name, mappedName ) 8175 { 8176 if ( Array.isArray( name ) ) { 8177 $.each( name, function (i, val) { 8178 if ( Array.isArray( val ) ) { 8179 _fnMap( ret, src, val[0], val[1] ); 8180 } 8181 else { 8182 _fnMap( ret, src, val ); 8183 } 8184 } ); 8185 8186 return; 8187 } 8188 8189 if ( mappedName === undefined ) { 8190 mappedName = name; 8191 } 8192 8193 if ( src[name] !== undefined ) { 8194 ret[mappedName] = src[name]; 8195 } 8196 } 8197 8198 8199 /** 8200 * Extend objects - very similar to jQuery.extend, but deep copy objects, and 8201 * shallow copy arrays. The reason we need to do this, is that we don't want to 8202 * deep copy array init values (such as aaSorting) since the dev wouldn't be 8203 * able to override them, but we do want to deep copy arrays. 8204 * @param {object} out Object to extend 8205 * @param {object} extender Object from which the properties will be applied to 8206 * out 8207 * @param {boolean} breakRefs If true, then arrays will be sliced to take an 8208 * independent copy with the exception of the `data` or `aaData` parameters 8209 * if they are present. This is so you can pass in a collection to 8210 * DataTables and have that used as your data source without breaking the 8211 * references 8212 * @returns {object} out Reference, just for convenience - out === the return. 8213 * @memberof DataTable#oApi 8214 * @todo This doesn't take account of arrays inside the deep copied objects. 8215 */ 8216 function _fnExtend( out, extender, breakRefs ) 8217 { 8218 var val; 8219 8220 for ( var prop in extender ) { 8221 if ( extender.hasOwnProperty(prop) ) { 8222 val = extender[prop]; 8223 8224 if ( $.isPlainObject( val ) ) { 8225 if ( ! $.isPlainObject( out[prop] ) ) { 8226 out[prop] = {}; 8227 } 8228 $.extend( true, out[prop], val ); 8229 } 8230 else if ( breakRefs && prop !== 'data' && prop !== 'aaData' && Array.isArray(val) ) { 8231 out[prop] = val.slice(); 8232 } 8233 else { 8234 out[prop] = val; 8235 } 8236 } 8237 } 8238 8239 return out; 8240 } 8241 8242 8243 /** 8244 * Bind an event handers to allow a click or return key to activate the callback. 8245 * This is good for accessibility since a return on the keyboard will have the 8246 * same effect as a click, if the element has focus. 8247 * @param {element} n Element to bind the action to 8248 * @param {object} oData Data object to pass to the triggered function 8249 * @param {function} fn Callback function for when the event is triggered 8250 * @memberof DataTable#oApi 8251 */ 8252 function _fnBindAction( n, oData, fn ) 8253 { 8254 $(n) 8255 .on( 'click.DT', oData, function (e) { 8256 $(n).trigger('blur'); // Remove focus outline for mouse users 8257 fn(e); 8258 } ) 8259 .on( 'keypress.DT', oData, function (e){ 8260 if ( e.which === 13 ) { 8261 e.preventDefault(); 8262 fn(e); 8263 } 8264 } ) 8265 .on( 'selectstart.DT', function () { 8266 /* Take the brutal approach to cancelling text selection */ 8267 return false; 8268 } ); 8269 } 8270 8271 8272 /** 8273 * Register a callback function. Easily allows a callback function to be added to 8274 * an array store of callback functions that can then all be called together. 8275 * @param {object} oSettings dataTables settings object 8276 * @param {string} sStore Name of the array storage for the callbacks in oSettings 8277 * @param {function} fn Function to be called back 8278 * @param {string} sName Identifying name for the callback (i.e. a label) 8279 * @memberof DataTable#oApi 8280 */ 8281 function _fnCallbackReg( oSettings, sStore, fn, sName ) 8282 { 8283 if ( fn ) 8284 { 8285 oSettings[sStore].push( { 8286 "fn": fn, 8287 "sName": sName 8288 } ); 8289 } 8290 } 8291 8292 8293 /** 8294 * Fire callback functions and trigger events. Note that the loop over the 8295 * callback array store is done backwards! Further note that you do not want to 8296 * fire off triggers in time sensitive applications (for example cell creation) 8297 * as its slow. 8298 * @param {object} settings dataTables settings object 8299 * @param {string} callbackArr Name of the array storage for the callbacks in 8300 * oSettings 8301 * @param {string} eventName Name of the jQuery custom event to trigger. If 8302 * null no trigger is fired 8303 * @param {array} args Array of arguments to pass to the callback function / 8304 * trigger 8305 * @memberof DataTable#oApi 8306 */ 8307 function _fnCallbackFire( settings, callbackArr, eventName, args ) 8308 { 8309 var ret = []; 8310 8311 if ( callbackArr ) { 8312 ret = $.map( settings[callbackArr].slice().reverse(), function (val, i) { 8313 return val.fn.apply( settings.oInstance, args ); 8314 } ); 8315 } 8316 8317 if ( eventName !== null ) { 8318 var e = $.Event( eventName+'.dt' ); 8319 8320 $(settings.nTable).trigger( e, args ); 8321 8322 ret.push( e.result ); 8323 } 8324 8325 return ret; 8326 } 8327 8328 8329 function _fnLengthOverflow ( settings ) 8330 { 8331 var 8332 start = settings._iDisplayStart, 8333 end = settings.fnDisplayEnd(), 8334 len = settings._iDisplayLength; 8335 8336 /* If we have space to show extra rows (backing up from the end point - then do so */ 8337 if ( start >= end ) 8338 { 8339 start = end - len; 8340 } 8341 8342 // Keep the start record on the current page 8343 start -= (start % len); 8344 8345 if ( len === -1 || start < 0 ) 8346 { 8347 start = 0; 8348 } 8349 8350 settings._iDisplayStart = start; 8351 } 8352 8353 8354 function _fnRenderer( settings, type ) 8355 { 8356 var renderer = settings.renderer; 8357 var host = DataTable.ext.renderer[type]; 8358 8359 if ( $.isPlainObject( renderer ) && renderer[type] ) { 8360 // Specific renderer for this type. If available use it, otherwise use 8361 // the default. 8362 return host[renderer[type]] || host._; 8363 } 8364 else if ( typeof renderer === 'string' ) { 8365 // Common renderer - if there is one available for this type use it, 8366 // otherwise use the default 8367 return host[renderer] || host._; 8368 } 8369 8370 // Use the default 8371 return host._; 8372 } 8373 8374 8375 /** 8376 * Detect the data source being used for the table. Used to simplify the code 8377 * a little (ajax) and to make it compress a little smaller. 8378 * 8379 * @param {object} settings dataTables settings object 8380 * @returns {string} Data source 8381 * @memberof DataTable#oApi 8382 */ 8383 function _fnDataSource ( settings ) 8384 { 8385 if ( settings.oFeatures.bServerSide ) { 8386 return 'ssp'; 8387 } 8388 else if ( settings.ajax || settings.sAjaxSource ) { 8389 return 'ajax'; 8390 } 8391 return 'dom'; 8392 } 8393 8394 8395 8396 8397 /** 8398 * Computed structure of the DataTables API, defined by the options passed to 8399 * `DataTable.Api.register()` when building the API. 8400 * 8401 * The structure is built in order to speed creation and extension of the Api 8402 * objects since the extensions are effectively pre-parsed. 8403 * 8404 * The array is an array of objects with the following structure, where this 8405 * base array represents the Api prototype base: 8406 * 8407 * [ 8408 * { 8409 * name: 'data' -- string - Property name 8410 * val: function () {}, -- function - Api method (or undefined if just an object 8411 * methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result 8412 * propExt: [ ... ] -- array - Array of Api object definitions to extend the property 8413 * }, 8414 * { 8415 * name: 'row' 8416 * val: {}, 8417 * methodExt: [ ... ], 8418 * propExt: [ 8419 * { 8420 * name: 'data' 8421 * val: function () {}, 8422 * methodExt: [ ... ], 8423 * propExt: [ ... ] 8424 * }, 8425 * ... 8426 * ] 8427 * } 8428 * ] 8429 * 8430 * @type {Array} 8431 * @ignore 8432 */ 8433 var __apiStruct = []; 8434 8435 8436 /** 8437 * `Array.prototype` reference. 8438 * 8439 * @type object 8440 * @ignore 8441 */ 8442 var __arrayProto = Array.prototype; 8443 8444 8445 /** 8446 * Abstraction for `context` parameter of the `Api` constructor to allow it to 8447 * take several different forms for ease of use. 8448 * 8449 * Each of the input parameter types will be converted to a DataTables settings 8450 * object where possible. 8451 * 8452 * @param {string|node|jQuery|object} mixed DataTable identifier. Can be one 8453 * of: 8454 * 8455 * * `string` - jQuery selector. Any DataTables' matching the given selector 8456 * with be found and used. 8457 * * `node` - `TABLE` node which has already been formed into a DataTable. 8458 * * `jQuery` - A jQuery object of `TABLE` nodes. 8459 * * `object` - DataTables settings object 8460 * * `DataTables.Api` - API instance 8461 * @return {array|null} Matching DataTables settings objects. `null` or 8462 * `undefined` is returned if no matching DataTable is found. 8463 * @ignore 8464 */ 8465 var _toSettings = function ( mixed ) 8466 { 8467 var idx, jq; 8468 var settings = DataTable.settings; 8469 var tables = $.map( settings, function (el, i) { 8470 return el.nTable; 8471 } ); 8472 8473 if ( ! mixed ) { 8474 return []; 8475 } 8476 else if ( mixed.nTable && mixed.oApi ) { 8477 // DataTables settings object 8478 return [ mixed ]; 8479 } 8480 else if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) { 8481 // Table node 8482 idx = $.inArray( mixed, tables ); 8483 return idx !== -1 ? [ settings[idx] ] : null; 8484 } 8485 else if ( mixed && typeof mixed.settings === 'function' ) { 8486 return mixed.settings().toArray(); 8487 } 8488 else if ( typeof mixed === 'string' ) { 8489 // jQuery selector 8490 jq = $(mixed); 8491 } 8492 else if ( mixed instanceof $ ) { 8493 // jQuery object (also DataTables instance) 8494 jq = mixed; 8495 } 8496 8497 if ( jq ) { 8498 return jq.map( function(i) { 8499 idx = $.inArray( this, tables ); 8500 return idx !== -1 ? settings[idx] : null; 8501 } ).toArray(); 8502 } 8503 }; 8504 8505 8506 /** 8507 * DataTables API class - used to control and interface with one or more 8508 * DataTables enhanced tables. 8509 * 8510 * The API class is heavily based on jQuery, presenting a chainable interface 8511 * that you can use to interact with tables. Each instance of the API class has 8512 * a "context" - i.e. the tables that it will operate on. This could be a single 8513 * table, all tables on a page or a sub-set thereof. 8514 * 8515 * Additionally the API is designed to allow you to easily work with the data in 8516 * the tables, retrieving and manipulating it as required. This is done by 8517 * presenting the API class as an array like interface. The contents of the 8518 * array depend upon the actions requested by each method (for example 8519 * `rows().nodes()` will return an array of nodes, while `rows().data()` will 8520 * return an array of objects or arrays depending upon your table's 8521 * configuration). The API object has a number of array like methods (`push`, 8522 * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`, 8523 * `unique` etc) to assist your working with the data held in a table. 8524 * 8525 * Most methods (those which return an Api instance) are chainable, which means 8526 * the return from a method call also has all of the methods available that the 8527 * top level object had. For example, these two calls are equivalent: 8528 * 8529 * // Not chained 8530 * api.row.add( {...} ); 8531 * api.draw(); 8532 * 8533 * // Chained 8534 * api.row.add( {...} ).draw(); 8535 * 8536 * @class DataTable.Api 8537 * @param {array|object|string|jQuery} context DataTable identifier. This is 8538 * used to define which DataTables enhanced tables this API will operate on. 8539 * Can be one of: 8540 * 8541 * * `string` - jQuery selector. Any DataTables' matching the given selector 8542 * with be found and used. 8543 * * `node` - `TABLE` node which has already been formed into a DataTable. 8544 * * `jQuery` - A jQuery object of `TABLE` nodes. 8545 * * `object` - DataTables settings object 8546 * @param {array} [data] Data to initialise the Api instance with. 8547 * 8548 * @example 8549 * // Direct initialisation during DataTables construction 8550 * var api = $('#example').DataTable(); 8551 * 8552 * @example 8553 * // Initialisation using a DataTables jQuery object 8554 * var api = $('#example').dataTable().api(); 8555 * 8556 * @example 8557 * // Initialisation as a constructor 8558 * var api = new $.fn.DataTable.Api( 'table.dataTable' ); 8559 */ 8560 _Api = function ( context, data ) 8561 { 8562 if ( ! (this instanceof _Api) ) { 8563 return new _Api( context, data ); 8564 } 8565 8566 var settings = []; 8567 var ctxSettings = function ( o ) { 8568 var a = _toSettings( o ); 8569 if ( a ) { 8570 settings.push.apply( settings, a ); 8571 } 8572 }; 8573 8574 if ( Array.isArray( context ) ) { 8575 for ( var i=0, ien=context.length ; i<ien ; i++ ) { 8576 ctxSettings( context[i] ); 8577 } 8578 } 8579 else { 8580 ctxSettings( context ); 8581 } 8582 8583 // Remove duplicates 8584 this.context = _unique( settings ); 8585 8586 // Initial data 8587 if ( data ) { 8588 $.merge( this, data ); 8589 } 8590 8591 // selector 8592 this.selector = { 8593 rows: null, 8594 cols: null, 8595 opts: null 8596 }; 8597 8598 _Api.extend( this, this, __apiStruct ); 8599 }; 8600 8601 DataTable.Api = _Api; 8602 8603 // Don't destroy the existing prototype, just extend it. Required for jQuery 2's 8604 // isPlainObject. 8605 $.extend( _Api.prototype, { 8606 any: function () 8607 { 8608 return this.count() !== 0; 8609 }, 8610 8611 8612 concat: __arrayProto.concat, 8613 8614 8615 context: [], // array of table settings objects 8616 8617 8618 count: function () 8619 { 8620 return this.flatten().length; 8621 }, 8622 8623 8624 each: function ( fn ) 8625 { 8626 for ( var i=0, ien=this.length ; i<ien; i++ ) { 8627 fn.call( this, this[i], i, this ); 8628 } 8629 8630 return this; 8631 }, 8632 8633 8634 eq: function ( idx ) 8635 { 8636 var ctx = this.context; 8637 8638 return ctx.length > idx ? 8639 new _Api( ctx[idx], this[idx] ) : 8640 null; 8641 }, 8642 8643 8644 filter: function ( fn ) 8645 { 8646 var a = []; 8647 8648 if ( __arrayProto.filter ) { 8649 a = __arrayProto.filter.call( this, fn, this ); 8650 } 8651 else { 8652 // Compatibility for browsers without EMCA-252-5 (JS 1.6) 8653 for ( var i=0, ien=this.length ; i<ien ; i++ ) { 8654 if ( fn.call( this, this[i], i, this ) ) { 8655 a.push( this[i] ); 8656 } 8657 } 8658 } 8659 8660 return new _Api( this.context, a ); 8661 }, 8662 8663 8664 flatten: function () 8665 { 8666 var a = []; 8667 return new _Api( this.context, a.concat.apply( a, this.toArray() ) ); 8668 }, 8669 8670 8671 join: __arrayProto.join, 8672 8673 8674 indexOf: __arrayProto.indexOf || function (obj, start) 8675 { 8676 for ( var i=(start || 0), ien=this.length ; i<ien ; i++ ) { 8677 if ( this[i] === obj ) { 8678 return i; 8679 } 8680 } 8681 return -1; 8682 }, 8683 8684 iterator: function ( flatten, type, fn, alwaysNew ) { 8685 var 8686 a = [], ret, 8687 i, ien, j, jen, 8688 context = this.context, 8689 rows, items, item, 8690 selector = this.selector; 8691 8692 // Argument shifting 8693 if ( typeof flatten === 'string' ) { 8694 alwaysNew = fn; 8695 fn = type; 8696 type = flatten; 8697 flatten = false; 8698 } 8699 8700 for ( i=0, ien=context.length ; i<ien ; i++ ) { 8701 var apiInst = new _Api( context[i] ); 8702 8703 if ( type === 'table' ) { 8704 ret = fn.call( apiInst, context[i], i ); 8705 8706 if ( ret !== undefined ) { 8707 a.push( ret ); 8708 } 8709 } 8710 else if ( type === 'columns' || type === 'rows' ) { 8711 // this has same length as context - one entry for each table 8712 ret = fn.call( apiInst, context[i], this[i], i ); 8713 8714 if ( ret !== undefined ) { 8715 a.push( ret ); 8716 } 8717 } 8718 else if ( type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) { 8719 // columns and rows share the same structure. 8720 // 'this' is an array of column indexes for each context 8721 items = this[i]; 8722 8723 if ( type === 'column-rows' ) { 8724 rows = _selector_row_indexes( context[i], selector.opts ); 8725 } 8726 8727 for ( j=0, jen=items.length ; j<jen ; j++ ) { 8728 item = items[j]; 8729 8730 if ( type === 'cell' ) { 8731 ret = fn.call( apiInst, context[i], item.row, item.column, i, j ); 8732 } 8733 else { 8734 ret = fn.call( apiInst, context[i], item, i, j, rows ); 8735 } 8736 8737 if ( ret !== undefined ) { 8738 a.push( ret ); 8739 } 8740 } 8741 } 8742 } 8743 8744 if ( a.length || alwaysNew ) { 8745 var api = new _Api( context, flatten ? a.concat.apply( [], a ) : a ); 8746 var apiSelector = api.selector; 8747 apiSelector.rows = selector.rows; 8748 apiSelector.cols = selector.cols; 8749 apiSelector.opts = selector.opts; 8750 return api; 8751 } 8752 return this; 8753 }, 8754 8755 8756 lastIndexOf: __arrayProto.lastIndexOf || function (obj, start) 8757 { 8758 // Bit cheeky... 8759 return this.indexOf.apply( this.toArray.reverse(), arguments ); 8760 }, 8761 8762 8763 length: 0, 8764 8765 8766 map: function ( fn ) 8767 { 8768 var a = []; 8769 8770 if ( __arrayProto.map ) { 8771 a = __arrayProto.map.call( this, fn, this ); 8772 } 8773 else { 8774 // Compatibility for browsers without EMCA-252-5 (JS 1.6) 8775 for ( var i=0, ien=this.length ; i<ien ; i++ ) { 8776 a.push( fn.call( this, this[i], i ) ); 8777 } 8778 } 8779 8780 return new _Api( this.context, a ); 8781 }, 8782 8783 8784 pluck: function ( prop ) 8785 { 8786 return this.map( function ( el ) { 8787 return el[ prop ]; 8788 } ); 8789 }, 8790 8791 pop: __arrayProto.pop, 8792 8793 8794 push: __arrayProto.push, 8795 8796 8797 // Does not return an API instance 8798 reduce: __arrayProto.reduce || function ( fn, init ) 8799 { 8800 return _fnReduce( this, fn, init, 0, this.length, 1 ); 8801 }, 8802 8803 8804 reduceRight: __arrayProto.reduceRight || function ( fn, init ) 8805 { 8806 return _fnReduce( this, fn, init, this.length-1, -1, -1 ); 8807 }, 8808 8809 8810 reverse: __arrayProto.reverse, 8811 8812 8813 // Object with rows, columns and opts 8814 selector: null, 8815 8816 8817 shift: __arrayProto.shift, 8818 8819 8820 slice: function () { 8821 return new _Api( this.context, this ); 8822 }, 8823 8824 8825 sort: __arrayProto.sort, // ? name - order? 8826 8827 8828 splice: __arrayProto.splice, 8829 8830 8831 toArray: function () 8832 { 8833 return __arrayProto.slice.call( this ); 8834 }, 8835 8836 8837 to$: function () 8838 { 8839 return $( this ); 8840 }, 8841 8842 8843 toJQuery: function () 8844 { 8845 return $( this ); 8846 }, 8847 8848 8849 unique: function () 8850 { 8851 return new _Api( this.context, _unique(this) ); 8852 }, 8853 8854 8855 unshift: __arrayProto.unshift 8856 } ); 8857 8858 8859 _Api.extend = function ( scope, obj, ext ) 8860 { 8861 // Only extend API instances and static properties of the API 8862 if ( ! ext.length || ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) { 8863 return; 8864 } 8865 8866 var 8867 i, ien, 8868 struct, 8869 methodScoping = function ( scope, fn, struc ) { 8870 return function () { 8871 var ret = fn.apply( scope, arguments ); 8872 8873 // Method extension 8874 _Api.extend( ret, ret, struc.methodExt ); 8875 return ret; 8876 }; 8877 }; 8878 8879 for ( i=0, ien=ext.length ; i<ien ; i++ ) { 8880 struct = ext[i]; 8881 8882 // Value 8883 obj[ struct.name ] = struct.type === 'function' ? 8884 methodScoping( scope, struct.val, struct ) : 8885 struct.type === 'object' ? 8886 {} : 8887 struct.val; 8888 8889 obj[ struct.name ].__dt_wrapper = true; 8890 8891 // Property extension 8892 _Api.extend( scope, obj[ struct.name ], struct.propExt ); 8893 } 8894 }; 8895 8896 8897 // @todo - Is there need for an augment function? 8898 // _Api.augment = function ( inst, name ) 8899 // { 8900 // // Find src object in the structure from the name 8901 // var parts = name.split('.'); 8902 8903 // _Api.extend( inst, obj ); 8904 // }; 8905 8906 8907 // [ 8908 // { 8909 // name: 'data' -- string - Property name 8910 // val: function () {}, -- function - Api method (or undefined if just an object 8911 // methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result 8912 // propExt: [ ... ] -- array - Array of Api object definitions to extend the property 8913 // }, 8914 // { 8915 // name: 'row' 8916 // val: {}, 8917 // methodExt: [ ... ], 8918 // propExt: [ 8919 // { 8920 // name: 'data' 8921 // val: function () {}, 8922 // methodExt: [ ... ], 8923 // propExt: [ ... ] 8924 // }, 8925 // ... 8926 // ] 8927 // } 8928 // ] 8929 8930 _Api.register = _api_register = function ( name, val ) 8931 { 8932 if ( Array.isArray( name ) ) { 8933 for ( var j=0, jen=name.length ; j<jen ; j++ ) { 8934 _Api.register( name[j], val ); 8935 } 8936 return; 8937 } 8938 8939 var 8940 i, ien, 8941 heir = name.split('.'), 8942 struct = __apiStruct, 8943 key, method; 8944 8945 var find = function ( src, name ) { 8946 for ( var i=0, ien=src.length ; i<ien ; i++ ) { 8947 if ( src[i].name === name ) { 8948 return src[i]; 8949 } 8950 } 8951 return null; 8952 }; 8953 8954 for ( i=0, ien=heir.length ; i<ien ; i++ ) { 8955 method = heir[i].indexOf('()') !== -1; 8956 key = method ? 8957 heir[i].replace('()', '') : 8958 heir[i]; 8959 8960 var src = find( struct, key ); 8961 if ( ! src ) { 8962 src = { 8963 name: key, 8964 val: {}, 8965 methodExt: [], 8966 propExt: [], 8967 type: 'object' 8968 }; 8969 struct.push( src ); 8970 } 8971 8972 if ( i === ien-1 ) { 8973 src.val = val; 8974 src.type = typeof val === 'function' ? 8975 'function' : 8976 $.isPlainObject( val ) ? 8977 'object' : 8978 'other'; 8979 } 8980 else { 8981 struct = method ? 8982 src.methodExt : 8983 src.propExt; 8984 } 8985 } 8986 }; 8987 8988 _Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) { 8989 _Api.register( pluralName, val ); 8990 8991 _Api.register( singularName, function () { 8992 var ret = val.apply( this, arguments ); 8993 8994 if ( ret === this ) { 8995 // Returned item is the API instance that was passed in, return it 8996 return this; 8997 } 8998 else if ( ret instanceof _Api ) { 8999 // New API instance returned, want the value from the first item 9000 // in the returned array for the singular result. 9001 return ret.length ? 9002 Array.isArray( ret[0] ) ? 9003 new _Api( ret.context, ret[0] ) : // Array results are 'enhanced' 9004 ret[0] : 9005 undefined; 9006 } 9007 9008 // Non-API return - just fire it back 9009 return ret; 9010 } ); 9011 }; 9012 9013 9014 /** 9015 * Selector for HTML tables. Apply the given selector to the give array of 9016 * DataTables settings objects. 9017 * 9018 * @param {string|integer} [selector] jQuery selector string or integer 9019 * @param {array} Array of DataTables settings objects to be filtered 9020 * @return {array} 9021 * @ignore 9022 */ 9023 var __table_selector = function ( selector, a ) 9024 { 9025 if ( Array.isArray(selector) ) { 9026 return $.map( selector, function (item) { 9027 return __table_selector(item, a); 9028 } ); 9029 } 9030 9031 // Integer is used to pick out a table by index 9032 if ( typeof selector === 'number' ) { 9033 return [ a[ selector ] ]; 9034 } 9035 9036 // Perform a jQuery selector on the table nodes 9037 var nodes = $.map( a, function (el, i) { 9038 return el.nTable; 9039 } ); 9040 9041 return $(nodes) 9042 .filter( selector ) 9043 .map( function (i) { 9044 // Need to translate back from the table node to the settings 9045 var idx = $.inArray( this, nodes ); 9046 return a[ idx ]; 9047 } ) 9048 .toArray(); 9049 }; 9050 9051 9052 9053 /** 9054 * Context selector for the API's context (i.e. the tables the API instance 9055 * refers to. 9056 * 9057 * @name DataTable.Api#tables 9058 * @param {string|integer} [selector] Selector to pick which tables the iterator 9059 * should operate on. If not given, all tables in the current context are 9060 * used. This can be given as a jQuery selector (for example `':gt(0)'`) to 9061 * select multiple tables or as an integer to select a single table. 9062 * @returns {DataTable.Api} Returns a new API instance if a selector is given. 9063 */ 9064 _api_register( 'tables()', function ( selector ) { 9065 // A new instance is created if there was a selector specified 9066 return selector !== undefined && selector !== null ? 9067 new _Api( __table_selector( selector, this.context ) ) : 9068 this; 9069 } ); 9070 9071 9072 _api_register( 'table()', function ( selector ) { 9073 var tables = this.tables( selector ); 9074 var ctx = tables.context; 9075 9076 // Truncate to the first matched table 9077 return ctx.length ? 9078 new _Api( ctx[0] ) : 9079 tables; 9080 } ); 9081 9082 9083 _api_registerPlural( 'tables().nodes()', 'table().node()' , function () { 9084 return this.iterator( 'table', function ( ctx ) { 9085 return ctx.nTable; 9086 }, 1 ); 9087 } ); 9088 9089 9090 _api_registerPlural( 'tables().body()', 'table().body()' , function () { 9091 return this.iterator( 'table', function ( ctx ) { 9092 return ctx.nTBody; 9093 }, 1 ); 9094 } ); 9095 9096 9097 _api_registerPlural( 'tables().header()', 'table().header()' , function () { 9098 return this.iterator( 'table', function ( ctx ) { 9099 return ctx.nTHead; 9100 }, 1 ); 9101 } ); 9102 9103 9104 _api_registerPlural( 'tables().footer()', 'table().footer()' , function () { 9105 return this.iterator( 'table', function ( ctx ) { 9106 return ctx.nTFoot; 9107 }, 1 ); 9108 } ); 9109 9110 9111 _api_registerPlural( 'tables().containers()', 'table().container()' , function () { 9112 return this.iterator( 'table', function ( ctx ) { 9113 return ctx.nTableWrapper; 9114 }, 1 ); 9115 } ); 9116 9117 9118 9119 /** 9120 * Redraw the tables in the current context. 9121 */ 9122 _api_register( 'draw()', function ( paging ) { 9123 return this.iterator( 'table', function ( settings ) { 9124 if ( paging === 'page' ) { 9125 _fnDraw( settings ); 9126 } 9127 else { 9128 if ( typeof paging === 'string' ) { 9129 paging = paging === 'full-hold' ? 9130 false : 9131 true; 9132 } 9133 9134 _fnReDraw( settings, paging===false ); 9135 } 9136 } ); 9137 } ); 9138 9139 9140 9141 /** 9142 * Get the current page index. 9143 * 9144 * @return {integer} Current page index (zero based) 9145 *//** 9146 * Set the current page. 9147 * 9148 * Note that if you attempt to show a page which does not exist, DataTables will 9149 * not throw an error, but rather reset the paging. 9150 * 9151 * @param {integer|string} action The paging action to take. This can be one of: 9152 * * `integer` - The page index to jump to 9153 * * `string` - An action to take: 9154 * * `first` - Jump to first page. 9155 * * `next` - Jump to the next page 9156 * * `previous` - Jump to previous page 9157 * * `last` - Jump to the last page. 9158 * @returns {DataTables.Api} this 9159 */ 9160 _api_register( 'page()', function ( action ) { 9161 if ( action === undefined ) { 9162 return this.page.info().page; // not an expensive call 9163 } 9164 9165 // else, have an action to take on all tables 9166 return this.iterator( 'table', function ( settings ) { 9167 _fnPageChange( settings, action ); 9168 } ); 9169 } ); 9170 9171 9172 /** 9173 * Paging information for the first table in the current context. 9174 * 9175 * If you require paging information for another table, use the `table()` method 9176 * with a suitable selector. 9177 * 9178 * @return {object} Object with the following properties set: 9179 * * `page` - Current page index (zero based - i.e. the first page is `0`) 9180 * * `pages` - Total number of pages 9181 * * `start` - Display index for the first record shown on the current page 9182 * * `end` - Display index for the last record shown on the current page 9183 * * `length` - Display length (number of records). Note that generally `start 9184 * + length = end`, but this is not always true, for example if there are 9185 * only 2 records to show on the final page, with a length of 10. 9186 * * `recordsTotal` - Full data set length 9187 * * `recordsDisplay` - Data set length once the current filtering criterion 9188 * are applied. 9189 */ 9190 _api_register( 'page.info()', function ( action ) { 9191 if ( this.context.length === 0 ) { 9192 return undefined; 9193 } 9194 9195 var 9196 settings = this.context[0], 9197 start = settings._iDisplayStart, 9198 len = settings.oFeatures.bPaginate ? settings._iDisplayLength : -1, 9199 visRecords = settings.fnRecordsDisplay(), 9200 all = len === -1; 9201 9202 return { 9203 "page": all ? 0 : Math.floor( start / len ), 9204 "pages": all ? 1 : Math.ceil( visRecords / len ), 9205 "start": start, 9206 "end": settings.fnDisplayEnd(), 9207 "length": len, 9208 "recordsTotal": settings.fnRecordsTotal(), 9209 "recordsDisplay": visRecords, 9210 "serverSide": _fnDataSource( settings ) === 'ssp' 9211 }; 9212 } ); 9213 9214 9215 /** 9216 * Get the current page length. 9217 * 9218 * @return {integer} Current page length. Note `-1` indicates that all records 9219 * are to be shown. 9220 *//** 9221 * Set the current page length. 9222 * 9223 * @param {integer} Page length to set. Use `-1` to show all records. 9224 * @returns {DataTables.Api} this 9225 */ 9226 _api_register( 'page.len()', function ( len ) { 9227 // Note that we can't call this function 'length()' because `length` 9228 // is a Javascript property of functions which defines how many arguments 9229 // the function expects. 9230 if ( len === undefined ) { 9231 return this.context.length !== 0 ? 9232 this.context[0]._iDisplayLength : 9233 undefined; 9234 } 9235 9236 // else, set the page length 9237 return this.iterator( 'table', function ( settings ) { 9238 _fnLengthChange( settings, len ); 9239 } ); 9240 } ); 9241 9242 9243 9244 var __reload = function ( settings, holdPosition, callback ) { 9245 // Use the draw event to trigger a callback 9246 if ( callback ) { 9247 var api = new _Api( settings ); 9248 9249 api.one( 'draw', function () { 9250 callback( api.ajax.json() ); 9251 } ); 9252 } 9253 9254 if ( _fnDataSource( settings ) == 'ssp' ) { 9255 _fnReDraw( settings, holdPosition ); 9256 } 9257 else { 9258 _fnProcessingDisplay( settings, true ); 9259 9260 // Cancel an existing request 9261 var xhr = settings.jqXHR; 9262 if ( xhr && xhr.readyState !== 4 ) { 9263 xhr.abort(); 9264 } 9265 9266 // Trigger xhr 9267 _fnBuildAjax( settings, [], function( json ) { 9268 _fnClearTable( settings ); 9269 9270 var data = _fnAjaxDataSrc( settings, json ); 9271 for ( var i=0, ien=data.length ; i<ien ; i++ ) { 9272 _fnAddData( settings, data[i] ); 9273 } 9274 9275 _fnReDraw( settings, holdPosition ); 9276 _fnProcessingDisplay( settings, false ); 9277 } ); 9278 } 9279 }; 9280 9281 9282 /** 9283 * Get the JSON response from the last Ajax request that DataTables made to the 9284 * server. Note that this returns the JSON from the first table in the current 9285 * context. 9286 * 9287 * @return {object} JSON received from the server. 9288 */ 9289 _api_register( 'ajax.json()', function () { 9290 var ctx = this.context; 9291 9292 if ( ctx.length > 0 ) { 9293 return ctx[0].json; 9294 } 9295 9296 // else return undefined; 9297 } ); 9298 9299 9300 /** 9301 * Get the data submitted in the last Ajax request 9302 */ 9303 _api_register( 'ajax.params()', function () { 9304 var ctx = this.context; 9305 9306 if ( ctx.length > 0 ) { 9307 return ctx[0].oAjaxData; 9308 } 9309 9310 // else return undefined; 9311 } ); 9312 9313 9314 /** 9315 * Reload tables from the Ajax data source. Note that this function will 9316 * automatically re-draw the table when the remote data has been loaded. 9317 * 9318 * @param {boolean} [reset=true] Reset (default) or hold the current paging 9319 * position. A full re-sort and re-filter is performed when this method is 9320 * called, which is why the pagination reset is the default action. 9321 * @returns {DataTables.Api} this 9322 */ 9323 _api_register( 'ajax.reload()', function ( callback, resetPaging ) { 9324 return this.iterator( 'table', function (settings) { 9325 __reload( settings, resetPaging===false, callback ); 9326 } ); 9327 } ); 9328 9329 9330 /** 9331 * Get the current Ajax URL. Note that this returns the URL from the first 9332 * table in the current context. 9333 * 9334 * @return {string} Current Ajax source URL 9335 *//** 9336 * Set the Ajax URL. Note that this will set the URL for all tables in the 9337 * current context. 9338 * 9339 * @param {string} url URL to set. 9340 * @returns {DataTables.Api} this 9341 */ 9342 _api_register( 'ajax.url()', function ( url ) { 9343 var ctx = this.context; 9344 9345 if ( url === undefined ) { 9346 // get 9347 if ( ctx.length === 0 ) { 9348 return undefined; 9349 } 9350 ctx = ctx[0]; 9351 9352 return ctx.ajax ? 9353 $.isPlainObject( ctx.ajax ) ? 9354 ctx.ajax.url : 9355 ctx.ajax : 9356 ctx.sAjaxSource; 9357 } 9358 9359 // set 9360 return this.iterator( 'table', function ( settings ) { 9361 if ( $.isPlainObject( settings.ajax ) ) { 9362 settings.ajax.url = url; 9363 } 9364 else { 9365 settings.ajax = url; 9366 } 9367 // No need to consider sAjaxSource here since DataTables gives priority 9368 // to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any 9369 // value of `sAjaxSource` redundant. 9370 } ); 9371 } ); 9372 9373 9374 /** 9375 * Load data from the newly set Ajax URL. Note that this method is only 9376 * available when `ajax.url()` is used to set a URL. Additionally, this method 9377 * has the same effect as calling `ajax.reload()` but is provided for 9378 * convenience when setting a new URL. Like `ajax.reload()` it will 9379 * automatically redraw the table once the remote data has been loaded. 9380 * 9381 * @returns {DataTables.Api} this 9382 */ 9383 _api_register( 'ajax.url().load()', function ( callback, resetPaging ) { 9384 // Same as a reload, but makes sense to present it for easy access after a 9385 // url change 9386 return this.iterator( 'table', function ( ctx ) { 9387 __reload( ctx, resetPaging===false, callback ); 9388 } ); 9389 } ); 9390 9391 9392 9393 9394 var _selector_run = function ( type, selector, selectFn, settings, opts ) 9395 { 9396 var 9397 out = [], res, 9398 a, i, ien, j, jen, 9399 selectorType = typeof selector; 9400 9401 // Can't just check for isArray here, as an API or jQuery instance might be 9402 // given with their array like look 9403 if ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) { 9404 selector = [ selector ]; 9405 } 9406 9407 for ( i=0, ien=selector.length ; i<ien ; i++ ) { 9408 // Only split on simple strings - complex expressions will be jQuery selectors 9409 a = selector[i] && selector[i].split && ! selector[i].match(/[\[\(:]/) ? 9410 selector[i].split(',') : 9411 [ selector[i] ]; 9412 9413 for ( j=0, jen=a.length ; j<jen ; j++ ) { 9414 res = selectFn( typeof a[j] === 'string' ? (a[j]).trim() : a[j] ); 9415 9416 if ( res && res.length ) { 9417 out = out.concat( res ); 9418 } 9419 } 9420 } 9421 9422 // selector extensions 9423 var ext = _ext.selector[ type ]; 9424 if ( ext.length ) { 9425 for ( i=0, ien=ext.length ; i<ien ; i++ ) { 9426 out = ext[i]( settings, opts, out ); 9427 } 9428 } 9429 9430 return _unique( out ); 9431 }; 9432 9433 9434 var _selector_opts = function ( opts ) 9435 { 9436 if ( ! opts ) { 9437 opts = {}; 9438 } 9439 9440 // Backwards compatibility for 1.9- which used the terminology filter rather 9441 // than search 9442 if ( opts.filter && opts.search === undefined ) { 9443 opts.search = opts.filter; 9444 } 9445 9446 return $.extend( { 9447 search: 'none', 9448 order: 'current', 9449 page: 'all' 9450 }, opts ); 9451 }; 9452 9453 9454 var _selector_first = function ( inst ) 9455 { 9456 // Reduce the API instance to the first item found 9457 for ( var i=0, ien=inst.length ; i<ien ; i++ ) { 9458 if ( inst[i].length > 0 ) { 9459 // Assign the first element to the first item in the instance 9460 // and truncate the instance and context 9461 inst[0] = inst[i]; 9462 inst[0].length = 1; 9463 inst.length = 1; 9464 inst.context = [ inst.context[i] ]; 9465 9466 return inst; 9467 } 9468 } 9469 9470 // Not found - return an empty instance 9471 inst.length = 0; 9472 return inst; 9473 }; 9474 9475 9476 var _selector_row_indexes = function ( settings, opts ) 9477 { 9478 var 9479 i, ien, tmp, a=[], 9480 displayFiltered = settings.aiDisplay, 9481 displayMaster = settings.aiDisplayMaster; 9482 9483 var 9484 search = opts.search, // none, applied, removed 9485 order = opts.order, // applied, current, index (original - compatibility with 1.9) 9486 page = opts.page; // all, current 9487 9488 if ( _fnDataSource( settings ) == 'ssp' ) { 9489 // In server-side processing mode, most options are irrelevant since 9490 // rows not shown don't exist and the index order is the applied order 9491 // Removed is a special case - for consistency just return an empty 9492 // array 9493 return search === 'removed' ? 9494 [] : 9495 _range( 0, displayMaster.length ); 9496 } 9497 else if ( page == 'current' ) { 9498 // Current page implies that order=current and fitler=applied, since it is 9499 // fairly senseless otherwise, regardless of what order and search actually 9500 // are 9501 for ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) { 9502 a.push( displayFiltered[i] ); 9503 } 9504 } 9505 else if ( order == 'current' || order == 'applied' ) { 9506 if ( search == 'none') { 9507 a = displayMaster.slice(); 9508 } 9509 else if ( search == 'applied' ) { 9510 a = displayFiltered.slice(); 9511 } 9512 else if ( search == 'removed' ) { 9513 // O(n+m) solution by creating a hash map 9514 var displayFilteredMap = {}; 9515 9516 for ( var i=0, ien=displayFiltered.length ; i<ien ; i++ ) { 9517 displayFilteredMap[displayFiltered[i]] = null; 9518 } 9519 9520 a = $.map( displayMaster, function (el) { 9521 return ! displayFilteredMap.hasOwnProperty(el) ? 9522 el : 9523 null; 9524 } ); 9525 } 9526 } 9527 else if ( order == 'index' || order == 'original' ) { 9528 for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) { 9529 if ( search == 'none' ) { 9530 a.push( i ); 9531 } 9532 else { // applied | removed 9533 tmp = $.inArray( i, displayFiltered ); 9534 9535 if ((tmp === -1 && search == 'removed') || 9536 (tmp >= 0 && search == 'applied') ) 9537 { 9538 a.push( i ); 9539 } 9540 } 9541 } 9542 } 9543 9544 return a; 9545 }; 9546 9547 9548 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 9549 * Rows 9550 * 9551 * {} - no selector - use all available rows 9552 * {integer} - row aoData index 9553 * {node} - TR node 9554 * {string} - jQuery selector to apply to the TR elements 9555 * {array} - jQuery array of nodes, or simply an array of TR nodes 9556 * 9557 */ 9558 var __row_selector = function ( settings, selector, opts ) 9559 { 9560 var rows; 9561 var run = function ( sel ) { 9562 var selInt = _intVal( sel ); 9563 var i, ien; 9564 var aoData = settings.aoData; 9565 9566 // Short cut - selector is a number and no options provided (default is 9567 // all records, so no need to check if the index is in there, since it 9568 // must be - dev error if the index doesn't exist). 9569 if ( selInt !== null && ! opts ) { 9570 return [ selInt ]; 9571 } 9572 9573 if ( ! rows ) { 9574 rows = _selector_row_indexes( settings, opts ); 9575 } 9576 9577 if ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) { 9578 // Selector - integer 9579 return [ selInt ]; 9580 } 9581 else if ( sel === null || sel === undefined || sel === '' ) { 9582 // Selector - none 9583 return rows; 9584 } 9585 9586 // Selector - function 9587 if ( typeof sel === 'function' ) { 9588 return $.map( rows, function (idx) { 9589 var row = aoData[ idx ]; 9590 return sel( idx, row._aData, row.nTr ) ? idx : null; 9591 } ); 9592 } 9593 9594 // Selector - node 9595 if ( sel.nodeName ) { 9596 var rowIdx = sel._DT_RowIndex; // Property added by DT for fast lookup 9597 var cellIdx = sel._DT_CellIndex; 9598 9599 if ( rowIdx !== undefined ) { 9600 // Make sure that the row is actually still present in the table 9601 return aoData[ rowIdx ] && aoData[ rowIdx ].nTr === sel ? 9602 [ rowIdx ] : 9603 []; 9604 } 9605 else if ( cellIdx ) { 9606 return aoData[ cellIdx.row ] && aoData[ cellIdx.row ].nTr === sel.parentNode ? 9607 [ cellIdx.row ] : 9608 []; 9609 } 9610 else { 9611 var host = $(sel).closest('*[data-dt-row]'); 9612 return host.length ? 9613 [ host.data('dt-row') ] : 9614 []; 9615 } 9616 } 9617 9618 // ID selector. Want to always be able to select rows by id, regardless 9619 // of if the tr element has been created or not, so can't rely upon 9620 // jQuery here - hence a custom implementation. This does not match 9621 // Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything, 9622 // but to select it using a CSS selector engine (like Sizzle or 9623 // querySelect) it would need to need to be escaped for some characters. 9624 // DataTables simplifies this for row selectors since you can select 9625 // only a row. A # indicates an id any anything that follows is the id - 9626 // unescaped. 9627 if ( typeof sel === 'string' && sel.charAt(0) === '#' ) { 9628 // get row index from id 9629 var rowObj = settings.aIds[ sel.replace( /^#/, '' ) ]; 9630 if ( rowObj !== undefined ) { 9631 return [ rowObj.idx ]; 9632 } 9633 9634 // need to fall through to jQuery in case there is DOM id that 9635 // matches 9636 } 9637 9638 // Get nodes in the order from the `rows` array with null values removed 9639 var nodes = _removeEmpty( 9640 _pluck_order( settings.aoData, rows, 'nTr' ) 9641 ); 9642 9643 // Selector - jQuery selector string, array of nodes or jQuery object/ 9644 // As jQuery's .filter() allows jQuery objects to be passed in filter, 9645 // it also allows arrays, so this will cope with all three options 9646 return $(nodes) 9647 .filter( sel ) 9648 .map( function () { 9649 return this._DT_RowIndex; 9650 } ) 9651 .toArray(); 9652 }; 9653 9654 return _selector_run( 'row', selector, run, settings, opts ); 9655 }; 9656 9657 9658 _api_register( 'rows()', function ( selector, opts ) { 9659 // argument shifting 9660 if ( selector === undefined ) { 9661 selector = ''; 9662 } 9663 else if ( $.isPlainObject( selector ) ) { 9664 opts = selector; 9665 selector = ''; 9666 } 9667 9668 opts = _selector_opts( opts ); 9669 9670 var inst = this.iterator( 'table', function ( settings ) { 9671 return __row_selector( settings, selector, opts ); 9672 }, 1 ); 9673 9674 // Want argument shifting here and in __row_selector? 9675 inst.selector.rows = selector; 9676 inst.selector.opts = opts; 9677 9678 return inst; 9679 } ); 9680 9681 _api_register( 'rows().nodes()', function () { 9682 return this.iterator( 'row', function ( settings, row ) { 9683 return settings.aoData[ row ].nTr || undefined; 9684 }, 1 ); 9685 } ); 9686 9687 _api_register( 'rows().data()', function () { 9688 return this.iterator( true, 'rows', function ( settings, rows ) { 9689 return _pluck_order( settings.aoData, rows, '_aData' ); 9690 }, 1 ); 9691 } ); 9692 9693 _api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) { 9694 return this.iterator( 'row', function ( settings, row ) { 9695 var r = settings.aoData[ row ]; 9696 return type === 'search' ? r._aFilterData : r._aSortData; 9697 }, 1 ); 9698 } ); 9699 9700 _api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) { 9701 return this.iterator( 'row', function ( settings, row ) { 9702 _fnInvalidate( settings, row, src ); 9703 } ); 9704 } ); 9705 9706 _api_registerPlural( 'rows().indexes()', 'row().index()', function () { 9707 return this.iterator( 'row', function ( settings, row ) { 9708 return row; 9709 }, 1 ); 9710 } ); 9711 9712 _api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) { 9713 var a = []; 9714 var context = this.context; 9715 9716 // `iterator` will drop undefined values, but in this case we want them 9717 for ( var i=0, ien=context.length ; i<ien ; i++ ) { 9718 for ( var j=0, jen=this[i].length ; j<jen ; j++ ) { 9719 var id = context[i].rowIdFn( context[i].aoData[ this[i][j] ]._aData ); 9720 a.push( (hash === true ? '#' : '' )+ id ); 9721 } 9722 } 9723 9724 return new _Api( context, a ); 9725 } ); 9726 9727 _api_registerPlural( 'rows().remove()', 'row().remove()', function () { 9728 var that = this; 9729 9730 this.iterator( 'row', function ( settings, row, thatIdx ) { 9731 var data = settings.aoData; 9732 var rowData = data[ row ]; 9733 var i, ien, j, jen; 9734 var loopRow, loopCells; 9735 9736 data.splice( row, 1 ); 9737 9738 // Update the cached indexes 9739 for ( i=0, ien=data.length ; i<ien ; i++ ) { 9740 loopRow = data[i]; 9741 loopCells = loopRow.anCells; 9742 9743 // Rows 9744 if ( loopRow.nTr !== null ) { 9745 loopRow.nTr._DT_RowIndex = i; 9746 } 9747 9748 // Cells 9749 if ( loopCells !== null ) { 9750 for ( j=0, jen=loopCells.length ; j<jen ; j++ ) { 9751 loopCells[j]._DT_CellIndex.row = i; 9752 } 9753 } 9754 } 9755 9756 // Delete from the display arrays 9757 _fnDeleteIndex( settings.aiDisplayMaster, row ); 9758 _fnDeleteIndex( settings.aiDisplay, row ); 9759 _fnDeleteIndex( that[ thatIdx ], row, false ); // maintain local indexes 9760 9761 // For server-side processing tables - subtract the deleted row from the count 9762 if ( settings._iRecordsDisplay > 0 ) { 9763 settings._iRecordsDisplay--; 9764 } 9765 9766 // Check for an 'overflow' they case for displaying the table 9767 _fnLengthOverflow( settings ); 9768 9769 // Remove the row's ID reference if there is one 9770 var id = settings.rowIdFn( rowData._aData ); 9771 if ( id !== undefined ) { 9772 delete settings.aIds[ id ]; 9773 } 9774 } ); 9775 9776 this.iterator( 'table', function ( settings ) { 9777 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) { 9778 settings.aoData[i].idx = i; 9779 } 9780 } ); 9781 9782 return this; 9783 } ); 9784 9785 9786 _api_register( 'rows.add()', function ( rows ) { 9787 var newRows = this.iterator( 'table', function ( settings ) { 9788 var row, i, ien; 9789 var out = []; 9790 9791 for ( i=0, ien=rows.length ; i<ien ; i++ ) { 9792 row = rows[i]; 9793 9794 if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) { 9795 out.push( _fnAddTr( settings, row )[0] ); 9796 } 9797 else { 9798 out.push( _fnAddData( settings, row ) ); 9799 } 9800 } 9801 9802 return out; 9803 }, 1 ); 9804 9805 // Return an Api.rows() extended instance, so rows().nodes() etc can be used 9806 var modRows = this.rows( -1 ); 9807 modRows.pop(); 9808 $.merge( modRows, newRows ); 9809 9810 return modRows; 9811 } ); 9812 9813 9814 9815 9816 9817 /** 9818 * 9819 */ 9820 _api_register( 'row()', function ( selector, opts ) { 9821 return _selector_first( this.rows( selector, opts ) ); 9822 } ); 9823 9824 9825 _api_register( 'row().data()', function ( data ) { 9826 var ctx = this.context; 9827 9828 if ( data === undefined ) { 9829 // Get 9830 return ctx.length && this.length ? 9831 ctx[0].aoData[ this[0] ]._aData : 9832 undefined; 9833 } 9834 9835 // Set 9836 var row = ctx[0].aoData[ this[0] ]; 9837 row._aData = data; 9838 9839 // If the DOM has an id, and the data source is an array 9840 if ( Array.isArray( data ) && row.nTr && row.nTr.id ) { 9841 _fnSetObjectDataFn( ctx[0].rowId )( data, row.nTr.id ); 9842 } 9843 9844 // Automatically invalidate 9845 _fnInvalidate( ctx[0], this[0], 'data' ); 9846 9847 return this; 9848 } ); 9849 9850 9851 _api_register( 'row().node()', function () { 9852 var ctx = this.context; 9853 9854 return ctx.length && this.length ? 9855 ctx[0].aoData[ this[0] ].nTr || null : 9856 null; 9857 } ); 9858 9859 9860 _api_register( 'row.add()', function ( row ) { 9861 // Allow a jQuery object to be passed in - only a single row is added from 9862 // it though - the first element in the set 9863 if ( row instanceof $ && row.length ) { 9864 row = row[0]; 9865 } 9866 9867 var rows = this.iterator( 'table', function ( settings ) { 9868 if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) { 9869 return _fnAddTr( settings, row )[0]; 9870 } 9871 return _fnAddData( settings, row ); 9872 } ); 9873 9874 // Return an Api.rows() extended instance, with the newly added row selected 9875 return this.row( rows[0] ); 9876 } ); 9877 9878 9879 9880 var __details_add = function ( ctx, row, data, klass ) 9881 { 9882 // Convert to array of TR elements 9883 var rows = []; 9884 var addRow = function ( r, k ) { 9885 // Recursion to allow for arrays of jQuery objects 9886 if ( Array.isArray( r ) || r instanceof $ ) { 9887 for ( var i=0, ien=r.length ; i<ien ; i++ ) { 9888 addRow( r[i], k ); 9889 } 9890 return; 9891 } 9892 9893 // If we get a TR element, then just add it directly - up to the dev 9894 // to add the correct number of columns etc 9895 if ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) { 9896 rows.push( r ); 9897 } 9898 else { 9899 // Otherwise create a row with a wrapper 9900 var created = $('<tr><td></td></tr>').addClass( k ); 9901 $('td', created) 9902 .addClass( k ) 9903 .html( r ) 9904 [0].colSpan = _fnVisbleColumns( ctx ); 9905 9906 rows.push( created[0] ); 9907 } 9908 }; 9909 9910 addRow( data, klass ); 9911 9912 if ( row._details ) { 9913 row._details.detach(); 9914 } 9915 9916 row._details = $(rows); 9917 9918 // If the children were already shown, that state should be retained 9919 if ( row._detailsShow ) { 9920 row._details.insertAfter( row.nTr ); 9921 } 9922 }; 9923 9924 9925 var __details_remove = function ( api, idx ) 9926 { 9927 var ctx = api.context; 9928 9929 if ( ctx.length ) { 9930 var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ]; 9931 9932 if ( row && row._details ) { 9933 row._details.remove(); 9934 9935 row._detailsShow = undefined; 9936 row._details = undefined; 9937 } 9938 } 9939 }; 9940 9941 9942 var __details_display = function ( api, show ) { 9943 var ctx = api.context; 9944 9945 if ( ctx.length && api.length ) { 9946 var row = ctx[0].aoData[ api[0] ]; 9947 9948 if ( row._details ) { 9949 row._detailsShow = show; 9950 9951 if ( show ) { 9952 row._details.insertAfter( row.nTr ); 9953 } 9954 else { 9955 row._details.detach(); 9956 } 9957 9958 __details_events( ctx[0] ); 9959 } 9960 } 9961 }; 9962 9963 9964 var __details_events = function ( settings ) 9965 { 9966 var api = new _Api( settings ); 9967 var namespace = '.dt.DT_details'; 9968 var drawEvent = 'draw'+namespace; 9969 var colvisEvent = 'column-visibility'+namespace; 9970 var destroyEvent = 'destroy'+namespace; 9971 var data = settings.aoData; 9972 9973 api.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent ); 9974 9975 if ( _pluck( data, '_details' ).length > 0 ) { 9976 // On each draw, insert the required elements into the document 9977 api.on( drawEvent, function ( e, ctx ) { 9978 if ( settings !== ctx ) { 9979 return; 9980 } 9981 9982 api.rows( {page:'current'} ).eq(0).each( function (idx) { 9983 // Internal data grab 9984 var row = data[ idx ]; 9985 9986 if ( row._detailsShow ) { 9987 row._details.insertAfter( row.nTr ); 9988 } 9989 } ); 9990 } ); 9991 9992 // Column visibility change - update the colspan 9993 api.on( colvisEvent, function ( e, ctx, idx, vis ) { 9994 if ( settings !== ctx ) { 9995 return; 9996 } 9997 9998 // Update the colspan for the details rows (note, only if it already has 9999 // a colspan) 10000 var row, visible = _fnVisbleColumns( ctx ); 10001 10002 for ( var i=0, ien=data.length ; i<ien ; i++ ) { 10003 row = data[i]; 10004 10005 if ( row._details ) { 10006 row._details.children('td[colspan]').attr('colspan', visible ); 10007 } 10008 } 10009 } ); 10010 10011 // Table destroyed - nuke any child rows 10012 api.on( destroyEvent, function ( e, ctx ) { 10013 if ( settings !== ctx ) { 10014 return; 10015 } 10016 10017 for ( var i=0, ien=data.length ; i<ien ; i++ ) { 10018 if ( data[i]._details ) { 10019 __details_remove( api, i ); 10020 } 10021 } 10022 } ); 10023 } 10024 }; 10025 10026 // Strings for the method names to help minification 10027 var _emp = ''; 10028 var _child_obj = _emp+'row().child'; 10029 var _child_mth = _child_obj+'()'; 10030 10031 // data can be: 10032 // tr 10033 // string 10034 // jQuery or array of any of the above 10035 _api_register( _child_mth, function ( data, klass ) { 10036 var ctx = this.context; 10037 10038 if ( data === undefined ) { 10039 // get 10040 return ctx.length && this.length ? 10041 ctx[0].aoData[ this[0] ]._details : 10042 undefined; 10043 } 10044 else if ( data === true ) { 10045 // show 10046 this.child.show(); 10047 } 10048 else if ( data === false ) { 10049 // remove 10050 __details_remove( this ); 10051 } 10052 else if ( ctx.length && this.length ) { 10053 // set 10054 __details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass ); 10055 } 10056 10057 return this; 10058 } ); 10059 10060 10061 _api_register( [ 10062 _child_obj+'.show()', 10063 _child_mth+'.show()' // only when `child()` was called with parameters (without 10064 ], function ( show ) { // it returns an object and this method is not executed) 10065 __details_display( this, true ); 10066 return this; 10067 } ); 10068 10069 10070 _api_register( [ 10071 _child_obj+'.hide()', 10072 _child_mth+'.hide()' // only when `child()` was called with parameters (without 10073 ], function () { // it returns an object and this method is not executed) 10074 __details_display( this, false ); 10075 return this; 10076 } ); 10077 10078 10079 _api_register( [ 10080 _child_obj+'.remove()', 10081 _child_mth+'.remove()' // only when `child()` was called with parameters (without 10082 ], function () { // it returns an object and this method is not executed) 10083 __details_remove( this ); 10084 return this; 10085 } ); 10086 10087 10088 _api_register( _child_obj+'.isShown()', function () { 10089 var ctx = this.context; 10090 10091 if ( ctx.length && this.length ) { 10092 // _detailsShown as false or undefined will fall through to return false 10093 return ctx[0].aoData[ this[0] ]._detailsShow || false; 10094 } 10095 return false; 10096 } ); 10097 10098 10099 10100 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 10101 * Columns 10102 * 10103 * {integer} - column index (>=0 count from left, <0 count from right) 10104 * "{integer}:visIdx" - visible column index (i.e. translate to column index) (>=0 count from left, <0 count from right) 10105 * "{integer}:visible" - alias for {integer}:visIdx (>=0 count from left, <0 count from right) 10106 * "{string}:name" - column name 10107 * "{string}" - jQuery selector on column header nodes 10108 * 10109 */ 10110 10111 // can be an array of these items, comma separated list, or an array of comma 10112 // separated lists 10113 10114 var __re_column_selector = /^([^:]+):(name|visIdx|visible)$/; 10115 10116 10117 // r1 and r2 are redundant - but it means that the parameters match for the 10118 // iterator callback in columns().data() 10119 var __columnData = function ( settings, column, r1, r2, rows ) { 10120 var a = []; 10121 for ( var row=0, ien=rows.length ; row<ien ; row++ ) { 10122 a.push( _fnGetCellData( settings, rows[row], column ) ); 10123 } 10124 return a; 10125 }; 10126 10127 10128 var __column_selector = function ( settings, selector, opts ) 10129 { 10130 var 10131 columns = settings.aoColumns, 10132 names = _pluck( columns, 'sName' ), 10133 nodes = _pluck( columns, 'nTh' ); 10134 10135 var run = function ( s ) { 10136 var selInt = _intVal( s ); 10137 10138 // Selector - all 10139 if ( s === '' ) { 10140 return _range( columns.length ); 10141 } 10142 10143 // Selector - index 10144 if ( selInt !== null ) { 10145 return [ selInt >= 0 ? 10146 selInt : // Count from left 10147 columns.length + selInt // Count from right (+ because its a negative value) 10148 ]; 10149 } 10150 10151 // Selector = function 10152 if ( typeof s === 'function' ) { 10153 var rows = _selector_row_indexes( settings, opts ); 10154 10155 return $.map( columns, function (col, idx) { 10156 return s( 10157 idx, 10158 __columnData( settings, idx, 0, 0, rows ), 10159 nodes[ idx ] 10160 ) ? idx : null; 10161 } ); 10162 } 10163 10164 // jQuery or string selector 10165 var match = typeof s === 'string' ? 10166 s.match( __re_column_selector ) : 10167 ''; 10168 10169 if ( match ) { 10170 switch( match[2] ) { 10171 case 'visIdx': 10172 case 'visible': 10173 var idx = parseInt( match[1], 10 ); 10174 // Visible index given, convert to column index 10175 if ( idx < 0 ) { 10176 // Counting from the right 10177 var visColumns = $.map( columns, function (col,i) { 10178 return col.bVisible ? i : null; 10179 } ); 10180 return [ visColumns[ visColumns.length + idx ] ]; 10181 } 10182 // Counting from the left 10183 return [ _fnVisibleToColumnIndex( settings, idx ) ]; 10184 10185 case 'name': 10186 // match by name. `names` is column index complete and in order 10187 return $.map( names, function (name, i) { 10188 return name === match[1] ? i : null; 10189 } ); 10190 10191 default: 10192 return []; 10193 } 10194 } 10195 10196 // Cell in the table body 10197 if ( s.nodeName && s._DT_CellIndex ) { 10198 return [ s._DT_CellIndex.column ]; 10199 } 10200 10201 // jQuery selector on the TH elements for the columns 10202 var jqResult = $( nodes ) 10203 .filter( s ) 10204 .map( function () { 10205 return $.inArray( this, nodes ); // `nodes` is column index complete and in order 10206 } ) 10207 .toArray(); 10208 10209 if ( jqResult.length || ! s.nodeName ) { 10210 return jqResult; 10211 } 10212 10213 // Otherwise a node which might have a `dt-column` data attribute, or be 10214 // a child or such an element 10215 var host = $(s).closest('*[data-dt-column]'); 10216 return host.length ? 10217 [ host.data('dt-column') ] : 10218 []; 10219 }; 10220 10221 return _selector_run( 'column', selector, run, settings, opts ); 10222 }; 10223 10224 10225 var __setColumnVis = function ( settings, column, vis ) { 10226 var 10227 cols = settings.aoColumns, 10228 col = cols[ column ], 10229 data = settings.aoData, 10230 row, cells, i, ien, tr; 10231 10232 // Get 10233 if ( vis === undefined ) { 10234 return col.bVisible; 10235 } 10236 10237 // Set 10238 // No change 10239 if ( col.bVisible === vis ) { 10240 return; 10241 } 10242 10243 if ( vis ) { 10244 // Insert column 10245 // Need to decide if we should use appendChild or insertBefore 10246 var insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 ); 10247 10248 for ( i=0, ien=data.length ; i<ien ; i++ ) { 10249 tr = data[i].nTr; 10250 cells = data[i].anCells; 10251 10252 if ( tr ) { 10253 // insertBefore can act like appendChild if 2nd arg is null 10254 tr.insertBefore( cells[ column ], cells[ insertBefore ] || null ); 10255 } 10256 } 10257 } 10258 else { 10259 // Remove column 10260 $( _pluck( settings.aoData, 'anCells', column ) ).detach(); 10261 } 10262 10263 // Common actions 10264 col.bVisible = vis; 10265 }; 10266 10267 10268 _api_register( 'columns()', function ( selector, opts ) { 10269 // argument shifting 10270 if ( selector === undefined ) { 10271 selector = ''; 10272 } 10273 else if ( $.isPlainObject( selector ) ) { 10274 opts = selector; 10275 selector = ''; 10276 } 10277 10278 opts = _selector_opts( opts ); 10279 10280 var inst = this.iterator( 'table', function ( settings ) { 10281 return __column_selector( settings, selector, opts ); 10282 }, 1 ); 10283 10284 // Want argument shifting here and in _row_selector? 10285 inst.selector.cols = selector; 10286 inst.selector.opts = opts; 10287 10288 return inst; 10289 } ); 10290 10291 _api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) { 10292 return this.iterator( 'column', function ( settings, column ) { 10293 return settings.aoColumns[column].nTh; 10294 }, 1 ); 10295 } ); 10296 10297 _api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) { 10298 return this.iterator( 'column', function ( settings, column ) { 10299 return settings.aoColumns[column].nTf; 10300 }, 1 ); 10301 } ); 10302 10303 _api_registerPlural( 'columns().data()', 'column().data()', function () { 10304 return this.iterator( 'column-rows', __columnData, 1 ); 10305 } ); 10306 10307 _api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () { 10308 return this.iterator( 'column', function ( settings, column ) { 10309 return settings.aoColumns[column].mData; 10310 }, 1 ); 10311 } ); 10312 10313 _api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) { 10314 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) { 10315 return _pluck_order( settings.aoData, rows, 10316 type === 'search' ? '_aFilterData' : '_aSortData', column 10317 ); 10318 }, 1 ); 10319 } ); 10320 10321 _api_registerPlural( 'columns().nodes()', 'column().nodes()', function () { 10322 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) { 10323 return _pluck_order( settings.aoData, rows, 'anCells', column ) ; 10324 }, 1 ); 10325 } ); 10326 10327 _api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) { 10328 var that = this; 10329 var ret = this.iterator( 'column', function ( settings, column ) { 10330 if ( vis === undefined ) { 10331 return settings.aoColumns[ column ].bVisible; 10332 } // else 10333 __setColumnVis( settings, column, vis ); 10334 } ); 10335 10336 // Group the column visibility changes 10337 if ( vis !== undefined ) { 10338 this.iterator( 'table', function ( settings ) { 10339 // Redraw the header after changes 10340 _fnDrawHead( settings, settings.aoHeader ); 10341 _fnDrawHead( settings, settings.aoFooter ); 10342 10343 // Update colspan for no records display. Child rows and extensions will use their own 10344 // listeners to do this - only need to update the empty table item here 10345 if ( ! settings.aiDisplay.length ) { 10346 $(settings.nTBody).find('td[colspan]').attr('colspan', _fnVisbleColumns(settings)); 10347 } 10348 10349 _fnSaveState( settings ); 10350 10351 // Second loop once the first is done for events 10352 that.iterator( 'column', function ( settings, column ) { 10353 _fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis, calc] ); 10354 } ); 10355 10356 if ( calc === undefined || calc ) { 10357 that.columns.adjust(); 10358 } 10359 }); 10360 } 10361 10362 return ret; 10363 } ); 10364 10365 _api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) { 10366 return this.iterator( 'column', function ( settings, column ) { 10367 return type === 'visible' ? 10368 _fnColumnIndexToVisible( settings, column ) : 10369 column; 10370 }, 1 ); 10371 } ); 10372 10373 _api_register( 'columns.adjust()', function () { 10374 return this.iterator( 'table', function ( settings ) { 10375 _fnAdjustColumnSizing( settings ); 10376 }, 1 ); 10377 } ); 10378 10379 _api_register( 'column.index()', function ( type, idx ) { 10380 if ( this.context.length !== 0 ) { 10381 var ctx = this.context[0]; 10382 10383 if ( type === 'fromVisible' || type === 'toData' ) { 10384 return _fnVisibleToColumnIndex( ctx, idx ); 10385 } 10386 else if ( type === 'fromData' || type === 'toVisible' ) { 10387 return _fnColumnIndexToVisible( ctx, idx ); 10388 } 10389 } 10390 } ); 10391 10392 _api_register( 'column()', function ( selector, opts ) { 10393 return _selector_first( this.columns( selector, opts ) ); 10394 } ); 10395 10396 var __cell_selector = function ( settings, selector, opts ) 10397 { 10398 var data = settings.aoData; 10399 var rows = _selector_row_indexes( settings, opts ); 10400 var cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) ); 10401 var allCells = $(_flatten( [], cells )); 10402 var row; 10403 var columns = settings.aoColumns.length; 10404 var a, i, ien, j, o, host; 10405 10406 var run = function ( s ) { 10407 var fnSelector = typeof s === 'function'; 10408 10409 if ( s === null || s === undefined || fnSelector ) { 10410 // All cells and function selectors 10411 a = []; 10412 10413 for ( i=0, ien=rows.length ; i<ien ; i++ ) { 10414 row = rows[i]; 10415 10416 for ( j=0 ; j<columns ; j++ ) { 10417 o = { 10418 row: row, 10419 column: j 10420 }; 10421 10422 if ( fnSelector ) { 10423 // Selector - function 10424 host = data[ row ]; 10425 10426 if ( s( o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null ) ) { 10427 a.push( o ); 10428 } 10429 } 10430 else { 10431 // Selector - all 10432 a.push( o ); 10433 } 10434 } 10435 } 10436 10437 return a; 10438 } 10439 10440 // Selector - index 10441 if ( $.isPlainObject( s ) ) { 10442 // Valid cell index and its in the array of selectable rows 10443 return s.column !== undefined && s.row !== undefined && $.inArray( s.row, rows ) !== -1 ? 10444 [s] : 10445 []; 10446 } 10447 10448 // Selector - jQuery filtered cells 10449 var jqResult = allCells 10450 .filter( s ) 10451 .map( function (i, el) { 10452 return { // use a new object, in case someone changes the values 10453 row: el._DT_CellIndex.row, 10454 column: el._DT_CellIndex.column 10455 }; 10456 } ) 10457 .toArray(); 10458 10459 if ( jqResult.length || ! s.nodeName ) { 10460 return jqResult; 10461 } 10462 10463 // Otherwise the selector is a node, and there is one last option - the 10464 // element might be a child of an element which has dt-row and dt-column 10465 // data attributes 10466 host = $(s).closest('*[data-dt-row]'); 10467 return host.length ? 10468 [ { 10469 row: host.data('dt-row'), 10470 column: host.data('dt-column') 10471 } ] : 10472 []; 10473 }; 10474 10475 return _selector_run( 'cell', selector, run, settings, opts ); 10476 }; 10477 10478 10479 10480 10481 _api_register( 'cells()', function ( rowSelector, columnSelector, opts ) { 10482 // Argument shifting 10483 if ( $.isPlainObject( rowSelector ) ) { 10484 // Indexes 10485 if ( rowSelector.row === undefined ) { 10486 // Selector options in first parameter 10487 opts = rowSelector; 10488 rowSelector = null; 10489 } 10490 else { 10491 // Cell index objects in first parameter 10492 opts = columnSelector; 10493 columnSelector = null; 10494 } 10495 } 10496 if ( $.isPlainObject( columnSelector ) ) { 10497 opts = columnSelector; 10498 columnSelector = null; 10499 } 10500 10501 // Cell selector 10502 if ( columnSelector === null || columnSelector === undefined ) { 10503 return this.iterator( 'table', function ( settings ) { 10504 return __cell_selector( settings, rowSelector, _selector_opts( opts ) ); 10505 } ); 10506 } 10507 10508 // The default built in options need to apply to row and columns 10509 var internalOpts = opts ? { 10510 page: opts.page, 10511 order: opts.order, 10512 search: opts.search 10513 } : {}; 10514 10515 // Row + column selector 10516 var columns = this.columns( columnSelector, internalOpts ); 10517 var rows = this.rows( rowSelector, internalOpts ); 10518 var i, ien, j, jen; 10519 10520 var cellsNoOpts = this.iterator( 'table', function ( settings, idx ) { 10521 var a = []; 10522 10523 for ( i=0, ien=rows[idx].length ; i<ien ; i++ ) { 10524 for ( j=0, jen=columns[idx].length ; j<jen ; j++ ) { 10525 a.push( { 10526 row: rows[idx][i], 10527 column: columns[idx][j] 10528 } ); 10529 } 10530 } 10531 10532 return a; 10533 }, 1 ); 10534 10535 // There is currently only one extension which uses a cell selector extension 10536 // It is a _major_ performance drag to run this if it isn't needed, so this is 10537 // an extension specific check at the moment 10538 var cells = opts && opts.selected ? 10539 this.cells( cellsNoOpts, opts ) : 10540 cellsNoOpts; 10541 10542 $.extend( cells.selector, { 10543 cols: columnSelector, 10544 rows: rowSelector, 10545 opts: opts 10546 } ); 10547 10548 return cells; 10549 } ); 10550 10551 10552 _api_registerPlural( 'cells().nodes()', 'cell().node()', function () { 10553 return this.iterator( 'cell', function ( settings, row, column ) { 10554 var data = settings.aoData[ row ]; 10555 10556 return data && data.anCells ? 10557 data.anCells[ column ] : 10558 undefined; 10559 }, 1 ); 10560 } ); 10561 10562 10563 _api_register( 'cells().data()', function () { 10564 return this.iterator( 'cell', function ( settings, row, column ) { 10565 return _fnGetCellData( settings, row, column ); 10566 }, 1 ); 10567 } ); 10568 10569 10570 _api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) { 10571 type = type === 'search' ? '_aFilterData' : '_aSortData'; 10572 10573 return this.iterator( 'cell', function ( settings, row, column ) { 10574 return settings.aoData[ row ][ type ][ column ]; 10575 }, 1 ); 10576 } ); 10577 10578 10579 _api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) { 10580 return this.iterator( 'cell', function ( settings, row, column ) { 10581 return _fnGetCellData( settings, row, column, type ); 10582 }, 1 ); 10583 } ); 10584 10585 10586 _api_registerPlural( 'cells().indexes()', 'cell().index()', function () { 10587 return this.iterator( 'cell', function ( settings, row, column ) { 10588 return { 10589 row: row, 10590 column: column, 10591 columnVisible: _fnColumnIndexToVisible( settings, column ) 10592 }; 10593 }, 1 ); 10594 } ); 10595 10596 10597 _api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) { 10598 return this.iterator( 'cell', function ( settings, row, column ) { 10599 _fnInvalidate( settings, row, src, column ); 10600 } ); 10601 } ); 10602 10603 10604 10605 _api_register( 'cell()', function ( rowSelector, columnSelector, opts ) { 10606 return _selector_first( this.cells( rowSelector, columnSelector, opts ) ); 10607 } ); 10608 10609 10610 _api_register( 'cell().data()', function ( data ) { 10611 var ctx = this.context; 10612 var cell = this[0]; 10613 10614 if ( data === undefined ) { 10615 // Get 10616 return ctx.length && cell.length ? 10617 _fnGetCellData( ctx[0], cell[0].row, cell[0].column ) : 10618 undefined; 10619 } 10620 10621 // Set 10622 _fnSetCellData( ctx[0], cell[0].row, cell[0].column, data ); 10623 _fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column ); 10624 10625 return this; 10626 } ); 10627 10628 10629 10630 /** 10631 * Get current ordering (sorting) that has been applied to the table. 10632 * 10633 * @returns {array} 2D array containing the sorting information for the first 10634 * table in the current context. Each element in the parent array represents 10635 * a column being sorted upon (i.e. multi-sorting with two columns would have 10636 * 2 inner arrays). The inner arrays may have 2 or 3 elements. The first is 10637 * the column index that the sorting condition applies to, the second is the 10638 * direction of the sort (`desc` or `asc`) and, optionally, the third is the 10639 * index of the sorting order from the `column.sorting` initialisation array. 10640 *//** 10641 * Set the ordering for the table. 10642 * 10643 * @param {integer} order Column index to sort upon. 10644 * @param {string} direction Direction of the sort to be applied (`asc` or `desc`) 10645 * @returns {DataTables.Api} this 10646 *//** 10647 * Set the ordering for the table. 10648 * 10649 * @param {array} order 1D array of sorting information to be applied. 10650 * @param {array} [...] Optional additional sorting conditions 10651 * @returns {DataTables.Api} this 10652 *//** 10653 * Set the ordering for the table. 10654 * 10655 * @param {array} order 2D array of sorting information to be applied. 10656 * @returns {DataTables.Api} this 10657 */ 10658 _api_register( 'order()', function ( order, dir ) { 10659 var ctx = this.context; 10660 10661 if ( order === undefined ) { 10662 // get 10663 return ctx.length !== 0 ? 10664 ctx[0].aaSorting : 10665 undefined; 10666 } 10667 10668 // set 10669 if ( typeof order === 'number' ) { 10670 // Simple column / direction passed in 10671 order = [ [ order, dir ] ]; 10672 } 10673 else if ( order.length && ! Array.isArray( order[0] ) ) { 10674 // Arguments passed in (list of 1D arrays) 10675 order = Array.prototype.slice.call( arguments ); 10676 } 10677 // otherwise a 2D array was passed in 10678 10679 return this.iterator( 'table', function ( settings ) { 10680 settings.aaSorting = order.slice(); 10681 } ); 10682 } ); 10683 10684 10685 /** 10686 * Attach a sort listener to an element for a given column 10687 * 10688 * @param {node|jQuery|string} node Identifier for the element(s) to attach the 10689 * listener to. This can take the form of a single DOM node, a jQuery 10690 * collection of nodes or a jQuery selector which will identify the node(s). 10691 * @param {integer} column the column that a click on this node will sort on 10692 * @param {function} [callback] callback function when sort is run 10693 * @returns {DataTables.Api} this 10694 */ 10695 _api_register( 'order.listener()', function ( node, column, callback ) { 10696 return this.iterator( 'table', function ( settings ) { 10697 _fnSortAttachListener( settings, node, column, callback ); 10698 } ); 10699 } ); 10700 10701 10702 _api_register( 'order.fixed()', function ( set ) { 10703 if ( ! set ) { 10704 var ctx = this.context; 10705 var fixed = ctx.length ? 10706 ctx[0].aaSortingFixed : 10707 undefined; 10708 10709 return Array.isArray( fixed ) ? 10710 { pre: fixed } : 10711 fixed; 10712 } 10713 10714 return this.iterator( 'table', function ( settings ) { 10715 settings.aaSortingFixed = $.extend( true, {}, set ); 10716 } ); 10717 } ); 10718 10719 10720 // Order by the selected column(s) 10721 _api_register( [ 10722 'columns().order()', 10723 'column().order()' 10724 ], function ( dir ) { 10725 var that = this; 10726 10727 return this.iterator( 'table', function ( settings, i ) { 10728 var sort = []; 10729 10730 $.each( that[i], function (j, col) { 10731 sort.push( [ col, dir ] ); 10732 } ); 10733 10734 settings.aaSorting = sort; 10735 } ); 10736 } ); 10737 10738 10739 10740 _api_register( 'search()', function ( input, regex, smart, caseInsen ) { 10741 var ctx = this.context; 10742 10743 if ( input === undefined ) { 10744 // get 10745 return ctx.length !== 0 ? 10746 ctx[0].oPreviousSearch.sSearch : 10747 undefined; 10748 } 10749 10750 // set 10751 return this.iterator( 'table', function ( settings ) { 10752 if ( ! settings.oFeatures.bFilter ) { 10753 return; 10754 } 10755 10756 _fnFilterComplete( settings, $.extend( {}, settings.oPreviousSearch, { 10757 "sSearch": input+"", 10758 "bRegex": regex === null ? false : regex, 10759 "bSmart": smart === null ? true : smart, 10760 "bCaseInsensitive": caseInsen === null ? true : caseInsen 10761 } ), 1 ); 10762 } ); 10763 } ); 10764 10765 10766 _api_registerPlural( 10767 'columns().search()', 10768 'column().search()', 10769 function ( input, regex, smart, caseInsen ) { 10770 return this.iterator( 'column', function ( settings, column ) { 10771 var preSearch = settings.aoPreSearchCols; 10772 10773 if ( input === undefined ) { 10774 // get 10775 return preSearch[ column ].sSearch; 10776 } 10777 10778 // set 10779 if ( ! settings.oFeatures.bFilter ) { 10780 return; 10781 } 10782 10783 $.extend( preSearch[ column ], { 10784 "sSearch": input+"", 10785 "bRegex": regex === null ? false : regex, 10786 "bSmart": smart === null ? true : smart, 10787 "bCaseInsensitive": caseInsen === null ? true : caseInsen 10788 } ); 10789 10790 _fnFilterComplete( settings, settings.oPreviousSearch, 1 ); 10791 } ); 10792 } 10793 ); 10794 10795 /* 10796 * State API methods 10797 */ 10798 10799 _api_register( 'state()', function () { 10800 return this.context.length ? 10801 this.context[0].oSavedState : 10802 null; 10803 } ); 10804 10805 10806 _api_register( 'state.clear()', function () { 10807 return this.iterator( 'table', function ( settings ) { 10808 // Save an empty object 10809 settings.fnStateSaveCallback.call( settings.oInstance, settings, {} ); 10810 } ); 10811 } ); 10812 10813 10814 _api_register( 'state.loaded()', function () { 10815 return this.context.length ? 10816 this.context[0].oLoadedState : 10817 null; 10818 } ); 10819 10820 10821 _api_register( 'state.save()', function () { 10822 return this.iterator( 'table', function ( settings ) { 10823 _fnSaveState( settings ); 10824 } ); 10825 } ); 10826 10827 10828 10829 /** 10830 * Provide a common method for plug-ins to check the version of DataTables being 10831 * used, in order to ensure compatibility. 10832 * 10833 * @param {string} version Version string to check for, in the format "X.Y.Z". 10834 * Note that the formats "X" and "X.Y" are also acceptable. 10835 * @returns {boolean} true if this version of DataTables is greater or equal to 10836 * the required version, or false if this version of DataTales is not 10837 * suitable 10838 * @static 10839 * @dtopt API-Static 10840 * 10841 * @example 10842 * alert( $.fn.dataTable.versionCheck( '1.9.0' ) ); 10843 */ 10844 DataTable.versionCheck = DataTable.fnVersionCheck = function( version ) 10845 { 10846 var aThis = DataTable.version.split('.'); 10847 var aThat = version.split('.'); 10848 var iThis, iThat; 10849 10850 for ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) { 10851 iThis = parseInt( aThis[i], 10 ) || 0; 10852 iThat = parseInt( aThat[i], 10 ) || 0; 10853 10854 // Parts are the same, keep comparing 10855 if (iThis === iThat) { 10856 continue; 10857 } 10858 10859 // Parts are different, return immediately 10860 return iThis > iThat; 10861 } 10862 10863 return true; 10864 }; 10865 10866 10867 /** 10868 * Check if a `<table>` node is a DataTable table already or not. 10869 * 10870 * @param {node|jquery|string} table Table node, jQuery object or jQuery 10871 * selector for the table to test. Note that if more than more than one 10872 * table is passed on, only the first will be checked 10873 * @returns {boolean} true the table given is a DataTable, or false otherwise 10874 * @static 10875 * @dtopt API-Static 10876 * 10877 * @example 10878 * if ( ! $.fn.DataTable.isDataTable( '#example' ) ) { 10879 * $('#example').dataTable(); 10880 * } 10881 */ 10882 DataTable.isDataTable = DataTable.fnIsDataTable = function ( table ) 10883 { 10884 var t = $(table).get(0); 10885 var is = false; 10886 10887 if ( table instanceof DataTable.Api ) { 10888 return true; 10889 } 10890 10891 $.each( DataTable.settings, function (i, o) { 10892 var head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null; 10893 var foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null; 10894 10895 if ( o.nTable === t || head === t || foot === t ) { 10896 is = true; 10897 } 10898 } ); 10899 10900 return is; 10901 }; 10902 10903 10904 /** 10905 * Get all DataTable tables that have been initialised - optionally you can 10906 * select to get only currently visible tables. 10907 * 10908 * @param {boolean} [visible=false] Flag to indicate if you want all (default) 10909 * or visible tables only. 10910 * @returns {array} Array of `table` nodes (not DataTable instances) which are 10911 * DataTables 10912 * @static 10913 * @dtopt API-Static 10914 * 10915 * @example 10916 * $.each( $.fn.dataTable.tables(true), function () { 10917 * $(table).DataTable().columns.adjust(); 10918 * } ); 10919 */ 10920 DataTable.tables = DataTable.fnTables = function ( visible ) 10921 { 10922 var api = false; 10923 10924 if ( $.isPlainObject( visible ) ) { 10925 api = visible.api; 10926 visible = visible.visible; 10927 } 10928 10929 var a = $.map( DataTable.settings, function (o) { 10930 if ( !visible || (visible && $(o.nTable).is(':visible')) ) { 10931 return o.nTable; 10932 } 10933 } ); 10934 10935 return api ? 10936 new _Api( a ) : 10937 a; 10938 }; 10939 10940 10941 /** 10942 * Convert from camel case parameters to Hungarian notation. This is made public 10943 * for the extensions to provide the same ability as DataTables core to accept 10944 * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase 10945 * parameters. 10946 * 10947 * @param {object} src The model object which holds all parameters that can be 10948 * mapped. 10949 * @param {object} user The object to convert from camel case to Hungarian. 10950 * @param {boolean} force When set to `true`, properties which already have a 10951 * Hungarian value in the `user` object will be overwritten. Otherwise they 10952 * won't be. 10953 */ 10954 DataTable.camelToHungarian = _fnCamelToHungarian; 10955 10956 10957 10958 /** 10959 * 10960 */ 10961 _api_register( '$()', function ( selector, opts ) { 10962 var 10963 rows = this.rows( opts ).nodes(), // Get all rows 10964 jqRows = $(rows); 10965 10966 return $( [].concat( 10967 jqRows.filter( selector ).toArray(), 10968 jqRows.find( selector ).toArray() 10969 ) ); 10970 } ); 10971 10972 10973 // jQuery functions to operate on the tables 10974 $.each( [ 'on', 'one', 'off' ], function (i, key) { 10975 _api_register( key+'()', function ( /* event, handler */ ) { 10976 var args = Array.prototype.slice.call(arguments); 10977 10978 // Add the `dt` namespace automatically if it isn't already present 10979 args[0] = $.map( args[0].split( /\s/ ), function ( e ) { 10980 return ! e.match(/\.dt\b/) ? 10981 e+'.dt' : 10982 e; 10983 } ).join( ' ' ); 10984 10985 var inst = $( this.tables().nodes() ); 10986 inst[key].apply( inst, args ); 10987 return this; 10988 } ); 10989 } ); 10990 10991 10992 _api_register( 'clear()', function () { 10993 return this.iterator( 'table', function ( settings ) { 10994 _fnClearTable( settings ); 10995 } ); 10996 } ); 10997 10998 10999 _api_register( 'settings()', function () { 11000 return new _Api( this.context, this.context ); 11001 } ); 11002 11003 11004 _api_register( 'init()', function () { 11005 var ctx = this.context; 11006 return ctx.length ? ctx[0].oInit : null; 11007 } ); 11008 11009 11010 _api_register( 'data()', function () { 11011 return this.iterator( 'table', function ( settings ) { 11012 return _pluck( settings.aoData, '_aData' ); 11013 } ).flatten(); 11014 } ); 11015 11016 11017 _api_register( 'destroy()', function ( remove ) { 11018 remove = remove || false; 11019 11020 return this.iterator( 'table', function ( settings ) { 11021 var orig = settings.nTableWrapper.parentNode; 11022 var classes = settings.oClasses; 11023 var table = settings.nTable; 11024 var tbody = settings.nTBody; 11025 var thead = settings.nTHead; 11026 var tfoot = settings.nTFoot; 11027 var jqTable = $(table); 11028 var jqTbody = $(tbody); 11029 var jqWrapper = $(settings.nTableWrapper); 11030 var rows = $.map( settings.aoData, function (r) { return r.nTr; } ); 11031 var i, ien; 11032 11033 // Flag to note that the table is currently being destroyed - no action 11034 // should be taken 11035 settings.bDestroying = true; 11036 11037 // Fire off the destroy callbacks for plug-ins etc 11038 _fnCallbackFire( settings, "aoDestroyCallback", "destroy", [settings] ); 11039 11040 // If not being removed from the document, make all columns visible 11041 if ( ! remove ) { 11042 new _Api( settings ).columns().visible( true ); 11043 } 11044 11045 // Blitz all `DT` namespaced events (these are internal events, the 11046 // lowercase, `dt` events are user subscribed and they are responsible 11047 // for removing them 11048 jqWrapper.off('.DT').find(':not(tbody *)').off('.DT'); 11049 $(window).off('.DT-'+settings.sInstance); 11050 11051 // When scrolling we had to break the table up - restore it 11052 if ( table != thead.parentNode ) { 11053 jqTable.children('thead').detach(); 11054 jqTable.append( thead ); 11055 } 11056 11057 if ( tfoot && table != tfoot.parentNode ) { 11058 jqTable.children('tfoot').detach(); 11059 jqTable.append( tfoot ); 11060 } 11061 11062 settings.aaSorting = []; 11063 settings.aaSortingFixed = []; 11064 _fnSortingClasses( settings ); 11065 11066 $( rows ).removeClass( settings.asStripeClasses.join(' ') ); 11067 11068 $('th, td', thead).removeClass( classes.sSortable+' '+ 11069 classes.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone 11070 ); 11071 11072 // Add the TR elements back into the table in their original order 11073 jqTbody.children().detach(); 11074 jqTbody.append( rows ); 11075 11076 // Remove the DataTables generated nodes, events and classes 11077 var removedMethod = remove ? 'remove' : 'detach'; 11078 jqTable[ removedMethod ](); 11079 jqWrapper[ removedMethod ](); 11080 11081 // If we need to reattach the table to the document 11082 if ( ! remove && orig ) { 11083 // insertBefore acts like appendChild if !arg[1] 11084 orig.insertBefore( table, settings.nTableReinsertBefore ); 11085 11086 // Restore the width of the original table - was read from the style property, 11087 // so we can restore directly to that 11088 jqTable 11089 .css( 'width', settings.sDestroyWidth ) 11090 .removeClass( classes.sTable ); 11091 11092 // If the were originally stripe classes - then we add them back here. 11093 // Note this is not fool proof (for example if not all rows had stripe 11094 // classes - but it's a good effort without getting carried away 11095 ien = settings.asDestroyStripes.length; 11096 11097 if ( ien ) { 11098 jqTbody.children().each( function (i) { 11099 $(this).addClass( settings.asDestroyStripes[i % ien] ); 11100 } ); 11101 } 11102 } 11103 11104 /* Remove the settings object from the settings array */ 11105 var idx = $.inArray( settings, DataTable.settings ); 11106 if ( idx !== -1 ) { 11107 DataTable.settings.splice( idx, 1 ); 11108 } 11109 } ); 11110 } ); 11111 11112 11113 // Add the `every()` method for rows, columns and cells in a compact form 11114 $.each( [ 'column', 'row', 'cell' ], function ( i, type ) { 11115 _api_register( type+'s().every()', function ( fn ) { 11116 var opts = this.selector.opts; 11117 var api = this; 11118 11119 return this.iterator( type, function ( settings, arg1, arg2, arg3, arg4 ) { 11120 // Rows and columns: 11121 // arg1 - index 11122 // arg2 - table counter 11123 // arg3 - loop counter 11124 // arg4 - undefined 11125 // Cells: 11126 // arg1 - row index 11127 // arg2 - column index 11128 // arg3 - table counter 11129 // arg4 - loop counter 11130 fn.call( 11131 api[ type ]( 11132 arg1, 11133 type==='cell' ? arg2 : opts, 11134 type==='cell' ? opts : undefined 11135 ), 11136 arg1, arg2, arg3, arg4 11137 ); 11138 } ); 11139 } ); 11140 } ); 11141 11142 11143 // i18n method for extensions to be able to use the language object from the 11144 // DataTable 11145 _api_register( 'i18n()', function ( token, def, plural ) { 11146 var ctx = this.context[0]; 11147 var resolved = _fnGetObjectDataFn( token )( ctx.oLanguage ); 11148 11149 if ( resolved === undefined ) { 11150 resolved = def; 11151 } 11152 11153 if ( plural !== undefined && $.isPlainObject( resolved ) ) { 11154 resolved = resolved[ plural ] !== undefined ? 11155 resolved[ plural ] : 11156 resolved._; 11157 } 11158 11159 return resolved.replace( '%d', plural ); // nb: plural might be undefined, 11160 } ); 11161 /** 11162 * Version string for plug-ins to check compatibility. Allowed format is 11163 * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used 11164 * only for non-release builds. See http://semver.org/ for more information. 11165 * @member 11166 * @type string 11167 * @default Version number 11168 */ 11169 DataTable.version = "1.10.24"; 11170 11171 /** 11172 * Private data store, containing all of the settings objects that are 11173 * created for the tables on a given page. 11174 * 11175 * Note that the `DataTable.settings` object is aliased to 11176 * `jQuery.fn.dataTableExt` through which it may be accessed and 11177 * manipulated, or `jQuery.fn.dataTable.settings`. 11178 * @member 11179 * @type array 11180 * @default [] 11181 * @private 11182 */ 11183 DataTable.settings = []; 11184 11185 /** 11186 * Object models container, for the various models that DataTables has 11187 * available to it. These models define the objects that are used to hold 11188 * the active state and configuration of the table. 11189 * @namespace 11190 */ 11191 DataTable.models = {}; 11192 11193 11194 11195 /** 11196 * Template object for the way in which DataTables holds information about 11197 * search information for the global filter and individual column filters. 11198 * @namespace 11199 */ 11200 DataTable.models.oSearch = { 11201 /** 11202 * Flag to indicate if the filtering should be case insensitive or not 11203 * @type boolean 11204 * @default true 11205 */ 11206 "bCaseInsensitive": true, 11207 11208 /** 11209 * Applied search term 11210 * @type string 11211 * @default <i>Empty string</i> 11212 */ 11213 "sSearch": "", 11214 11215 /** 11216 * Flag to indicate if the search term should be interpreted as a 11217 * regular expression (true) or not (false) and therefore and special 11218 * regex characters escaped. 11219 * @type boolean 11220 * @default false 11221 */ 11222 "bRegex": false, 11223 11224 /** 11225 * Flag to indicate if DataTables is to use its smart filtering or not. 11226 * @type boolean 11227 * @default true 11228 */ 11229 "bSmart": true 11230 }; 11231 11232 11233 11234 11235 /** 11236 * Template object for the way in which DataTables holds information about 11237 * each individual row. This is the object format used for the settings 11238 * aoData array. 11239 * @namespace 11240 */ 11241 DataTable.models.oRow = { 11242 /** 11243 * TR element for the row 11244 * @type node 11245 * @default null 11246 */ 11247 "nTr": null, 11248 11249 /** 11250 * Array of TD elements for each row. This is null until the row has been 11251 * created. 11252 * @type array nodes 11253 * @default [] 11254 */ 11255 "anCells": null, 11256 11257 /** 11258 * Data object from the original data source for the row. This is either 11259 * an array if using the traditional form of DataTables, or an object if 11260 * using mData options. The exact type will depend on the passed in 11261 * data from the data source, or will be an array if using DOM a data 11262 * source. 11263 * @type array|object 11264 * @default [] 11265 */ 11266 "_aData": [], 11267 11268 /** 11269 * Sorting data cache - this array is ostensibly the same length as the 11270 * number of columns (although each index is generated only as it is 11271 * needed), and holds the data that is used for sorting each column in the 11272 * row. We do this cache generation at the start of the sort in order that 11273 * the formatting of the sort data need be done only once for each cell 11274 * per sort. This array should not be read from or written to by anything 11275 * other than the master sorting methods. 11276 * @type array 11277 * @default null 11278 * @private 11279 */ 11280 "_aSortData": null, 11281 11282 /** 11283 * Per cell filtering data cache. As per the sort data cache, used to 11284 * increase the performance of the filtering in DataTables 11285 * @type array 11286 * @default null 11287 * @private 11288 */ 11289 "_aFilterData": null, 11290 11291 /** 11292 * Filtering data cache. This is the same as the cell filtering cache, but 11293 * in this case a string rather than an array. This is easily computed with 11294 * a join on `_aFilterData`, but is provided as a cache so the join isn't 11295 * needed on every search (memory traded for performance) 11296 * @type array 11297 * @default null 11298 * @private 11299 */ 11300 "_sFilterRow": null, 11301 11302 /** 11303 * Cache of the class name that DataTables has applied to the row, so we 11304 * can quickly look at this variable rather than needing to do a DOM check 11305 * on className for the nTr property. 11306 * @type string 11307 * @default <i>Empty string</i> 11308 * @private 11309 */ 11310 "_sRowStripe": "", 11311 11312 /** 11313 * Denote if the original data source was from the DOM, or the data source 11314 * object. This is used for invalidating data, so DataTables can 11315 * automatically read data from the original source, unless uninstructed 11316 * otherwise. 11317 * @type string 11318 * @default null 11319 * @private 11320 */ 11321 "src": null, 11322 11323 /** 11324 * Index in the aoData array. This saves an indexOf lookup when we have the 11325 * object, but want to know the index 11326 * @type integer 11327 * @default -1 11328 * @private 11329 */ 11330 "idx": -1 11331 }; 11332 11333 11334 /** 11335 * Template object for the column information object in DataTables. This object 11336 * is held in the settings aoColumns array and contains all the information that 11337 * DataTables needs about each individual column. 11338 * 11339 * Note that this object is related to {@link DataTable.defaults.column} 11340 * but this one is the internal data store for DataTables's cache of columns. 11341 * It should NOT be manipulated outside of DataTables. Any configuration should 11342 * be done through the initialisation options. 11343 * @namespace 11344 */ 11345 DataTable.models.oColumn = { 11346 /** 11347 * Column index. This could be worked out on-the-fly with $.inArray, but it 11348 * is faster to just hold it as a variable 11349 * @type integer 11350 * @default null 11351 */ 11352 "idx": null, 11353 11354 /** 11355 * A list of the columns that sorting should occur on when this column 11356 * is sorted. That this property is an array allows multi-column sorting 11357 * to be defined for a column (for example first name / last name columns 11358 * would benefit from this). The values are integers pointing to the 11359 * columns to be sorted on (typically it will be a single integer pointing 11360 * at itself, but that doesn't need to be the case). 11361 * @type array 11362 */ 11363 "aDataSort": null, 11364 11365 /** 11366 * Define the sorting directions that are applied to the column, in sequence 11367 * as the column is repeatedly sorted upon - i.e. the first value is used 11368 * as the sorting direction when the column if first sorted (clicked on). 11369 * Sort it again (click again) and it will move on to the next index. 11370 * Repeat until loop. 11371 * @type array 11372 */ 11373 "asSorting": null, 11374 11375 /** 11376 * Flag to indicate if the column is searchable, and thus should be included 11377 * in the filtering or not. 11378 * @type boolean 11379 */ 11380 "bSearchable": null, 11381 11382 /** 11383 * Flag to indicate if the column is sortable or not. 11384 * @type boolean 11385 */ 11386 "bSortable": null, 11387 11388 /** 11389 * Flag to indicate if the column is currently visible in the table or not 11390 * @type boolean 11391 */ 11392 "bVisible": null, 11393 11394 /** 11395 * Store for manual type assignment using the `column.type` option. This 11396 * is held in store so we can manipulate the column's `sType` property. 11397 * @type string 11398 * @default null 11399 * @private 11400 */ 11401 "_sManualType": null, 11402 11403 /** 11404 * Flag to indicate if HTML5 data attributes should be used as the data 11405 * source for filtering or sorting. True is either are. 11406 * @type boolean 11407 * @default false 11408 * @private 11409 */ 11410 "_bAttrSrc": false, 11411 11412 /** 11413 * Developer definable function that is called whenever a cell is created (Ajax source, 11414 * etc) or processed for input (DOM source). This can be used as a compliment to mRender 11415 * allowing you to modify the DOM element (add background colour for example) when the 11416 * element is available. 11417 * @type function 11418 * @param {element} nTd The TD node that has been created 11419 * @param {*} sData The Data for the cell 11420 * @param {array|object} oData The data for the whole row 11421 * @param {int} iRow The row index for the aoData data store 11422 * @default null 11423 */ 11424 "fnCreatedCell": null, 11425 11426 /** 11427 * Function to get data from a cell in a column. You should <b>never</b> 11428 * access data directly through _aData internally in DataTables - always use 11429 * the method attached to this property. It allows mData to function as 11430 * required. This function is automatically assigned by the column 11431 * initialisation method 11432 * @type function 11433 * @param {array|object} oData The data array/object for the array 11434 * (i.e. aoData[]._aData) 11435 * @param {string} sSpecific The specific data type you want to get - 11436 * 'display', 'type' 'filter' 'sort' 11437 * @returns {*} The data for the cell from the given row's data 11438 * @default null 11439 */ 11440 "fnGetData": null, 11441 11442 /** 11443 * Function to set data for a cell in the column. You should <b>never</b> 11444 * set the data directly to _aData internally in DataTables - always use 11445 * this method. It allows mData to function as required. This function 11446 * is automatically assigned by the column initialisation method 11447 * @type function 11448 * @param {array|object} oData The data array/object for the array 11449 * (i.e. aoData[]._aData) 11450 * @param {*} sValue Value to set 11451 * @default null 11452 */ 11453 "fnSetData": null, 11454 11455 /** 11456 * Property to read the value for the cells in the column from the data 11457 * source array / object. If null, then the default content is used, if a 11458 * function is given then the return from the function is used. 11459 * @type function|int|string|null 11460 * @default null 11461 */ 11462 "mData": null, 11463 11464 /** 11465 * Partner property to mData which is used (only when defined) to get 11466 * the data - i.e. it is basically the same as mData, but without the 11467 * 'set' option, and also the data fed to it is the result from mData. 11468 * This is the rendering method to match the data method of mData. 11469 * @type function|int|string|null 11470 * @default null 11471 */ 11472 "mRender": null, 11473 11474 /** 11475 * Unique header TH/TD element for this column - this is what the sorting 11476 * listener is attached to (if sorting is enabled.) 11477 * @type node 11478 * @default null 11479 */ 11480 "nTh": null, 11481 11482 /** 11483 * Unique footer TH/TD element for this column (if there is one). Not used 11484 * in DataTables as such, but can be used for plug-ins to reference the 11485 * footer for each column. 11486 * @type node 11487 * @default null 11488 */ 11489 "nTf": null, 11490 11491 /** 11492 * The class to apply to all TD elements in the table's TBODY for the column 11493 * @type string 11494 * @default null 11495 */ 11496 "sClass": null, 11497 11498 /** 11499 * When DataTables calculates the column widths to assign to each column, 11500 * it finds the longest string in each column and then constructs a 11501 * temporary table and reads the widths from that. The problem with this 11502 * is that "mmm" is much wider then "iiii", but the latter is a longer 11503 * string - thus the calculation can go wrong (doing it properly and putting 11504 * it into an DOM object and measuring that is horribly(!) slow). Thus as 11505 * a "work around" we provide this option. It will append its value to the 11506 * text that is found to be the longest string for the column - i.e. padding. 11507 * @type string 11508 */ 11509 "sContentPadding": null, 11510 11511 /** 11512 * Allows a default value to be given for a column's data, and will be used 11513 * whenever a null data source is encountered (this can be because mData 11514 * is set to null, or because the data source itself is null). 11515 * @type string 11516 * @default null 11517 */ 11518 "sDefaultContent": null, 11519 11520 /** 11521 * Name for the column, allowing reference to the column by name as well as 11522 * by index (needs a lookup to work by name). 11523 * @type string 11524 */ 11525 "sName": null, 11526 11527 /** 11528 * Custom sorting data type - defines which of the available plug-ins in 11529 * afnSortData the custom sorting will use - if any is defined. 11530 * @type string 11531 * @default std 11532 */ 11533 "sSortDataType": 'std', 11534 11535 /** 11536 * Class to be applied to the header element when sorting on this column 11537 * @type string 11538 * @default null 11539 */ 11540 "sSortingClass": null, 11541 11542 /** 11543 * Class to be applied to the header element when sorting on this column - 11544 * when jQuery UI theming is used. 11545 * @type string 11546 * @default null 11547 */ 11548 "sSortingClassJUI": null, 11549 11550 /** 11551 * Title of the column - what is seen in the TH element (nTh). 11552 * @type string 11553 */ 11554 "sTitle": null, 11555 11556 /** 11557 * Column sorting and filtering type 11558 * @type string 11559 * @default null 11560 */ 11561 "sType": null, 11562 11563 /** 11564 * Width of the column 11565 * @type string 11566 * @default null 11567 */ 11568 "sWidth": null, 11569 11570 /** 11571 * Width of the column when it was first "encountered" 11572 * @type string 11573 * @default null 11574 */ 11575 "sWidthOrig": null 11576 }; 11577 11578 11579 /* 11580 * Developer note: The properties of the object below are given in Hungarian 11581 * notation, that was used as the interface for DataTables prior to v1.10, however 11582 * from v1.10 onwards the primary interface is camel case. In order to avoid 11583 * breaking backwards compatibility utterly with this change, the Hungarian 11584 * version is still, internally the primary interface, but is is not documented 11585 * - hence the @name tags in each doc comment. This allows a Javascript function 11586 * to create a map from Hungarian notation to camel case (going the other direction 11587 * would require each property to be listed, which would add around 3K to the size 11588 * of DataTables, while this method is about a 0.5K hit). 11589 * 11590 * Ultimately this does pave the way for Hungarian notation to be dropped 11591 * completely, but that is a massive amount of work and will break current 11592 * installs (therefore is on-hold until v2). 11593 */ 11594 11595 /** 11596 * Initialisation options that can be given to DataTables at initialisation 11597 * time. 11598 * @namespace 11599 */ 11600 DataTable.defaults = { 11601 /** 11602 * An array of data to use for the table, passed in at initialisation which 11603 * will be used in preference to any data which is already in the DOM. This is 11604 * particularly useful for constructing tables purely in Javascript, for 11605 * example with a custom Ajax call. 11606 * @type array 11607 * @default null 11608 * 11609 * @dtopt Option 11610 * @name DataTable.defaults.data 11611 * 11612 * @example 11613 * // Using a 2D array data source 11614 * $(document).ready( function () { 11615 * $('#example').dataTable( { 11616 * "data": [ 11617 * ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'], 11618 * ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'], 11619 * ], 11620 * "columns": [ 11621 * { "title": "Engine" }, 11622 * { "title": "Browser" }, 11623 * { "title": "Platform" }, 11624 * { "title": "Version" }, 11625 * { "title": "Grade" } 11626 * ] 11627 * } ); 11628 * } ); 11629 * 11630 * @example 11631 * // Using an array of objects as a data source (`data`) 11632 * $(document).ready( function () { 11633 * $('#example').dataTable( { 11634 * "data": [ 11635 * { 11636 * "engine": "Trident", 11637 * "browser": "Internet Explorer 4.0", 11638 * "platform": "Win 95+", 11639 * "version": 4, 11640 * "grade": "X" 11641 * }, 11642 * { 11643 * "engine": "Trident", 11644 * "browser": "Internet Explorer 5.0", 11645 * "platform": "Win 95+", 11646 * "version": 5, 11647 * "grade": "C" 11648 * } 11649 * ], 11650 * "columns": [ 11651 * { "title": "Engine", "data": "engine" }, 11652 * { "title": "Browser", "data": "browser" }, 11653 * { "title": "Platform", "data": "platform" }, 11654 * { "title": "Version", "data": "version" }, 11655 * { "title": "Grade", "data": "grade" } 11656 * ] 11657 * } ); 11658 * } ); 11659 */ 11660 "aaData": null, 11661 11662 11663 /** 11664 * If ordering is enabled, then DataTables will perform a first pass sort on 11665 * initialisation. You can define which column(s) the sort is performed 11666 * upon, and the sorting direction, with this variable. The `sorting` array 11667 * should contain an array for each column to be sorted initially containing 11668 * the column's index and a direction string ('asc' or 'desc'). 11669 * @type array 11670 * @default [[0,'asc']] 11671 * 11672 * @dtopt Option 11673 * @name DataTable.defaults.order 11674 * 11675 * @example 11676 * // Sort by 3rd column first, and then 4th column 11677 * $(document).ready( function() { 11678 * $('#example').dataTable( { 11679 * "order": [[2,'asc'], [3,'desc']] 11680 * } ); 11681 * } ); 11682 * 11683 * // No initial sorting 11684 * $(document).ready( function() { 11685 * $('#example').dataTable( { 11686 * "order": [] 11687 * } ); 11688 * } ); 11689 */ 11690 "aaSorting": [[0,'asc']], 11691 11692 11693 /** 11694 * This parameter is basically identical to the `sorting` parameter, but 11695 * cannot be overridden by user interaction with the table. What this means 11696 * is that you could have a column (visible or hidden) which the sorting 11697 * will always be forced on first - any sorting after that (from the user) 11698 * will then be performed as required. This can be useful for grouping rows 11699 * together. 11700 * @type array 11701 * @default null 11702 * 11703 * @dtopt Option 11704 * @name DataTable.defaults.orderFixed 11705 * 11706 * @example 11707 * $(document).ready( function() { 11708 * $('#example').dataTable( { 11709 * "orderFixed": [[0,'asc']] 11710 * } ); 11711 * } ) 11712 */ 11713 "aaSortingFixed": [], 11714 11715 11716 /** 11717 * DataTables can be instructed to load data to display in the table from a 11718 * Ajax source. This option defines how that Ajax call is made and where to. 11719 * 11720 * The `ajax` property has three different modes of operation, depending on 11721 * how it is defined. These are: 11722 * 11723 * * `string` - Set the URL from where the data should be loaded from. 11724 * * `object` - Define properties for `jQuery.ajax`. 11725 * * `function` - Custom data get function 11726 * 11727 * `string` 11728 * -------- 11729 * 11730 * As a string, the `ajax` property simply defines the URL from which 11731 * DataTables will load data. 11732 * 11733 * `object` 11734 * -------- 11735 * 11736 * As an object, the parameters in the object are passed to 11737 * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control 11738 * of the Ajax request. DataTables has a number of default parameters which 11739 * you can override using this option. Please refer to the jQuery 11740 * documentation for a full description of the options available, although 11741 * the following parameters provide additional options in DataTables or 11742 * require special consideration: 11743 * 11744 * * `data` - As with jQuery, `data` can be provided as an object, but it 11745 * can also be used as a function to manipulate the data DataTables sends 11746 * to the server. The function takes a single parameter, an object of 11747 * parameters with the values that DataTables has readied for sending. An 11748 * object may be returned which will be merged into the DataTables 11749 * defaults, or you can add the items to the object that was passed in and 11750 * not return anything from the function. This supersedes `fnServerParams` 11751 * from DataTables 1.9-. 11752 * 11753 * * `dataSrc` - By default DataTables will look for the property `data` (or 11754 * `aaData` for compatibility with DataTables 1.9-) when obtaining data 11755 * from an Ajax source or for server-side processing - this parameter 11756 * allows that property to be changed. You can use Javascript dotted 11757 * object notation to get a data source for multiple levels of nesting, or 11758 * it my be used as a function. As a function it takes a single parameter, 11759 * the JSON returned from the server, which can be manipulated as 11760 * required, with the returned value being that used by DataTables as the 11761 * data source for the table. This supersedes `sAjaxDataProp` from 11762 * DataTables 1.9-. 11763 * 11764 * * `success` - Should not be overridden it is used internally in 11765 * DataTables. To manipulate / transform the data returned by the server 11766 * use `ajax.dataSrc`, or use `ajax` as a function (see below). 11767 * 11768 * `function` 11769 * ---------- 11770 * 11771 * As a function, making the Ajax call is left up to yourself allowing 11772 * complete control of the Ajax request. Indeed, if desired, a method other 11773 * than Ajax could be used to obtain the required data, such as Web storage 11774 * or an AIR database. 11775 * 11776 * The function is given four parameters and no return is required. The 11777 * parameters are: 11778 * 11779 * 1. _object_ - Data to send to the server 11780 * 2. _function_ - Callback function that must be executed when the required 11781 * data has been obtained. That data should be passed into the callback 11782 * as the only parameter 11783 * 3. _object_ - DataTables settings object for the table 11784 * 11785 * Note that this supersedes `fnServerData` from DataTables 1.9-. 11786 * 11787 * @type string|object|function 11788 * @default null 11789 * 11790 * @dtopt Option 11791 * @name DataTable.defaults.ajax 11792 * @since 1.10.0 11793 * 11794 * @example 11795 * // Get JSON data from a file via Ajax. 11796 * // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default). 11797 * $('#example').dataTable( { 11798 * "ajax": "data.json" 11799 * } ); 11800 * 11801 * @example 11802 * // Get JSON data from a file via Ajax, using `dataSrc` to change 11803 * // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`) 11804 * $('#example').dataTable( { 11805 * "ajax": { 11806 * "url": "data.json", 11807 * "dataSrc": "tableData" 11808 * } 11809 * } ); 11810 * 11811 * @example 11812 * // Get JSON data from a file via Ajax, using `dataSrc` to read data 11813 * // from a plain array rather than an array in an object 11814 * $('#example').dataTable( { 11815 * "ajax": { 11816 * "url": "data.json", 11817 * "dataSrc": "" 11818 * } 11819 * } ); 11820 * 11821 * @example 11822 * // Manipulate the data returned from the server - add a link to data 11823 * // (note this can, should, be done using `render` for the column - this 11824 * // is just a simple example of how the data can be manipulated). 11825 * $('#example').dataTable( { 11826 * "ajax": { 11827 * "url": "data.json", 11828 * "dataSrc": function ( json ) { 11829 * for ( var i=0, ien=json.length ; i<ien ; i++ ) { 11830 * json[i][0] = '<a href="/message/'+json[i][0]+'>View message</a>'; 11831 * } 11832 * return json; 11833 * } 11834 * } 11835 * } ); 11836 * 11837 * @example 11838 * // Add data to the request 11839 * $('#example').dataTable( { 11840 * "ajax": { 11841 * "url": "data.json", 11842 * "data": function ( d ) { 11843 * return { 11844 * "extra_search": $('#extra').val() 11845 * }; 11846 * } 11847 * } 11848 * } ); 11849 * 11850 * @example 11851 * // Send request as POST 11852 * $('#example').dataTable( { 11853 * "ajax": { 11854 * "url": "data.json", 11855 * "type": "POST" 11856 * } 11857 * } ); 11858 * 11859 * @example 11860 * // Get the data from localStorage (could interface with a form for 11861 * // adding, editing and removing rows). 11862 * $('#example').dataTable( { 11863 * "ajax": function (data, callback, settings) { 11864 * callback( 11865 * JSON.parse( localStorage.getItem('dataTablesData') ) 11866 * ); 11867 * } 11868 * } ); 11869 */ 11870 "ajax": null, 11871 11872 11873 /** 11874 * This parameter allows you to readily specify the entries in the length drop 11875 * down menu that DataTables shows when pagination is enabled. It can be 11876 * either a 1D array of options which will be used for both the displayed 11877 * option and the value, or a 2D array which will use the array in the first 11878 * position as the value, and the array in the second position as the 11879 * displayed options (useful for language strings such as 'All'). 11880 * 11881 * Note that the `pageLength` property will be automatically set to the 11882 * first value given in this array, unless `pageLength` is also provided. 11883 * @type array 11884 * @default [ 10, 25, 50, 100 ] 11885 * 11886 * @dtopt Option 11887 * @name DataTable.defaults.lengthMenu 11888 * 11889 * @example 11890 * $(document).ready( function() { 11891 * $('#example').dataTable( { 11892 * "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]] 11893 * } ); 11894 * } ); 11895 */ 11896 "aLengthMenu": [ 10, 25, 50, 100 ], 11897 11898 11899 /** 11900 * The `columns` option in the initialisation parameter allows you to define 11901 * details about the way individual columns behave. For a full list of 11902 * column options that can be set, please see 11903 * {@link DataTable.defaults.column}. Note that if you use `columns` to 11904 * define your columns, you must have an entry in the array for every single 11905 * column that you have in your table (these can be null if you don't which 11906 * to specify any options). 11907 * @member 11908 * 11909 * @name DataTable.defaults.column 11910 */ 11911 "aoColumns": null, 11912 11913 /** 11914 * Very similar to `columns`, `columnDefs` allows you to target a specific 11915 * column, multiple columns, or all columns, using the `targets` property of 11916 * each object in the array. This allows great flexibility when creating 11917 * tables, as the `columnDefs` arrays can be of any length, targeting the 11918 * columns you specifically want. `columnDefs` may use any of the column 11919 * options available: {@link DataTable.defaults.column}, but it _must_ 11920 * have `targets` defined in each object in the array. Values in the `targets` 11921 * array may be: 11922 * <ul> 11923 * <li>a string - class name will be matched on the TH for the column</li> 11924 * <li>0 or a positive integer - column index counting from the left</li> 11925 * <li>a negative integer - column index counting from the right</li> 11926 * <li>the string "_all" - all columns (i.e. assign a default)</li> 11927 * </ul> 11928 * @member 11929 * 11930 * @name DataTable.defaults.columnDefs 11931 */ 11932 "aoColumnDefs": null, 11933 11934 11935 /** 11936 * Basically the same as `search`, this parameter defines the individual column 11937 * filtering state at initialisation time. The array must be of the same size 11938 * as the number of columns, and each element be an object with the parameters 11939 * `search` and `escapeRegex` (the latter is optional). 'null' is also 11940 * accepted and the default will be used. 11941 * @type array 11942 * @default [] 11943 * 11944 * @dtopt Option 11945 * @name DataTable.defaults.searchCols 11946 * 11947 * @example 11948 * $(document).ready( function() { 11949 * $('#example').dataTable( { 11950 * "searchCols": [ 11951 * null, 11952 * { "search": "My filter" }, 11953 * null, 11954 * { "search": "^[0-9]", "escapeRegex": false } 11955 * ] 11956 * } ); 11957 * } ) 11958 */ 11959 "aoSearchCols": [], 11960 11961 11962 /** 11963 * An array of CSS classes that should be applied to displayed rows. This 11964 * array may be of any length, and DataTables will apply each class 11965 * sequentially, looping when required. 11966 * @type array 11967 * @default null <i>Will take the values determined by the `oClasses.stripe*` 11968 * options</i> 11969 * 11970 * @dtopt Option 11971 * @name DataTable.defaults.stripeClasses 11972 * 11973 * @example 11974 * $(document).ready( function() { 11975 * $('#example').dataTable( { 11976 * "stripeClasses": [ 'strip1', 'strip2', 'strip3' ] 11977 * } ); 11978 * } ) 11979 */ 11980 "asStripeClasses": null, 11981 11982 11983 /** 11984 * Enable or disable automatic column width calculation. This can be disabled 11985 * as an optimisation (it takes some time to calculate the widths) if the 11986 * tables widths are passed in using `columns`. 11987 * @type boolean 11988 * @default true 11989 * 11990 * @dtopt Features 11991 * @name DataTable.defaults.autoWidth 11992 * 11993 * @example 11994 * $(document).ready( function () { 11995 * $('#example').dataTable( { 11996 * "autoWidth": false 11997 * } ); 11998 * } ); 11999 */ 12000 "bAutoWidth": true, 12001 12002 12003 /** 12004 * Deferred rendering can provide DataTables with a huge speed boost when you 12005 * are using an Ajax or JS data source for the table. This option, when set to 12006 * true, will cause DataTables to defer the creation of the table elements for 12007 * each row until they are needed for a draw - saving a significant amount of 12008 * time. 12009 * @type boolean 12010 * @default false 12011 * 12012 * @dtopt Features 12013 * @name DataTable.defaults.deferRender 12014 * 12015 * @example 12016 * $(document).ready( function() { 12017 * $('#example').dataTable( { 12018 * "ajax": "sources/arrays.txt", 12019 * "deferRender": true 12020 * } ); 12021 * } ); 12022 */ 12023 "bDeferRender": false, 12024 12025 12026 /** 12027 * Replace a DataTable which matches the given selector and replace it with 12028 * one which has the properties of the new initialisation object passed. If no 12029 * table matches the selector, then the new DataTable will be constructed as 12030 * per normal. 12031 * @type boolean 12032 * @default false 12033 * 12034 * @dtopt Options 12035 * @name DataTable.defaults.destroy 12036 * 12037 * @example 12038 * $(document).ready( function() { 12039 * $('#example').dataTable( { 12040 * "srollY": "200px", 12041 * "paginate": false 12042 * } ); 12043 * 12044 * // Some time later.... 12045 * $('#example').dataTable( { 12046 * "filter": false, 12047 * "destroy": true 12048 * } ); 12049 * } ); 12050 */ 12051 "bDestroy": false, 12052 12053 12054 /** 12055 * Enable or disable filtering of data. Filtering in DataTables is "smart" in 12056 * that it allows the end user to input multiple words (space separated) and 12057 * will match a row containing those words, even if not in the order that was 12058 * specified (this allow matching across multiple columns). Note that if you 12059 * wish to use filtering in DataTables this must remain 'true' - to remove the 12060 * default filtering input box and retain filtering abilities, please use 12061 * {@link DataTable.defaults.dom}. 12062 * @type boolean 12063 * @default true 12064 * 12065 * @dtopt Features 12066 * @name DataTable.defaults.searching 12067 * 12068 * @example 12069 * $(document).ready( function () { 12070 * $('#example').dataTable( { 12071 * "searching": false 12072 * } ); 12073 * } ); 12074 */ 12075 "bFilter": true, 12076 12077 12078 /** 12079 * Enable or disable the table information display. This shows information 12080 * about the data that is currently visible on the page, including information 12081 * about filtered data if that action is being performed. 12082 * @type boolean 12083 * @default true 12084 * 12085 * @dtopt Features 12086 * @name DataTable.defaults.info 12087 * 12088 * @example 12089 * $(document).ready( function () { 12090 * $('#example').dataTable( { 12091 * "info": false 12092 * } ); 12093 * } ); 12094 */ 12095 "bInfo": true, 12096 12097 12098 /** 12099 * Allows the end user to select the size of a formatted page from a select 12100 * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`). 12101 * @type boolean 12102 * @default true 12103 * 12104 * @dtopt Features 12105 * @name DataTable.defaults.lengthChange 12106 * 12107 * @example 12108 * $(document).ready( function () { 12109 * $('#example').dataTable( { 12110 * "lengthChange": false 12111 * } ); 12112 * } ); 12113 */ 12114 "bLengthChange": true, 12115 12116 12117 /** 12118 * Enable or disable pagination. 12119 * @type boolean 12120 * @default true 12121 * 12122 * @dtopt Features 12123 * @name DataTable.defaults.paging 12124 * 12125 * @example 12126 * $(document).ready( function () { 12127 * $('#example').dataTable( { 12128 * "paging": false 12129 * } ); 12130 * } ); 12131 */ 12132 "bPaginate": true, 12133 12134 12135 /** 12136 * Enable or disable the display of a 'processing' indicator when the table is 12137 * being processed (e.g. a sort). This is particularly useful for tables with 12138 * large amounts of data where it can take a noticeable amount of time to sort 12139 * the entries. 12140 * @type boolean 12141 * @default false 12142 * 12143 * @dtopt Features 12144 * @name DataTable.defaults.processing 12145 * 12146 * @example 12147 * $(document).ready( function () { 12148 * $('#example').dataTable( { 12149 * "processing": true 12150 * } ); 12151 * } ); 12152 */ 12153 "bProcessing": false, 12154 12155 12156 /** 12157 * Retrieve the DataTables object for the given selector. Note that if the 12158 * table has already been initialised, this parameter will cause DataTables 12159 * to simply return the object that has already been set up - it will not take 12160 * account of any changes you might have made to the initialisation object 12161 * passed to DataTables (setting this parameter to true is an acknowledgement 12162 * that you understand this). `destroy` can be used to reinitialise a table if 12163 * you need. 12164 * @type boolean 12165 * @default false 12166 * 12167 * @dtopt Options 12168 * @name DataTable.defaults.retrieve 12169 * 12170 * @example 12171 * $(document).ready( function() { 12172 * initTable(); 12173 * tableActions(); 12174 * } ); 12175 * 12176 * function initTable () 12177 * { 12178 * return $('#example').dataTable( { 12179 * "scrollY": "200px", 12180 * "paginate": false, 12181 * "retrieve": true 12182 * } ); 12183 * } 12184 * 12185 * function tableActions () 12186 * { 12187 * var table = initTable(); 12188 * // perform API operations with oTable 12189 * } 12190 */ 12191 "bRetrieve": false, 12192 12193 12194 /** 12195 * When vertical (y) scrolling is enabled, DataTables will force the height of 12196 * the table's viewport to the given height at all times (useful for layout). 12197 * However, this can look odd when filtering data down to a small data set, 12198 * and the footer is left "floating" further down. This parameter (when 12199 * enabled) will cause DataTables to collapse the table's viewport down when 12200 * the result set will fit within the given Y height. 12201 * @type boolean 12202 * @default false 12203 * 12204 * @dtopt Options 12205 * @name DataTable.defaults.scrollCollapse 12206 * 12207 * @example 12208 * $(document).ready( function() { 12209 * $('#example').dataTable( { 12210 * "scrollY": "200", 12211 * "scrollCollapse": true 12212 * } ); 12213 * } ); 12214 */ 12215 "bScrollCollapse": false, 12216 12217 12218 /** 12219 * Configure DataTables to use server-side processing. Note that the 12220 * `ajax` parameter must also be given in order to give DataTables a 12221 * source to obtain the required data for each draw. 12222 * @type boolean 12223 * @default false 12224 * 12225 * @dtopt Features 12226 * @dtopt Server-side 12227 * @name DataTable.defaults.serverSide 12228 * 12229 * @example 12230 * $(document).ready( function () { 12231 * $('#example').dataTable( { 12232 * "serverSide": true, 12233 * "ajax": "xhr.php" 12234 * } ); 12235 * } ); 12236 */ 12237 "bServerSide": false, 12238 12239 12240 /** 12241 * Enable or disable sorting of columns. Sorting of individual columns can be 12242 * disabled by the `sortable` option for each column. 12243 * @type boolean 12244 * @default true 12245 * 12246 * @dtopt Features 12247 * @name DataTable.defaults.ordering 12248 * 12249 * @example 12250 * $(document).ready( function () { 12251 * $('#example').dataTable( { 12252 * "ordering": false 12253 * } ); 12254 * } ); 12255 */ 12256 "bSort": true, 12257 12258 12259 /** 12260 * Enable or display DataTables' ability to sort multiple columns at the 12261 * same time (activated by shift-click by the user). 12262 * @type boolean 12263 * @default true 12264 * 12265 * @dtopt Options 12266 * @name DataTable.defaults.orderMulti 12267 * 12268 * @example 12269 * // Disable multiple column sorting ability 12270 * $(document).ready( function () { 12271 * $('#example').dataTable( { 12272 * "orderMulti": false 12273 * } ); 12274 * } ); 12275 */ 12276 "bSortMulti": true, 12277 12278 12279 /** 12280 * Allows control over whether DataTables should use the top (true) unique 12281 * cell that is found for a single column, or the bottom (false - default). 12282 * This is useful when using complex headers. 12283 * @type boolean 12284 * @default false 12285 * 12286 * @dtopt Options 12287 * @name DataTable.defaults.orderCellsTop 12288 * 12289 * @example 12290 * $(document).ready( function() { 12291 * $('#example').dataTable( { 12292 * "orderCellsTop": true 12293 * } ); 12294 * } ); 12295 */ 12296 "bSortCellsTop": false, 12297 12298 12299 /** 12300 * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and 12301 * `sorting\_3` to the columns which are currently being sorted on. This is 12302 * presented as a feature switch as it can increase processing time (while 12303 * classes are removed and added) so for large data sets you might want to 12304 * turn this off. 12305 * @type boolean 12306 * @default true 12307 * 12308 * @dtopt Features 12309 * @name DataTable.defaults.orderClasses 12310 * 12311 * @example 12312 * $(document).ready( function () { 12313 * $('#example').dataTable( { 12314 * "orderClasses": false 12315 * } ); 12316 * } ); 12317 */ 12318 "bSortClasses": true, 12319 12320 12321 /** 12322 * Enable or disable state saving. When enabled HTML5 `localStorage` will be 12323 * used to save table display information such as pagination information, 12324 * display length, filtering and sorting. As such when the end user reloads 12325 * the page the display display will match what thy had previously set up. 12326 * 12327 * Due to the use of `localStorage` the default state saving is not supported 12328 * in IE6 or 7. If state saving is required in those browsers, use 12329 * `stateSaveCallback` to provide a storage solution such as cookies. 12330 * @type boolean 12331 * @default false 12332 * 12333 * @dtopt Features 12334 * @name DataTable.defaults.stateSave 12335 * 12336 * @example 12337 * $(document).ready( function () { 12338 * $('#example').dataTable( { 12339 * "stateSave": true 12340 * } ); 12341 * } ); 12342 */ 12343 "bStateSave": false, 12344 12345 12346 /** 12347 * This function is called when a TR element is created (and all TD child 12348 * elements have been inserted), or registered if using a DOM source, allowing 12349 * manipulation of the TR element (adding classes etc). 12350 * @type function 12351 * @param {node} row "TR" element for the current row 12352 * @param {array} data Raw data array for this row 12353 * @param {int} dataIndex The index of this row in the internal aoData array 12354 * 12355 * @dtopt Callbacks 12356 * @name DataTable.defaults.createdRow 12357 * 12358 * @example 12359 * $(document).ready( function() { 12360 * $('#example').dataTable( { 12361 * "createdRow": function( row, data, dataIndex ) { 12362 * // Bold the grade for all 'A' grade browsers 12363 * if ( data[4] == "A" ) 12364 * { 12365 * $('td:eq(4)', row).html( '<b>A</b>' ); 12366 * } 12367 * } 12368 * } ); 12369 * } ); 12370 */ 12371 "fnCreatedRow": null, 12372 12373 12374 /** 12375 * This function is called on every 'draw' event, and allows you to 12376 * dynamically modify any aspect you want about the created DOM. 12377 * @type function 12378 * @param {object} settings DataTables settings object 12379 * 12380 * @dtopt Callbacks 12381 * @name DataTable.defaults.drawCallback 12382 * 12383 * @example 12384 * $(document).ready( function() { 12385 * $('#example').dataTable( { 12386 * "drawCallback": function( settings ) { 12387 * alert( 'DataTables has redrawn the table' ); 12388 * } 12389 * } ); 12390 * } ); 12391 */ 12392 "fnDrawCallback": null, 12393 12394 12395 /** 12396 * Identical to fnHeaderCallback() but for the table footer this function 12397 * allows you to modify the table footer on every 'draw' event. 12398 * @type function 12399 * @param {node} foot "TR" element for the footer 12400 * @param {array} data Full table data (as derived from the original HTML) 12401 * @param {int} start Index for the current display starting point in the 12402 * display array 12403 * @param {int} end Index for the current display ending point in the 12404 * display array 12405 * @param {array int} display Index array to translate the visual position 12406 * to the full data array 12407 * 12408 * @dtopt Callbacks 12409 * @name DataTable.defaults.footerCallback 12410 * 12411 * @example 12412 * $(document).ready( function() { 12413 * $('#example').dataTable( { 12414 * "footerCallback": function( tfoot, data, start, end, display ) { 12415 * tfoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+start; 12416 * } 12417 * } ); 12418 * } ) 12419 */ 12420 "fnFooterCallback": null, 12421 12422 12423 /** 12424 * When rendering large numbers in the information element for the table 12425 * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers 12426 * to have a comma separator for the 'thousands' units (e.g. 1 million is 12427 * rendered as "1,000,000") to help readability for the end user. This 12428 * function will override the default method DataTables uses. 12429 * @type function 12430 * @member 12431 * @param {int} toFormat number to be formatted 12432 * @returns {string} formatted string for DataTables to show the number 12433 * 12434 * @dtopt Callbacks 12435 * @name DataTable.defaults.formatNumber 12436 * 12437 * @example 12438 * // Format a number using a single quote for the separator (note that 12439 * // this can also be done with the language.thousands option) 12440 * $(document).ready( function() { 12441 * $('#example').dataTable( { 12442 * "formatNumber": function ( toFormat ) { 12443 * return toFormat.toString().replace( 12444 * /\B(?=(\d{3})+(?!\d))/g, "'" 12445 * ); 12446 * }; 12447 * } ); 12448 * } ); 12449 */ 12450 "fnFormatNumber": function ( toFormat ) { 12451 return toFormat.toString().replace( 12452 /\B(?=(\d{3})+(?!\d))/g, 12453 this.oLanguage.sThousands 12454 ); 12455 }, 12456 12457 12458 /** 12459 * This function is called on every 'draw' event, and allows you to 12460 * dynamically modify the header row. This can be used to calculate and 12461 * display useful information about the table. 12462 * @type function 12463 * @param {node} head "TR" element for the header 12464 * @param {array} data Full table data (as derived from the original HTML) 12465 * @param {int} start Index for the current display starting point in the 12466 * display array 12467 * @param {int} end Index for the current display ending point in the 12468 * display array 12469 * @param {array int} display Index array to translate the visual position 12470 * to the full data array 12471 * 12472 * @dtopt Callbacks 12473 * @name DataTable.defaults.headerCallback 12474 * 12475 * @example 12476 * $(document).ready( function() { 12477 * $('#example').dataTable( { 12478 * "fheaderCallback": function( head, data, start, end, display ) { 12479 * head.getElementsByTagName('th')[0].innerHTML = "Displaying "+(end-start)+" records"; 12480 * } 12481 * } ); 12482 * } ) 12483 */ 12484 "fnHeaderCallback": null, 12485 12486 12487 /** 12488 * The information element can be used to convey information about the current 12489 * state of the table. Although the internationalisation options presented by 12490 * DataTables are quite capable of dealing with most customisations, there may 12491 * be times where you wish to customise the string further. This callback 12492 * allows you to do exactly that. 12493 * @type function 12494 * @param {object} oSettings DataTables settings object 12495 * @param {int} start Starting position in data for the draw 12496 * @param {int} end End position in data for the draw 12497 * @param {int} max Total number of rows in the table (regardless of 12498 * filtering) 12499 * @param {int} total Total number of rows in the data set, after filtering 12500 * @param {string} pre The string that DataTables has formatted using it's 12501 * own rules 12502 * @returns {string} The string to be displayed in the information element. 12503 * 12504 * @dtopt Callbacks 12505 * @name DataTable.defaults.infoCallback 12506 * 12507 * @example 12508 * $('#example').dataTable( { 12509 * "infoCallback": function( settings, start, end, max, total, pre ) { 12510 * return start +" to "+ end; 12511 * } 12512 * } ); 12513 */ 12514 "fnInfoCallback": null, 12515 12516 12517 /** 12518 * Called when the table has been initialised. Normally DataTables will 12519 * initialise sequentially and there will be no need for this function, 12520 * however, this does not hold true when using external language information 12521 * since that is obtained using an async XHR call. 12522 * @type function 12523 * @param {object} settings DataTables settings object 12524 * @param {object} json The JSON object request from the server - only 12525 * present if client-side Ajax sourced data is used 12526 * 12527 * @dtopt Callbacks 12528 * @name DataTable.defaults.initComplete 12529 * 12530 * @example 12531 * $(document).ready( function() { 12532 * $('#example').dataTable( { 12533 * "initComplete": function(settings, json) { 12534 * alert( 'DataTables has finished its initialisation.' ); 12535 * } 12536 * } ); 12537 * } ) 12538 */ 12539 "fnInitComplete": null, 12540 12541 12542 /** 12543 * Called at the very start of each table draw and can be used to cancel the 12544 * draw by returning false, any other return (including undefined) results in 12545 * the full draw occurring). 12546 * @type function 12547 * @param {object} settings DataTables settings object 12548 * @returns {boolean} False will cancel the draw, anything else (including no 12549 * return) will allow it to complete. 12550 * 12551 * @dtopt Callbacks 12552 * @name DataTable.defaults.preDrawCallback 12553 * 12554 * @example 12555 * $(document).ready( function() { 12556 * $('#example').dataTable( { 12557 * "preDrawCallback": function( settings ) { 12558 * if ( $('#test').val() == 1 ) { 12559 * return false; 12560 * } 12561 * } 12562 * } ); 12563 * } ); 12564 */ 12565 "fnPreDrawCallback": null, 12566 12567 12568 /** 12569 * This function allows you to 'post process' each row after it have been 12570 * generated for each table draw, but before it is rendered on screen. This 12571 * function might be used for setting the row class name etc. 12572 * @type function 12573 * @param {node} row "TR" element for the current row 12574 * @param {array} data Raw data array for this row 12575 * @param {int} displayIndex The display index for the current table draw 12576 * @param {int} displayIndexFull The index of the data in the full list of 12577 * rows (after filtering) 12578 * 12579 * @dtopt Callbacks 12580 * @name DataTable.defaults.rowCallback 12581 * 12582 * @example 12583 * $(document).ready( function() { 12584 * $('#example').dataTable( { 12585 * "rowCallback": function( row, data, displayIndex, displayIndexFull ) { 12586 * // Bold the grade for all 'A' grade browsers 12587 * if ( data[4] == "A" ) { 12588 * $('td:eq(4)', row).html( '<b>A</b>' ); 12589 * } 12590 * } 12591 * } ); 12592 * } ); 12593 */ 12594 "fnRowCallback": null, 12595 12596 12597 /** 12598 * __Deprecated__ The functionality provided by this parameter has now been 12599 * superseded by that provided through `ajax`, which should be used instead. 12600 * 12601 * This parameter allows you to override the default function which obtains 12602 * the data from the server so something more suitable for your application. 12603 * For example you could use POST data, or pull information from a Gears or 12604 * AIR database. 12605 * @type function 12606 * @member 12607 * @param {string} source HTTP source to obtain the data from (`ajax`) 12608 * @param {array} data A key/value pair object containing the data to send 12609 * to the server 12610 * @param {function} callback to be called on completion of the data get 12611 * process that will draw the data on the page. 12612 * @param {object} settings DataTables settings object 12613 * 12614 * @dtopt Callbacks 12615 * @dtopt Server-side 12616 * @name DataTable.defaults.serverData 12617 * 12618 * @deprecated 1.10. Please use `ajax` for this functionality now. 12619 */ 12620 "fnServerData": null, 12621 12622 12623 /** 12624 * __Deprecated__ The functionality provided by this parameter has now been 12625 * superseded by that provided through `ajax`, which should be used instead. 12626 * 12627 * It is often useful to send extra data to the server when making an Ajax 12628 * request - for example custom filtering information, and this callback 12629 * function makes it trivial to send extra information to the server. The 12630 * passed in parameter is the data set that has been constructed by 12631 * DataTables, and you can add to this or modify it as you require. 12632 * @type function 12633 * @param {array} data Data array (array of objects which are name/value 12634 * pairs) that has been constructed by DataTables and will be sent to the 12635 * server. In the case of Ajax sourced data with server-side processing 12636 * this will be an empty array, for server-side processing there will be a 12637 * significant number of parameters! 12638 * @returns {undefined} Ensure that you modify the data array passed in, 12639 * as this is passed by reference. 12640 * 12641 * @dtopt Callbacks 12642 * @dtopt Server-side 12643 * @name DataTable.defaults.serverParams 12644 * 12645 * @deprecated 1.10. Please use `ajax` for this functionality now. 12646 */ 12647 "fnServerParams": null, 12648 12649 12650 /** 12651 * Load the table state. With this function you can define from where, and how, the 12652 * state of a table is loaded. By default DataTables will load from `localStorage` 12653 * but you might wish to use a server-side database or cookies. 12654 * @type function 12655 * @member 12656 * @param {object} settings DataTables settings object 12657 * @param {object} callback Callback that can be executed when done. It 12658 * should be passed the loaded state object. 12659 * @return {object} The DataTables state object to be loaded 12660 * 12661 * @dtopt Callbacks 12662 * @name DataTable.defaults.stateLoadCallback 12663 * 12664 * @example 12665 * $(document).ready( function() { 12666 * $('#example').dataTable( { 12667 * "stateSave": true, 12668 * "stateLoadCallback": function (settings, callback) { 12669 * $.ajax( { 12670 * "url": "/state_load", 12671 * "dataType": "json", 12672 * "success": function (json) { 12673 * callback( json ); 12674 * } 12675 * } ); 12676 * } 12677 * } ); 12678 * } ); 12679 */ 12680 "fnStateLoadCallback": function ( settings ) { 12681 try { 12682 return JSON.parse( 12683 (settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem( 12684 'DataTables_'+settings.sInstance+'_'+location.pathname 12685 ) 12686 ); 12687 } catch (e) { 12688 return {}; 12689 } 12690 }, 12691 12692 12693 /** 12694 * Callback which allows modification of the saved state prior to loading that state. 12695 * This callback is called when the table is loading state from the stored data, but 12696 * prior to the settings object being modified by the saved state. Note that for 12697 * plug-in authors, you should use the `stateLoadParams` event to load parameters for 12698 * a plug-in. 12699 * @type function 12700 * @param {object} settings DataTables settings object 12701 * @param {object} data The state object that is to be loaded 12702 * 12703 * @dtopt Callbacks 12704 * @name DataTable.defaults.stateLoadParams 12705 * 12706 * @example 12707 * // Remove a saved filter, so filtering is never loaded 12708 * $(document).ready( function() { 12709 * $('#example').dataTable( { 12710 * "stateSave": true, 12711 * "stateLoadParams": function (settings, data) { 12712 * data.oSearch.sSearch = ""; 12713 * } 12714 * } ); 12715 * } ); 12716 * 12717 * @example 12718 * // Disallow state loading by returning false 12719 * $(document).ready( function() { 12720 * $('#example').dataTable( { 12721 * "stateSave": true, 12722 * "stateLoadParams": function (settings, data) { 12723 * return false; 12724 * } 12725 * } ); 12726 * } ); 12727 */ 12728 "fnStateLoadParams": null, 12729 12730 12731 /** 12732 * Callback that is called when the state has been loaded from the state saving method 12733 * and the DataTables settings object has been modified as a result of the loaded state. 12734 * @type function 12735 * @param {object} settings DataTables settings object 12736 * @param {object} data The state object that was loaded 12737 * 12738 * @dtopt Callbacks 12739 * @name DataTable.defaults.stateLoaded 12740 * 12741 * @example 12742 * // Show an alert with the filtering value that was saved 12743 * $(document).ready( function() { 12744 * $('#example').dataTable( { 12745 * "stateSave": true, 12746 * "stateLoaded": function (settings, data) { 12747 * alert( 'Saved filter was: '+data.oSearch.sSearch ); 12748 * } 12749 * } ); 12750 * } ); 12751 */ 12752 "fnStateLoaded": null, 12753 12754 12755 /** 12756 * Save the table state. This function allows you to define where and how the state 12757 * information for the table is stored By default DataTables will use `localStorage` 12758 * but you might wish to use a server-side database or cookies. 12759 * @type function 12760 * @member 12761 * @param {object} settings DataTables settings object 12762 * @param {object} data The state object to be saved 12763 * 12764 * @dtopt Callbacks 12765 * @name DataTable.defaults.stateSaveCallback 12766 * 12767 * @example 12768 * $(document).ready( function() { 12769 * $('#example').dataTable( { 12770 * "stateSave": true, 12771 * "stateSaveCallback": function (settings, data) { 12772 * // Send an Ajax request to the server with the state object 12773 * $.ajax( { 12774 * "url": "/state_save", 12775 * "data": data, 12776 * "dataType": "json", 12777 * "method": "POST" 12778 * "success": function () {} 12779 * } ); 12780 * } 12781 * } ); 12782 * } ); 12783 */ 12784 "fnStateSaveCallback": function ( settings, data ) { 12785 try { 12786 (settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem( 12787 'DataTables_'+settings.sInstance+'_'+location.pathname, 12788 JSON.stringify( data ) 12789 ); 12790 } catch (e) {} 12791 }, 12792 12793 12794 /** 12795 * Callback which allows modification of the state to be saved. Called when the table 12796 * has changed state a new state save is required. This method allows modification of 12797 * the state saving object prior to actually doing the save, including addition or 12798 * other state properties or modification. Note that for plug-in authors, you should 12799 * use the `stateSaveParams` event to save parameters for a plug-in. 12800 * @type function 12801 * @param {object} settings DataTables settings object 12802 * @param {object} data The state object to be saved 12803 * 12804 * @dtopt Callbacks 12805 * @name DataTable.defaults.stateSaveParams 12806 * 12807 * @example 12808 * // Remove a saved filter, so filtering is never saved 12809 * $(document).ready( function() { 12810 * $('#example').dataTable( { 12811 * "stateSave": true, 12812 * "stateSaveParams": function (settings, data) { 12813 * data.oSearch.sSearch = ""; 12814 * } 12815 * } ); 12816 * } ); 12817 */ 12818 "fnStateSaveParams": null, 12819 12820 12821 /** 12822 * Duration for which the saved state information is considered valid. After this period 12823 * has elapsed the state will be returned to the default. 12824 * Value is given in seconds. 12825 * @type int 12826 * @default 7200 <i>(2 hours)</i> 12827 * 12828 * @dtopt Options 12829 * @name DataTable.defaults.stateDuration 12830 * 12831 * @example 12832 * $(document).ready( function() { 12833 * $('#example').dataTable( { 12834 * "stateDuration": 60*60*24; // 1 day 12835 * } ); 12836 * } ) 12837 */ 12838 "iStateDuration": 7200, 12839 12840 12841 /** 12842 * When enabled DataTables will not make a request to the server for the first 12843 * page draw - rather it will use the data already on the page (no sorting etc 12844 * will be applied to it), thus saving on an XHR at load time. `deferLoading` 12845 * is used to indicate that deferred loading is required, but it is also used 12846 * to tell DataTables how many records there are in the full table (allowing 12847 * the information element and pagination to be displayed correctly). In the case 12848 * where a filtering is applied to the table on initial load, this can be 12849 * indicated by giving the parameter as an array, where the first element is 12850 * the number of records available after filtering and the second element is the 12851 * number of records without filtering (allowing the table information element 12852 * to be shown correctly). 12853 * @type int | array 12854 * @default null 12855 * 12856 * @dtopt Options 12857 * @name DataTable.defaults.deferLoading 12858 * 12859 * @example 12860 * // 57 records available in the table, no filtering applied 12861 * $(document).ready( function() { 12862 * $('#example').dataTable( { 12863 * "serverSide": true, 12864 * "ajax": "scripts/server_processing.php", 12865 * "deferLoading": 57 12866 * } ); 12867 * } ); 12868 * 12869 * @example 12870 * // 57 records after filtering, 100 without filtering (an initial filter applied) 12871 * $(document).ready( function() { 12872 * $('#example').dataTable( { 12873 * "serverSide": true, 12874 * "ajax": "scripts/server_processing.php", 12875 * "deferLoading": [ 57, 100 ], 12876 * "search": { 12877 * "search": "my_filter" 12878 * } 12879 * } ); 12880 * } ); 12881 */ 12882 "iDeferLoading": null, 12883 12884 12885 /** 12886 * Number of rows to display on a single page when using pagination. If 12887 * feature enabled (`lengthChange`) then the end user will be able to override 12888 * this to a custom setting using a pop-up menu. 12889 * @type int 12890 * @default 10 12891 * 12892 * @dtopt Options 12893 * @name DataTable.defaults.pageLength 12894 * 12895 * @example 12896 * $(document).ready( function() { 12897 * $('#example').dataTable( { 12898 * "pageLength": 50 12899 * } ); 12900 * } ) 12901 */ 12902 "iDisplayLength": 10, 12903 12904 12905 /** 12906 * Define the starting point for data display when using DataTables with 12907 * pagination. Note that this parameter is the number of records, rather than 12908 * the page number, so if you have 10 records per page and want to start on 12909 * the third page, it should be "20". 12910 * @type int 12911 * @default 0 12912 * 12913 * @dtopt Options 12914 * @name DataTable.defaults.displayStart 12915 * 12916 * @example 12917 * $(document).ready( function() { 12918 * $('#example').dataTable( { 12919 * "displayStart": 20 12920 * } ); 12921 * } ) 12922 */ 12923 "iDisplayStart": 0, 12924 12925 12926 /** 12927 * By default DataTables allows keyboard navigation of the table (sorting, paging, 12928 * and filtering) by adding a `tabindex` attribute to the required elements. This 12929 * allows you to tab through the controls and press the enter key to activate them. 12930 * The tabindex is default 0, meaning that the tab follows the flow of the document. 12931 * You can overrule this using this parameter if you wish. Use a value of -1 to 12932 * disable built-in keyboard navigation. 12933 * @type int 12934 * @default 0 12935 * 12936 * @dtopt Options 12937 * @name DataTable.defaults.tabIndex 12938 * 12939 * @example 12940 * $(document).ready( function() { 12941 * $('#example').dataTable( { 12942 * "tabIndex": 1 12943 * } ); 12944 * } ); 12945 */ 12946 "iTabIndex": 0, 12947 12948 12949 /** 12950 * Classes that DataTables assigns to the various components and features 12951 * that it adds to the HTML table. This allows classes to be configured 12952 * during initialisation in addition to through the static 12953 * {@link DataTable.ext.oStdClasses} object). 12954 * @namespace 12955 * @name DataTable.defaults.classes 12956 */ 12957 "oClasses": {}, 12958 12959 12960 /** 12961 * All strings that DataTables uses in the user interface that it creates 12962 * are defined in this object, allowing you to modified them individually or 12963 * completely replace them all as required. 12964 * @namespace 12965 * @name DataTable.defaults.language 12966 */ 12967 "oLanguage": { 12968 /** 12969 * Strings that are used for WAI-ARIA labels and controls only (these are not 12970 * actually visible on the page, but will be read by screenreaders, and thus 12971 * must be internationalised as well). 12972 * @namespace 12973 * @name DataTable.defaults.language.aria 12974 */ 12975 "oAria": { 12976 /** 12977 * ARIA label that is added to the table headers when the column may be 12978 * sorted ascending by activing the column (click or return when focused). 12979 * Note that the column header is prefixed to this string. 12980 * @type string 12981 * @default : activate to sort column ascending 12982 * 12983 * @dtopt Language 12984 * @name DataTable.defaults.language.aria.sortAscending 12985 * 12986 * @example 12987 * $(document).ready( function() { 12988 * $('#example').dataTable( { 12989 * "language": { 12990 * "aria": { 12991 * "sortAscending": " - click/return to sort ascending" 12992 * } 12993 * } 12994 * } ); 12995 * } ); 12996 */ 12997 "sSortAscending": ": activate to sort column ascending", 12998 12999 /** 13000 * ARIA label that is added to the table headers when the column may be 13001 * sorted descending by activing the column (click or return when focused). 13002 * Note that the column header is prefixed to this string. 13003 * @type string 13004 * @default : activate to sort column ascending 13005 * 13006 * @dtopt Language 13007 * @name DataTable.defaults.language.aria.sortDescending 13008 * 13009 * @example 13010 * $(document).ready( function() { 13011 * $('#example').dataTable( { 13012 * "language": { 13013 * "aria": { 13014 * "sortDescending": " - click/return to sort descending" 13015 * } 13016 * } 13017 * } ); 13018 * } ); 13019 */ 13020 "sSortDescending": ": activate to sort column descending" 13021 }, 13022 13023 /** 13024 * Pagination string used by DataTables for the built-in pagination 13025 * control types. 13026 * @namespace 13027 * @name DataTable.defaults.language.paginate 13028 */ 13029 "oPaginate": { 13030 /** 13031 * Text to use when using the 'full_numbers' type of pagination for the 13032 * button to take the user to the first page. 13033 * @type string 13034 * @default First 13035 * 13036 * @dtopt Language 13037 * @name DataTable.defaults.language.paginate.first 13038 * 13039 * @example 13040 * $(document).ready( function() { 13041 * $('#example').dataTable( { 13042 * "language": { 13043 * "paginate": { 13044 * "first": "First page" 13045 * } 13046 * } 13047 * } ); 13048 * } ); 13049 */ 13050 "sFirst": "First", 13051 13052 13053 /** 13054 * Text to use when using the 'full_numbers' type of pagination for the 13055 * button to take the user to the last page. 13056 * @type string 13057 * @default Last 13058 * 13059 * @dtopt Language 13060 * @name DataTable.defaults.language.paginate.last 13061 * 13062 * @example 13063 * $(document).ready( function() { 13064 * $('#example').dataTable( { 13065 * "language": { 13066 * "paginate": { 13067 * "last": "Last page" 13068 * } 13069 * } 13070 * } ); 13071 * } ); 13072 */ 13073 "sLast": "Last", 13074 13075 13076 /** 13077 * Text to use for the 'next' pagination button (to take the user to the 13078 * next page). 13079 * @type string 13080 * @default Next 13081 * 13082 * @dtopt Language 13083 * @name DataTable.defaults.language.paginate.next 13084 * 13085 * @example 13086 * $(document).ready( function() { 13087 * $('#example').dataTable( { 13088 * "language": { 13089 * "paginate": { 13090 * "next": "Next page" 13091 * } 13092 * } 13093 * } ); 13094 * } ); 13095 */ 13096 "sNext": "Next", 13097 13098 13099 /** 13100 * Text to use for the 'previous' pagination button (to take the user to 13101 * the previous page). 13102 * @type string 13103 * @default Previous 13104 * 13105 * @dtopt Language 13106 * @name DataTable.defaults.language.paginate.previous 13107 * 13108 * @example 13109 * $(document).ready( function() { 13110 * $('#example').dataTable( { 13111 * "language": { 13112 * "paginate": { 13113 * "previous": "Previous page" 13114 * } 13115 * } 13116 * } ); 13117 * } ); 13118 */ 13119 "sPrevious": "Previous" 13120 }, 13121 13122 /** 13123 * This string is shown in preference to `zeroRecords` when the table is 13124 * empty of data (regardless of filtering). Note that this is an optional 13125 * parameter - if it is not given, the value of `zeroRecords` will be used 13126 * instead (either the default or given value). 13127 * @type string 13128 * @default No data available in table 13129 * 13130 * @dtopt Language 13131 * @name DataTable.defaults.language.emptyTable 13132 * 13133 * @example 13134 * $(document).ready( function() { 13135 * $('#example').dataTable( { 13136 * "language": { 13137 * "emptyTable": "No data available in table" 13138 * } 13139 * } ); 13140 * } ); 13141 */ 13142 "sEmptyTable": "No data available in table", 13143 13144 13145 /** 13146 * This string gives information to the end user about the information 13147 * that is current on display on the page. The following tokens can be 13148 * used in the string and will be dynamically replaced as the table 13149 * display updates. This tokens can be placed anywhere in the string, or 13150 * removed as needed by the language requires: 13151 * 13152 * * `\_START\_` - Display index of the first record on the current page 13153 * * `\_END\_` - Display index of the last record on the current page 13154 * * `\_TOTAL\_` - Number of records in the table after filtering 13155 * * `\_MAX\_` - Number of records in the table without filtering 13156 * * `\_PAGE\_` - Current page number 13157 * * `\_PAGES\_` - Total number of pages of data in the table 13158 * 13159 * @type string 13160 * @default Showing _START_ to _END_ of _TOTAL_ entries 13161 * 13162 * @dtopt Language 13163 * @name DataTable.defaults.language.info 13164 * 13165 * @example 13166 * $(document).ready( function() { 13167 * $('#example').dataTable( { 13168 * "language": { 13169 * "info": "Showing page _PAGE_ of _PAGES_" 13170 * } 13171 * } ); 13172 * } ); 13173 */ 13174 "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries", 13175 13176 13177 /** 13178 * Display information string for when the table is empty. Typically the 13179 * format of this string should match `info`. 13180 * @type string 13181 * @default Showing 0 to 0 of 0 entries 13182 * 13183 * @dtopt Language 13184 * @name DataTable.defaults.language.infoEmpty 13185 * 13186 * @example 13187 * $(document).ready( function() { 13188 * $('#example').dataTable( { 13189 * "language": { 13190 * "infoEmpty": "No entries to show" 13191 * } 13192 * } ); 13193 * } ); 13194 */ 13195 "sInfoEmpty": "Showing 0 to 0 of 0 entries", 13196 13197 13198 /** 13199 * When a user filters the information in a table, this string is appended 13200 * to the information (`info`) to give an idea of how strong the filtering 13201 * is. The variable _MAX_ is dynamically updated. 13202 * @type string 13203 * @default (filtered from _MAX_ total entries) 13204 * 13205 * @dtopt Language 13206 * @name DataTable.defaults.language.infoFiltered 13207 * 13208 * @example 13209 * $(document).ready( function() { 13210 * $('#example').dataTable( { 13211 * "language": { 13212 * "infoFiltered": " - filtering from _MAX_ records" 13213 * } 13214 * } ); 13215 * } ); 13216 */ 13217 "sInfoFiltered": "(filtered from _MAX_ total entries)", 13218 13219 13220 /** 13221 * If can be useful to append extra information to the info string at times, 13222 * and this variable does exactly that. This information will be appended to 13223 * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are 13224 * being used) at all times. 13225 * @type string 13226 * @default <i>Empty string</i> 13227 * 13228 * @dtopt Language 13229 * @name DataTable.defaults.language.infoPostFix 13230 * 13231 * @example 13232 * $(document).ready( function() { 13233 * $('#example').dataTable( { 13234 * "language": { 13235 * "infoPostFix": "All records shown are derived from real information." 13236 * } 13237 * } ); 13238 * } ); 13239 */ 13240 "sInfoPostFix": "", 13241 13242 13243 /** 13244 * This decimal place operator is a little different from the other 13245 * language options since DataTables doesn't output floating point 13246 * numbers, so it won't ever use this for display of a number. Rather, 13247 * what this parameter does is modify the sort methods of the table so 13248 * that numbers which are in a format which has a character other than 13249 * a period (`.`) as a decimal place will be sorted numerically. 13250 * 13251 * Note that numbers with different decimal places cannot be shown in 13252 * the same table and still be sortable, the table must be consistent. 13253 * However, multiple different tables on the page can use different 13254 * decimal place characters. 13255 * @type string 13256 * @default 13257 * 13258 * @dtopt Language 13259 * @name DataTable.defaults.language.decimal 13260 * 13261 * @example 13262 * $(document).ready( function() { 13263 * $('#example').dataTable( { 13264 * "language": { 13265 * "decimal": "," 13266 * "thousands": "." 13267 * } 13268 * } ); 13269 * } ); 13270 */ 13271 "sDecimal": "", 13272 13273 13274 /** 13275 * DataTables has a build in number formatter (`formatNumber`) which is 13276 * used to format large numbers that are used in the table information. 13277 * By default a comma is used, but this can be trivially changed to any 13278 * character you wish with this parameter. 13279 * @type string 13280 * @default , 13281 * 13282 * @dtopt Language 13283 * @name DataTable.defaults.language.thousands 13284 * 13285 * @example 13286 * $(document).ready( function() { 13287 * $('#example').dataTable( { 13288 * "language": { 13289 * "thousands": "'" 13290 * } 13291 * } ); 13292 * } ); 13293 */ 13294 "sThousands": ",", 13295 13296 13297 /** 13298 * Detail the action that will be taken when the drop down menu for the 13299 * pagination length option is changed. The '_MENU_' variable is replaced 13300 * with a default select list of 10, 25, 50 and 100, and can be replaced 13301 * with a custom select box if required. 13302 * @type string 13303 * @default Show _MENU_ entries 13304 * 13305 * @dtopt Language 13306 * @name DataTable.defaults.language.lengthMenu 13307 * 13308 * @example 13309 * // Language change only 13310 * $(document).ready( function() { 13311 * $('#example').dataTable( { 13312 * "language": { 13313 * "lengthMenu": "Display _MENU_ records" 13314 * } 13315 * } ); 13316 * } ); 13317 * 13318 * @example 13319 * // Language and options change 13320 * $(document).ready( function() { 13321 * $('#example').dataTable( { 13322 * "language": { 13323 * "lengthMenu": 'Display <select>'+ 13324 * '<option value="10">10</option>'+ 13325 * '<option value="20">20</option>'+ 13326 * '<option value="30">30</option>'+ 13327 * '<option value="40">40</option>'+ 13328 * '<option value="50">50</option>'+ 13329 * '<option value="-1">All</option>'+ 13330 * '</select> records' 13331 * } 13332 * } ); 13333 * } ); 13334 */ 13335 "sLengthMenu": "Show _MENU_ entries", 13336 13337 13338 /** 13339 * When using Ajax sourced data and during the first draw when DataTables is 13340 * gathering the data, this message is shown in an empty row in the table to 13341 * indicate to the end user the the data is being loaded. Note that this 13342 * parameter is not used when loading data by server-side processing, just 13343 * Ajax sourced data with client-side processing. 13344 * @type string 13345 * @default Loading... 13346 * 13347 * @dtopt Language 13348 * @name DataTable.defaults.language.loadingRecords 13349 * 13350 * @example 13351 * $(document).ready( function() { 13352 * $('#example').dataTable( { 13353 * "language": { 13354 * "loadingRecords": "Please wait - loading..." 13355 * } 13356 * } ); 13357 * } ); 13358 */ 13359 "sLoadingRecords": "Loading...", 13360 13361 13362 /** 13363 * Text which is displayed when the table is processing a user action 13364 * (usually a sort command or similar). 13365 * @type string 13366 * @default Processing... 13367 * 13368 * @dtopt Language 13369 * @name DataTable.defaults.language.processing 13370 * 13371 * @example 13372 * $(document).ready( function() { 13373 * $('#example').dataTable( { 13374 * "language": { 13375 * "processing": "DataTables is currently busy" 13376 * } 13377 * } ); 13378 * } ); 13379 */ 13380 "sProcessing": "Processing...", 13381 13382 13383 /** 13384 * Details the actions that will be taken when the user types into the 13385 * filtering input text box. The variable "_INPUT_", if used in the string, 13386 * is replaced with the HTML text box for the filtering input allowing 13387 * control over where it appears in the string. If "_INPUT_" is not given 13388 * then the input box is appended to the string automatically. 13389 * @type string 13390 * @default Search: 13391 * 13392 * @dtopt Language 13393 * @name DataTable.defaults.language.search 13394 * 13395 * @example 13396 * // Input text box will be appended at the end automatically 13397 * $(document).ready( function() { 13398 * $('#example').dataTable( { 13399 * "language": { 13400 * "search": "Filter records:" 13401 * } 13402 * } ); 13403 * } ); 13404 * 13405 * @example 13406 * // Specify where the filter should appear 13407 * $(document).ready( function() { 13408 * $('#example').dataTable( { 13409 * "language": { 13410 * "search": "Apply filter _INPUT_ to table" 13411 * } 13412 * } ); 13413 * } ); 13414 */ 13415 "sSearch": "Search:", 13416 13417 13418 /** 13419 * Assign a `placeholder` attribute to the search `input` element 13420 * @type string 13421 * @default 13422 * 13423 * @dtopt Language 13424 * @name DataTable.defaults.language.searchPlaceholder 13425 */ 13426 "sSearchPlaceholder": "", 13427 13428 13429 /** 13430 * All of the language information can be stored in a file on the 13431 * server-side, which DataTables will look up if this parameter is passed. 13432 * It must store the URL of the language file, which is in a JSON format, 13433 * and the object has the same properties as the oLanguage object in the 13434 * initialiser object (i.e. the above parameters). Please refer to one of 13435 * the example language files to see how this works in action. 13436 * @type string 13437 * @default <i>Empty string - i.e. disabled</i> 13438 * 13439 * @dtopt Language 13440 * @name DataTable.defaults.language.url 13441 * 13442 * @example 13443 * $(document).ready( function() { 13444 * $('#example').dataTable( { 13445 * "language": { 13446 * "url": "http://www.sprymedia.co.uk/dataTables/lang.txt" 13447 * } 13448 * } ); 13449 * } ); 13450 */ 13451 "sUrl": "", 13452 13453 13454 /** 13455 * Text shown inside the table records when the is no information to be 13456 * displayed after filtering. `emptyTable` is shown when there is simply no 13457 * information in the table at all (regardless of filtering). 13458 * @type string 13459 * @default No matching records found 13460 * 13461 * @dtopt Language 13462 * @name DataTable.defaults.language.zeroRecords 13463 * 13464 * @example 13465 * $(document).ready( function() { 13466 * $('#example').dataTable( { 13467 * "language": { 13468 * "zeroRecords": "No records to display" 13469 * } 13470 * } ); 13471 * } ); 13472 */ 13473 "sZeroRecords": "No matching records found" 13474 }, 13475 13476 13477 /** 13478 * This parameter allows you to have define the global filtering state at 13479 * initialisation time. As an object the `search` parameter must be 13480 * defined, but all other parameters are optional. When `regex` is true, 13481 * the search string will be treated as a regular expression, when false 13482 * (default) it will be treated as a straight string. When `smart` 13483 * DataTables will use it's smart filtering methods (to word match at 13484 * any point in the data), when false this will not be done. 13485 * @namespace 13486 * @extends DataTable.models.oSearch 13487 * 13488 * @dtopt Options 13489 * @name DataTable.defaults.search 13490 * 13491 * @example 13492 * $(document).ready( function() { 13493 * $('#example').dataTable( { 13494 * "search": {"search": "Initial search"} 13495 * } ); 13496 * } ) 13497 */ 13498 "oSearch": $.extend( {}, DataTable.models.oSearch ), 13499 13500 13501 /** 13502 * __Deprecated__ The functionality provided by this parameter has now been 13503 * superseded by that provided through `ajax`, which should be used instead. 13504 * 13505 * By default DataTables will look for the property `data` (or `aaData` for 13506 * compatibility with DataTables 1.9-) when obtaining data from an Ajax 13507 * source or for server-side processing - this parameter allows that 13508 * property to be changed. You can use Javascript dotted object notation to 13509 * get a data source for multiple levels of nesting. 13510 * @type string 13511 * @default data 13512 * 13513 * @dtopt Options 13514 * @dtopt Server-side 13515 * @name DataTable.defaults.ajaxDataProp 13516 * 13517 * @deprecated 1.10. Please use `ajax` for this functionality now. 13518 */ 13519 "sAjaxDataProp": "data", 13520 13521 13522 /** 13523 * __Deprecated__ The functionality provided by this parameter has now been 13524 * superseded by that provided through `ajax`, which should be used instead. 13525 * 13526 * You can instruct DataTables to load data from an external 13527 * source using this parameter (use aData if you want to pass data in you 13528 * already have). Simply provide a url a JSON object can be obtained from. 13529 * @type string 13530 * @default null 13531 * 13532 * @dtopt Options 13533 * @dtopt Server-side 13534 * @name DataTable.defaults.ajaxSource 13535 * 13536 * @deprecated 1.10. Please use `ajax` for this functionality now. 13537 */ 13538 "sAjaxSource": null, 13539 13540 13541 /** 13542 * This initialisation variable allows you to specify exactly where in the 13543 * DOM you want DataTables to inject the various controls it adds to the page 13544 * (for example you might want the pagination controls at the top of the 13545 * table). DIV elements (with or without a custom class) can also be added to 13546 * aid styling. The follow syntax is used: 13547 * <ul> 13548 * <li>The following options are allowed: 13549 * <ul> 13550 * <li>'l' - Length changing</li> 13551 * <li>'f' - Filtering input</li> 13552 * <li>'t' - The table!</li> 13553 * <li>'i' - Information</li> 13554 * <li>'p' - Pagination</li> 13555 * <li>'r' - pRocessing</li> 13556 * </ul> 13557 * </li> 13558 * <li>The following constants are allowed: 13559 * <ul> 13560 * <li>'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li> 13561 * <li>'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li> 13562 * </ul> 13563 * </li> 13564 * <li>The following syntax is expected: 13565 * <ul> 13566 * <li>'<' and '>' - div elements</li> 13567 * <li>'<"class" and '>' - div with a class</li> 13568 * <li>'<"#id" and '>' - div with an ID</li> 13569 * </ul> 13570 * </li> 13571 * <li>Examples: 13572 * <ul> 13573 * <li>'<"wrapper"flipt>'</li> 13574 * <li>'<lf<t>ip>'</li> 13575 * </ul> 13576 * </li> 13577 * </ul> 13578 * @type string 13579 * @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b> 13580 * <"H"lfr>t<"F"ip> <i>(when `jQueryUI` is true)</i> 13581 * 13582 * @dtopt Options 13583 * @name DataTable.defaults.dom 13584 * 13585 * @example 13586 * $(document).ready( function() { 13587 * $('#example').dataTable( { 13588 * "dom": '<"top"i>rt<"bottom"flp><"clear">' 13589 * } ); 13590 * } ); 13591 */ 13592 "sDom": "lfrtip", 13593 13594 13595 /** 13596 * Search delay option. This will throttle full table searches that use the 13597 * DataTables provided search input element (it does not effect calls to 13598 * `dt-api search()`, providing a delay before the search is made. 13599 * @type integer 13600 * @default 0 13601 * 13602 * @dtopt Options 13603 * @name DataTable.defaults.searchDelay 13604 * 13605 * @example 13606 * $(document).ready( function() { 13607 * $('#example').dataTable( { 13608 * "searchDelay": 200 13609 * } ); 13610 * } ) 13611 */ 13612 "searchDelay": null, 13613 13614 13615 /** 13616 * DataTables features six different built-in options for the buttons to 13617 * display for pagination control: 13618 * 13619 * * `numbers` - Page number buttons only 13620 * * `simple` - 'Previous' and 'Next' buttons only 13621 * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers 13622 * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons 13623 * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus page numbers 13624 * * `first_last_numbers` - 'First' and 'Last' buttons, plus page numbers 13625 * 13626 * Further methods can be added using {@link DataTable.ext.oPagination}. 13627 * @type string 13628 * @default simple_numbers 13629 * 13630 * @dtopt Options 13631 * @name DataTable.defaults.pagingType 13632 * 13633 * @example 13634 * $(document).ready( function() { 13635 * $('#example').dataTable( { 13636 * "pagingType": "full_numbers" 13637 * } ); 13638 * } ) 13639 */ 13640 "sPaginationType": "simple_numbers", 13641 13642 13643 /** 13644 * Enable horizontal scrolling. When a table is too wide to fit into a 13645 * certain layout, or you have a large number of columns in the table, you 13646 * can enable x-scrolling to show the table in a viewport, which can be 13647 * scrolled. This property can be `true` which will allow the table to 13648 * scroll horizontally when needed, or any CSS unit, or a number (in which 13649 * case it will be treated as a pixel measurement). Setting as simply `true` 13650 * is recommended. 13651 * @type boolean|string 13652 * @default <i>blank string - i.e. disabled</i> 13653 * 13654 * @dtopt Features 13655 * @name DataTable.defaults.scrollX 13656 * 13657 * @example 13658 * $(document).ready( function() { 13659 * $('#example').dataTable( { 13660 * "scrollX": true, 13661 * "scrollCollapse": true 13662 * } ); 13663 * } ); 13664 */ 13665 "sScrollX": "", 13666 13667 13668 /** 13669 * This property can be used to force a DataTable to use more width than it 13670 * might otherwise do when x-scrolling is enabled. For example if you have a 13671 * table which requires to be well spaced, this parameter is useful for 13672 * "over-sizing" the table, and thus forcing scrolling. This property can by 13673 * any CSS unit, or a number (in which case it will be treated as a pixel 13674 * measurement). 13675 * @type string 13676 * @default <i>blank string - i.e. disabled</i> 13677 * 13678 * @dtopt Options 13679 * @name DataTable.defaults.scrollXInner 13680 * 13681 * @example 13682 * $(document).ready( function() { 13683 * $('#example').dataTable( { 13684 * "scrollX": "100%", 13685 * "scrollXInner": "110%" 13686 * } ); 13687 * } ); 13688 */ 13689 "sScrollXInner": "", 13690 13691 13692 /** 13693 * Enable vertical scrolling. Vertical scrolling will constrain the DataTable 13694 * to the given height, and enable scrolling for any data which overflows the 13695 * current viewport. This can be used as an alternative to paging to display 13696 * a lot of data in a small area (although paging and scrolling can both be 13697 * enabled at the same time). This property can be any CSS unit, or a number 13698 * (in which case it will be treated as a pixel measurement). 13699 * @type string 13700 * @default <i>blank string - i.e. disabled</i> 13701 * 13702 * @dtopt Features 13703 * @name DataTable.defaults.scrollY 13704 * 13705 * @example 13706 * $(document).ready( function() { 13707 * $('#example').dataTable( { 13708 * "scrollY": "200px", 13709 * "paginate": false 13710 * } ); 13711 * } ); 13712 */ 13713 "sScrollY": "", 13714 13715 13716 /** 13717 * __Deprecated__ The functionality provided by this parameter has now been 13718 * superseded by that provided through `ajax`, which should be used instead. 13719 * 13720 * Set the HTTP method that is used to make the Ajax call for server-side 13721 * processing or Ajax sourced data. 13722 * @type string 13723 * @default GET 13724 * 13725 * @dtopt Options 13726 * @dtopt Server-side 13727 * @name DataTable.defaults.serverMethod 13728 * 13729 * @deprecated 1.10. Please use `ajax` for this functionality now. 13730 */ 13731 "sServerMethod": "GET", 13732 13733 13734 /** 13735 * DataTables makes use of renderers when displaying HTML elements for 13736 * a table. These renderers can be added or modified by plug-ins to 13737 * generate suitable mark-up for a site. For example the Bootstrap 13738 * integration plug-in for DataTables uses a paging button renderer to 13739 * display pagination buttons in the mark-up required by Bootstrap. 13740 * 13741 * For further information about the renderers available see 13742 * DataTable.ext.renderer 13743 * @type string|object 13744 * @default null 13745 * 13746 * @name DataTable.defaults.renderer 13747 * 13748 */ 13749 "renderer": null, 13750 13751 13752 /** 13753 * Set the data property name that DataTables should use to get a row's id 13754 * to set as the `id` property in the node. 13755 * @type string 13756 * @default DT_RowId 13757 * 13758 * @name DataTable.defaults.rowId 13759 */ 13760 "rowId": "DT_RowId" 13761 }; 13762 13763 _fnHungarianMap( DataTable.defaults ); 13764 13765 13766 13767 /* 13768 * Developer note - See note in model.defaults.js about the use of Hungarian 13769 * notation and camel case. 13770 */ 13771 13772 /** 13773 * Column options that can be given to DataTables at initialisation time. 13774 * @namespace 13775 */ 13776 DataTable.defaults.column = { 13777 /** 13778 * Define which column(s) an order will occur on for this column. This 13779 * allows a column's ordering to take multiple columns into account when 13780 * doing a sort or use the data from a different column. For example first 13781 * name / last name columns make sense to do a multi-column sort over the 13782 * two columns. 13783 * @type array|int 13784 * @default null <i>Takes the value of the column index automatically</i> 13785 * 13786 * @name DataTable.defaults.column.orderData 13787 * @dtopt Columns 13788 * 13789 * @example 13790 * // Using `columnDefs` 13791 * $(document).ready( function() { 13792 * $('#example').dataTable( { 13793 * "columnDefs": [ 13794 * { "orderData": [ 0, 1 ], "targets": [ 0 ] }, 13795 * { "orderData": [ 1, 0 ], "targets": [ 1 ] }, 13796 * { "orderData": 2, "targets": [ 2 ] } 13797 * ] 13798 * } ); 13799 * } ); 13800 * 13801 * @example 13802 * // Using `columns` 13803 * $(document).ready( function() { 13804 * $('#example').dataTable( { 13805 * "columns": [ 13806 * { "orderData": [ 0, 1 ] }, 13807 * { "orderData": [ 1, 0 ] }, 13808 * { "orderData": 2 }, 13809 * null, 13810 * null 13811 * ] 13812 * } ); 13813 * } ); 13814 */ 13815 "aDataSort": null, 13816 "iDataSort": -1, 13817 13818 13819 /** 13820 * You can control the default ordering direction, and even alter the 13821 * behaviour of the sort handler (i.e. only allow ascending ordering etc) 13822 * using this parameter. 13823 * @type array 13824 * @default [ 'asc', 'desc' ] 13825 * 13826 * @name DataTable.defaults.column.orderSequence 13827 * @dtopt Columns 13828 * 13829 * @example 13830 * // Using `columnDefs` 13831 * $(document).ready( function() { 13832 * $('#example').dataTable( { 13833 * "columnDefs": [ 13834 * { "orderSequence": [ "asc" ], "targets": [ 1 ] }, 13835 * { "orderSequence": [ "desc", "asc", "asc" ], "targets": [ 2 ] }, 13836 * { "orderSequence": [ "desc" ], "targets": [ 3 ] } 13837 * ] 13838 * } ); 13839 * } ); 13840 * 13841 * @example 13842 * // Using `columns` 13843 * $(document).ready( function() { 13844 * $('#example').dataTable( { 13845 * "columns": [ 13846 * null, 13847 * { "orderSequence": [ "asc" ] }, 13848 * { "orderSequence": [ "desc", "asc", "asc" ] }, 13849 * { "orderSequence": [ "desc" ] }, 13850 * null 13851 * ] 13852 * } ); 13853 * } ); 13854 */ 13855 "asSorting": [ 'asc', 'desc' ], 13856 13857 13858 /** 13859 * Enable or disable filtering on the data in this column. 13860 * @type boolean 13861 * @default true 13862 * 13863 * @name DataTable.defaults.column.searchable 13864 * @dtopt Columns 13865 * 13866 * @example 13867 * // Using `columnDefs` 13868 * $(document).ready( function() { 13869 * $('#example').dataTable( { 13870 * "columnDefs": [ 13871 * { "searchable": false, "targets": [ 0 ] } 13872 * ] } ); 13873 * } ); 13874 * 13875 * @example 13876 * // Using `columns` 13877 * $(document).ready( function() { 13878 * $('#example').dataTable( { 13879 * "columns": [ 13880 * { "searchable": false }, 13881 * null, 13882 * null, 13883 * null, 13884 * null 13885 * ] } ); 13886 * } ); 13887 */ 13888 "bSearchable": true, 13889 13890 13891 /** 13892 * Enable or disable ordering on this column. 13893 * @type boolean 13894 * @default true 13895 * 13896 * @name DataTable.defaults.column.orderable 13897 * @dtopt Columns 13898 * 13899 * @example 13900 * // Using `columnDefs` 13901 * $(document).ready( function() { 13902 * $('#example').dataTable( { 13903 * "columnDefs": [ 13904 * { "orderable": false, "targets": [ 0 ] } 13905 * ] } ); 13906 * } ); 13907 * 13908 * @example 13909 * // Using `columns` 13910 * $(document).ready( function() { 13911 * $('#example').dataTable( { 13912 * "columns": [ 13913 * { "orderable": false }, 13914 * null, 13915 * null, 13916 * null, 13917 * null 13918 * ] } ); 13919 * } ); 13920 */ 13921 "bSortable": true, 13922 13923 13924 /** 13925 * Enable or disable the display of this column. 13926 * @type boolean 13927 * @default true 13928 * 13929 * @name DataTable.defaults.column.visible 13930 * @dtopt Columns 13931 * 13932 * @example 13933 * // Using `columnDefs` 13934 * $(document).ready( function() { 13935 * $('#example').dataTable( { 13936 * "columnDefs": [ 13937 * { "visible": false, "targets": [ 0 ] } 13938 * ] } ); 13939 * } ); 13940 * 13941 * @example 13942 * // Using `columns` 13943 * $(document).ready( function() { 13944 * $('#example').dataTable( { 13945 * "columns": [ 13946 * { "visible": false }, 13947 * null, 13948 * null, 13949 * null, 13950 * null 13951 * ] } ); 13952 * } ); 13953 */ 13954 "bVisible": true, 13955 13956 13957 /** 13958 * Developer definable function that is called whenever a cell is created (Ajax source, 13959 * etc) or processed for input (DOM source). This can be used as a compliment to mRender 13960 * allowing you to modify the DOM element (add background colour for example) when the 13961 * element is available. 13962 * @type function 13963 * @param {element} td The TD node that has been created 13964 * @param {*} cellData The Data for the cell 13965 * @param {array|object} rowData The data for the whole row 13966 * @param {int} row The row index for the aoData data store 13967 * @param {int} col The column index for aoColumns 13968 * 13969 * @name DataTable.defaults.column.createdCell 13970 * @dtopt Columns 13971 * 13972 * @example 13973 * $(document).ready( function() { 13974 * $('#example').dataTable( { 13975 * "columnDefs": [ { 13976 * "targets": [3], 13977 * "createdCell": function (td, cellData, rowData, row, col) { 13978 * if ( cellData == "1.7" ) { 13979 * $(td).css('color', 'blue') 13980 * } 13981 * } 13982 * } ] 13983 * }); 13984 * } ); 13985 */ 13986 "fnCreatedCell": null, 13987 13988 13989 /** 13990 * This parameter has been replaced by `data` in DataTables to ensure naming 13991 * consistency. `dataProp` can still be used, as there is backwards 13992 * compatibility in DataTables for this option, but it is strongly 13993 * recommended that you use `data` in preference to `dataProp`. 13994 * @name DataTable.defaults.column.dataProp 13995 */ 13996 13997 13998 /** 13999 * This property can be used to read data from any data source property, 14000 * including deeply nested objects / properties. `data` can be given in a 14001 * number of different ways which effect its behaviour: 14002 * 14003 * * `integer` - treated as an array index for the data source. This is the 14004 * default that DataTables uses (incrementally increased for each column). 14005 * * `string` - read an object property from the data source. There are 14006 * three 'special' options that can be used in the string to alter how 14007 * DataTables reads the data from the source object: 14008 * * `.` - Dotted Javascript notation. Just as you use a `.` in 14009 * Javascript to read from nested objects, so to can the options 14010 * specified in `data`. For example: `browser.version` or 14011 * `browser.name`. If your object parameter name contains a period, use 14012 * `\\` to escape it - i.e. `first\\.name`. 14013 * * `[]` - Array notation. DataTables can automatically combine data 14014 * from and array source, joining the data with the characters provided 14015 * between the two brackets. For example: `name[, ]` would provide a 14016 * comma-space separated list from the source array. If no characters 14017 * are provided between the brackets, the original array source is 14018 * returned. 14019 * * `()` - Function notation. Adding `()` to the end of a parameter will 14020 * execute a function of the name given. For example: `browser()` for a 14021 * simple function on the data source, `browser.version()` for a 14022 * function in a nested property or even `browser().version` to get an 14023 * object property if the function called returns an object. Note that 14024 * function notation is recommended for use in `render` rather than 14025 * `data` as it is much simpler to use as a renderer. 14026 * * `null` - use the original data source for the row rather than plucking 14027 * data directly from it. This action has effects on two other 14028 * initialisation options: 14029 * * `defaultContent` - When null is given as the `data` option and 14030 * `defaultContent` is specified for the column, the value defined by 14031 * `defaultContent` will be used for the cell. 14032 * * `render` - When null is used for the `data` option and the `render` 14033 * option is specified for the column, the whole data source for the 14034 * row is used for the renderer. 14035 * * `function` - the function given will be executed whenever DataTables 14036 * needs to set or get the data for a cell in the column. The function 14037 * takes three parameters: 14038 * * Parameters: 14039 * * `{array|object}` The data source for the row 14040 * * `{string}` The type call data requested - this will be 'set' when 14041 * setting data or 'filter', 'display', 'type', 'sort' or undefined 14042 * when gathering data. Note that when `undefined` is given for the 14043 * type DataTables expects to get the raw data for the object back< 14044 * * `{*}` Data to set when the second parameter is 'set'. 14045 * * Return: 14046 * * The return value from the function is not required when 'set' is 14047 * the type of call, but otherwise the return is what will be used 14048 * for the data requested. 14049 * 14050 * Note that `data` is a getter and setter option. If you just require 14051 * formatting of data for output, you will likely want to use `render` which 14052 * is simply a getter and thus simpler to use. 14053 * 14054 * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The 14055 * name change reflects the flexibility of this property and is consistent 14056 * with the naming of mRender. If 'mDataProp' is given, then it will still 14057 * be used by DataTables, as it automatically maps the old name to the new 14058 * if required. 14059 * 14060 * @type string|int|function|null 14061 * @default null <i>Use automatically calculated column index</i> 14062 * 14063 * @name DataTable.defaults.column.data 14064 * @dtopt Columns 14065 * 14066 * @example 14067 * // Read table data from objects 14068 * // JSON structure for each row: 14069 * // { 14070 * // "engine": {value}, 14071 * // "browser": {value}, 14072 * // "platform": {value}, 14073 * // "version": {value}, 14074 * // "grade": {value} 14075 * // } 14076 * $(document).ready( function() { 14077 * $('#example').dataTable( { 14078 * "ajaxSource": "sources/objects.txt", 14079 * "columns": [ 14080 * { "data": "engine" }, 14081 * { "data": "browser" }, 14082 * { "data": "platform" }, 14083 * { "data": "version" }, 14084 * { "data": "grade" } 14085 * ] 14086 * } ); 14087 * } ); 14088 * 14089 * @example 14090 * // Read information from deeply nested objects 14091 * // JSON structure for each row: 14092 * // { 14093 * // "engine": {value}, 14094 * // "browser": {value}, 14095 * // "platform": { 14096 * // "inner": {value} 14097 * // }, 14098 * // "details": [ 14099 * // {value}, {value} 14100 * // ] 14101 * // } 14102 * $(document).ready( function() { 14103 * $('#example').dataTable( { 14104 * "ajaxSource": "sources/deep.txt", 14105 * "columns": [ 14106 * { "data": "engine" }, 14107 * { "data": "browser" }, 14108 * { "data": "platform.inner" }, 14109 * { "data": "details.0" }, 14110 * { "data": "details.1" } 14111 * ] 14112 * } ); 14113 * } ); 14114 * 14115 * @example 14116 * // Using `data` as a function to provide different information for 14117 * // sorting, filtering and display. In this case, currency (price) 14118 * $(document).ready( function() { 14119 * $('#example').dataTable( { 14120 * "columnDefs": [ { 14121 * "targets": [ 0 ], 14122 * "data": function ( source, type, val ) { 14123 * if (type === 'set') { 14124 * source.price = val; 14125 * // Store the computed dislay and filter values for efficiency 14126 * source.price_display = val=="" ? "" : "$"+numberFormat(val); 14127 * source.price_filter = val=="" ? "" : "$"+numberFormat(val)+" "+val; 14128 * return; 14129 * } 14130 * else if (type === 'display') { 14131 * return source.price_display; 14132 * } 14133 * else if (type === 'filter') { 14134 * return source.price_filter; 14135 * } 14136 * // 'sort', 'type' and undefined all just use the integer 14137 * return source.price; 14138 * } 14139 * } ] 14140 * } ); 14141 * } ); 14142 * 14143 * @example 14144 * // Using default content 14145 * $(document).ready( function() { 14146 * $('#example').dataTable( { 14147 * "columnDefs": [ { 14148 * "targets": [ 0 ], 14149 * "data": null, 14150 * "defaultContent": "Click to edit" 14151 * } ] 14152 * } ); 14153 * } ); 14154 * 14155 * @example 14156 * // Using array notation - outputting a list from an array 14157 * $(document).ready( function() { 14158 * $('#example').dataTable( { 14159 * "columnDefs": [ { 14160 * "targets": [ 0 ], 14161 * "data": "name[, ]" 14162 * } ] 14163 * } ); 14164 * } ); 14165 * 14166 */ 14167 "mData": null, 14168 14169 14170 /** 14171 * This property is the rendering partner to `data` and it is suggested that 14172 * when you want to manipulate data for display (including filtering, 14173 * sorting etc) without altering the underlying data for the table, use this 14174 * property. `render` can be considered to be the the read only companion to 14175 * `data` which is read / write (then as such more complex). Like `data` 14176 * this option can be given in a number of different ways to effect its 14177 * behaviour: 14178 * 14179 * * `integer` - treated as an array index for the data source. This is the 14180 * default that DataTables uses (incrementally increased for each column). 14181 * * `string` - read an object property from the data source. There are 14182 * three 'special' options that can be used in the string to alter how 14183 * DataTables reads the data from the source object: 14184 * * `.` - Dotted Javascript notation. Just as you use a `.` in 14185 * Javascript to read from nested objects, so to can the options 14186 * specified in `data`. For example: `browser.version` or 14187 * `browser.name`. If your object parameter name contains a period, use 14188 * `\\` to escape it - i.e. `first\\.name`. 14189 * * `[]` - Array notation. DataTables can automatically combine data 14190 * from and array source, joining the data with the characters provided 14191 * between the two brackets. For example: `name[, ]` would provide a 14192 * comma-space separated list from the source array. If no characters 14193 * are provided between the brackets, the original array source is 14194 * returned. 14195 * * `()` - Function notation. Adding `()` to the end of a parameter will 14196 * execute a function of the name given. For example: `browser()` for a 14197 * simple function on the data source, `browser.version()` for a 14198 * function in a nested property or even `browser().version` to get an 14199 * object property if the function called returns an object. 14200 * * `object` - use different data for the different data types requested by 14201 * DataTables ('filter', 'display', 'type' or 'sort'). The property names 14202 * of the object is the data type the property refers to and the value can 14203 * defined using an integer, string or function using the same rules as 14204 * `render` normally does. Note that an `_` option _must_ be specified. 14205 * This is the default value to use if you haven't specified a value for 14206 * the data type requested by DataTables. 14207 * * `function` - the function given will be executed whenever DataTables 14208 * needs to set or get the data for a cell in the column. The function 14209 * takes three parameters: 14210 * * Parameters: 14211 * * {array|object} The data source for the row (based on `data`) 14212 * * {string} The type call data requested - this will be 'filter', 14213 * 'display', 'type' or 'sort'. 14214 * * {array|object} The full data source for the row (not based on 14215 * `data`) 14216 * * Return: 14217 * * The return value from the function is what will be used for the 14218 * data requested. 14219 * 14220 * @type string|int|function|object|null 14221 * @default null Use the data source value. 14222 * 14223 * @name DataTable.defaults.column.render 14224 * @dtopt Columns 14225 * 14226 * @example 14227 * // Create a comma separated list from an array of objects 14228 * $(document).ready( function() { 14229 * $('#example').dataTable( { 14230 * "ajaxSource": "sources/deep.txt", 14231 * "columns": [ 14232 * { "data": "engine" }, 14233 * { "data": "browser" }, 14234 * { 14235 * "data": "platform", 14236 * "render": "[, ].name" 14237 * } 14238 * ] 14239 * } ); 14240 * } ); 14241 * 14242 * @example 14243 * // Execute a function to obtain data 14244 * $(document).ready( function() { 14245 * $('#example').dataTable( { 14246 * "columnDefs": [ { 14247 * "targets": [ 0 ], 14248 * "data": null, // Use the full data source object for the renderer's source 14249 * "render": "browserName()" 14250 * } ] 14251 * } ); 14252 * } ); 14253 * 14254 * @example 14255 * // As an object, extracting different data for the different types 14256 * // This would be used with a data source such as: 14257 * // { "phone": 5552368, "phone_filter": "5552368 555-2368", "phone_display": "555-2368" } 14258 * // Here the `phone` integer is used for sorting and type detection, while `phone_filter` 14259 * // (which has both forms) is used for filtering for if a user inputs either format, while 14260 * // the formatted phone number is the one that is shown in the table. 14261 * $(document).ready( function() { 14262 * $('#example').dataTable( { 14263 * "columnDefs": [ { 14264 * "targets": [ 0 ], 14265 * "data": null, // Use the full data source object for the renderer's source 14266 * "render": { 14267 * "_": "phone", 14268 * "filter": "phone_filter", 14269 * "display": "phone_display" 14270 * } 14271 * } ] 14272 * } ); 14273 * } ); 14274 * 14275 * @example 14276 * // Use as a function to create a link from the data source 14277 * $(document).ready( function() { 14278 * $('#example').dataTable( { 14279 * "columnDefs": [ { 14280 * "targets": [ 0 ], 14281 * "data": "download_link", 14282 * "render": function ( data, type, full ) { 14283 * return '<a href="'+data+'">Download</a>'; 14284 * } 14285 * } ] 14286 * } ); 14287 * } ); 14288 */ 14289 "mRender": null, 14290 14291 14292 /** 14293 * Change the cell type created for the column - either TD cells or TH cells. This 14294 * can be useful as TH cells have semantic meaning in the table body, allowing them 14295 * to act as a header for a row (you may wish to add scope='row' to the TH elements). 14296 * @type string 14297 * @default td 14298 * 14299 * @name DataTable.defaults.column.cellType 14300 * @dtopt Columns 14301 * 14302 * @example 14303 * // Make the first column use TH cells 14304 * $(document).ready( function() { 14305 * $('#example').dataTable( { 14306 * "columnDefs": [ { 14307 * "targets": [ 0 ], 14308 * "cellType": "th" 14309 * } ] 14310 * } ); 14311 * } ); 14312 */ 14313 "sCellType": "td", 14314 14315 14316 /** 14317 * Class to give to each cell in this column. 14318 * @type string 14319 * @default <i>Empty string</i> 14320 * 14321 * @name DataTable.defaults.column.class 14322 * @dtopt Columns 14323 * 14324 * @example 14325 * // Using `columnDefs` 14326 * $(document).ready( function() { 14327 * $('#example').dataTable( { 14328 * "columnDefs": [ 14329 * { "class": "my_class", "targets": [ 0 ] } 14330 * ] 14331 * } ); 14332 * } ); 14333 * 14334 * @example 14335 * // Using `columns` 14336 * $(document).ready( function() { 14337 * $('#example').dataTable( { 14338 * "columns": [ 14339 * { "class": "my_class" }, 14340 * null, 14341 * null, 14342 * null, 14343 * null 14344 * ] 14345 * } ); 14346 * } ); 14347 */ 14348 "sClass": "", 14349 14350 /** 14351 * When DataTables calculates the column widths to assign to each column, 14352 * it finds the longest string in each column and then constructs a 14353 * temporary table and reads the widths from that. The problem with this 14354 * is that "mmm" is much wider then "iiii", but the latter is a longer 14355 * string - thus the calculation can go wrong (doing it properly and putting 14356 * it into an DOM object and measuring that is horribly(!) slow). Thus as 14357 * a "work around" we provide this option. It will append its value to the 14358 * text that is found to be the longest string for the column - i.e. padding. 14359 * Generally you shouldn't need this! 14360 * @type string 14361 * @default <i>Empty string<i> 14362 * 14363 * @name DataTable.defaults.column.contentPadding 14364 * @dtopt Columns 14365 * 14366 * @example 14367 * // Using `columns` 14368 * $(document).ready( function() { 14369 * $('#example').dataTable( { 14370 * "columns": [ 14371 * null, 14372 * null, 14373 * null, 14374 * { 14375 * "contentPadding": "mmm" 14376 * } 14377 * ] 14378 * } ); 14379 * } ); 14380 */ 14381 "sContentPadding": "", 14382 14383 14384 /** 14385 * Allows a default value to be given for a column's data, and will be used 14386 * whenever a null data source is encountered (this can be because `data` 14387 * is set to null, or because the data source itself is null). 14388 * @type string 14389 * @default null 14390 * 14391 * @name DataTable.defaults.column.defaultContent 14392 * @dtopt Columns 14393 * 14394 * @example 14395 * // Using `columnDefs` 14396 * $(document).ready( function() { 14397 * $('#example').dataTable( { 14398 * "columnDefs": [ 14399 * { 14400 * "data": null, 14401 * "defaultContent": "Edit", 14402 * "targets": [ -1 ] 14403 * } 14404 * ] 14405 * } ); 14406 * } ); 14407 * 14408 * @example 14409 * // Using `columns` 14410 * $(document).ready( function() { 14411 * $('#example').dataTable( { 14412 * "columns": [ 14413 * null, 14414 * null, 14415 * null, 14416 * { 14417 * "data": null, 14418 * "defaultContent": "Edit" 14419 * } 14420 * ] 14421 * } ); 14422 * } ); 14423 */ 14424 "sDefaultContent": null, 14425 14426 14427 /** 14428 * This parameter is only used in DataTables' server-side processing. It can 14429 * be exceptionally useful to know what columns are being displayed on the 14430 * client side, and to map these to database fields. When defined, the names 14431 * also allow DataTables to reorder information from the server if it comes 14432 * back in an unexpected order (i.e. if you switch your columns around on the 14433 * client-side, your server-side code does not also need updating). 14434 * @type string 14435 * @default <i>Empty string</i> 14436 * 14437 * @name DataTable.defaults.column.name 14438 * @dtopt Columns 14439 * 14440 * @example 14441 * // Using `columnDefs` 14442 * $(document).ready( function() { 14443 * $('#example').dataTable( { 14444 * "columnDefs": [ 14445 * { "name": "engine", "targets": [ 0 ] }, 14446 * { "name": "browser", "targets": [ 1 ] }, 14447 * { "name": "platform", "targets": [ 2 ] }, 14448 * { "name": "version", "targets": [ 3 ] }, 14449 * { "name": "grade", "targets": [ 4 ] } 14450 * ] 14451 * } ); 14452 * } ); 14453 * 14454 * @example 14455 * // Using `columns` 14456 * $(document).ready( function() { 14457 * $('#example').dataTable( { 14458 * "columns": [ 14459 * { "name": "engine" }, 14460 * { "name": "browser" }, 14461 * { "name": "platform" }, 14462 * { "name": "version" }, 14463 * { "name": "grade" } 14464 * ] 14465 * } ); 14466 * } ); 14467 */ 14468 "sName": "", 14469 14470 14471 /** 14472 * Defines a data source type for the ordering which can be used to read 14473 * real-time information from the table (updating the internally cached 14474 * version) prior to ordering. This allows ordering to occur on user 14475 * editable elements such as form inputs. 14476 * @type string 14477 * @default std 14478 * 14479 * @name DataTable.defaults.column.orderDataType 14480 * @dtopt Columns 14481 * 14482 * @example 14483 * // Using `columnDefs` 14484 * $(document).ready( function() { 14485 * $('#example').dataTable( { 14486 * "columnDefs": [ 14487 * { "orderDataType": "dom-text", "targets": [ 2, 3 ] }, 14488 * { "type": "numeric", "targets": [ 3 ] }, 14489 * { "orderDataType": "dom-select", "targets": [ 4 ] }, 14490 * { "orderDataType": "dom-checkbox", "targets": [ 5 ] } 14491 * ] 14492 * } ); 14493 * } ); 14494 * 14495 * @example 14496 * // Using `columns` 14497 * $(document).ready( function() { 14498 * $('#example').dataTable( { 14499 * "columns": [ 14500 * null, 14501 * null, 14502 * { "orderDataType": "dom-text" }, 14503 * { "orderDataType": "dom-text", "type": "numeric" }, 14504 * { "orderDataType": "dom-select" }, 14505 * { "orderDataType": "dom-checkbox" } 14506 * ] 14507 * } ); 14508 * } ); 14509 */ 14510 "sSortDataType": "std", 14511 14512 14513 /** 14514 * The title of this column. 14515 * @type string 14516 * @default null <i>Derived from the 'TH' value for this column in the 14517 * original HTML table.</i> 14518 * 14519 * @name DataTable.defaults.column.title 14520 * @dtopt Columns 14521 * 14522 * @example 14523 * // Using `columnDefs` 14524 * $(document).ready( function() { 14525 * $('#example').dataTable( { 14526 * "columnDefs": [ 14527 * { "title": "My column title", "targets": [ 0 ] } 14528 * ] 14529 * } ); 14530 * } ); 14531 * 14532 * @example 14533 * // Using `columns` 14534 * $(document).ready( function() { 14535 * $('#example').dataTable( { 14536 * "columns": [ 14537 * { "title": "My column title" }, 14538 * null, 14539 * null, 14540 * null, 14541 * null 14542 * ] 14543 * } ); 14544 * } ); 14545 */ 14546 "sTitle": null, 14547 14548 14549 /** 14550 * The type allows you to specify how the data for this column will be 14551 * ordered. Four types (string, numeric, date and html (which will strip 14552 * HTML tags before ordering)) are currently available. Note that only date 14553 * formats understood by Javascript's Date() object will be accepted as type 14554 * date. For example: "Mar 26, 2008 5:03 PM". May take the values: 'string', 14555 * 'numeric', 'date' or 'html' (by default). Further types can be adding 14556 * through plug-ins. 14557 * @type string 14558 * @default null <i>Auto-detected from raw data</i> 14559 * 14560 * @name DataTable.defaults.column.type 14561 * @dtopt Columns 14562 * 14563 * @example 14564 * // Using `columnDefs` 14565 * $(document).ready( function() { 14566 * $('#example').dataTable( { 14567 * "columnDefs": [ 14568 * { "type": "html", "targets": [ 0 ] } 14569 * ] 14570 * } ); 14571 * } ); 14572 * 14573 * @example 14574 * // Using `columns` 14575 * $(document).ready( function() { 14576 * $('#example').dataTable( { 14577 * "columns": [ 14578 * { "type": "html" }, 14579 * null, 14580 * null, 14581 * null, 14582 * null 14583 * ] 14584 * } ); 14585 * } ); 14586 */ 14587 "sType": null, 14588 14589 14590 /** 14591 * Defining the width of the column, this parameter may take any CSS value 14592 * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not 14593 * been given a specific width through this interface ensuring that the table 14594 * remains readable. 14595 * @type string 14596 * @default null <i>Automatic</i> 14597 * 14598 * @name DataTable.defaults.column.width 14599 * @dtopt Columns 14600 * 14601 * @example 14602 * // Using `columnDefs` 14603 * $(document).ready( function() { 14604 * $('#example').dataTable( { 14605 * "columnDefs": [ 14606 * { "width": "20%", "targets": [ 0 ] } 14607 * ] 14608 * } ); 14609 * } ); 14610 * 14611 * @example 14612 * // Using `columns` 14613 * $(document).ready( function() { 14614 * $('#example').dataTable( { 14615 * "columns": [ 14616 * { "width": "20%" }, 14617 * null, 14618 * null, 14619 * null, 14620 * null 14621 * ] 14622 * } ); 14623 * } ); 14624 */ 14625 "sWidth": null 14626 }; 14627 14628 _fnHungarianMap( DataTable.defaults.column ); 14629 14630 14631 14632 /** 14633 * DataTables settings object - this holds all the information needed for a 14634 * given table, including configuration, data and current application of the 14635 * table options. DataTables does not have a single instance for each DataTable 14636 * with the settings attached to that instance, but rather instances of the 14637 * DataTable "class" are created on-the-fly as needed (typically by a 14638 * $().dataTable() call) and the settings object is then applied to that 14639 * instance. 14640 * 14641 * Note that this object is related to {@link DataTable.defaults} but this 14642 * one is the internal data store for DataTables's cache of columns. It should 14643 * NOT be manipulated outside of DataTables. Any configuration should be done 14644 * through the initialisation options. 14645 * @namespace 14646 * @todo Really should attach the settings object to individual instances so we 14647 * don't need to create new instances on each $().dataTable() call (if the 14648 * table already exists). It would also save passing oSettings around and 14649 * into every single function. However, this is a very significant 14650 * architecture change for DataTables and will almost certainly break 14651 * backwards compatibility with older installations. This is something that 14652 * will be done in 2.0. 14653 */ 14654 DataTable.models.oSettings = { 14655 /** 14656 * Primary features of DataTables and their enablement state. 14657 * @namespace 14658 */ 14659 "oFeatures": { 14660 14661 /** 14662 * Flag to say if DataTables should automatically try to calculate the 14663 * optimum table and columns widths (true) or not (false). 14664 * Note that this parameter will be set by the initialisation routine. To 14665 * set a default use {@link DataTable.defaults}. 14666 * @type boolean 14667 */ 14668 "bAutoWidth": null, 14669 14670 /** 14671 * Delay the creation of TR and TD elements until they are actually 14672 * needed by a driven page draw. This can give a significant speed 14673 * increase for Ajax source and Javascript source data, but makes no 14674 * difference at all fro DOM and server-side processing tables. 14675 * Note that this parameter will be set by the initialisation routine. To 14676 * set a default use {@link DataTable.defaults}. 14677 * @type boolean 14678 */ 14679 "bDeferRender": null, 14680 14681 /** 14682 * Enable filtering on the table or not. Note that if this is disabled 14683 * then there is no filtering at all on the table, including fnFilter. 14684 * To just remove the filtering input use sDom and remove the 'f' option. 14685 * Note that this parameter will be set by the initialisation routine. To 14686 * set a default use {@link DataTable.defaults}. 14687 * @type boolean 14688 */ 14689 "bFilter": null, 14690 14691 /** 14692 * Table information element (the 'Showing x of y records' div) enable 14693 * flag. 14694 * Note that this parameter will be set by the initialisation routine. To 14695 * set a default use {@link DataTable.defaults}. 14696 * @type boolean 14697 */ 14698 "bInfo": null, 14699 14700 /** 14701 * Present a user control allowing the end user to change the page size 14702 * when pagination is enabled. 14703 * Note that this parameter will be set by the initialisation routine. To 14704 * set a default use {@link DataTable.defaults}. 14705 * @type boolean 14706 */ 14707 "bLengthChange": null, 14708 14709 /** 14710 * Pagination enabled or not. Note that if this is disabled then length 14711 * changing must also be disabled. 14712 * Note that this parameter will be set by the initialisation routine. To 14713 * set a default use {@link DataTable.defaults}. 14714 * @type boolean 14715 */ 14716 "bPaginate": null, 14717 14718 /** 14719 * Processing indicator enable flag whenever DataTables is enacting a 14720 * user request - typically an Ajax request for server-side processing. 14721 * Note that this parameter will be set by the initialisation routine. To 14722 * set a default use {@link DataTable.defaults}. 14723 * @type boolean 14724 */ 14725 "bProcessing": null, 14726 14727 /** 14728 * Server-side processing enabled flag - when enabled DataTables will 14729 * get all data from the server for every draw - there is no filtering, 14730 * sorting or paging done on the client-side. 14731 * Note that this parameter will be set by the initialisation routine. To 14732 * set a default use {@link DataTable.defaults}. 14733 * @type boolean 14734 */ 14735 "bServerSide": null, 14736 14737 /** 14738 * Sorting enablement flag. 14739 * Note that this parameter will be set by the initialisation routine. To 14740 * set a default use {@link DataTable.defaults}. 14741 * @type boolean 14742 */ 14743 "bSort": null, 14744 14745 /** 14746 * Multi-column sorting 14747 * Note that this parameter will be set by the initialisation routine. To 14748 * set a default use {@link DataTable.defaults}. 14749 * @type boolean 14750 */ 14751 "bSortMulti": null, 14752 14753 /** 14754 * Apply a class to the columns which are being sorted to provide a 14755 * visual highlight or not. This can slow things down when enabled since 14756 * there is a lot of DOM interaction. 14757 * Note that this parameter will be set by the initialisation routine. To 14758 * set a default use {@link DataTable.defaults}. 14759 * @type boolean 14760 */ 14761 "bSortClasses": null, 14762 14763 /** 14764 * State saving enablement flag. 14765 * Note that this parameter will be set by the initialisation routine. To 14766 * set a default use {@link DataTable.defaults}. 14767 * @type boolean 14768 */ 14769 "bStateSave": null 14770 }, 14771 14772 14773 /** 14774 * Scrolling settings for a table. 14775 * @namespace 14776 */ 14777 "oScroll": { 14778 /** 14779 * When the table is shorter in height than sScrollY, collapse the 14780 * table container down to the height of the table (when true). 14781 * Note that this parameter will be set by the initialisation routine. To 14782 * set a default use {@link DataTable.defaults}. 14783 * @type boolean 14784 */ 14785 "bCollapse": null, 14786 14787 /** 14788 * Width of the scrollbar for the web-browser's platform. Calculated 14789 * during table initialisation. 14790 * @type int 14791 * @default 0 14792 */ 14793 "iBarWidth": 0, 14794 14795 /** 14796 * Viewport width for horizontal scrolling. Horizontal scrolling is 14797 * disabled if an empty string. 14798 * Note that this parameter will be set by the initialisation routine. To 14799 * set a default use {@link DataTable.defaults}. 14800 * @type string 14801 */ 14802 "sX": null, 14803 14804 /** 14805 * Width to expand the table to when using x-scrolling. Typically you 14806 * should not need to use this. 14807 * Note that this parameter will be set by the initialisation routine. To 14808 * set a default use {@link DataTable.defaults}. 14809 * @type string 14810 * @deprecated 14811 */ 14812 "sXInner": null, 14813 14814 /** 14815 * Viewport height for vertical scrolling. Vertical scrolling is disabled 14816 * if an empty string. 14817 * Note that this parameter will be set by the initialisation routine. To 14818 * set a default use {@link DataTable.defaults}. 14819 * @type string 14820 */ 14821 "sY": null 14822 }, 14823 14824 /** 14825 * Language information for the table. 14826 * @namespace 14827 * @extends DataTable.defaults.oLanguage 14828 */ 14829 "oLanguage": { 14830 /** 14831 * Information callback function. See 14832 * {@link DataTable.defaults.fnInfoCallback} 14833 * @type function 14834 * @default null 14835 */ 14836 "fnInfoCallback": null 14837 }, 14838 14839 /** 14840 * Browser support parameters 14841 * @namespace 14842 */ 14843 "oBrowser": { 14844 /** 14845 * Indicate if the browser incorrectly calculates width:100% inside a 14846 * scrolling element (IE6/7) 14847 * @type boolean 14848 * @default false 14849 */ 14850 "bScrollOversize": false, 14851 14852 /** 14853 * Determine if the vertical scrollbar is on the right or left of the 14854 * scrolling container - needed for rtl language layout, although not 14855 * all browsers move the scrollbar (Safari). 14856 * @type boolean 14857 * @default false 14858 */ 14859 "bScrollbarLeft": false, 14860 14861 /** 14862 * Flag for if `getBoundingClientRect` is fully supported or not 14863 * @type boolean 14864 * @default false 14865 */ 14866 "bBounding": false, 14867 14868 /** 14869 * Browser scrollbar width 14870 * @type integer 14871 * @default 0 14872 */ 14873 "barWidth": 0 14874 }, 14875 14876 14877 "ajax": null, 14878 14879 14880 /** 14881 * Array referencing the nodes which are used for the features. The 14882 * parameters of this object match what is allowed by sDom - i.e. 14883 * <ul> 14884 * <li>'l' - Length changing</li> 14885 * <li>'f' - Filtering input</li> 14886 * <li>'t' - The table!</li> 14887 * <li>'i' - Information</li> 14888 * <li>'p' - Pagination</li> 14889 * <li>'r' - pRocessing</li> 14890 * </ul> 14891 * @type array 14892 * @default [] 14893 */ 14894 "aanFeatures": [], 14895 14896 /** 14897 * Store data information - see {@link DataTable.models.oRow} for detailed 14898 * information. 14899 * @type array 14900 * @default [] 14901 */ 14902 "aoData": [], 14903 14904 /** 14905 * Array of indexes which are in the current display (after filtering etc) 14906 * @type array 14907 * @default [] 14908 */ 14909 "aiDisplay": [], 14910 14911 /** 14912 * Array of indexes for display - no filtering 14913 * @type array 14914 * @default [] 14915 */ 14916 "aiDisplayMaster": [], 14917 14918 /** 14919 * Map of row ids to data indexes 14920 * @type object 14921 * @default {} 14922 */ 14923 "aIds": {}, 14924 14925 /** 14926 * Store information about each column that is in use 14927 * @type array 14928 * @default [] 14929 */ 14930 "aoColumns": [], 14931 14932 /** 14933 * Store information about the table's header 14934 * @type array 14935 * @default [] 14936 */ 14937 "aoHeader": [], 14938 14939 /** 14940 * Store information about the table's footer 14941 * @type array 14942 * @default [] 14943 */ 14944 "aoFooter": [], 14945 14946 /** 14947 * Store the applied global search information in case we want to force a 14948 * research or compare the old search to a new one. 14949 * Note that this parameter will be set by the initialisation routine. To 14950 * set a default use {@link DataTable.defaults}. 14951 * @namespace 14952 * @extends DataTable.models.oSearch 14953 */ 14954 "oPreviousSearch": {}, 14955 14956 /** 14957 * Store the applied search for each column - see 14958 * {@link DataTable.models.oSearch} for the format that is used for the 14959 * filtering information for each column. 14960 * @type array 14961 * @default [] 14962 */ 14963 "aoPreSearchCols": [], 14964 14965 /** 14966 * Sorting that is applied to the table. Note that the inner arrays are 14967 * used in the following manner: 14968 * <ul> 14969 * <li>Index 0 - column number</li> 14970 * <li>Index 1 - current sorting direction</li> 14971 * </ul> 14972 * Note that this parameter will be set by the initialisation routine. To 14973 * set a default use {@link DataTable.defaults}. 14974 * @type array 14975 * @todo These inner arrays should really be objects 14976 */ 14977 "aaSorting": null, 14978 14979 /** 14980 * Sorting that is always applied to the table (i.e. prefixed in front of 14981 * aaSorting). 14982 * Note that this parameter will be set by the initialisation routine. To 14983 * set a default use {@link DataTable.defaults}. 14984 * @type array 14985 * @default [] 14986 */ 14987 "aaSortingFixed": [], 14988 14989 /** 14990 * Classes to use for the striping of a table. 14991 * Note that this parameter will be set by the initialisation routine. To 14992 * set a default use {@link DataTable.defaults}. 14993 * @type array 14994 * @default [] 14995 */ 14996 "asStripeClasses": null, 14997 14998 /** 14999 * If restoring a table - we should restore its striping classes as well 15000 * @type array 15001 * @default [] 15002 */ 15003 "asDestroyStripes": [], 15004 15005 /** 15006 * If restoring a table - we should restore its width 15007 * @type int 15008 * @default 0 15009 */ 15010 "sDestroyWidth": 0, 15011 15012 /** 15013 * Callback functions array for every time a row is inserted (i.e. on a draw). 15014 * @type array 15015 * @default [] 15016 */ 15017 "aoRowCallback": [], 15018 15019 /** 15020 * Callback functions for the header on each draw. 15021 * @type array 15022 * @default [] 15023 */ 15024 "aoHeaderCallback": [], 15025 15026 /** 15027 * Callback function for the footer on each draw. 15028 * @type array 15029 * @default [] 15030 */ 15031 "aoFooterCallback": [], 15032 15033 /** 15034 * Array of callback functions for draw callback functions 15035 * @type array 15036 * @default [] 15037 */ 15038 "aoDrawCallback": [], 15039 15040 /** 15041 * Array of callback functions for row created function 15042 * @type array 15043 * @default [] 15044 */ 15045 "aoRowCreatedCallback": [], 15046 15047 /** 15048 * Callback functions for just before the table is redrawn. A return of 15049 * false will be used to cancel the draw. 15050 * @type array 15051 * @default [] 15052 */ 15053 "aoPreDrawCallback": [], 15054 15055 /** 15056 * Callback functions for when the table has been initialised. 15057 * @type array 15058 * @default [] 15059 */ 15060 "aoInitComplete": [], 15061 15062 15063 /** 15064 * Callbacks for modifying the settings to be stored for state saving, prior to 15065 * saving state. 15066 * @type array 15067 * @default [] 15068 */ 15069 "aoStateSaveParams": [], 15070 15071 /** 15072 * Callbacks for modifying the settings that have been stored for state saving 15073 * prior to using the stored values to restore the state. 15074 * @type array 15075 * @default [] 15076 */ 15077 "aoStateLoadParams": [], 15078 15079 /** 15080 * Callbacks for operating on the settings object once the saved state has been 15081 * loaded 15082 * @type array 15083 * @default [] 15084 */ 15085 "aoStateLoaded": [], 15086 15087 /** 15088 * Cache the table ID for quick access 15089 * @type string 15090 * @default <i>Empty string</i> 15091 */ 15092 "sTableId": "", 15093 15094 /** 15095 * The TABLE node for the main table 15096 * @type node 15097 * @default null 15098 */ 15099 "nTable": null, 15100 15101 /** 15102 * Permanent ref to the thead element 15103 * @type node 15104 * @default null 15105 */ 15106 "nTHead": null, 15107 15108 /** 15109 * Permanent ref to the tfoot element - if it exists 15110 * @type node 15111 * @default null 15112 */ 15113 "nTFoot": null, 15114 15115 /** 15116 * Permanent ref to the tbody element 15117 * @type node 15118 * @default null 15119 */ 15120 "nTBody": null, 15121 15122 /** 15123 * Cache the wrapper node (contains all DataTables controlled elements) 15124 * @type node 15125 * @default null 15126 */ 15127 "nTableWrapper": null, 15128 15129 /** 15130 * Indicate if when using server-side processing the loading of data 15131 * should be deferred until the second draw. 15132 * Note that this parameter will be set by the initialisation routine. To 15133 * set a default use {@link DataTable.defaults}. 15134 * @type boolean 15135 * @default false 15136 */ 15137 "bDeferLoading": false, 15138 15139 /** 15140 * Indicate if all required information has been read in 15141 * @type boolean 15142 * @default false 15143 */ 15144 "bInitialised": false, 15145 15146 /** 15147 * Information about open rows. Each object in the array has the parameters 15148 * 'nTr' and 'nParent' 15149 * @type array 15150 * @default [] 15151 */ 15152 "aoOpenRows": [], 15153 15154 /** 15155 * Dictate the positioning of DataTables' control elements - see 15156 * {@link DataTable.model.oInit.sDom}. 15157 * Note that this parameter will be set by the initialisation routine. To 15158 * set a default use {@link DataTable.defaults}. 15159 * @type string 15160 * @default null 15161 */ 15162 "sDom": null, 15163 15164 /** 15165 * Search delay (in mS) 15166 * @type integer 15167 * @default null 15168 */ 15169 "searchDelay": null, 15170 15171 /** 15172 * Which type of pagination should be used. 15173 * Note that this parameter will be set by the initialisation routine. To 15174 * set a default use {@link DataTable.defaults}. 15175 * @type string 15176 * @default two_button 15177 */ 15178 "sPaginationType": "two_button", 15179 15180 /** 15181 * The state duration (for `stateSave`) in seconds. 15182 * Note that this parameter will be set by the initialisation routine. To 15183 * set a default use {@link DataTable.defaults}. 15184 * @type int 15185 * @default 0 15186 */ 15187 "iStateDuration": 0, 15188 15189 /** 15190 * Array of callback functions for state saving. Each array element is an 15191 * object with the following parameters: 15192 * <ul> 15193 * <li>function:fn - function to call. Takes two parameters, oSettings 15194 * and the JSON string to save that has been thus far created. Returns 15195 * a JSON string to be inserted into a json object 15196 * (i.e. '"param": [ 0, 1, 2]')</li> 15197 * <li>string:sName - name of callback</li> 15198 * </ul> 15199 * @type array 15200 * @default [] 15201 */ 15202 "aoStateSave": [], 15203 15204 /** 15205 * Array of callback functions for state loading. Each array element is an 15206 * object with the following parameters: 15207 * <ul> 15208 * <li>function:fn - function to call. Takes two parameters, oSettings 15209 * and the object stored. May return false to cancel state loading</li> 15210 * <li>string:sName - name of callback</li> 15211 * </ul> 15212 * @type array 15213 * @default [] 15214 */ 15215 "aoStateLoad": [], 15216 15217 /** 15218 * State that was saved. Useful for back reference 15219 * @type object 15220 * @default null 15221 */ 15222 "oSavedState": null, 15223 15224 /** 15225 * State that was loaded. Useful for back reference 15226 * @type object 15227 * @default null 15228 */ 15229 "oLoadedState": null, 15230 15231 /** 15232 * Source url for AJAX data for the table. 15233 * Note that this parameter will be set by the initialisation routine. To 15234 * set a default use {@link DataTable.defaults}. 15235 * @type string 15236 * @default null 15237 */ 15238 "sAjaxSource": null, 15239 15240 /** 15241 * Property from a given object from which to read the table data from. This 15242 * can be an empty string (when not server-side processing), in which case 15243 * it is assumed an an array is given directly. 15244 * Note that this parameter will be set by the initialisation routine. To 15245 * set a default use {@link DataTable.defaults}. 15246 * @type string 15247 */ 15248 "sAjaxDataProp": null, 15249 15250 /** 15251 * Note if draw should be blocked while getting data 15252 * @type boolean 15253 * @default true 15254 */ 15255 "bAjaxDataGet": true, 15256 15257 /** 15258 * The last jQuery XHR object that was used for server-side data gathering. 15259 * This can be used for working with the XHR information in one of the 15260 * callbacks 15261 * @type object 15262 * @default null 15263 */ 15264 "jqXHR": null, 15265 15266 /** 15267 * JSON returned from the server in the last Ajax request 15268 * @type object 15269 * @default undefined 15270 */ 15271 "json": undefined, 15272 15273 /** 15274 * Data submitted as part of the last Ajax request 15275 * @type object 15276 * @default undefined 15277 */ 15278 "oAjaxData": undefined, 15279 15280 /** 15281 * Function to get the server-side data. 15282 * Note that this parameter will be set by the initialisation routine. To 15283 * set a default use {@link DataTable.defaults}. 15284 * @type function 15285 */ 15286 "fnServerData": null, 15287 15288 /** 15289 * Functions which are called prior to sending an Ajax request so extra 15290 * parameters can easily be sent to the server 15291 * @type array 15292 * @default [] 15293 */ 15294 "aoServerParams": [], 15295 15296 /** 15297 * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if 15298 * required). 15299 * Note that this parameter will be set by the initialisation routine. To 15300 * set a default use {@link DataTable.defaults}. 15301 * @type string 15302 */ 15303 "sServerMethod": null, 15304 15305 /** 15306 * Format numbers for display. 15307 * Note that this parameter will be set by the initialisation routine. To 15308 * set a default use {@link DataTable.defaults}. 15309 * @type function 15310 */ 15311 "fnFormatNumber": null, 15312 15313 /** 15314 * List of options that can be used for the user selectable length menu. 15315 * Note that this parameter will be set by the initialisation routine. To 15316 * set a default use {@link DataTable.defaults}. 15317 * @type array 15318 * @default [] 15319 */ 15320 "aLengthMenu": null, 15321 15322 /** 15323 * Counter for the draws that the table does. Also used as a tracker for 15324 * server-side processing 15325 * @type int 15326 * @default 0 15327 */ 15328 "iDraw": 0, 15329 15330 /** 15331 * Indicate if a redraw is being done - useful for Ajax 15332 * @type boolean 15333 * @default false 15334 */ 15335 "bDrawing": false, 15336 15337 /** 15338 * Draw index (iDraw) of the last error when parsing the returned data 15339 * @type int 15340 * @default -1 15341 */ 15342 "iDrawError": -1, 15343 15344 /** 15345 * Paging display length 15346 * @type int 15347 * @default 10 15348 */ 15349 "_iDisplayLength": 10, 15350 15351 /** 15352 * Paging start point - aiDisplay index 15353 * @type int 15354 * @default 0 15355 */ 15356 "_iDisplayStart": 0, 15357 15358 /** 15359 * Server-side processing - number of records in the result set 15360 * (i.e. before filtering), Use fnRecordsTotal rather than 15361 * this property to get the value of the number of records, regardless of 15362 * the server-side processing setting. 15363 * @type int 15364 * @default 0 15365 * @private 15366 */ 15367 "_iRecordsTotal": 0, 15368 15369 /** 15370 * Server-side processing - number of records in the current display set 15371 * (i.e. after filtering). Use fnRecordsDisplay rather than 15372 * this property to get the value of the number of records, regardless of 15373 * the server-side processing setting. 15374 * @type boolean 15375 * @default 0 15376 * @private 15377 */ 15378 "_iRecordsDisplay": 0, 15379 15380 /** 15381 * The classes to use for the table 15382 * @type object 15383 * @default {} 15384 */ 15385 "oClasses": {}, 15386 15387 /** 15388 * Flag attached to the settings object so you can check in the draw 15389 * callback if filtering has been done in the draw. Deprecated in favour of 15390 * events. 15391 * @type boolean 15392 * @default false 15393 * @deprecated 15394 */ 15395 "bFiltered": false, 15396 15397 /** 15398 * Flag attached to the settings object so you can check in the draw 15399 * callback if sorting has been done in the draw. Deprecated in favour of 15400 * events. 15401 * @type boolean 15402 * @default false 15403 * @deprecated 15404 */ 15405 "bSorted": false, 15406 15407 /** 15408 * Indicate that if multiple rows are in the header and there is more than 15409 * one unique cell per column, if the top one (true) or bottom one (false) 15410 * should be used for sorting / title by DataTables. 15411 * Note that this parameter will be set by the initialisation routine. To 15412 * set a default use {@link DataTable.defaults}. 15413 * @type boolean 15414 */ 15415 "bSortCellsTop": null, 15416 15417 /** 15418 * Initialisation object that is used for the table 15419 * @type object 15420 * @default null 15421 */ 15422 "oInit": null, 15423 15424 /** 15425 * Destroy callback functions - for plug-ins to attach themselves to the 15426 * destroy so they can clean up markup and events. 15427 * @type array 15428 * @default [] 15429 */ 15430 "aoDestroyCallback": [], 15431 15432 15433 /** 15434 * Get the number of records in the current record set, before filtering 15435 * @type function 15436 */ 15437 "fnRecordsTotal": function () 15438 { 15439 return _fnDataSource( this ) == 'ssp' ? 15440 this._iRecordsTotal * 1 : 15441 this.aiDisplayMaster.length; 15442 }, 15443 15444 /** 15445 * Get the number of records in the current record set, after filtering 15446 * @type function 15447 */ 15448 "fnRecordsDisplay": function () 15449 { 15450 return _fnDataSource( this ) == 'ssp' ? 15451 this._iRecordsDisplay * 1 : 15452 this.aiDisplay.length; 15453 }, 15454 15455 /** 15456 * Get the display end point - aiDisplay index 15457 * @type function 15458 */ 15459 "fnDisplayEnd": function () 15460 { 15461 var 15462 len = this._iDisplayLength, 15463 start = this._iDisplayStart, 15464 calc = start + len, 15465 records = this.aiDisplay.length, 15466 features = this.oFeatures, 15467 paginate = features.bPaginate; 15468 15469 if ( features.bServerSide ) { 15470 return paginate === false || len === -1 ? 15471 start + records : 15472 Math.min( start+len, this._iRecordsDisplay ); 15473 } 15474 else { 15475 return ! paginate || calc>records || len===-1 ? 15476 records : 15477 calc; 15478 } 15479 }, 15480 15481 /** 15482 * The DataTables object for this table 15483 * @type object 15484 * @default null 15485 */ 15486 "oInstance": null, 15487 15488 /** 15489 * Unique identifier for each instance of the DataTables object. If there 15490 * is an ID on the table node, then it takes that value, otherwise an 15491 * incrementing internal counter is used. 15492 * @type string 15493 * @default null 15494 */ 15495 "sInstance": null, 15496 15497 /** 15498 * tabindex attribute value that is added to DataTables control elements, allowing 15499 * keyboard navigation of the table and its controls. 15500 */ 15501 "iTabIndex": 0, 15502 15503 /** 15504 * DIV container for the footer scrolling table if scrolling 15505 */ 15506 "nScrollHead": null, 15507 15508 /** 15509 * DIV container for the footer scrolling table if scrolling 15510 */ 15511 "nScrollFoot": null, 15512 15513 /** 15514 * Last applied sort 15515 * @type array 15516 * @default [] 15517 */ 15518 "aLastSort": [], 15519 15520 /** 15521 * Stored plug-in instances 15522 * @type object 15523 * @default {} 15524 */ 15525 "oPlugins": {}, 15526 15527 /** 15528 * Function used to get a row's id from the row's data 15529 * @type function 15530 * @default null 15531 */ 15532 "rowIdFn": null, 15533 15534 /** 15535 * Data location where to store a row's id 15536 * @type string 15537 * @default null 15538 */ 15539 "rowId": null 15540 }; 15541 15542 /** 15543 * Extension object for DataTables that is used to provide all extension 15544 * options. 15545 * 15546 * Note that the `DataTable.ext` object is available through 15547 * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is 15548 * also aliased to `jQuery.fn.dataTableExt` for historic reasons. 15549 * @namespace 15550 * @extends DataTable.models.ext 15551 */ 15552 15553 15554 /** 15555 * DataTables extensions 15556 * 15557 * This namespace acts as a collection area for plug-ins that can be used to 15558 * extend DataTables capabilities. Indeed many of the build in methods 15559 * use this method to provide their own capabilities (sorting methods for 15560 * example). 15561 * 15562 * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy 15563 * reasons 15564 * 15565 * @namespace 15566 */ 15567 DataTable.ext = _ext = { 15568 /** 15569 * Buttons. For use with the Buttons extension for DataTables. This is 15570 * defined here so other extensions can define buttons regardless of load 15571 * order. It is _not_ used by DataTables core. 15572 * 15573 * @type object 15574 * @default {} 15575 */ 15576 buttons: {}, 15577 15578 15579 /** 15580 * Element class names 15581 * 15582 * @type object 15583 * @default {} 15584 */ 15585 classes: {}, 15586 15587 15588 /** 15589 * DataTables build type (expanded by the download builder) 15590 * 15591 * @type string 15592 */ 15593 builder: "-source-", 15594 15595 15596 /** 15597 * Error reporting. 15598 * 15599 * How should DataTables report an error. Can take the value 'alert', 15600 * 'throw', 'none' or a function. 15601 * 15602 * @type string|function 15603 * @default alert 15604 */ 15605 errMode: "alert", 15606 15607 15608 /** 15609 * Feature plug-ins. 15610 * 15611 * This is an array of objects which describe the feature plug-ins that are 15612 * available to DataTables. These feature plug-ins are then available for 15613 * use through the `dom` initialisation option. 15614 * 15615 * Each feature plug-in is described by an object which must have the 15616 * following properties: 15617 * 15618 * * `fnInit` - function that is used to initialise the plug-in, 15619 * * `cFeature` - a character so the feature can be enabled by the `dom` 15620 * instillation option. This is case sensitive. 15621 * 15622 * The `fnInit` function has the following input parameters: 15623 * 15624 * 1. `{object}` DataTables settings object: see 15625 * {@link DataTable.models.oSettings} 15626 * 15627 * And the following return is expected: 15628 * 15629 * * {node|null} The element which contains your feature. Note that the 15630 * return may also be void if your plug-in does not require to inject any 15631 * DOM elements into DataTables control (`dom`) - for example this might 15632 * be useful when developing a plug-in which allows table control via 15633 * keyboard entry 15634 * 15635 * @type array 15636 * 15637 * @example 15638 * $.fn.dataTable.ext.features.push( { 15639 * "fnInit": function( oSettings ) { 15640 * return new TableTools( { "oDTSettings": oSettings } ); 15641 * }, 15642 * "cFeature": "T" 15643 * } ); 15644 */ 15645 feature: [], 15646 15647 15648 /** 15649 * Row searching. 15650 * 15651 * This method of searching is complimentary to the default type based 15652 * searching, and a lot more comprehensive as it allows you complete control 15653 * over the searching logic. Each element in this array is a function 15654 * (parameters described below) that is called for every row in the table, 15655 * and your logic decides if it should be included in the searching data set 15656 * or not. 15657 * 15658 * Searching functions have the following input parameters: 15659 * 15660 * 1. `{object}` DataTables settings object: see 15661 * {@link DataTable.models.oSettings} 15662 * 2. `{array|object}` Data for the row to be processed (same as the 15663 * original format that was passed in as the data source, or an array 15664 * from a DOM data source 15665 * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which 15666 * can be useful to retrieve the `TR` element if you need DOM interaction. 15667 * 15668 * And the following return is expected: 15669 * 15670 * * {boolean} Include the row in the searched result set (true) or not 15671 * (false) 15672 * 15673 * Note that as with the main search ability in DataTables, technically this 15674 * is "filtering", since it is subtractive. However, for consistency in 15675 * naming we call it searching here. 15676 * 15677 * @type array 15678 * @default [] 15679 * 15680 * @example 15681 * // The following example shows custom search being applied to the 15682 * // fourth column (i.e. the data[3] index) based on two input values 15683 * // from the end-user, matching the data in a certain range. 15684 * $.fn.dataTable.ext.search.push( 15685 * function( settings, data, dataIndex ) { 15686 * var min = document.getElementById('min').value * 1; 15687 * var max = document.getElementById('max').value * 1; 15688 * var version = data[3] == "-" ? 0 : data[3]*1; 15689 * 15690 * if ( min == "" && max == "" ) { 15691 * return true; 15692 * } 15693 * else if ( min == "" && version < max ) { 15694 * return true; 15695 * } 15696 * else if ( min < version && "" == max ) { 15697 * return true; 15698 * } 15699 * else if ( min < version && version < max ) { 15700 * return true; 15701 * } 15702 * return false; 15703 * } 15704 * ); 15705 */ 15706 search: [], 15707 15708 15709 /** 15710 * Selector extensions 15711 * 15712 * The `selector` option can be used to extend the options available for the 15713 * selector modifier options (`selector-modifier` object data type) that 15714 * each of the three built in selector types offer (row, column and cell + 15715 * their plural counterparts). For example the Select extension uses this 15716 * mechanism to provide an option to select only rows, columns and cells 15717 * that have been marked as selected by the end user (`{selected: true}`), 15718 * which can be used in conjunction with the existing built in selector 15719 * options. 15720 * 15721 * Each property is an array to which functions can be pushed. The functions 15722 * take three attributes: 15723 * 15724 * * Settings object for the host table 15725 * * Options object (`selector-modifier` object type) 15726 * * Array of selected item indexes 15727 * 15728 * The return is an array of the resulting item indexes after the custom 15729 * selector has been applied. 15730 * 15731 * @type object 15732 */ 15733 selector: { 15734 cell: [], 15735 column: [], 15736 row: [] 15737 }, 15738 15739 15740 /** 15741 * Internal functions, exposed for used in plug-ins. 15742 * 15743 * Please note that you should not need to use the internal methods for 15744 * anything other than a plug-in (and even then, try to avoid if possible). 15745 * The internal function may change between releases. 15746 * 15747 * @type object 15748 * @default {} 15749 */ 15750 internal: {}, 15751 15752 15753 /** 15754 * Legacy configuration options. Enable and disable legacy options that 15755 * are available in DataTables. 15756 * 15757 * @type object 15758 */ 15759 legacy: { 15760 /** 15761 * Enable / disable DataTables 1.9 compatible server-side processing 15762 * requests 15763 * 15764 * @type boolean 15765 * @default null 15766 */ 15767 ajax: null 15768 }, 15769 15770 15771 /** 15772 * Pagination plug-in methods. 15773 * 15774 * Each entry in this object is a function and defines which buttons should 15775 * be shown by the pagination rendering method that is used for the table: 15776 * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the 15777 * buttons are displayed in the document, while the functions here tell it 15778 * what buttons to display. This is done by returning an array of button 15779 * descriptions (what each button will do). 15780 * 15781 * Pagination types (the four built in options and any additional plug-in 15782 * options defined here) can be used through the `paginationType` 15783 * initialisation parameter. 15784 * 15785 * The functions defined take two parameters: 15786 * 15787 * 1. `{int} page` The current page index 15788 * 2. `{int} pages` The number of pages in the table 15789 * 15790 * Each function is expected to return an array where each element of the 15791 * array can be one of: 15792 * 15793 * * `first` - Jump to first page when activated 15794 * * `last` - Jump to last page when activated 15795 * * `previous` - Show previous page when activated 15796 * * `next` - Show next page when activated 15797 * * `{int}` - Show page of the index given 15798 * * `{array}` - A nested array containing the above elements to add a 15799 * containing 'DIV' element (might be useful for styling). 15800 * 15801 * Note that DataTables v1.9- used this object slightly differently whereby 15802 * an object with two functions would be defined for each plug-in. That 15803 * ability is still supported by DataTables 1.10+ to provide backwards 15804 * compatibility, but this option of use is now decremented and no longer 15805 * documented in DataTables 1.10+. 15806 * 15807 * @type object 15808 * @default {} 15809 * 15810 * @example 15811 * // Show previous, next and current page buttons only 15812 * $.fn.dataTableExt.oPagination.current = function ( page, pages ) { 15813 * return [ 'previous', page, 'next' ]; 15814 * }; 15815 */ 15816 pager: {}, 15817 15818 15819 renderer: { 15820 pageButton: {}, 15821 header: {} 15822 }, 15823 15824 15825 /** 15826 * Ordering plug-ins - custom data source 15827 * 15828 * The extension options for ordering of data available here is complimentary 15829 * to the default type based ordering that DataTables typically uses. It 15830 * allows much greater control over the the data that is being used to 15831 * order a column, but is necessarily therefore more complex. 15832 * 15833 * This type of ordering is useful if you want to do ordering based on data 15834 * live from the DOM (for example the contents of an 'input' element) rather 15835 * than just the static string that DataTables knows of. 15836 * 15837 * The way these plug-ins work is that you create an array of the values you 15838 * wish to be ordering for the column in question and then return that 15839 * array. The data in the array much be in the index order of the rows in 15840 * the table (not the currently ordering order!). Which order data gathering 15841 * function is run here depends on the `dt-init columns.orderDataType` 15842 * parameter that is used for the column (if any). 15843 * 15844 * The functions defined take two parameters: 15845 * 15846 * 1. `{object}` DataTables settings object: see 15847 * {@link DataTable.models.oSettings} 15848 * 2. `{int}` Target column index 15849 * 15850 * Each function is expected to return an array: 15851 * 15852 * * `{array}` Data for the column to be ordering upon 15853 * 15854 * @type array 15855 * 15856 * @example 15857 * // Ordering using `input` node values 15858 * $.fn.dataTable.ext.order['dom-text'] = function ( settings, col ) 15859 * { 15860 * return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) { 15861 * return $('input', td).val(); 15862 * } ); 15863 * } 15864 */ 15865 order: {}, 15866 15867 15868 /** 15869 * Type based plug-ins. 15870 * 15871 * Each column in DataTables has a type assigned to it, either by automatic 15872 * detection or by direct assignment using the `type` option for the column. 15873 * The type of a column will effect how it is ordering and search (plug-ins 15874 * can also make use of the column type if required). 15875 * 15876 * @namespace 15877 */ 15878 type: { 15879 /** 15880 * Type detection functions. 15881 * 15882 * The functions defined in this object are used to automatically detect 15883 * a column's type, making initialisation of DataTables super easy, even 15884 * when complex data is in the table. 15885 * 15886 * The functions defined take two parameters: 15887 * 15888 * 1. `{*}` Data from the column cell to be analysed 15889 * 2. `{settings}` DataTables settings object. This can be used to 15890 * perform context specific type detection - for example detection 15891 * based on language settings such as using a comma for a decimal 15892 * place. Generally speaking the options from the settings will not 15893 * be required 15894 * 15895 * Each function is expected to return: 15896 * 15897 * * `{string|null}` Data type detected, or null if unknown (and thus 15898 * pass it on to the other type detection functions. 15899 * 15900 * @type array 15901 * 15902 * @example 15903 * // Currency type detection plug-in: 15904 * $.fn.dataTable.ext.type.detect.push( 15905 * function ( data, settings ) { 15906 * // Check the numeric part 15907 * if ( ! data.substring(1).match(/[0-9]/) ) { 15908 * return null; 15909 * } 15910 * 15911 * // Check prefixed by currency 15912 * if ( data.charAt(0) == '$' || data.charAt(0) == '£' ) { 15913 * return 'currency'; 15914 * } 15915 * return null; 15916 * } 15917 * ); 15918 */ 15919 detect: [], 15920 15921 15922 /** 15923 * Type based search formatting. 15924 * 15925 * The type based searching functions can be used to pre-format the 15926 * data to be search on. For example, it can be used to strip HTML 15927 * tags or to de-format telephone numbers for numeric only searching. 15928 * 15929 * Note that is a search is not defined for a column of a given type, 15930 * no search formatting will be performed. 15931 * 15932 * Pre-processing of searching data plug-ins - When you assign the sType 15933 * for a column (or have it automatically detected for you by DataTables 15934 * or a type detection plug-in), you will typically be using this for 15935 * custom sorting, but it can also be used to provide custom searching 15936 * by allowing you to pre-processing the data and returning the data in 15937 * the format that should be searched upon. This is done by adding 15938 * functions this object with a parameter name which matches the sType 15939 * for that target column. This is the corollary of <i>afnSortData</i> 15940 * for searching data. 15941 * 15942 * The functions defined take a single parameter: 15943 * 15944 * 1. `{*}` Data from the column cell to be prepared for searching 15945 * 15946 * Each function is expected to return: 15947 * 15948 * * `{string|null}` Formatted string that will be used for the searching. 15949 * 15950 * @type object 15951 * @default {} 15952 * 15953 * @example 15954 * $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) { 15955 * return d.replace(/\n/g," ").replace( /<.*?>/g, "" ); 15956 * } 15957 */ 15958 search: {}, 15959 15960 15961 /** 15962 * Type based ordering. 15963 * 15964 * The column type tells DataTables what ordering to apply to the table 15965 * when a column is sorted upon. The order for each type that is defined, 15966 * is defined by the functions available in this object. 15967 * 15968 * Each ordering option can be described by three properties added to 15969 * this object: 15970 * 15971 * * `{type}-pre` - Pre-formatting function 15972 * * `{type}-asc` - Ascending order function 15973 * * `{type}-desc` - Descending order function 15974 * 15975 * All three can be used together, only `{type}-pre` or only 15976 * `{type}-asc` and `{type}-desc` together. It is generally recommended 15977 * that only `{type}-pre` is used, as this provides the optimal 15978 * implementation in terms of speed, although the others are provided 15979 * for compatibility with existing Javascript sort functions. 15980 * 15981 * `{type}-pre`: Functions defined take a single parameter: 15982 * 15983 * 1. `{*}` Data from the column cell to be prepared for ordering 15984 * 15985 * And return: 15986 * 15987 * * `{*}` Data to be sorted upon 15988 * 15989 * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort 15990 * functions, taking two parameters: 15991 * 15992 * 1. `{*}` Data to compare to the second parameter 15993 * 2. `{*}` Data to compare to the first parameter 15994 * 15995 * And returning: 15996 * 15997 * * `{*}` Ordering match: <0 if first parameter should be sorted lower 15998 * than the second parameter, ===0 if the two parameters are equal and 15999 * >0 if the first parameter should be sorted height than the second 16000 * parameter. 16001 * 16002 * @type object 16003 * @default {} 16004 * 16005 * @example 16006 * // Numeric ordering of formatted numbers with a pre-formatter 16007 * $.extend( $.fn.dataTable.ext.type.order, { 16008 * "string-pre": function(x) { 16009 * a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" ); 16010 * return parseFloat( a ); 16011 * } 16012 * } ); 16013 * 16014 * @example 16015 * // Case-sensitive string ordering, with no pre-formatting method 16016 * $.extend( $.fn.dataTable.ext.order, { 16017 * "string-case-asc": function(x,y) { 16018 * return ((x < y) ? -1 : ((x > y) ? 1 : 0)); 16019 * }, 16020 * "string-case-desc": function(x,y) { 16021 * return ((x < y) ? 1 : ((x > y) ? -1 : 0)); 16022 * } 16023 * } ); 16024 */ 16025 order: {} 16026 }, 16027 16028 /** 16029 * Unique DataTables instance counter 16030 * 16031 * @type int 16032 * @private 16033 */ 16034 _unique: 0, 16035 16036 16037 // 16038 // Depreciated 16039 // The following properties are retained for backwards compatiblity only. 16040 // The should not be used in new projects and will be removed in a future 16041 // version 16042 // 16043 16044 /** 16045 * Version check function. 16046 * @type function 16047 * @depreciated Since 1.10 16048 */ 16049 fnVersionCheck: DataTable.fnVersionCheck, 16050 16051 16052 /** 16053 * Index for what 'this' index API functions should use 16054 * @type int 16055 * @deprecated Since v1.10 16056 */ 16057 iApiIndex: 0, 16058 16059 16060 /** 16061 * jQuery UI class container 16062 * @type object 16063 * @deprecated Since v1.10 16064 */ 16065 oJUIClasses: {}, 16066 16067 16068 /** 16069 * Software version 16070 * @type string 16071 * @deprecated Since v1.10 16072 */ 16073 sVersion: DataTable.version 16074 }; 16075 16076 16077 // 16078 // Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts 16079 // 16080 $.extend( _ext, { 16081 afnFiltering: _ext.search, 16082 aTypes: _ext.type.detect, 16083 ofnSearch: _ext.type.search, 16084 oSort: _ext.type.order, 16085 afnSortData: _ext.order, 16086 aoFeatures: _ext.feature, 16087 oApi: _ext.internal, 16088 oStdClasses: _ext.classes, 16089 oPagination: _ext.pager 16090 } ); 16091 16092 16093 $.extend( DataTable.ext.classes, { 16094 "sTable": "dataTable", 16095 "sNoFooter": "no-footer", 16096 16097 /* Paging buttons */ 16098 "sPageButton": "paginate_button", 16099 "sPageButtonActive": "current", 16100 "sPageButtonDisabled": "disabled", 16101 16102 /* Striping classes */ 16103 "sStripeOdd": "odd", 16104 "sStripeEven": "even", 16105 16106 /* Empty row */ 16107 "sRowEmpty": "dataTables_empty", 16108 16109 /* Features */ 16110 "sWrapper": "dataTables_wrapper", 16111 "sFilter": "dataTables_filter", 16112 "sInfo": "dataTables_info", 16113 "sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */ 16114 "sLength": "dataTables_length", 16115 "sProcessing": "dataTables_processing", 16116 16117 /* Sorting */ 16118 "sSortAsc": "sorting_asc", 16119 "sSortDesc": "sorting_desc", 16120 "sSortable": "sorting", /* Sortable in both directions */ 16121 "sSortableAsc": "sorting_desc_disabled", 16122 "sSortableDesc": "sorting_asc_disabled", 16123 "sSortableNone": "sorting_disabled", 16124 "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */ 16125 16126 /* Filtering */ 16127 "sFilterInput": "", 16128 16129 /* Page length */ 16130 "sLengthSelect": "", 16131 16132 /* Scrolling */ 16133 "sScrollWrapper": "dataTables_scroll", 16134 "sScrollHead": "dataTables_scrollHead", 16135 "sScrollHeadInner": "dataTables_scrollHeadInner", 16136 "sScrollBody": "dataTables_scrollBody", 16137 "sScrollFoot": "dataTables_scrollFoot", 16138 "sScrollFootInner": "dataTables_scrollFootInner", 16139 16140 /* Misc */ 16141 "sHeaderTH": "", 16142 "sFooterTH": "", 16143 16144 // Deprecated 16145 "sSortJUIAsc": "", 16146 "sSortJUIDesc": "", 16147 "sSortJUI": "", 16148 "sSortJUIAscAllowed": "", 16149 "sSortJUIDescAllowed": "", 16150 "sSortJUIWrapper": "", 16151 "sSortIcon": "", 16152 "sJUIHeader": "", 16153 "sJUIFooter": "" 16154 } ); 16155 16156 16157 var extPagination = DataTable.ext.pager; 16158 16159 function _numbers ( page, pages ) { 16160 var 16161 numbers = [], 16162 buttons = extPagination.numbers_length, 16163 half = Math.floor( buttons / 2 ), 16164 i = 1; 16165 16166 if ( pages <= buttons ) { 16167 numbers = _range( 0, pages ); 16168 } 16169 else if ( page <= half ) { 16170 numbers = _range( 0, buttons-2 ); 16171 numbers.push( 'ellipsis' ); 16172 numbers.push( pages-1 ); 16173 } 16174 else if ( page >= pages - 1 - half ) { 16175 numbers = _range( pages-(buttons-2), pages ); 16176 numbers.splice( 0, 0, 'ellipsis' ); // no unshift in ie6 16177 numbers.splice( 0, 0, 0 ); 16178 } 16179 else { 16180 numbers = _range( page-half+2, page+half-1 ); 16181 numbers.push( 'ellipsis' ); 16182 numbers.push( pages-1 ); 16183 numbers.splice( 0, 0, 'ellipsis' ); 16184 numbers.splice( 0, 0, 0 ); 16185 } 16186 16187 numbers.DT_el = 'span'; 16188 return numbers; 16189 } 16190 16191 16192 $.extend( extPagination, { 16193 simple: function ( page, pages ) { 16194 return [ 'previous', 'next' ]; 16195 }, 16196 16197 full: function ( page, pages ) { 16198 return [ 'first', 'previous', 'next', 'last' ]; 16199 }, 16200 16201 numbers: function ( page, pages ) { 16202 return [ _numbers(page, pages) ]; 16203 }, 16204 16205 simple_numbers: function ( page, pages ) { 16206 return [ 'previous', _numbers(page, pages), 'next' ]; 16207 }, 16208 16209 full_numbers: function ( page, pages ) { 16210 return [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ]; 16211 }, 16212 16213 first_last_numbers: function (page, pages) { 16214 return ['first', _numbers(page, pages), 'last']; 16215 }, 16216 16217 // For testing and plug-ins to use 16218 _numbers: _numbers, 16219 16220 // Number of number buttons (including ellipsis) to show. _Must be odd!_ 16221 numbers_length: 7 16222 } ); 16223 16224 16225 $.extend( true, DataTable.ext.renderer, { 16226 pageButton: { 16227 _: function ( settings, host, idx, buttons, page, pages ) { 16228 var classes = settings.oClasses; 16229 var lang = settings.oLanguage.oPaginate; 16230 var aria = settings.oLanguage.oAria.paginate || {}; 16231 var btnDisplay, btnClass, counter=0; 16232 16233 var attach = function( container, buttons ) { 16234 var i, ien, node, button, tabIndex; 16235 var disabledClass = classes.sPageButtonDisabled; 16236 var clickHandler = function ( e ) { 16237 _fnPageChange( settings, e.data.action, true ); 16238 }; 16239 16240 for ( i=0, ien=buttons.length ; i<ien ; i++ ) { 16241 button = buttons[i]; 16242 16243 if ( Array.isArray( button ) ) { 16244 var inner = $( '<'+(button.DT_el || 'div')+'/>' ) 16245 .appendTo( container ); 16246 attach( inner, button ); 16247 } 16248 else { 16249 btnDisplay = null; 16250 btnClass = button; 16251 tabIndex = settings.iTabIndex; 16252 16253 switch ( button ) { 16254 case 'ellipsis': 16255 container.append('<span class="ellipsis">…</span>'); 16256 break; 16257 16258 case 'first': 16259 btnDisplay = lang.sFirst; 16260 16261 if ( page === 0 ) { 16262 tabIndex = -1; 16263 btnClass += ' ' + disabledClass; 16264 } 16265 break; 16266 16267 case 'previous': 16268 btnDisplay = lang.sPrevious; 16269 16270 if ( page === 0 ) { 16271 tabIndex = -1; 16272 btnClass += ' ' + disabledClass; 16273 } 16274 break; 16275 16276 case 'next': 16277 btnDisplay = lang.sNext; 16278 16279 if ( pages === 0 || page === pages-1 ) { 16280 tabIndex = -1; 16281 btnClass += ' ' + disabledClass; 16282 } 16283 break; 16284 16285 case 'last': 16286 btnDisplay = lang.sLast; 16287 16288 if ( pages === 0 || page === pages-1 ) { 16289 tabIndex = -1; 16290 btnClass += ' ' + disabledClass; 16291 } 16292 break; 16293 16294 default: 16295 btnDisplay = settings.fnFormatNumber( button + 1 ); 16296 btnClass = page === button ? 16297 classes.sPageButtonActive : ''; 16298 break; 16299 } 16300 16301 if ( btnDisplay !== null ) { 16302 node = $('<a>', { 16303 'class': classes.sPageButton+' '+btnClass, 16304 'aria-controls': settings.sTableId, 16305 'aria-label': aria[ button ], 16306 'data-dt-idx': counter, 16307 'tabindex': tabIndex, 16308 'id': idx === 0 && typeof button === 'string' ? 16309 settings.sTableId +'_'+ button : 16310 null 16311 } ) 16312 .html( btnDisplay ) 16313 .appendTo( container ); 16314 16315 _fnBindAction( 16316 node, {action: button}, clickHandler 16317 ); 16318 16319 counter++; 16320 } 16321 } 16322 } 16323 }; 16324 16325 // IE9 throws an 'unknown error' if document.activeElement is used 16326 // inside an iframe or frame. Try / catch the error. Not good for 16327 // accessibility, but neither are frames. 16328 var activeEl; 16329 16330 try { 16331 // Because this approach is destroying and recreating the paging 16332 // elements, focus is lost on the select button which is bad for 16333 // accessibility. So we want to restore focus once the draw has 16334 // completed 16335 activeEl = $(host).find(document.activeElement).data('dt-idx'); 16336 } 16337 catch (e) {} 16338 16339 attach( $(host).empty(), buttons ); 16340 16341 if ( activeEl !== undefined ) { 16342 $(host).find( '[data-dt-idx='+activeEl+']' ).trigger('focus'); 16343 } 16344 } 16345 } 16346 } ); 16347 16348 16349 16350 // Built in type detection. See model.ext.aTypes for information about 16351 // what is required from this methods. 16352 $.extend( DataTable.ext.type.detect, [ 16353 // Plain numbers - first since V8 detects some plain numbers as dates 16354 // e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...). 16355 function ( d, settings ) 16356 { 16357 var decimal = settings.oLanguage.sDecimal; 16358 return _isNumber( d, decimal ) ? 'num'+decimal : null; 16359 }, 16360 16361 // Dates (only those recognised by the browser's Date.parse) 16362 function ( d, settings ) 16363 { 16364 // V8 tries _very_ hard to make a string passed into `Date.parse()` 16365 // valid, so we need to use a regex to restrict date formats. Use a 16366 // plug-in for anything other than ISO8601 style strings 16367 if ( d && !(d instanceof Date) && ! _re_date.test(d) ) { 16368 return null; 16369 } 16370 var parsed = Date.parse(d); 16371 return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null; 16372 }, 16373 16374 // Formatted numbers 16375 function ( d, settings ) 16376 { 16377 var decimal = settings.oLanguage.sDecimal; 16378 return _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null; 16379 }, 16380 16381 // HTML numeric 16382 function ( d, settings ) 16383 { 16384 var decimal = settings.oLanguage.sDecimal; 16385 return _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null; 16386 }, 16387 16388 // HTML numeric, formatted 16389 function ( d, settings ) 16390 { 16391 var decimal = settings.oLanguage.sDecimal; 16392 return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null; 16393 }, 16394 16395 // HTML (this is strict checking - there must be html) 16396 function ( d, settings ) 16397 { 16398 return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ? 16399 'html' : null; 16400 } 16401 ] ); 16402 16403 16404 16405 // Filter formatting functions. See model.ext.ofnSearch for information about 16406 // what is required from these methods. 16407 // 16408 // Note that additional search methods are added for the html numbers and 16409 // html formatted numbers by `_addNumericSort()` when we know what the decimal 16410 // place is 16411 16412 16413 $.extend( DataTable.ext.type.search, { 16414 html: function ( data ) { 16415 return _empty(data) ? 16416 data : 16417 typeof data === 'string' ? 16418 data 16419 .replace( _re_new_lines, " " ) 16420 .replace( _re_html, "" ) : 16421 ''; 16422 }, 16423 16424 string: function ( data ) { 16425 return _empty(data) ? 16426 data : 16427 typeof data === 'string' ? 16428 data.replace( _re_new_lines, " " ) : 16429 data; 16430 } 16431 } ); 16432 16433 16434 16435 var __numericReplace = function ( d, decimalPlace, re1, re2 ) { 16436 if ( d !== 0 && (!d || d === '-') ) { 16437 return -Infinity; 16438 } 16439 16440 // If a decimal place other than `.` is used, it needs to be given to the 16441 // function so we can detect it and replace with a `.` which is the only 16442 // decimal place Javascript recognises - it is not locale aware. 16443 if ( decimalPlace ) { 16444 d = _numToDecimal( d, decimalPlace ); 16445 } 16446 16447 if ( d.replace ) { 16448 if ( re1 ) { 16449 d = d.replace( re1, '' ); 16450 } 16451 16452 if ( re2 ) { 16453 d = d.replace( re2, '' ); 16454 } 16455 } 16456 16457 return d * 1; 16458 }; 16459 16460 16461 // Add the numeric 'deformatting' functions for sorting and search. This is done 16462 // in a function to provide an easy ability for the language options to add 16463 // additional methods if a non-period decimal place is used. 16464 function _addNumericSort ( decimalPlace ) { 16465 $.each( 16466 { 16467 // Plain numbers 16468 "num": function ( d ) { 16469 return __numericReplace( d, decimalPlace ); 16470 }, 16471 16472 // Formatted numbers 16473 "num-fmt": function ( d ) { 16474 return __numericReplace( d, decimalPlace, _re_formatted_numeric ); 16475 }, 16476 16477 // HTML numeric 16478 "html-num": function ( d ) { 16479 return __numericReplace( d, decimalPlace, _re_html ); 16480 }, 16481 16482 // HTML numeric, formatted 16483 "html-num-fmt": function ( d ) { 16484 return __numericReplace( d, decimalPlace, _re_html, _re_formatted_numeric ); 16485 } 16486 }, 16487 function ( key, fn ) { 16488 // Add the ordering method 16489 _ext.type.order[ key+decimalPlace+'-pre' ] = fn; 16490 16491 // For HTML types add a search formatter that will strip the HTML 16492 if ( key.match(/^html\-/) ) { 16493 _ext.type.search[ key+decimalPlace ] = _ext.type.search.html; 16494 } 16495 } 16496 ); 16497 } 16498 16499 16500 // Default sort methods 16501 $.extend( _ext.type.order, { 16502 // Dates 16503 "date-pre": function ( d ) { 16504 var ts = Date.parse( d ); 16505 return isNaN(ts) ? -Infinity : ts; 16506 }, 16507 16508 // html 16509 "html-pre": function ( a ) { 16510 return _empty(a) ? 16511 '' : 16512 a.replace ? 16513 a.replace( /<.*?>/g, "" ).toLowerCase() : 16514 a+''; 16515 }, 16516 16517 // string 16518 "string-pre": function ( a ) { 16519 // This is a little complex, but faster than always calling toString, 16520 // http://jsperf.com/tostring-v-check 16521 return _empty(a) ? 16522 '' : 16523 typeof a === 'string' ? 16524 a.toLowerCase() : 16525 ! a.toString ? 16526 '' : 16527 a.toString(); 16528 }, 16529 16530 // string-asc and -desc are retained only for compatibility with the old 16531 // sort methods 16532 "string-asc": function ( x, y ) { 16533 return ((x < y) ? -1 : ((x > y) ? 1 : 0)); 16534 }, 16535 16536 "string-desc": function ( x, y ) { 16537 return ((x < y) ? 1 : ((x > y) ? -1 : 0)); 16538 } 16539 } ); 16540 16541 16542 // Numeric sorting types - order doesn't matter here 16543 _addNumericSort( '' ); 16544 16545 16546 $.extend( true, DataTable.ext.renderer, { 16547 header: { 16548 _: function ( settings, cell, column, classes ) { 16549 // No additional mark-up required 16550 // Attach a sort listener to update on sort - note that using the 16551 // `DT` namespace will allow the event to be removed automatically 16552 // on destroy, while the `dt` namespaced event is the one we are 16553 // listening for 16554 $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) { 16555 if ( settings !== ctx ) { // need to check this this is the host 16556 return; // table, not a nested one 16557 } 16558 16559 var colIdx = column.idx; 16560 16561 cell 16562 .removeClass( 16563 classes.sSortAsc +' '+ 16564 classes.sSortDesc 16565 ) 16566 .addClass( columns[ colIdx ] == 'asc' ? 16567 classes.sSortAsc : columns[ colIdx ] == 'desc' ? 16568 classes.sSortDesc : 16569 column.sSortingClass 16570 ); 16571 } ); 16572 }, 16573 16574 jqueryui: function ( settings, cell, column, classes ) { 16575 $('<div/>') 16576 .addClass( classes.sSortJUIWrapper ) 16577 .append( cell.contents() ) 16578 .append( $('<span/>') 16579 .addClass( classes.sSortIcon+' '+column.sSortingClassJUI ) 16580 ) 16581 .appendTo( cell ); 16582 16583 // Attach a sort listener to update on sort 16584 $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) { 16585 if ( settings !== ctx ) { 16586 return; 16587 } 16588 16589 var colIdx = column.idx; 16590 16591 cell 16592 .removeClass( classes.sSortAsc +" "+classes.sSortDesc ) 16593 .addClass( columns[ colIdx ] == 'asc' ? 16594 classes.sSortAsc : columns[ colIdx ] == 'desc' ? 16595 classes.sSortDesc : 16596 column.sSortingClass 16597 ); 16598 16599 cell 16600 .find( 'span.'+classes.sSortIcon ) 16601 .removeClass( 16602 classes.sSortJUIAsc +" "+ 16603 classes.sSortJUIDesc +" "+ 16604 classes.sSortJUI +" "+ 16605 classes.sSortJUIAscAllowed +" "+ 16606 classes.sSortJUIDescAllowed 16607 ) 16608 .addClass( columns[ colIdx ] == 'asc' ? 16609 classes.sSortJUIAsc : columns[ colIdx ] == 'desc' ? 16610 classes.sSortJUIDesc : 16611 column.sSortingClassJUI 16612 ); 16613 } ); 16614 } 16615 } 16616 } ); 16617 16618 /* 16619 * Public helper functions. These aren't used internally by DataTables, or 16620 * called by any of the options passed into DataTables, but they can be used 16621 * externally by developers working with DataTables. They are helper functions 16622 * to make working with DataTables a little bit easier. 16623 */ 16624 16625 var __htmlEscapeEntities = function ( d ) { 16626 return typeof d === 'string' ? 16627 d 16628 .replace(/&/g, '&') 16629 .replace(/</g, '<') 16630 .replace(/>/g, '>') 16631 .replace(/"/g, '"') : 16632 d; 16633 }; 16634 16635 /** 16636 * Helpers for `columns.render`. 16637 * 16638 * The options defined here can be used with the `columns.render` initialisation 16639 * option to provide a display renderer. The following functions are defined: 16640 * 16641 * * `number` - Will format numeric data (defined by `columns.data`) for 16642 * display, retaining the original unformatted data for sorting and filtering. 16643 * It takes 5 parameters: 16644 * * `string` - Thousands grouping separator 16645 * * `string` - Decimal point indicator 16646 * * `integer` - Number of decimal points to show 16647 * * `string` (optional) - Prefix. 16648 * * `string` (optional) - Postfix (/suffix). 16649 * * `text` - Escape HTML to help prevent XSS attacks. It has no optional 16650 * parameters. 16651 * 16652 * @example 16653 * // Column definition using the number renderer 16654 * { 16655 * data: "salary", 16656 * render: $.fn.dataTable.render.number( '\'', '.', 0, '$' ) 16657 * } 16658 * 16659 * @namespace 16660 */ 16661 DataTable.render = { 16662 number: function ( thousands, decimal, precision, prefix, postfix ) { 16663 return { 16664 display: function ( d ) { 16665 if ( typeof d !== 'number' && typeof d !== 'string' ) { 16666 return d; 16667 } 16668 16669 var negative = d < 0 ? '-' : ''; 16670 var flo = parseFloat( d ); 16671 16672 // If NaN then there isn't much formatting that we can do - just 16673 // return immediately, escaping any HTML (this was supposed to 16674 // be a number after all) 16675 if ( isNaN( flo ) ) { 16676 return __htmlEscapeEntities( d ); 16677 } 16678 16679 flo = flo.toFixed( precision ); 16680 d = Math.abs( flo ); 16681 16682 var intPart = parseInt( d, 10 ); 16683 var floatPart = precision ? 16684 decimal+(d - intPart).toFixed( precision ).substring( 2 ): 16685 ''; 16686 16687 return negative + (prefix||'') + 16688 intPart.toString().replace( 16689 /\B(?=(\d{3})+(?!\d))/g, thousands 16690 ) + 16691 floatPart + 16692 (postfix||''); 16693 } 16694 }; 16695 }, 16696 16697 text: function () { 16698 return { 16699 display: __htmlEscapeEntities, 16700 filter: __htmlEscapeEntities 16701 }; 16702 } 16703 }; 16704 16705 16706 /* 16707 * This is really a good bit rubbish this method of exposing the internal methods 16708 * publicly... - To be fixed in 2.0 using methods on the prototype 16709 */ 16710 16711 16712 /** 16713 * Create a wrapper function for exporting an internal functions to an external API. 16714 * @param {string} fn API function name 16715 * @returns {function} wrapped function 16716 * @memberof DataTable#internal 16717 */ 16718 function _fnExternApiFunc (fn) 16719 { 16720 return function() { 16721 var args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat( 16722 Array.prototype.slice.call(arguments) 16723 ); 16724 return DataTable.ext.internal[fn].apply( this, args ); 16725 }; 16726 } 16727 16728 16729 /** 16730 * Reference to internal functions for use by plug-in developers. Note that 16731 * these methods are references to internal functions and are considered to be 16732 * private. If you use these methods, be aware that they are liable to change 16733 * between versions. 16734 * @namespace 16735 */ 16736 $.extend( DataTable.ext.internal, { 16737 _fnExternApiFunc: _fnExternApiFunc, 16738 _fnBuildAjax: _fnBuildAjax, 16739 _fnAjaxUpdate: _fnAjaxUpdate, 16740 _fnAjaxParameters: _fnAjaxParameters, 16741 _fnAjaxUpdateDraw: _fnAjaxUpdateDraw, 16742 _fnAjaxDataSrc: _fnAjaxDataSrc, 16743 _fnAddColumn: _fnAddColumn, 16744 _fnColumnOptions: _fnColumnOptions, 16745 _fnAdjustColumnSizing: _fnAdjustColumnSizing, 16746 _fnVisibleToColumnIndex: _fnVisibleToColumnIndex, 16747 _fnColumnIndexToVisible: _fnColumnIndexToVisible, 16748 _fnVisbleColumns: _fnVisbleColumns, 16749 _fnGetColumns: _fnGetColumns, 16750 _fnColumnTypes: _fnColumnTypes, 16751 _fnApplyColumnDefs: _fnApplyColumnDefs, 16752 _fnHungarianMap: _fnHungarianMap, 16753 _fnCamelToHungarian: _fnCamelToHungarian, 16754 _fnLanguageCompat: _fnLanguageCompat, 16755 _fnBrowserDetect: _fnBrowserDetect, 16756 _fnAddData: _fnAddData, 16757 _fnAddTr: _fnAddTr, 16758 _fnNodeToDataIndex: _fnNodeToDataIndex, 16759 _fnNodeToColumnIndex: _fnNodeToColumnIndex, 16760 _fnGetCellData: _fnGetCellData, 16761 _fnSetCellData: _fnSetCellData, 16762 _fnSplitObjNotation: _fnSplitObjNotation, 16763 _fnGetObjectDataFn: _fnGetObjectDataFn, 16764 _fnSetObjectDataFn: _fnSetObjectDataFn, 16765 _fnGetDataMaster: _fnGetDataMaster, 16766 _fnClearTable: _fnClearTable, 16767 _fnDeleteIndex: _fnDeleteIndex, 16768 _fnInvalidate: _fnInvalidate, 16769 _fnGetRowElements: _fnGetRowElements, 16770 _fnCreateTr: _fnCreateTr, 16771 _fnBuildHead: _fnBuildHead, 16772 _fnDrawHead: _fnDrawHead, 16773 _fnDraw: _fnDraw, 16774 _fnReDraw: _fnReDraw, 16775 _fnAddOptionsHtml: _fnAddOptionsHtml, 16776 _fnDetectHeader: _fnDetectHeader, 16777 _fnGetUniqueThs: _fnGetUniqueThs, 16778 _fnFeatureHtmlFilter: _fnFeatureHtmlFilter, 16779 _fnFilterComplete: _fnFilterComplete, 16780 _fnFilterCustom: _fnFilterCustom, 16781 _fnFilterColumn: _fnFilterColumn, 16782 _fnFilter: _fnFilter, 16783 _fnFilterCreateSearch: _fnFilterCreateSearch, 16784 _fnEscapeRegex: _fnEscapeRegex, 16785 _fnFilterData: _fnFilterData, 16786 _fnFeatureHtmlInfo: _fnFeatureHtmlInfo, 16787 _fnUpdateInfo: _fnUpdateInfo, 16788 _fnInfoMacros: _fnInfoMacros, 16789 _fnInitialise: _fnInitialise, 16790 _fnInitComplete: _fnInitComplete, 16791 _fnLengthChange: _fnLengthChange, 16792 _fnFeatureHtmlLength: _fnFeatureHtmlLength, 16793 _fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate, 16794 _fnPageChange: _fnPageChange, 16795 _fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing, 16796 _fnProcessingDisplay: _fnProcessingDisplay, 16797 _fnFeatureHtmlTable: _fnFeatureHtmlTable, 16798 _fnScrollDraw: _fnScrollDraw, 16799 _fnApplyToChildren: _fnApplyToChildren, 16800 _fnCalculateColumnWidths: _fnCalculateColumnWidths, 16801 _fnThrottle: _fnThrottle, 16802 _fnConvertToWidth: _fnConvertToWidth, 16803 _fnGetWidestNode: _fnGetWidestNode, 16804 _fnGetMaxLenString: _fnGetMaxLenString, 16805 _fnStringToCss: _fnStringToCss, 16806 _fnSortFlatten: _fnSortFlatten, 16807 _fnSort: _fnSort, 16808 _fnSortAria: _fnSortAria, 16809 _fnSortListener: _fnSortListener, 16810 _fnSortAttachListener: _fnSortAttachListener, 16811 _fnSortingClasses: _fnSortingClasses, 16812 _fnSortData: _fnSortData, 16813 _fnSaveState: _fnSaveState, 16814 _fnLoadState: _fnLoadState, 16815 _fnSettingsFromNode: _fnSettingsFromNode, 16816 _fnLog: _fnLog, 16817 _fnMap: _fnMap, 16818 _fnBindAction: _fnBindAction, 16819 _fnCallbackReg: _fnCallbackReg, 16820 _fnCallbackFire: _fnCallbackFire, 16821 _fnLengthOverflow: _fnLengthOverflow, 16822 _fnRenderer: _fnRenderer, 16823 _fnDataSource: _fnDataSource, 16824 _fnRowAttributes: _fnRowAttributes, 16825 _fnExtend: _fnExtend, 16826 _fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant 16827 // in 1.10, so this dead-end function is 16828 // added to prevent errors 16829 } ); 16830 16831 16832 // jQuery access 16833 $.fn.dataTable = DataTable; 16834 16835 // Provide access to the host jQuery object (circular reference) 16836 DataTable.$ = $; 16837 16838 // Legacy aliases 16839 $.fn.dataTableSettings = DataTable.settings; 16840 $.fn.dataTableExt = DataTable.ext; 16841 16842 // With a capital `D` we return a DataTables API instance rather than a 16843 // jQuery object 16844 $.fn.DataTable = function ( opts ) { 16845 return $(this).dataTable( opts ).api(); 16846 }; 16847 16848 // All properties that are available to $.fn.dataTable should also be 16849 // available on $.fn.DataTable 16850 $.each( DataTable, function ( prop, val ) { 16851 $.fn.DataTable[ prop ] = val; 16852 } ); 16853 16854 16855 // Information about events fired by DataTables - for documentation. 16856 /** 16857 * Draw event, fired whenever the table is redrawn on the page, at the same 16858 * point as fnDrawCallback. This may be useful for binding events or 16859 * performing calculations when the table is altered at all. 16860 * @name DataTable#draw.dt 16861 * @event 16862 * @param {event} e jQuery event object 16863 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 16864 */ 16865 16866 /** 16867 * Search event, fired when the searching applied to the table (using the 16868 * built-in global search, or column filters) is altered. 16869 * @name DataTable#search.dt 16870 * @event 16871 * @param {event} e jQuery event object 16872 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 16873 */ 16874 16875 /** 16876 * Page change event, fired when the paging of the table is altered. 16877 * @name DataTable#page.dt 16878 * @event 16879 * @param {event} e jQuery event object 16880 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 16881 */ 16882 16883 /** 16884 * Order event, fired when the ordering applied to the table is altered. 16885 * @name DataTable#order.dt 16886 * @event 16887 * @param {event} e jQuery event object 16888 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 16889 */ 16890 16891 /** 16892 * DataTables initialisation complete event, fired when the table is fully 16893 * drawn, including Ajax data loaded, if Ajax data is required. 16894 * @name DataTable#init.dt 16895 * @event 16896 * @param {event} e jQuery event object 16897 * @param {object} oSettings DataTables settings object 16898 * @param {object} json The JSON object request from the server - only 16899 * present if client-side Ajax sourced data is used</li></ol> 16900 */ 16901 16902 /** 16903 * State save event, fired when the table has changed state a new state save 16904 * is required. This event allows modification of the state saving object 16905 * prior to actually doing the save, including addition or other state 16906 * properties (for plug-ins) or modification of a DataTables core property. 16907 * @name DataTable#stateSaveParams.dt 16908 * @event 16909 * @param {event} e jQuery event object 16910 * @param {object} oSettings DataTables settings object 16911 * @param {object} json The state information to be saved 16912 */ 16913 16914 /** 16915 * State load event, fired when the table is loading state from the stored 16916 * data, but prior to the settings object being modified by the saved state 16917 * - allowing modification of the saved state is required or loading of 16918 * state for a plug-in. 16919 * @name DataTable#stateLoadParams.dt 16920 * @event 16921 * @param {event} e jQuery event object 16922 * @param {object} oSettings DataTables settings object 16923 * @param {object} json The saved state information 16924 */ 16925 16926 /** 16927 * State loaded event, fired when state has been loaded from stored data and 16928 * the settings object has been modified by the loaded data. 16929 * @name DataTable#stateLoaded.dt 16930 * @event 16931 * @param {event} e jQuery event object 16932 * @param {object} oSettings DataTables settings object 16933 * @param {object} json The saved state information 16934 */ 16935 16936 /** 16937 * Processing event, fired when DataTables is doing some kind of processing 16938 * (be it, order, search or anything else). It can be used to indicate to 16939 * the end user that there is something happening, or that something has 16940 * finished. 16941 * @name DataTable#processing.dt 16942 * @event 16943 * @param {event} e jQuery event object 16944 * @param {object} oSettings DataTables settings object 16945 * @param {boolean} bShow Flag for if DataTables is doing processing or not 16946 */ 16947 16948 /** 16949 * Ajax (XHR) event, fired whenever an Ajax request is completed from a 16950 * request to made to the server for new data. This event is called before 16951 * DataTables processed the returned data, so it can also be used to pre- 16952 * process the data returned from the server, if needed. 16953 * 16954 * Note that this trigger is called in `fnServerData`, if you override 16955 * `fnServerData` and which to use this event, you need to trigger it in you 16956 * success function. 16957 * @name DataTable#xhr.dt 16958 * @event 16959 * @param {event} e jQuery event object 16960 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 16961 * @param {object} json JSON returned from the server 16962 * 16963 * @example 16964 * // Use a custom property returned from the server in another DOM element 16965 * $('#table').dataTable().on('xhr.dt', function (e, settings, json) { 16966 * $('#status').html( json.status ); 16967 * } ); 16968 * 16969 * @example 16970 * // Pre-process the data returned from the server 16971 * $('#table').dataTable().on('xhr.dt', function (e, settings, json) { 16972 * for ( var i=0, ien=json.aaData.length ; i<ien ; i++ ) { 16973 * json.aaData[i].sum = json.aaData[i].one + json.aaData[i].two; 16974 * } 16975 * // Note no return - manipulate the data directly in the JSON object. 16976 * } ); 16977 */ 16978 16979 /** 16980 * Destroy event, fired when the DataTable is destroyed by calling fnDestroy 16981 * or passing the bDestroy:true parameter in the initialisation object. This 16982 * can be used to remove bound events, added DOM nodes, etc. 16983 * @name DataTable#destroy.dt 16984 * @event 16985 * @param {event} e jQuery event object 16986 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 16987 */ 16988 16989 /** 16990 * Page length change event, fired when number of records to show on each 16991 * page (the length) is changed. 16992 * @name DataTable#length.dt 16993 * @event 16994 * @param {event} e jQuery event object 16995 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 16996 * @param {integer} len New length 16997 */ 16998 16999 /** 17000 * Column sizing has changed. 17001 * @name DataTable#column-sizing.dt 17002 * @event 17003 * @param {event} e jQuery event object 17004 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 17005 */ 17006 17007 /** 17008 * Column visibility has changed. 17009 * @name DataTable#column-visibility.dt 17010 * @event 17011 * @param {event} e jQuery event object 17012 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 17013 * @param {int} column Column index 17014 * @param {bool} vis `false` if column now hidden, or `true` if visible 17015 */ 17016 17017 return $.fn.dataTable; 17018})); 17019 17020 17021/***/ }), 17022
vendor: 290,128 bytes, lines 17023-27926
17023/***/ "./node_modules/jquery/dist/jquery.js": 17024/*!********************************************!*\ 17025 !*** ./node_modules/jquery/dist/jquery.js ***! 17026 \********************************************/ 17027/*! no static exports found */ 17028/***/ (function(module, exports, __webpack_require__) { 17029 17030var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*! 17031 * jQuery JavaScript Library v3.6.0 17032 * https://jquery.com/ 17033 * 17034 * Includes Sizzle.js 17035 * https://sizzlejs.com/ 17036 * 17037 * Copyright OpenJS Foundation and other contributors 17038 * Released under the MIT license 17039 * https://jquery.org/license 17040 * 17041 * Date: 2021-03-02T17:08Z 17042 */ 17043( function( global, factory ) { 17044 17045 "use strict"; 17046 17047 if ( true && typeof module.exports === "object" ) { 17048 17049 // For CommonJS and CommonJS-like environments where a proper `window` 17050 // is present, execute the factory and get jQuery. 17051 // For environments that do not have a `window` with a `document` 17052 // (such as Node.js), expose a factory as module.exports. 17053 // This accentuates the need for the creation of a real `window`. 17054 // e.g. var jQuery = require("jquery")(window); 17055 // See ticket #14549 for more info. 17056 module.exports = global.document ? 17057 factory( global, true ) : 17058 function( w ) { 17059 if ( !w.document ) { 17060 throw new Error( "jQuery requires a window with a document" ); 17061 } 17062 return factory( w ); 17063 }; 17064 } else { 17065 factory( global ); 17066 } 17067 17068// Pass this if window is not defined yet 17069} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { 17070 17071// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 17072// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode 17073// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common 17074// enough that all such attempts are guarded in a try block. 17075"use strict"; 17076 17077var arr = []; 17078 17079var getProto = Object.getPrototypeOf; 17080 17081var slice = arr.slice; 17082 17083var flat = arr.flat ? function( array ) { 17084 return arr.flat.call( array ); 17085} : function( array ) { 17086 return arr.concat.apply( [], array ); 17087}; 17088 17089 17090var push = arr.push; 17091 17092var indexOf = arr.indexOf; 17093 17094var class2type = {}; 17095 17096var toString = class2type.toString; 17097 17098var hasOwn = class2type.hasOwnProperty; 17099 17100var fnToString = hasOwn.toString; 17101 17102var ObjectFunctionString = fnToString.call( Object ); 17103 17104var support = {}; 17105 17106var isFunction = function isFunction( obj ) { 17107 17108 // Support: Chrome <=57, Firefox <=52 17109 // In some browsers, typeof returns "function" for HTML <object> elements 17110 // (i.e., `typeof document.createElement( "object" ) === "function"`). 17111 // We don't want to classify *any* DOM node as a function. 17112 // Support: QtWeb <=3.8.5, WebKit <=534.34, wkhtmltopdf tool <=0.12.5 17113 // Plus for old WebKit, typeof returns "function" for HTML collections 17114 // (e.g., `typeof document.getElementsByTagName("div") === "function"`). (gh-4756) 17115 return typeof obj === "function" && typeof obj.nodeType !== "number" && 17116 typeof obj.item !== "function"; 17117 }; 17118 17119 17120var isWindow = function isWindow( obj ) { 17121 return obj != null && obj === obj.window; 17122 }; 17123 17124 17125var document = window.document; 17126 17127 17128 17129 var preservedScriptAttributes = { 17130 type: true, 17131 src: true, 17132 nonce: true, 17133 noModule: true 17134 }; 17135 17136 function DOMEval( code, node, doc ) { 17137 doc = doc || document; 17138 17139 var i, val, 17140 script = doc.createElement( "script" ); 17141 17142 script.text = code; 17143 if ( node ) { 17144 for ( i in preservedScriptAttributes ) { 17145 17146 // Support: Firefox 64+, Edge 18+ 17147 // Some browsers don't support the "nonce" property on scripts. 17148 // On the other hand, just using `getAttribute` is not enough as 17149 // the `nonce` attribute is reset to an empty string whenever it 17150 // becomes browsing-context connected. 17151 // See https://github.com/whatwg/html/issues/2369 17152 // See https://html.spec.whatwg.org/#nonce-attributes 17153 // The `node.getAttribute` check was added for the sake of 17154 // `jQuery.globalEval` so that it can fake a nonce-containing node 17155 // via an object. 17156 val = node[ i ] || node.getAttribute && node.getAttribute( i ); 17157 if ( val ) { 17158 script.setAttribute( i, val ); 17159 } 17160 } 17161 } 17162 doc.head.appendChild( script ).parentNode.removeChild( script ); 17163 } 17164 17165 17166function toType( obj ) { 17167 if ( obj == null ) { 17168 return obj + ""; 17169 } 17170 17171 // Support: Android <=2.3 only (functionish RegExp) 17172 return typeof obj === "object" || typeof obj === "function" ? 17173 class2type[ toString.call( obj ) ] || "object" : 17174 typeof obj; 17175} 17176/* global Symbol */ 17177// Defining this global in .eslintrc.json would create a danger of using the global 17178// unguarded in another place, it seems safer to define global only for this module 17179 17180 17181 17182var 17183 version = "3.6.0", 17184 17185 // Define a local copy of jQuery 17186 jQuery = function( selector, context ) { 17187 17188 // The jQuery object is actually just the init constructor 'enhanced' 17189 // Need init if jQuery is called (just allow error to be thrown if not included) 17190 return new jQuery.fn.init( selector, context ); 17191 }; 17192 17193jQuery.fn = jQuery.prototype = { 17194 17195 // The current version of jQuery being used 17196 jquery: version, 17197 17198 constructor: jQuery, 17199 17200 // The default length of a jQuery object is 0 17201 length: 0, 17202 17203 toArray: function() { 17204 return slice.call( this ); 17205 }, 17206 17207 // Get the Nth element in the matched element set OR 17208 // Get the whole matched element set as a clean array 17209 get: function( num ) { 17210 17211 // Return all the elements in a clean array 17212 if ( num == null ) { 17213 return slice.call( this ); 17214 } 17215 17216 // Return just the one element from the set 17217 return num < 0 ? this[ num + this.length ] : this[ num ]; 17218 }, 17219 17220 // Take an array of elements and push it onto the stack 17221 // (returning the new matched element set) 17222 pushStack: function( elems ) { 17223 17224 // Build a new jQuery matched element set 17225 var ret = jQuery.merge( this.constructor(), elems ); 17226 17227 // Add the old object onto the stack (as a reference) 17228 ret.prevObject = this; 17229 17230 // Return the newly-formed element set 17231 return ret; 17232 }, 17233 17234 // Execute a callback for every element in the matched set. 17235 each: function( callback ) { 17236 return jQuery.each( this, callback ); 17237 }, 17238 17239 map: function( callback ) { 17240 return this.pushStack( jQuery.map( this, function( elem, i ) { 17241 return callback.call( elem, i, elem ); 17242 } ) ); 17243 }, 17244 17245 slice: function() { 17246 return this.pushStack( slice.apply( this, arguments ) ); 17247 }, 17248 17249 first: function() { 17250 return this.eq( 0 ); 17251 }, 17252 17253 last: function() { 17254 return this.eq( -1 ); 17255 }, 17256 17257 even: function() { 17258 return this.pushStack( jQuery.grep( this, function( _elem, i ) { 17259 return ( i + 1 ) % 2; 17260 } ) ); 17261 }, 17262 17263 odd: function() { 17264 return this.pushStack( jQuery.grep( this, function( _elem, i ) { 17265 return i % 2; 17266 } ) ); 17267 }, 17268 17269 eq: function( i ) { 17270 var len = this.length, 17271 j = +i + ( i < 0 ? len : 0 ); 17272 return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); 17273 }, 17274 17275 end: function() { 17276 return this.prevObject || this.constructor(); 17277 }, 17278 17279 // For internal use only. 17280 // Behaves like an Array's method, not like a jQuery method. 17281 push: push, 17282 sort: arr.sort, 17283 splice: arr.splice 17284}; 17285 17286jQuery.extend = jQuery.fn.extend = function() { 17287 var options, name, src, copy, copyIsArray, clone, 17288 target = arguments[ 0 ] || {}, 17289 i = 1, 17290 length = arguments.length, 17291 deep = false; 17292 17293 // Handle a deep copy situation 17294 if ( typeof target === "boolean" ) { 17295 deep = target; 17296 17297 // Skip the boolean and the target 17298 target = arguments[ i ] || {}; 17299 i++; 17300 } 17301 17302 // Handle case when target is a string or something (possible in deep copy) 17303 if ( typeof target !== "object" && !isFunction( target ) ) { 17304 target = {}; 17305 } 17306 17307 // Extend jQuery itself if only one argument is passed 17308 if ( i === length ) { 17309 target = this; 17310 i--; 17311 } 17312 17313 for ( ; i < length; i++ ) { 17314 17315 // Only deal with non-null/undefined values 17316 if ( ( options = arguments[ i ] ) != null ) { 17317 17318 // Extend the base object 17319 for ( name in options ) { 17320 copy = options[ name ]; 17321 17322 // Prevent Object.prototype pollution 17323 // Prevent never-ending loop 17324 if ( name === "__proto__" || target === copy ) { 17325 continue; 17326 } 17327 17328 // Recurse if we're merging plain objects or arrays 17329 if ( deep && copy && ( jQuery.isPlainObject( copy ) || 17330 ( copyIsArray = Array.isArray( copy ) ) ) ) { 17331 src = target[ name ]; 17332 17333 // Ensure proper type for the source value 17334 if ( copyIsArray && !Array.isArray( src ) ) { 17335 clone = []; 17336 } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) { 17337 clone = {}; 17338 } else { 17339 clone = src; 17340 } 17341 copyIsArray = false; 17342 17343 // Never move original objects, clone them 17344 target[ name ] = jQuery.extend( deep, clone, copy ); 17345 17346 // Don't bring in undefined values 17347 } else if ( copy !== undefined ) { 17348 target[ name ] = copy; 17349 } 17350 } 17351 } 17352 } 17353 17354 // Return the modified object 17355 return target; 17356}; 17357 17358jQuery.extend( { 17359 17360 // Unique for each copy of jQuery on the page 17361 expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), 17362 17363 // Assume jQuery is ready without the ready module 17364 isReady: true, 17365 17366 error: function( msg ) { 17367 throw new Error( msg ); 17368 }, 17369 17370 noop: function() {}, 17371 17372 isPlainObject: function( obj ) { 17373 var proto, Ctor; 17374 17375 // Detect obvious negatives 17376 // Use toString instead of jQuery.type to catch host objects 17377 if ( !obj || toString.call( obj ) !== "[object Object]" ) { 17378 return false; 17379 } 17380 17381 proto = getProto( obj ); 17382 17383 // Objects with no prototype (e.g., `Object.create( null )`) are plain 17384 if ( !proto ) { 17385 return true; 17386 } 17387 17388 // Objects with prototype are plain iff they were constructed by a global Object function 17389 Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; 17390 return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; 17391 }, 17392 17393 isEmptyObject: function( obj ) { 17394 var name; 17395 17396 for ( name in obj ) { 17397 return false; 17398 } 17399 return true; 17400 }, 17401 17402 // Evaluates a script in a provided context; falls back to the global one 17403 // if not specified. 17404 globalEval: function( code, options, doc ) { 17405 DOMEval( code, { nonce: options && options.nonce }, doc ); 17406 }, 17407 17408 each: function( obj, callback ) { 17409 var length, i = 0; 17410 17411 if ( isArrayLike( obj ) ) { 17412 length = obj.length; 17413 for ( ; i < length; i++ ) { 17414 if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { 17415 break; 17416 } 17417 } 17418 } else { 17419 for ( i in obj ) { 17420 if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { 17421 break; 17422 } 17423 } 17424 } 17425 17426 return obj; 17427 }, 17428 17429 // results is for internal usage only 17430 makeArray: function( arr, results ) { 17431 var ret = results || []; 17432 17433 if ( arr != null ) { 17434 if ( isArrayLike( Object( arr ) ) ) { 17435 jQuery.merge( ret, 17436 typeof arr === "string" ? 17437 [ arr ] : arr 17438 ); 17439 } else { 17440 push.call( ret, arr ); 17441 } 17442 } 17443 17444 return ret; 17445 }, 17446 17447 inArray: function( elem, arr, i ) { 17448 return arr == null ? -1 : indexOf.call( arr, elem, i ); 17449 }, 17450 17451 // Support: Android <=4.0 only, PhantomJS 1 only 17452 // push.apply(_, arraylike) throws on ancient WebKit 17453 merge: function( first, second ) { 17454 var len = +second.length, 17455 j = 0, 17456 i = first.length; 17457 17458 for ( ; j < len; j++ ) { 17459 first[ i++ ] = second[ j ]; 17460 } 17461 17462 first.length = i; 17463 17464 return first; 17465 }, 17466 17467 grep: function( elems, callback, invert ) { 17468 var callbackInverse, 17469 matches = [], 17470 i = 0, 17471 length = elems.length, 17472 callbackExpect = !invert; 17473 17474 // Go through the array, only saving the items 17475 // that pass the validator function 17476 for ( ; i < length; i++ ) { 17477 callbackInverse = !callback( elems[ i ], i ); 17478 if ( callbackInverse !== callbackExpect ) { 17479 matches.push( elems[ i ] ); 17480 } 17481 } 17482 17483 return matches; 17484 }, 17485 17486 // arg is for internal usage only 17487 map: function( elems, callback, arg ) { 17488 var length, value, 17489 i = 0, 17490 ret = []; 17491 17492 // Go through the array, translating each of the items to their new values 17493 if ( isArrayLike( elems ) ) { 17494 length = elems.length; 17495 for ( ; i < length; i++ ) { 17496 value = callback( elems[ i ], i, arg ); 17497 17498 if ( value != null ) { 17499 ret.push( value ); 17500 } 17501 } 17502 17503 // Go through every key on the object, 17504 } else { 17505 for ( i in elems ) { 17506 value = callback( elems[ i ], i, arg ); 17507 17508 if ( value != null ) { 17509 ret.push( value ); 17510 } 17511 } 17512 } 17513 17514 // Flatten any nested arrays 17515 return flat( ret ); 17516 }, 17517 17518 // A global GUID counter for objects 17519 guid: 1, 17520 17521 // jQuery.support is not used in Core but other projects attach their 17522 // properties to it so it needs to exist. 17523 support: support 17524} ); 17525 17526if ( typeof Symbol === "function" ) { 17527 jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; 17528} 17529 17530// Populate the class2type map 17531jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), 17532 function( _i, name ) { 17533 class2type[ "[object " + name + "]" ] = name.toLowerCase(); 17534 } ); 17535 17536function isArrayLike( obj ) { 17537 17538 // Support: real iOS 8.2 only (not reproducible in simulator) 17539 // `in` check used to prevent JIT error (gh-2145) 17540 // hasOwn isn't used here due to false negatives 17541 // regarding Nodelist length in IE 17542 var length = !!obj && "length" in obj && obj.length, 17543 type = toType( obj ); 17544 17545 if ( isFunction( obj ) || isWindow( obj ) ) { 17546 return false; 17547 } 17548 17549 return type === "array" || length === 0 || 17550 typeof length === "number" && length > 0 && ( length - 1 ) in obj; 17551} 17552var Sizzle = 17553/*! 17554 * Sizzle CSS Selector Engine v2.3.6 17555 * https://sizzlejs.com/ 17556 * 17557 * Copyright JS Foundation and other contributors 17558 * Released under the MIT license 17559 * https://js.foundation/ 17560 * 17561 * Date: 2021-02-16 17562 */ 17563( function( window ) { 17564var i, 17565 support, 17566 Expr, 17567 getText, 17568 isXML, 17569 tokenize, 17570 compile, 17571 select, 17572 outermostContext, 17573 sortInput, 17574 hasDuplicate, 17575 17576 // Local document vars 17577 setDocument, 17578 document, 17579 docElem, 17580 documentIsHTML, 17581 rbuggyQSA, 17582 rbuggyMatches, 17583 matches, 17584 contains, 17585 17586 // Instance-specific data 17587 expando = "sizzle" + 1 * new Date(), 17588 preferredDoc = window.document, 17589 dirruns = 0, 17590 done = 0, 17591 classCache = createCache(), 17592 tokenCache = createCache(), 17593 compilerCache = createCache(), 17594 nonnativeSelectorCache = createCache(), 17595 sortOrder = function( a, b ) { 17596 if ( a === b ) { 17597 hasDuplicate = true; 17598 } 17599 return 0; 17600 }, 17601 17602 // Instance methods 17603 hasOwn = ( {} ).hasOwnProperty, 17604 arr = [], 17605 pop = arr.pop, 17606 pushNative = arr.push, 17607 push = arr.push, 17608 slice = arr.slice, 17609 17610 // Use a stripped-down indexOf as it's faster than native 17611 // https://jsperf.com/thor-indexof-vs-for/5 17612 indexOf = function( list, elem ) { 17613 var i = 0, 17614 len = list.length; 17615 for ( ; i < len; i++ ) { 17616 if ( list[ i ] === elem ) { 17617 return i; 17618 } 17619 } 17620 return -1; 17621 }, 17622 17623 booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|" + 17624 "ismap|loop|multiple|open|readonly|required|scoped", 17625 17626 // Regular expressions 17627 17628 // http://www.w3.org/TR/css3-selectors/#whitespace 17629 whitespace = "[\\x20\\t\\r\\n\\f]", 17630 17631 // https://www.w3.org/TR/css-syntax-3/#ident-token-diagram 17632 identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace + 17633 "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+", 17634 17635 // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors 17636 attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + 17637 17638 // Operator (capture 2) 17639 "*([*^$|!~]?=)" + whitespace + 17640 17641 // "Attribute values must be CSS identifiers [capture 5] 17642 // or strings [capture 3 or capture 4]" 17643 "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + 17644 whitespace + "*\\]", 17645 17646 pseudos = ":(" + identifier + ")(?:\\((" + 17647 17648 // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: 17649 // 1. quoted (capture 3; capture 4 or capture 5) 17650 "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + 17651 17652 // 2. simple (capture 6) 17653 "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + 17654 17655 // 3. anything else (capture 2) 17656 ".*" + 17657 ")\\)|)", 17658 17659 // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter 17660 rwhitespace = new RegExp( whitespace + "+", "g" ), 17661 rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + 17662 whitespace + "+$", "g" ), 17663 17664 rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), 17665 rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + 17666 "*" ), 17667 rdescend = new RegExp( whitespace + "|>" ), 17668 17669 rpseudo = new RegExp( pseudos ), 17670 ridentifier = new RegExp( "^" + identifier + "$" ), 17671 17672 matchExpr = { 17673 "ID": new RegExp( "^#(" + identifier + ")" ), 17674 "CLASS": new RegExp( "^\\.(" + identifier + ")" ), 17675 "TAG": new RegExp( "^(" + identifier + "|[*])" ), 17676 "ATTR": new RegExp( "^" + attributes ), 17677 "PSEUDO": new RegExp( "^" + pseudos ), 17678 "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + 17679 whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + 17680 whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), 17681 "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), 17682 17683 // For use in libraries implementing .is() 17684 // We use this for POS matching in `select` 17685 "needsContext": new RegExp( "^" + whitespace + 17686 "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + 17687 "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) 17688 }, 17689 17690 rhtml = /HTML$/i, 17691 rinputs = /^(?:input|select|textarea|button)$/i, 17692 rheader = /^h\d$/i, 17693 17694 rnative = /^[^{]+\{\s*\[native \w/, 17695 17696 // Easily-parseable/retrievable ID or TAG or CLASS selectors 17697 rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, 17698 17699 rsibling = /[+~]/, 17700 17701 // CSS escapes 17702 // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters 17703 runescape = new RegExp( "\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\([^\\r\\n\\f])", "g" ), 17704 funescape = function( escape, nonHex ) { 17705 var high = "0x" + escape.slice( 1 ) - 0x10000; 17706 17707 return nonHex ? 17708 17709 // Strip the backslash prefix from a non-hex escape sequence 17710 nonHex : 17711 17712 // Replace a hexadecimal escape sequence with the encoded Unicode code point 17713 // Support: IE <=11+ 17714 // For values outside the Basic Multilingual Plane (BMP), manually construct a 17715 // surrogate pair 17716 high < 0 ? 17717 String.fromCharCode( high + 0x10000 ) : 17718 String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); 17719 }, 17720 17721 // CSS string/identifier serialization 17722 // https://drafts.csswg.org/cssom/#common-serializing-idioms 17723 rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, 17724 fcssescape = function( ch, asCodePoint ) { 17725 if ( asCodePoint ) { 17726 17727 // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER 17728 if ( ch === "\0" ) { 17729 return "\uFFFD"; 17730 } 17731 17732 // Control characters and (dependent upon position) numbers get escaped as code points 17733 return ch.slice( 0, -1 ) + "\\" + 17734 ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; 17735 } 17736 17737 // Other potentially-special ASCII characters get backslash-escaped 17738 return "\\" + ch; 17739 }, 17740 17741 // Used for iframes 17742 // See setDocument() 17743 // Removing the function wrapper causes a "Permission Denied" 17744 // error in IE 17745 unloadHandler = function() { 17746 setDocument(); 17747 }, 17748 17749 inDisabledFieldset = addCombinator( 17750 function( elem ) { 17751 return elem.disabled === true && elem.nodeName.toLowerCase() === "fieldset"; 17752 }, 17753 { dir: "parentNode", next: "legend" } 17754 ); 17755 17756// Optimize for push.apply( _, NodeList ) 17757try { 17758 push.apply( 17759 ( arr = slice.call( preferredDoc.childNodes ) ), 17760 preferredDoc.childNodes 17761 ); 17762 17763 // Support: Android<4.0 17764 // Detect silently failing push.apply 17765 // eslint-disable-next-line no-unused-expressions 17766 arr[ preferredDoc.childNodes.length ].nodeType; 17767} catch ( e ) { 17768 push = { apply: arr.length ? 17769 17770 // Leverage slice if possible 17771 function( target, els ) { 17772 pushNative.apply( target, slice.call( els ) ); 17773 } : 17774 17775 // Support: IE<9 17776 // Otherwise append directly 17777 function( target, els ) { 17778 var j = target.length, 17779 i = 0; 17780 17781 // Can't trust NodeList.length 17782 while ( ( target[ j++ ] = els[ i++ ] ) ) {} 17783 target.length = j - 1; 17784 } 17785 }; 17786} 17787 17788function Sizzle( selector, context, results, seed ) { 17789 var m, i, elem, nid, match, groups, newSelector, 17790 newContext = context && context.ownerDocument, 17791 17792 // nodeType defaults to 9, since context defaults to document 17793 nodeType = context ? context.nodeType : 9; 17794 17795 results = results || []; 17796 17797 // Return early from calls with invalid selector or context 17798 if ( typeof selector !== "string" || !selector || 17799 nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { 17800 17801 return results; 17802 } 17803 17804 // Try to shortcut find operations (as opposed to filters) in HTML documents 17805 if ( !seed ) { 17806 setDocument( context ); 17807 context = context || document; 17808 17809 if ( documentIsHTML ) { 17810 17811 // If the selector is sufficiently simple, try using a "get*By*" DOM method 17812 // (excepting DocumentFragment context, where the methods don't exist) 17813 if ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) { 17814 17815 // ID selector 17816 if ( ( m = match[ 1 ] ) ) { 17817 17818 // Document context 17819 if ( nodeType === 9 ) { 17820 if ( ( elem = context.getElementById( m ) ) ) { 17821 17822 // Support: IE, Opera, Webkit 17823 // TODO: identify versions 17824 // getElementById can match elements by name instead of ID 17825 if ( elem.id === m ) { 17826 results.push( elem ); 17827 return results; 17828 } 17829 } else { 17830 return results; 17831 } 17832 17833 // Element context 17834 } else { 17835 17836 // Support: IE, Opera, Webkit 17837 // TODO: identify versions 17838 // getElementById can match elements by name instead of ID 17839 if ( newContext && ( elem = newContext.getElementById( m ) ) && 17840 contains( context, elem ) && 17841 elem.id === m ) { 17842 17843 results.push( elem ); 17844 return results; 17845 } 17846 } 17847 17848 // Type selector 17849 } else if ( match[ 2 ] ) { 17850 push.apply( results, context.getElementsByTagName( selector ) ); 17851 return results; 17852 17853 // Class selector 17854 } else if ( ( m = match[ 3 ] ) && support.getElementsByClassName && 17855 context.getElementsByClassName ) { 17856 17857 push.apply( results, context.getElementsByClassName( m ) ); 17858 return results; 17859 } 17860 } 17861 17862 // Take advantage of querySelectorAll 17863 if ( support.qsa && 17864 !nonnativeSelectorCache[ selector + " " ] && 17865 ( !rbuggyQSA || !rbuggyQSA.test( selector ) ) && 17866 17867 // Support: IE 8 only 17868 // Exclude object elements 17869 ( nodeType !== 1 || context.nodeName.toLowerCase() !== "object" ) ) { 17870 17871 newSelector = selector; 17872 newContext = context; 17873 17874 // qSA considers elements outside a scoping root when evaluating child or 17875 // descendant combinators, which is not what we want. 17876 // In such cases, we work around the behavior by prefixing every selector in the 17877 // list with an ID selector referencing the scope context. 17878 // The technique has to be used as well when a leading combinator is used 17879 // as such selectors are not recognized by querySelectorAll. 17880 // Thanks to Andrew Dupont for this technique. 17881 if ( nodeType === 1 && 17882 ( rdescend.test( selector ) || rcombinators.test( selector ) ) ) { 17883 17884 // Expand context for sibling selectors 17885 newContext = rsibling.test( selector ) && testContext( context.parentNode ) || 17886 context; 17887 17888 // We can use :scope instead of the ID hack if the browser 17889 // supports it & if we're not changing the context. 17890 if ( newContext !== context || !support.scope ) { 17891 17892 // Capture the context ID, setting it first if necessary 17893 if ( ( nid = context.getAttribute( "id" ) ) ) { 17894 nid = nid.replace( rcssescape, fcssescape ); 17895 } else { 17896 context.setAttribute( "id", ( nid = expando ) ); 17897 } 17898 } 17899 17900 // Prefix every selector in the list 17901 groups = tokenize( selector ); 17902 i = groups.length; 17903 while ( i-- ) { 17904 groups[ i ] = ( nid ? "#" + nid : ":scope" ) + " " + 17905 toSelector( groups[ i ] ); 17906 } 17907 newSelector = groups.join( "," ); 17908 } 17909 17910 try { 17911 push.apply( results, 17912 newContext.querySelectorAll( newSelector ) 17913 ); 17914 return results; 17915 } catch ( qsaError ) { 17916 nonnativeSelectorCache( selector, true ); 17917 } finally { 17918 if ( nid === expando ) { 17919 context.removeAttribute( "id" ); 17920 } 17921 } 17922 } 17923 } 17924 } 17925 17926 // All others 17927 return select( selector.replace( rtrim, "$1" ), context, results, seed ); 17928} 17929 17930/** 17931 * Create key-value caches of limited size 17932 * @returns {function(string, object)} Returns the Object data after storing it on itself with 17933 * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) 17934 * deleting the oldest entry 17935 */ 17936function createCache() { 17937 var keys = []; 17938 17939 function cache( key, value ) { 17940 17941 // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) 17942 if ( keys.push( key + " " ) > Expr.cacheLength ) { 17943 17944 // Only keep the most recent entries 17945 delete cache[ keys.shift() ]; 17946 } 17947 return ( cache[ key + " " ] = value ); 17948 } 17949 return cache; 17950} 17951 17952/** 17953 * Mark a function for special use by Sizzle 17954 * @param {Function} fn The function to mark 17955 */ 17956function markFunction( fn ) { 17957 fn[ expando ] = true; 17958 return fn; 17959} 17960 17961/** 17962 * Support testing using an element 17963 * @param {Function} fn Passed the created element and returns a boolean result 17964 */ 17965function assert( fn ) { 17966 var el = document.createElement( "fieldset" ); 17967 17968 try { 17969 return !!fn( el ); 17970 } catch ( e ) { 17971 return false; 17972 } finally { 17973 17974 // Remove from its parent by default 17975 if ( el.parentNode ) { 17976 el.parentNode.removeChild( el ); 17977 } 17978 17979 // release memory in IE 17980 el = null; 17981 } 17982} 17983 17984/** 17985 * Adds the same handler for all of the specified attrs 17986 * @param {String} attrs Pipe-separated list of attributes 17987 * @param {Function} handler The method that will be applied 17988 */ 17989function addHandle( attrs, handler ) { 17990 var arr = attrs.split( "|" ), 17991 i = arr.length; 17992 17993 while ( i-- ) { 17994 Expr.attrHandle[ arr[ i ] ] = handler; 17995 } 17996} 17997 17998/** 17999 * Checks document order of two siblings 18000 * @param {Element} a 18001 * @param {Element} b 18002 * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b 18003 */ 18004function siblingCheck( a, b ) { 18005 var cur = b && a, 18006 diff = cur && a.nodeType === 1 && b.nodeType === 1 && 18007 a.sourceIndex - b.sourceIndex; 18008 18009 // Use IE sourceIndex if available on both nodes 18010 if ( diff ) { 18011 return diff; 18012 } 18013 18014 // Check if b follows a 18015 if ( cur ) { 18016 while ( ( cur = cur.nextSibling ) ) { 18017 if ( cur === b ) { 18018 return -1; 18019 } 18020 } 18021 } 18022 18023 return a ? 1 : -1; 18024} 18025 18026/** 18027 * Returns a function to use in pseudos for input types 18028 * @param {String} type 18029 */ 18030function createInputPseudo( type ) { 18031 return function( elem ) { 18032 var name = elem.nodeName.toLowerCase(); 18033 return name === "input" && elem.type === type; 18034 }; 18035} 18036 18037/** 18038 * Returns a function to use in pseudos for buttons 18039 * @param {String} type 18040 */ 18041function createButtonPseudo( type ) { 18042 return function( elem ) { 18043 var name = elem.nodeName.toLowerCase(); 18044 return ( name === "input" || name === "button" ) && elem.type === type; 18045 }; 18046} 18047 18048/** 18049 * Returns a function to use in pseudos for :enabled/:disabled 18050 * @param {Boolean} disabled true for :disabled; false for :enabled 18051 */ 18052function createDisabledPseudo( disabled ) { 18053 18054 // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable 18055 return function( elem ) { 18056 18057 // Only certain elements can match :enabled or :disabled 18058 // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled 18059 // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled 18060 if ( "form" in elem ) { 18061 18062 // Check for inherited disabledness on relevant non-disabled elements: 18063 // * listed form-associated elements in a disabled fieldset 18064 // https://html.spec.whatwg.org/multipage/forms.html#category-listed 18065 // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled 18066 // * option elements in a disabled optgroup 18067 // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled 18068 // All such elements have a "form" property. 18069 if ( elem.parentNode && elem.disabled === false ) { 18070 18071 // Option elements defer to a parent optgroup if present 18072 if ( "label" in elem ) { 18073 if ( "label" in elem.parentNode ) { 18074 return elem.parentNode.disabled === disabled; 18075 } else { 18076 return elem.disabled === disabled; 18077 } 18078 } 18079 18080 // Support: IE 6 - 11 18081 // Use the isDisabled shortcut property to check for disabled fieldset ancestors 18082 return elem.isDisabled === disabled || 18083 18084 // Where there is no isDisabled, check manually 18085 /* jshint -W018 */ 18086 elem.isDisabled !== !disabled && 18087 inDisabledFieldset( elem ) === disabled; 18088 } 18089 18090 return elem.disabled === disabled; 18091 18092 // Try to winnow out elements that can't be disabled before trusting the disabled property. 18093 // Some victims get caught in our net (label, legend, menu, track), but it shouldn't 18094 // even exist on them, let alone have a boolean value. 18095 } else if ( "label" in elem ) { 18096 return elem.disabled === disabled; 18097 } 18098 18099 // Remaining elements are neither :enabled nor :disabled 18100 return false; 18101 }; 18102} 18103 18104/** 18105 * Returns a function to use in pseudos for positionals 18106 * @param {Function} fn 18107 */ 18108function createPositionalPseudo( fn ) { 18109 return markFunction( function( argument ) { 18110 argument = +argument; 18111 return markFunction( function( seed, matches ) { 18112 var j, 18113 matchIndexes = fn( [], seed.length, argument ), 18114 i = matchIndexes.length; 18115 18116 // Match elements found at the specified indexes 18117 while ( i-- ) { 18118 if ( seed[ ( j = matchIndexes[ i ] ) ] ) { 18119 seed[ j ] = !( matches[ j ] = seed[ j ] ); 18120 } 18121 } 18122 } ); 18123 } ); 18124} 18125 18126/** 18127 * Checks a node for validity as a Sizzle context 18128 * @param {Element|Object=} context 18129 * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value 18130 */ 18131function testContext( context ) { 18132 return context && typeof context.getElementsByTagName !== "undefined" && context; 18133} 18134 18135// Expose support vars for convenience 18136support = Sizzle.support = {}; 18137 18138/** 18139 * Detects XML nodes 18140 * @param {Element|Object} elem An element or a document 18141 * @returns {Boolean} True iff elem is a non-HTML XML node 18142 */ 18143isXML = Sizzle.isXML = function( elem ) { 18144 var namespace = elem && elem.namespaceURI, 18145 docElem = elem && ( elem.ownerDocument || elem ).documentElement; 18146 18147 // Support: IE <=8 18148 // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes 18149 // https://bugs.jquery.com/ticket/4833 18150 return !rhtml.test( namespace || docElem && docElem.nodeName || "HTML" ); 18151}; 18152 18153/** 18154 * Sets document-related variables once based on the current document 18155 * @param {Element|Object} [doc] An element or document object to use to set the document 18156 * @returns {Object} Returns the current document 18157 */ 18158setDocument = Sizzle.setDocument = function( node ) { 18159 var hasCompare, subWindow, 18160 doc = node ? node.ownerDocument || node : preferredDoc; 18161 18162 // Return early if doc is invalid or already selected 18163 // Support: IE 11+, Edge 17 - 18+ 18164 // IE/Edge sometimes throw a "Permission denied" error when strict-comparing 18165 // two documents; shallow comparisons work. 18166 // eslint-disable-next-line eqeqeq 18167 if ( doc == document || doc.nodeType !== 9 || !doc.documentElement ) { 18168 return document; 18169 } 18170 18171 // Update global variables 18172 document = doc; 18173 docElem = document.documentElement; 18174 documentIsHTML = !isXML( document ); 18175 18176 // Support: IE 9 - 11+, Edge 12 - 18+ 18177 // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) 18178 // Support: IE 11+, Edge 17 - 18+ 18179 // IE/Edge sometimes throw a "Permission denied" error when strict-comparing 18180 // two documents; shallow comparisons work. 18181 // eslint-disable-next-line eqeqeq 18182 if ( preferredDoc != document && 18183 ( subWindow = document.defaultView ) && subWindow.top !== subWindow ) { 18184 18185 // Support: IE 11, Edge 18186 if ( subWindow.addEventListener ) { 18187 subWindow.addEventListener( "unload", unloadHandler, false ); 18188 18189 // Support: IE 9 - 10 only 18190 } else if ( subWindow.attachEvent ) { 18191 subWindow.attachEvent( "onunload", unloadHandler ); 18192 } 18193 } 18194 18195 // Support: IE 8 - 11+, Edge 12 - 18+, Chrome <=16 - 25 only, Firefox <=3.6 - 31 only, 18196 // Safari 4 - 5 only, Opera <=11.6 - 12.x only 18197 // IE/Edge & older browsers don't support the :scope pseudo-class. 18198 // Support: Safari 6.0 only 18199 // Safari 6.0 supports :scope but it's an alias of :root there. 18200 support.scope = assert( function( el ) { 18201 docElem.appendChild( el ).appendChild( document.createElement( "div" ) ); 18202 return typeof el.querySelectorAll !== "undefined" && 18203 !el.querySelectorAll( ":scope fieldset div" ).length; 18204 } ); 18205 18206 /* Attributes 18207 ---------------------------------------------------------------------- */ 18208 18209 // Support: IE<8 18210 // Verify that getAttribute really returns attributes and not properties 18211 // (excepting IE8 booleans) 18212 support.attributes = assert( function( el ) { 18213 el.className = "i"; 18214 return !el.getAttribute( "className" ); 18215 } ); 18216 18217 /* getElement(s)By* 18218 ---------------------------------------------------------------------- */ 18219 18220 // Check if getElementsByTagName("*") returns only elements 18221 support.getElementsByTagName = assert( function( el ) { 18222 el.appendChild( document.createComment( "" ) ); 18223 return !el.getElementsByTagName( "*" ).length; 18224 } ); 18225 18226 // Support: IE<9 18227 support.getElementsByClassName = rnative.test( document.getElementsByClassName ); 18228 18229 // Support: IE<10 18230 // Check if getElementById returns elements by name 18231 // The broken getElementById methods don't pick up programmatically-set names, 18232 // so use a roundabout getElementsByName test 18233 support.getById = assert( function( el ) { 18234 docElem.appendChild( el ).id = expando; 18235 return !document.getElementsByName || !document.getElementsByName( expando ).length; 18236 } ); 18237 18238 // ID filter and find 18239 if ( support.getById ) { 18240 Expr.filter[ "ID" ] = function( id ) { 18241 var attrId = id.replace( runescape, funescape ); 18242 return function( elem ) { 18243 return elem.getAttribute( "id" ) === attrId; 18244 }; 18245 }; 18246 Expr.find[ "ID" ] = function( id, context ) { 18247 if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { 18248 var elem = context.getElementById( id ); 18249 return elem ? [ elem ] : []; 18250 } 18251 }; 18252 } else { 18253 Expr.filter[ "ID" ] = function( id ) { 18254 var attrId = id.replace( runescape, funescape ); 18255 return function( elem ) { 18256 var node = typeof elem.getAttributeNode !== "undefined" && 18257 elem.getAttributeNode( "id" ); 18258 return node && node.value === attrId; 18259 }; 18260 }; 18261 18262 // Support: IE 6 - 7 only 18263 // getElementById is not reliable as a find shortcut 18264 Expr.find[ "ID" ] = function( id, context ) { 18265 if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { 18266 var node, i, elems, 18267 elem = context.getElementById( id ); 18268 18269 if ( elem ) { 18270 18271 // Verify the id attribute 18272 node = elem.getAttributeNode( "id" ); 18273 if ( node && node.value === id ) { 18274 return [ elem ]; 18275 } 18276 18277 // Fall back on getElementsByName 18278 elems = context.getElementsByName( id ); 18279 i = 0; 18280 while ( ( elem = elems[ i++ ] ) ) { 18281 node = elem.getAttributeNode( "id" ); 18282 if ( node && node.value === id ) { 18283 return [ elem ]; 18284 } 18285 } 18286 } 18287 18288 return []; 18289 } 18290 }; 18291 } 18292 18293 // Tag 18294 Expr.find[ "TAG" ] = support.getElementsByTagName ? 18295 function( tag, context ) { 18296 if ( typeof context.getElementsByTagName !== "undefined" ) { 18297 return context.getElementsByTagName( tag ); 18298 18299 // DocumentFragment nodes don't have gEBTN 18300 } else if ( support.qsa ) { 18301 return context.querySelectorAll( tag ); 18302 } 18303 } : 18304 18305 function( tag, context ) { 18306 var elem, 18307 tmp = [], 18308 i = 0, 18309 18310 // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too 18311 results = context.getElementsByTagName( tag ); 18312 18313 // Filter out possible comments 18314 if ( tag === "*" ) { 18315 while ( ( elem = results[ i++ ] ) ) { 18316 if ( elem.nodeType === 1 ) { 18317 tmp.push( elem ); 18318 } 18319 } 18320 18321 return tmp; 18322 } 18323 return results; 18324 }; 18325 18326 // Class 18327 Expr.find[ "CLASS" ] = support.getElementsByClassName && function( className, context ) { 18328 if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { 18329 return context.getElementsByClassName( className ); 18330 } 18331 }; 18332 18333 /* QSA/matchesSelector 18334 ---------------------------------------------------------------------- */ 18335 18336 // QSA and matchesSelector support 18337 18338 // matchesSelector(:active) reports false when true (IE9/Opera 11.5) 18339 rbuggyMatches = []; 18340 18341 // qSa(:focus) reports false when true (Chrome 21) 18342 // We allow this because of a bug in IE8/9 that throws an error 18343 // whenever `document.activeElement` is accessed on an iframe 18344 // So, we allow :focus to pass through QSA all the time to avoid the IE error 18345 // See https://bugs.jquery.com/ticket/13378 18346 rbuggyQSA = []; 18347 18348 if ( ( support.qsa = rnative.test( document.querySelectorAll ) ) ) { 18349 18350 // Build QSA regex 18351 // Regex strategy adopted from Diego Perini 18352 assert( function( el ) { 18353 18354 var input; 18355 18356 // Select is set to empty string on purpose 18357 // This is to test IE's treatment of not explicitly 18358 // setting a boolean content attribute, 18359 // since its presence should be enough 18360 // https://bugs.jquery.com/ticket/12359 18361 docElem.appendChild( el ).innerHTML = "<a id='" + expando + "'></a>" + 18362 "<select id='" + expando + "-\r\\' msallowcapture=''>" + 18363 "<option selected=''></option></select>"; 18364 18365 // Support: IE8, Opera 11-12.16 18366 // Nothing should be selected when empty strings follow ^= or $= or *= 18367 // The test attribute must be unknown in Opera but "safe" for WinRT 18368 // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section 18369 if ( el.querySelectorAll( "[msallowcapture^='']" ).length ) { 18370 rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); 18371 } 18372 18373 // Support: IE8 18374 // Boolean attributes and "value" are not treated correctly 18375 if ( !el.querySelectorAll( "[selected]" ).length ) { 18376 rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); 18377 } 18378 18379 // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ 18380 if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { 18381 rbuggyQSA.push( "~=" ); 18382 } 18383 18384 // Support: IE 11+, Edge 15 - 18+ 18385 // IE 11/Edge don't find elements on a `[name='']` query in some cases. 18386 // Adding a temporary attribute to the document before the selection works 18387 // around the issue. 18388 // Interestingly, IE 10 & older don't seem to have the issue. 18389 input = document.createElement( "input" ); 18390 input.setAttribute( "name", "" ); 18391 el.appendChild( input ); 18392 if ( !el.querySelectorAll( "[name='']" ).length ) { 18393 rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" + 18394 whitespace + "*(?:''|\"\")" ); 18395 } 18396 18397 // Webkit/Opera - :checked should return selected option elements 18398 // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked 18399 // IE8 throws error here and will not see later tests 18400 if ( !el.querySelectorAll( ":checked" ).length ) { 18401 rbuggyQSA.push( ":checked" ); 18402 } 18403 18404 // Support: Safari 8+, iOS 8+ 18405 // https://bugs.webkit.org/show_bug.cgi?id=136851 18406 // In-page `selector#id sibling-combinator selector` fails 18407 if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { 18408 rbuggyQSA.push( ".#.+[+~]" ); 18409 } 18410 18411 // Support: Firefox <=3.6 - 5 only 18412 // Old Firefox doesn't throw on a badly-escaped identifier. 18413 el.querySelectorAll( "\\\f" ); 18414 rbuggyQSA.push( "[\\r\\n\\f]" ); 18415 } ); 18416 18417 assert( function( el ) { 18418 el.innerHTML = "<a href='' disabled='disabled'></a>" + 18419 "<select disabled='disabled'><option/></select>"; 18420 18421 // Support: Windows 8 Native Apps 18422 // The type and name attributes are restricted during .innerHTML assignment 18423 var input = document.createElement( "input" ); 18424 input.setAttribute( "type", "hidden" ); 18425 el.appendChild( input ).setAttribute( "name", "D" ); 18426 18427 // Support: IE8 18428 // Enforce case-sensitivity of name attribute 18429 if ( el.querySelectorAll( "[name=d]" ).length ) { 18430 rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); 18431 } 18432 18433 // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) 18434 // IE8 throws error here and will not see later tests 18435 if ( el.querySelectorAll( ":enabled" ).length !== 2 ) { 18436 rbuggyQSA.push( ":enabled", ":disabled" ); 18437 } 18438 18439 // Support: IE9-11+ 18440 // IE's :disabled selector does not pick up the children of disabled fieldsets 18441 docElem.appendChild( el ).disabled = true; 18442 if ( el.querySelectorAll( ":disabled" ).length !== 2 ) { 18443 rbuggyQSA.push( ":enabled", ":disabled" ); 18444 } 18445 18446 // Support: Opera 10 - 11 only 18447 // Opera 10-11 does not throw on post-comma invalid pseudos 18448 el.querySelectorAll( "*,:x" ); 18449 rbuggyQSA.push( ",.*:" ); 18450 } ); 18451 } 18452 18453 if ( ( support.matchesSelector = rnative.test( ( matches = docElem.matches || 18454 docElem.webkitMatchesSelector || 18455 docElem.mozMatchesSelector || 18456 docElem.oMatchesSelector || 18457 docElem.msMatchesSelector ) ) ) ) { 18458 18459 assert( function( el ) { 18460 18461 // Check to see if it's possible to do matchesSelector 18462 // on a disconnected node (IE 9) 18463 support.disconnectedMatch = matches.call( el, "*" ); 18464 18465 // This should fail with an exception 18466 // Gecko does not error, returns false instead 18467 matches.call( el, "[s!='']:x" ); 18468 rbuggyMatches.push( "!=", pseudos ); 18469 } ); 18470 } 18471 18472 rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) ); 18473 rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join( "|" ) ); 18474 18475 /* Contains 18476 ---------------------------------------------------------------------- */ 18477 hasCompare = rnative.test( docElem.compareDocumentPosition ); 18478 18479 // Element contains another 18480 // Purposefully self-exclusive 18481 // As in, an element does not contain itself 18482 contains = hasCompare || rnative.test( docElem.contains ) ? 18483 function( a, b ) { 18484 var adown = a.nodeType === 9 ? a.documentElement : a, 18485 bup = b && b.parentNode; 18486 return a === bup || !!( bup && bup.nodeType === 1 && ( 18487 adown.contains ? 18488 adown.contains( bup ) : 18489 a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 18490 ) ); 18491 } : 18492 function( a, b ) { 18493 if ( b ) { 18494 while ( ( b = b.parentNode ) ) { 18495 if ( b === a ) { 18496 return true; 18497 } 18498 } 18499 } 18500 return false; 18501 }; 18502 18503 /* Sorting 18504 ---------------------------------------------------------------------- */ 18505 18506 // Document order sorting 18507 sortOrder = hasCompare ? 18508 function( a, b ) { 18509 18510 // Flag for duplicate removal 18511 if ( a === b ) { 18512 hasDuplicate = true; 18513 return 0; 18514 } 18515 18516 // Sort on method existence if only one input has compareDocumentPosition 18517 var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; 18518 if ( compare ) { 18519 return compare; 18520 } 18521 18522 // Calculate position if both inputs belong to the same document 18523 // Support: IE 11+, Edge 17 - 18+ 18524 // IE/Edge sometimes throw a "Permission denied" error when strict-comparing 18525 // two documents; shallow comparisons work. 18526 // eslint-disable-next-line eqeqeq 18527 compare = ( a.ownerDocument || a ) == ( b.ownerDocument || b ) ? 18528 a.compareDocumentPosition( b ) : 18529 18530 // Otherwise we know they are disconnected 18531 1; 18532 18533 // Disconnected nodes 18534 if ( compare & 1 || 18535 ( !support.sortDetached && b.compareDocumentPosition( a ) === compare ) ) { 18536 18537 // Choose the first element that is related to our preferred document 18538 // Support: IE 11+, Edge 17 - 18+ 18539 // IE/Edge sometimes throw a "Permission denied" error when strict-comparing 18540 // two documents; shallow comparisons work. 18541 // eslint-disable-next-line eqeqeq 18542 if ( a == document || a.ownerDocument == preferredDoc && 18543 contains( preferredDoc, a ) ) { 18544 return -1; 18545 } 18546 18547 // Support: IE 11+, Edge 17 - 18+ 18548 // IE/Edge sometimes throw a "Permission denied" error when strict-comparing 18549 // two documents; shallow comparisons work. 18550 // eslint-disable-next-line eqeqeq 18551 if ( b == document || b.ownerDocument == preferredDoc && 18552 contains( preferredDoc, b ) ) { 18553 return 1; 18554 } 18555 18556 // Maintain original order 18557 return sortInput ? 18558 ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : 18559 0; 18560 } 18561 18562 return compare & 4 ? -1 : 1; 18563 } : 18564 function( a, b ) { 18565 18566 // Exit early if the nodes are identical 18567 if ( a === b ) { 18568 hasDuplicate = true; 18569 return 0; 18570 } 18571 18572 var cur, 18573 i = 0, 18574 aup = a.parentNode, 18575 bup = b.parentNode, 18576 ap = [ a ], 18577 bp = [ b ]; 18578 18579 // Parentless nodes are either documents or disconnected 18580 if ( !aup || !bup ) { 18581 18582 // Support: IE 11+, Edge 17 - 18+ 18583 // IE/Edge sometimes throw a "Permission denied" error when strict-comparing 18584 // two documents; shallow comparisons work. 18585 /* eslint-disable eqeqeq */ 18586 return a == document ? -1 : 18587 b == document ? 1 : 18588 /* eslint-enable eqeqeq */ 18589 aup ? -1 : 18590 bup ? 1 : 18591 sortInput ? 18592 ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : 18593 0; 18594 18595 // If the nodes are siblings, we can do a quick check 18596 } else if ( aup === bup ) { 18597 return siblingCheck( a, b ); 18598 } 18599 18600 // Otherwise we need full lists of their ancestors for comparison 18601 cur = a; 18602 while ( ( cur = cur.parentNode ) ) { 18603 ap.unshift( cur ); 18604 } 18605 cur = b; 18606 while ( ( cur = cur.parentNode ) ) { 18607 bp.unshift( cur ); 18608 } 18609 18610 // Walk down the tree looking for a discrepancy 18611 while ( ap[ i ] === bp[ i ] ) { 18612 i++; 18613 } 18614 18615 return i ? 18616 18617 // Do a sibling check if the nodes have a common ancestor 18618 siblingCheck( ap[ i ], bp[ i ] ) : 18619 18620 // Otherwise nodes in our document sort first 18621 // Support: IE 11+, Edge 17 - 18+ 18622 // IE/Edge sometimes throw a "Permission denied" error when strict-comparing 18623 // two documents; shallow comparisons work. 18624 /* eslint-disable eqeqeq */ 18625 ap[ i ] == preferredDoc ? -1 : 18626 bp[ i ] == preferredDoc ? 1 : 18627 /* eslint-enable eqeqeq */ 18628 0; 18629 }; 18630 18631 return document; 18632}; 18633 18634Sizzle.matches = function( expr, elements ) { 18635 return Sizzle( expr, null, null, elements ); 18636}; 18637 18638Sizzle.matchesSelector = function( elem, expr ) { 18639 setDocument( elem ); 18640 18641 if ( support.matchesSelector && documentIsHTML && 18642 !nonnativeSelectorCache[ expr + " " ] && 18643 ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && 18644 ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { 18645 18646 try { 18647 var ret = matches.call( elem, expr ); 18648 18649 // IE 9's matchesSelector returns false on disconnected nodes 18650 if ( ret || support.disconnectedMatch || 18651 18652 // As well, disconnected nodes are said to be in a document 18653 // fragment in IE 9 18654 elem.document && elem.document.nodeType !== 11 ) { 18655 return ret; 18656 } 18657 } catch ( e ) { 18658 nonnativeSelectorCache( expr, true ); 18659 } 18660 } 18661 18662 return Sizzle( expr, document, null, [ elem ] ).length > 0; 18663}; 18664 18665Sizzle.contains = function( context, elem ) { 18666 18667 // Set document vars if needed 18668 // Support: IE 11+, Edge 17 - 18+ 18669 // IE/Edge sometimes throw a "Permission denied" error when strict-comparing 18670 // two documents; shallow comparisons work. 18671 // eslint-disable-next-line eqeqeq 18672 if ( ( context.ownerDocument || context ) != document ) { 18673 setDocument( context ); 18674 } 18675 return contains( context, elem ); 18676}; 18677 18678Sizzle.attr = function( elem, name ) { 18679 18680 // Set document vars if needed 18681 // Support: IE 11+, Edge 17 - 18+ 18682 // IE/Edge sometimes throw a "Permission denied" error when strict-comparing 18683 // two documents; shallow comparisons work. 18684 // eslint-disable-next-line eqeqeq 18685 if ( ( elem.ownerDocument || elem ) != document ) { 18686 setDocument( elem ); 18687 } 18688 18689 var fn = Expr.attrHandle[ name.toLowerCase() ], 18690 18691 // Don't get fooled by Object.prototype properties (jQuery #13807) 18692 val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? 18693 fn( elem, name, !documentIsHTML ) : 18694 undefined; 18695 18696 return val !== undefined ? 18697 val : 18698 support.attributes || !documentIsHTML ? 18699 elem.getAttribute( name ) : 18700 ( val = elem.getAttributeNode( name ) ) && val.specified ? 18701 val.value : 18702 null; 18703}; 18704 18705Sizzle.escape = function( sel ) { 18706 return ( sel + "" ).replace( rcssescape, fcssescape ); 18707}; 18708 18709Sizzle.error = function( msg ) { 18710 throw new Error( "Syntax error, unrecognized expression: " + msg ); 18711}; 18712 18713/** 18714 * Document sorting and removing duplicates 18715 * @param {ArrayLike} results 18716 */ 18717Sizzle.uniqueSort = function( results ) { 18718 var elem, 18719 duplicates = [], 18720 j = 0, 18721 i = 0; 18722 18723 // Unless we *know* we can detect duplicates, assume their presence 18724 hasDuplicate = !support.detectDuplicates; 18725 sortInput = !support.sortStable && results.slice( 0 ); 18726 results.sort( sortOrder ); 18727 18728 if ( hasDuplicate ) { 18729 while ( ( elem = results[ i++ ] ) ) { 18730 if ( elem === results[ i ] ) { 18731 j = duplicates.push( i ); 18732 } 18733 } 18734 while ( j-- ) { 18735 results.splice( duplicates[ j ], 1 ); 18736 } 18737 } 18738 18739 // Clear input after sorting to release objects 18740 // See https://github.com/jquery/sizzle/pull/225 18741 sortInput = null; 18742 18743 return results; 18744}; 18745 18746/** 18747 * Utility function for retrieving the text value of an array of DOM nodes 18748 * @param {Array|Element} elem 18749 */ 18750getText = Sizzle.getText = function( elem ) { 18751 var node, 18752 ret = "", 18753 i = 0, 18754 nodeType = elem.nodeType; 18755 18756 if ( !nodeType ) { 18757 18758 // If no nodeType, this is expected to be an array 18759 while ( ( node = elem[ i++ ] ) ) { 18760 18761 // Do not traverse comment nodes 18762 ret += getText( node ); 18763 } 18764 } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { 18765 18766 // Use textContent for elements 18767 // innerText usage removed for consistency of new lines (jQuery #11153) 18768 if ( typeof elem.textContent === "string" ) { 18769 return elem.textContent; 18770 } else { 18771 18772 // Traverse its children 18773 for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { 18774 ret += getText( elem ); 18775 } 18776 } 18777 } else if ( nodeType === 3 || nodeType === 4 ) { 18778 return elem.nodeValue; 18779 } 18780 18781 // Do not include comment or processing instruction nodes 18782 18783 return ret; 18784}; 18785 18786Expr = Sizzle.selectors = { 18787 18788 // Can be adjusted by the user 18789 cacheLength: 50, 18790 18791 createPseudo: markFunction, 18792 18793 match: matchExpr, 18794 18795 attrHandle: {}, 18796 18797 find: {}, 18798 18799 relative: { 18800 ">": { dir: "parentNode", first: true }, 18801 " ": { dir: "parentNode" }, 18802 "+": { dir: "previousSibling", first: true }, 18803 "~": { dir: "previousSibling" } 18804 }, 18805 18806 preFilter: { 18807 "ATTR": function( match ) { 18808 match[ 1 ] = match[ 1 ].replace( runescape, funescape ); 18809 18810 // Move the given value to match[3] whether quoted or unquoted 18811 match[ 3 ] = ( match[ 3 ] || match[ 4 ] || 18812 match[ 5 ] || "" ).replace( runescape, funescape ); 18813 18814 if ( match[ 2 ] === "~=" ) { 18815 match[ 3 ] = " " + match[ 3 ] + " "; 18816 } 18817 18818 return match.slice( 0, 4 ); 18819 }, 18820 18821 "CHILD": function( match ) { 18822 18823 /* matches from matchExpr["CHILD"] 18824 1 type (only|nth|...) 18825 2 what (child|of-type) 18826 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) 18827 4 xn-component of xn+y argument ([+-]?\d*n|) 18828 5 sign of xn-component 18829 6 x of xn-component 18830 7 sign of y-component 18831 8 y of y-component 18832 */ 18833 match[ 1 ] = match[ 1 ].toLowerCase(); 18834 18835 if ( match[ 1 ].slice( 0, 3 ) === "nth" ) { 18836 18837 // nth-* requires argument 18838 if ( !match[ 3 ] ) { 18839 Sizzle.error( match[ 0 ] ); 18840 } 18841 18842 // numeric x and y parameters for Expr.filter.CHILD 18843 // remember that false/true cast respectively to 0/1 18844 match[ 4 ] = +( match[ 4 ] ? 18845 match[ 5 ] + ( match[ 6 ] || 1 ) : 18846 2 * ( match[ 3 ] === "even" || match[ 3 ] === "odd" ) ); 18847 match[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === "odd" ); 18848 18849 // other types prohibit arguments 18850 } else if ( match[ 3 ] ) { 18851 Sizzle.error( match[ 0 ] ); 18852 } 18853 18854 return match; 18855 }, 18856 18857 "PSEUDO": function( match ) { 18858 var excess, 18859 unquoted = !match[ 6 ] && match[ 2 ]; 18860 18861 if ( matchExpr[ "CHILD" ].test( match[ 0 ] ) ) { 18862 return null; 18863 } 18864 18865 // Accept quoted arguments as-is 18866 if ( match[ 3 ] ) { 18867 match[ 2 ] = match[ 4 ] || match[ 5 ] || ""; 18868 18869 // Strip excess characters from unquoted arguments 18870 } else if ( unquoted && rpseudo.test( unquoted ) && 18871 18872 // Get excess from tokenize (recursively) 18873 ( excess = tokenize( unquoted, true ) ) && 18874 18875 // advance to the next closing parenthesis 18876 ( excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length ) ) { 18877 18878 // excess is a negative index 18879 match[ 0 ] = match[ 0 ].slice( 0, excess ); 18880 match[ 2 ] = unquoted.slice( 0, excess ); 18881 } 18882 18883 // Return only captures needed by the pseudo filter method (type and argument) 18884 return match.slice( 0, 3 ); 18885 } 18886 }, 18887 18888 filter: { 18889 18890 "TAG": function( nodeNameSelector ) { 18891 var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); 18892 return nodeNameSelector === "*" ? 18893 function() { 18894 return true; 18895 } : 18896 function( elem ) { 18897 return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; 18898 }; 18899 }, 18900 18901 "CLASS": function( className ) { 18902 var pattern = classCache[ className + " " ]; 18903 18904 return pattern || 18905 ( pattern = new RegExp( "(^|" + whitespace + 18906 ")" + className + "(" + whitespace + "|$)" ) ) && classCache( 18907 className, function( elem ) { 18908 return pattern.test( 18909 typeof elem.className === "string" && elem.className || 18910 typeof elem.getAttribute !== "undefined" && 18911 elem.getAttribute( "class" ) || 18912 "" 18913 ); 18914 } ); 18915 }, 18916 18917 "ATTR": function( name, operator, check ) { 18918 return function( elem ) { 18919 var result = Sizzle.attr( elem, name ); 18920 18921 if ( result == null ) { 18922 return operator === "!="; 18923 } 18924 if ( !operator ) { 18925 return true; 18926 } 18927 18928 result += ""; 18929 18930 /* eslint-disable max-len */ 18931 18932 return operator === "=" ? result === check : 18933 operator === "!=" ? result !== check : 18934 operator === "^=" ? check && result.indexOf( check ) === 0 : 18935 operator === "*=" ? check && result.indexOf( check ) > -1 : 18936 operator === "$=" ? check && result.slice( -check.length ) === check : 18937 operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : 18938 operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : 18939 false; 18940 /* eslint-enable max-len */ 18941 18942 }; 18943 }, 18944 18945 "CHILD": function( type, what, _argument, first, last ) { 18946 var simple = type.slice( 0, 3 ) !== "nth", 18947 forward = type.slice( -4 ) !== "last", 18948 ofType = what === "of-type"; 18949 18950 return first === 1 && last === 0 ? 18951 18952 // Shortcut for :nth-*(n) 18953 function( elem ) { 18954 return !!elem.parentNode; 18955 } : 18956 18957 function( elem, _context, xml ) { 18958 var cache, uniqueCache, outerCache, node, nodeIndex, start, 18959 dir = simple !== forward ? "nextSibling" : "previousSibling", 18960 parent = elem.parentNode, 18961 name = ofType && elem.nodeName.toLowerCase(), 18962 useCache = !xml && !ofType, 18963 diff = false; 18964 18965 if ( parent ) { 18966 18967 // :(first|last|only)-(child|of-type) 18968 if ( simple ) { 18969 while ( dir ) { 18970 node = elem; 18971 while ( ( node = node[ dir ] ) ) { 18972 if ( ofType ? 18973 node.nodeName.toLowerCase() === name : 18974 node.nodeType === 1 ) { 18975 18976 return false; 18977 } 18978 } 18979 18980 // Reverse direction for :only-* (if we haven't yet done so) 18981 start = dir = type === "only" && !start && "nextSibling"; 18982 } 18983 return true; 18984 } 18985 18986 start = [ forward ? parent.firstChild : parent.lastChild ]; 18987 18988 // non-xml :nth-child(...) stores cache data on `parent` 18989 if ( forward && useCache ) { 18990 18991 // Seek `elem` from a previously-cached index 18992 18993 // ...in a gzip-friendly way 18994 node = parent; 18995 outerCache = node[ expando ] || ( node[ expando ] = {} ); 18996 18997 // Support: IE <9 only 18998 // Defend against cloned attroperties (jQuery gh-1709) 18999 uniqueCache = outerCache[ node.uniqueID ] || 19000 ( outerCache[ node.uniqueID ] = {} ); 19001 19002 cache = uniqueCache[ type ] || []; 19003 nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; 19004 diff = nodeIndex && cache[ 2 ]; 19005 node = nodeIndex && parent.childNodes[ nodeIndex ]; 19006 19007 while ( ( node = ++nodeIndex && node && node[ dir ] || 19008 19009 // Fallback to seeking `elem` from the start 19010 ( diff = nodeIndex = 0 ) || start.pop() ) ) { 19011 19012 // When found, cache indexes on `parent` and break 19013 if ( node.nodeType === 1 && ++diff && node === elem ) { 19014 uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; 19015 break; 19016 } 19017 } 19018 19019 } else { 19020 19021 // Use previously-cached element index if available 19022 if ( useCache ) { 19023 19024 // ...in a gzip-friendly way 19025 node = elem; 19026 outerCache = node[ expando ] || ( node[ expando ] = {} ); 19027 19028 // Support: IE <9 only 19029 // Defend against cloned attroperties (jQuery gh-1709) 19030 uniqueCache = outerCache[ node.uniqueID ] || 19031 ( outerCache[ node.uniqueID ] = {} ); 19032 19033 cache = uniqueCache[ type ] || []; 19034 nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; 19035 diff = nodeIndex; 19036 } 19037 19038 // xml :nth-child(...) 19039 // or :nth-last-child(...) or :nth(-last)?-of-type(...) 19040 if ( diff === false ) { 19041 19042 // Use the same loop as above to seek `elem` from the start 19043 while ( ( node = ++nodeIndex && node && node[ dir ] || 19044 ( diff = nodeIndex = 0 ) || start.pop() ) ) { 19045 19046 if ( ( ofType ? 19047 node.nodeName.toLowerCase() === name : 19048 node.nodeType === 1 ) && 19049 ++diff ) { 19050 19051 // Cache the index of each encountered element 19052 if ( useCache ) { 19053 outerCache = node[ expando ] || 19054 ( node[ expando ] = {} ); 19055 19056 // Support: IE <9 only 19057 // Defend against cloned attroperties (jQuery gh-1709) 19058 uniqueCache = outerCache[ node.uniqueID ] || 19059 ( outerCache[ node.uniqueID ] = {} ); 19060 19061 uniqueCache[ type ] = [ dirruns, diff ]; 19062 } 19063 19064 if ( node === elem ) { 19065 break; 19066 } 19067 } 19068 } 19069 } 19070 } 19071 19072 // Incorporate the offset, then check against cycle size 19073 diff -= last; 19074 return diff === first || ( diff % first === 0 && diff / first >= 0 ); 19075 } 19076 }; 19077 }, 19078 19079 "PSEUDO": function( pseudo, argument ) { 19080 19081 // pseudo-class names are case-insensitive 19082 // http://www.w3.org/TR/selectors/#pseudo-classes 19083 // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters 19084 // Remember that setFilters inherits from pseudos 19085 var args, 19086 fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || 19087 Sizzle.error( "unsupported pseudo: " + pseudo ); 19088 19089 // The user may use createPseudo to indicate that 19090 // arguments are needed to create the filter function 19091 // just as Sizzle does 19092 if ( fn[ expando ] ) { 19093 return fn( argument ); 19094 } 19095 19096 // But maintain support for old signatures 19097 if ( fn.length > 1 ) { 19098 args = [ pseudo, pseudo, "", argument ]; 19099 return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? 19100 markFunction( function( seed, matches ) { 19101 var idx, 19102 matched = fn( seed, argument ), 19103 i = matched.length; 19104 while ( i-- ) { 19105 idx = indexOf( seed, matched[ i ] ); 19106 seed[ idx ] = !( matches[ idx ] = matched[ i ] ); 19107 } 19108 } ) : 19109 function( elem ) { 19110 return fn( elem, 0, args ); 19111 }; 19112 } 19113 19114 return fn; 19115 } 19116 }, 19117 19118 pseudos: { 19119 19120 // Potentially complex pseudos 19121 "not": markFunction( function( selector ) { 19122 19123 // Trim the selector passed to compile 19124 // to avoid treating leading and trailing 19125 // spaces as combinators 19126 var input = [], 19127 results = [], 19128 matcher = compile( selector.replace( rtrim, "$1" ) ); 19129 19130 return matcher[ expando ] ? 19131 markFunction( function( seed, matches, _context, xml ) { 19132 var elem, 19133 unmatched = matcher( seed, null, xml, [] ), 19134 i = seed.length; 19135 19136 // Match elements unmatched by `matcher` 19137 while ( i-- ) { 19138 if ( ( elem = unmatched[ i ] ) ) { 19139 seed[ i ] = !( matches[ i ] = elem ); 19140 } 19141 } 19142 } ) : 19143 function( elem, _context, xml ) { 19144 input[ 0 ] = elem; 19145 matcher( input, null, xml, results ); 19146 19147 // Don't keep the element (issue #299) 19148 input[ 0 ] = null; 19149 return !results.pop(); 19150 }; 19151 } ), 19152 19153 "has": markFunction( function( selector ) { 19154 return function( elem ) { 19155 return Sizzle( selector, elem ).length > 0; 19156 }; 19157 } ), 19158 19159 "contains": markFunction( function( text ) { 19160 text = text.replace( runescape, funescape ); 19161 return function( elem ) { 19162 return ( elem.textContent || getText( elem ) ).indexOf( text ) > -1; 19163 }; 19164 } ), 19165 19166 // "Whether an element is represented by a :lang() selector 19167 // is based solely on the element's language value 19168 // being equal to the identifier C, 19169 // or beginning with the identifier C immediately followed by "-". 19170 // The matching of C against the element's language value is performed case-insensitively. 19171 // The identifier C does not have to be a valid language name." 19172 // http://www.w3.org/TR/selectors/#lang-pseudo 19173 "lang": markFunction( function( lang ) { 19174 19175 // lang value must be a valid identifier 19176 if ( !ridentifier.test( lang || "" ) ) { 19177 Sizzle.error( "unsupported lang: " + lang ); 19178 } 19179 lang = lang.replace( runescape, funescape ).toLowerCase(); 19180 return function( elem ) { 19181 var elemLang; 19182 do { 19183 if ( ( elemLang = documentIsHTML ? 19184 elem.lang : 19185 elem.getAttribute( "xml:lang" ) || elem.getAttribute( "lang" ) ) ) { 19186 19187 elemLang = elemLang.toLowerCase(); 19188 return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; 19189 } 19190 } while ( ( elem = elem.parentNode ) && elem.nodeType === 1 ); 19191 return false; 19192 }; 19193 } ), 19194 19195 // Miscellaneous 19196 "target": function( elem ) { 19197 var hash = window.location && window.location.hash; 19198 return hash && hash.slice( 1 ) === elem.id; 19199 }, 19200 19201 "root": function( elem ) { 19202 return elem === docElem; 19203 }, 19204 19205 "focus": function( elem ) { 19206 return elem === document.activeElement && 19207 ( !document.hasFocus || document.hasFocus() ) && 19208 !!( elem.type || elem.href || ~elem.tabIndex ); 19209 }, 19210 19211 // Boolean properties 19212 "enabled": createDisabledPseudo( false ), 19213 "disabled": createDisabledPseudo( true ), 19214 19215 "checked": function( elem ) { 19216 19217 // In CSS3, :checked should return both checked and selected elements 19218 // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked 19219 var nodeName = elem.nodeName.toLowerCase(); 19220 return ( nodeName === "input" && !!elem.checked ) || 19221 ( nodeName === "option" && !!elem.selected ); 19222 }, 19223 19224 "selected": function( elem ) { 19225 19226 // Accessing this property makes selected-by-default 19227 // options in Safari work properly 19228 if ( elem.parentNode ) { 19229 // eslint-disable-next-line no-unused-expressions 19230 elem.parentNode.selectedIndex; 19231 } 19232 19233 return elem.selected === true; 19234 }, 19235 19236 // Contents 19237 "empty": function( elem ) { 19238 19239 // http://www.w3.org/TR/selectors/#empty-pseudo 19240 // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), 19241 // but not by others (comment: 8; processing instruction: 7; etc.) 19242 // nodeType < 6 works because attributes (2) do not appear as children 19243 for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { 19244 if ( elem.nodeType < 6 ) { 19245 return false; 19246 } 19247 } 19248 return true; 19249 }, 19250 19251 "parent": function( elem ) { 19252 return !Expr.pseudos[ "empty" ]( elem ); 19253 }, 19254 19255 // Element/input types 19256 "header": function( elem ) { 19257 return rheader.test( elem.nodeName ); 19258 }, 19259 19260 "input": function( elem ) { 19261 return rinputs.test( elem.nodeName ); 19262 }, 19263 19264 "button": function( elem ) { 19265 var name = elem.nodeName.toLowerCase(); 19266 return name === "input" && elem.type === "button" || name === "button"; 19267 }, 19268 19269 "text": function( elem ) { 19270 var attr; 19271 return elem.nodeName.toLowerCase() === "input" && 19272 elem.type === "text" && 19273 19274 // Support: IE<8 19275 // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" 19276 ( ( attr = elem.getAttribute( "type" ) ) == null || 19277 attr.toLowerCase() === "text" ); 19278 }, 19279 19280 // Position-in-collection 19281 "first": createPositionalPseudo( function() { 19282 return [ 0 ]; 19283 } ), 19284 19285 "last": createPositionalPseudo( function( _matchIndexes, length ) { 19286 return [ length - 1 ]; 19287 } ), 19288 19289 "eq": createPositionalPseudo( function( _matchIndexes, length, argument ) { 19290 return [ argument < 0 ? argument + length : argument ]; 19291 } ), 19292 19293 "even": createPositionalPseudo( function( matchIndexes, length ) { 19294 var i = 0; 19295 for ( ; i < length; i += 2 ) { 19296 matchIndexes.push( i ); 19297 } 19298 return matchIndexes; 19299 } ), 19300 19301 "odd": createPositionalPseudo( function( matchIndexes, length ) { 19302 var i = 1; 19303 for ( ; i < length; i += 2 ) { 19304 matchIndexes.push( i ); 19305 } 19306 return matchIndexes; 19307 } ), 19308 19309 "lt": createPositionalPseudo( function( matchIndexes, length, argument ) { 19310 var i = argument < 0 ? 19311 argument + length : 19312 argument > length ? 19313 length : 19314 argument; 19315 for ( ; --i >= 0; ) { 19316 matchIndexes.push( i ); 19317 } 19318 return matchIndexes; 19319 } ), 19320 19321 "gt": createPositionalPseudo( function( matchIndexes, length, argument ) { 19322 var i = argument < 0 ? argument + length : argument; 19323 for ( ; ++i < length; ) { 19324 matchIndexes.push( i ); 19325 } 19326 return matchIndexes; 19327 } ) 19328 } 19329}; 19330 19331Expr.pseudos[ "nth" ] = Expr.pseudos[ "eq" ]; 19332 19333// Add button/input type pseudos 19334for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { 19335 Expr.pseudos[ i ] = createInputPseudo( i ); 19336} 19337for ( i in { submit: true, reset: true } ) { 19338 Expr.pseudos[ i ] = createButtonPseudo( i ); 19339} 19340 19341// Easy API for creating new setFilters 19342function setFilters() {} 19343setFilters.prototype = Expr.filters = Expr.pseudos; 19344Expr.setFilters = new setFilters(); 19345 19346tokenize = Sizzle.tokenize = function( selector, parseOnly ) { 19347 var matched, match, tokens, type, 19348 soFar, groups, preFilters, 19349 cached = tokenCache[ selector + " " ]; 19350 19351 if ( cached ) { 19352 return parseOnly ? 0 : cached.slice( 0 ); 19353 } 19354 19355 soFar = selector; 19356 groups = []; 19357 preFilters = Expr.preFilter; 19358 19359 while ( soFar ) { 19360 19361 // Comma and first run 19362 if ( !matched || ( match = rcomma.exec( soFar ) ) ) { 19363 if ( match ) { 19364 19365 // Don't consume trailing commas as valid 19366 soFar = soFar.slice( match[ 0 ].length ) || soFar; 19367 } 19368 groups.push( ( tokens = [] ) ); 19369 } 19370 19371 matched = false; 19372 19373 // Combinators 19374 if ( ( match = rcombinators.exec( soFar ) ) ) { 19375 matched = match.shift(); 19376 tokens.push( { 19377 value: matched, 19378 19379 // Cast descendant combinators to space 19380 type: match[ 0 ].replace( rtrim, " " ) 19381 } ); 19382 soFar = soFar.slice( matched.length ); 19383 } 19384 19385 // Filters 19386 for ( type in Expr.filter ) { 19387 if ( ( match = matchExpr[ type ].exec( soFar ) ) && ( !preFilters[ type ] || 19388 ( match = preFilters[ type ]( match ) ) ) ) { 19389 matched = match.shift(); 19390 tokens.push( { 19391 value: matched, 19392 type: type, 19393 matches: match 19394 } ); 19395 soFar = soFar.slice( matched.length ); 19396 } 19397 } 19398 19399 if ( !matched ) { 19400 break; 19401 } 19402 } 19403 19404 // Return the length of the invalid excess 19405 // if we're just parsing 19406 // Otherwise, throw an error or return tokens 19407 return parseOnly ? 19408 soFar.length : 19409 soFar ? 19410 Sizzle.error( selector ) : 19411 19412 // Cache the tokens 19413 tokenCache( selector, groups ).slice( 0 ); 19414}; 19415 19416function toSelector( tokens ) { 19417 var i = 0, 19418 len = tokens.length, 19419 selector = ""; 19420 for ( ; i < len; i++ ) { 19421 selector += tokens[ i ].value; 19422 } 19423 return selector; 19424} 19425 19426function addCombinator( matcher, combinator, base ) { 19427 var dir = combinator.dir, 19428 skip = combinator.next, 19429 key = skip || dir, 19430 checkNonElements = base && key === "parentNode", 19431 doneName = done++; 19432 19433 return combinator.first ? 19434 19435 // Check against closest ancestor/preceding element 19436 function( elem, context, xml ) { 19437 while ( ( elem = elem[ dir ] ) ) { 19438 if ( elem.nodeType === 1 || checkNonElements ) { 19439 return matcher( elem, context, xml ); 19440 } 19441 } 19442 return false; 19443 } : 19444 19445 // Check against all ancestor/preceding elements 19446 function( elem, context, xml ) { 19447 var oldCache, uniqueCache, outerCache, 19448 newCache = [ dirruns, doneName ]; 19449 19450 // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching 19451 if ( xml ) { 19452 while ( ( elem = elem[ dir ] ) ) { 19453 if ( elem.nodeType === 1 || checkNonElements ) { 19454 if ( matcher( elem, context, xml ) ) { 19455 return true; 19456 } 19457 } 19458 } 19459 } else { 19460 while ( ( elem = elem[ dir ] ) ) { 19461 if ( elem.nodeType === 1 || checkNonElements ) { 19462 outerCache = elem[ expando ] || ( elem[ expando ] = {} ); 19463 19464 // Support: IE <9 only 19465 // Defend against cloned attroperties (jQuery gh-1709) 19466 uniqueCache = outerCache[ elem.uniqueID ] || 19467 ( outerCache[ elem.uniqueID ] = {} ); 19468 19469 if ( skip && skip === elem.nodeName.toLowerCase() ) { 19470 elem = elem[ dir ] || elem; 19471 } else if ( ( oldCache = uniqueCache[ key ] ) && 19472 oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { 19473 19474 // Assign to newCache so results back-propagate to previous elements 19475 return ( newCache[ 2 ] = oldCache[ 2 ] ); 19476 } else { 19477 19478 // Reuse newcache so results back-propagate to previous elements 19479 uniqueCache[ key ] = newCache; 19480 19481 // A match means we're done; a fail means we have to keep checking 19482 if ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) { 19483 return true; 19484 } 19485 } 19486 } 19487 } 19488 } 19489 return false; 19490 }; 19491} 19492 19493function elementMatcher( matchers ) { 19494 return matchers.length > 1 ? 19495 function( elem, context, xml ) { 19496 var i = matchers.length; 19497 while ( i-- ) { 19498 if ( !matchers[ i ]( elem, context, xml ) ) { 19499 return false; 19500 } 19501 } 19502 return true; 19503 } : 19504 matchers[ 0 ]; 19505} 19506 19507function multipleContexts( selector, contexts, results ) { 19508 var i = 0, 19509 len = contexts.length; 19510 for ( ; i < len; i++ ) { 19511 Sizzle( selector, contexts[ i ], results ); 19512 } 19513 return results; 19514} 19515 19516function condense( unmatched, map, filter, context, xml ) { 19517 var elem, 19518 newUnmatched = [], 19519 i = 0, 19520 len = unmatched.length, 19521 mapped = map != null; 19522 19523 for ( ; i < len; i++ ) { 19524 if ( ( elem = unmatched[ i ] ) ) { 19525 if ( !filter || filter( elem, context, xml ) ) { 19526 newUnmatched.push( elem ); 19527 if ( mapped ) { 19528 map.push( i ); 19529 } 19530 } 19531 } 19532 } 19533 19534 return newUnmatched; 19535} 19536 19537function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { 19538 if ( postFilter && !postFilter[ expando ] ) { 19539 postFilter = setMatcher( postFilter ); 19540 } 19541 if ( postFinder && !postFinder[ expando ] ) { 19542 postFinder = setMatcher( postFinder, postSelector ); 19543 } 19544 return markFunction( function( seed, results, context, xml ) { 19545 var temp, i, elem, 19546 preMap = [], 19547 postMap = [], 19548 preexisting = results.length, 19549 19550 // Get initial elements from seed or context 19551 elems = seed || multipleContexts( 19552 selector || "*", 19553 context.nodeType ? [ context ] : context, 19554 [] 19555 ), 19556 19557 // Prefilter to get matcher input, preserving a map for seed-results synchronization 19558 matcherIn = preFilter && ( seed || !selector ) ? 19559 condense( elems, preMap, preFilter, context, xml ) : 19560 elems, 19561 19562 matcherOut = matcher ? 19563 19564 // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, 19565 postFinder || ( seed ? preFilter : preexisting || postFilter ) ? 19566 19567 // ...intermediate processing is necessary 19568 [] : 19569 19570 // ...otherwise use results directly 19571 results : 19572 matcherIn; 19573 19574 // Find primary matches 19575 if ( matcher ) { 19576 matcher( matcherIn, matcherOut, context, xml ); 19577 } 19578 19579 // Apply postFilter 19580 if ( postFilter ) { 19581 temp = condense( matcherOut, postMap ); 19582 postFilter( temp, [], context, xml ); 19583 19584 // Un-match failing elements by moving them back to matcherIn 19585 i = temp.length; 19586 while ( i-- ) { 19587 if ( ( elem = temp[ i ] ) ) { 19588 matcherOut[ postMap[ i ] ] = !( matcherIn[ postMap[ i ] ] = elem ); 19589 } 19590 } 19591 } 19592 19593 if ( seed ) { 19594 if ( postFinder || preFilter ) { 19595 if ( postFinder ) { 19596 19597 // Get the final matcherOut by condensing this intermediate into postFinder contexts 19598 temp = []; 19599 i = matcherOut.length; 19600 while ( i-- ) { 19601 if ( ( elem = matcherOut[ i ] ) ) { 19602 19603 // Restore matcherIn since elem is not yet a final match 19604 temp.push( ( matcherIn[ i ] = elem ) ); 19605 } 19606 } 19607 postFinder( null, ( matcherOut = [] ), temp, xml ); 19608 } 19609 19610 // Move matched elements from seed to results to keep them synchronized 19611 i = matcherOut.length; 19612 while ( i-- ) { 19613 if ( ( elem = matcherOut[ i ] ) && 19614 ( temp = postFinder ? indexOf( seed, elem ) : preMap[ i ] ) > -1 ) { 19615 19616 seed[ temp ] = !( results[ temp ] = elem ); 19617 } 19618 } 19619 } 19620 19621 // Add elements to results, through postFinder if defined 19622 } else { 19623 matcherOut = condense( 19624 matcherOut === results ? 19625 matcherOut.splice( preexisting, matcherOut.length ) : 19626 matcherOut 19627 ); 19628 if ( postFinder ) { 19629 postFinder( null, results, matcherOut, xml ); 19630 } else { 19631 push.apply( results, matcherOut ); 19632 } 19633 } 19634 } ); 19635} 19636 19637function matcherFromTokens( tokens ) { 19638 var checkContext, matcher, j, 19639 len = tokens.length, 19640 leadingRelative = Expr.relative[ tokens[ 0 ].type ], 19641 implicitRelative = leadingRelative || Expr.relative[ " " ], 19642 i = leadingRelative ? 1 : 0, 19643 19644 // The foundational matcher ensures that elements are reachable from top-level context(s) 19645 matchContext = addCombinator( function( elem ) { 19646 return elem === checkContext; 19647 }, implicitRelative, true ), 19648 matchAnyContext = addCombinator( function( elem ) { 19649 return indexOf( checkContext, elem ) > -1; 19650 }, implicitRelative, true ), 19651 matchers = [ function( elem, context, xml ) { 19652 var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( 19653 ( checkContext = context ).nodeType ? 19654 matchContext( elem, context, xml ) : 19655 matchAnyContext( elem, context, xml ) ); 19656 19657 // Avoid hanging onto element (issue #299) 19658 checkContext = null; 19659 return ret; 19660 } ]; 19661 19662 for ( ; i < len; i++ ) { 19663 if ( ( matcher = Expr.relative[ tokens[ i ].type ] ) ) { 19664 matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ]; 19665 } else { 19666 matcher = Expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches ); 19667 19668 // Return special upon seeing a positional matcher 19669 if ( matcher[ expando ] ) { 19670 19671 // Find the next relative operator (if any) for proper handling 19672 j = ++i; 19673 for ( ; j < len; j++ ) { 19674 if ( Expr.relative[ tokens[ j ].type ] ) { 19675 break; 19676 } 19677 } 19678 return setMatcher( 19679 i > 1 && elementMatcher( matchers ), 19680 i > 1 && toSelector( 19681 19682 // If the preceding token was a descendant combinator, insert an implicit any-element `*` 19683 tokens 19684 .slice( 0, i - 1 ) 19685 .concat( { value: tokens[ i - 2 ].type === " " ? "*" : "" } ) 19686 ).replace( rtrim, "$1" ), 19687 matcher, 19688 i < j && matcherFromTokens( tokens.slice( i, j ) ), 19689 j < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ), 19690 j < len && toSelector( tokens ) 19691 ); 19692 } 19693 matchers.push( matcher ); 19694 } 19695 } 19696 19697 return elementMatcher( matchers ); 19698} 19699 19700function matcherFromGroupMatchers( elementMatchers, setMatchers ) { 19701 var bySet = setMatchers.length > 0, 19702 byElement = elementMatchers.length > 0, 19703 superMatcher = function( seed, context, xml, results, outermost ) { 19704 var elem, j, matcher, 19705 matchedCount = 0, 19706 i = "0", 19707 unmatched = seed && [], 19708 setMatched = [], 19709 contextBackup = outermostContext, 19710 19711 // We must always have either seed elements or outermost context 19712 elems = seed || byElement && Expr.find[ "TAG" ]( "*", outermost ), 19713 19714 // Use integer dirruns iff this is the outermost matcher 19715 dirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 ), 19716 len = elems.length; 19717 19718 if ( outermost ) { 19719 19720 // Support: IE 11+, Edge 17 - 18+ 19721 // IE/Edge sometimes throw a "Permission denied" error when strict-comparing 19722 // two documents; shallow comparisons work. 19723 // eslint-disable-next-line eqeqeq 19724 outermostContext = context == document || context || outermost; 19725 } 19726 19727 // Add elements passing elementMatchers directly to results 19728 // Support: IE<9, Safari 19729 // Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id 19730 for ( ; i !== len && ( elem = elems[ i ] ) != null; i++ ) { 19731 if ( byElement && elem ) { 19732 j = 0; 19733 19734 // Support: IE 11+, Edge 17 - 18+ 19735 // IE/Edge sometimes throw a "Permission denied" error when strict-comparing 19736 // two documents; shallow comparisons work. 19737 // eslint-disable-next-line eqeqeq 19738 if ( !context && elem.ownerDocument != document ) { 19739 setDocument( elem ); 19740 xml = !documentIsHTML; 19741 } 19742 while ( ( matcher = elementMatchers[ j++ ] ) ) { 19743 if ( matcher( elem, context || document, xml ) ) { 19744 results.push( elem ); 19745 break; 19746 } 19747 } 19748 if ( outermost ) { 19749 dirruns = dirrunsUnique; 19750 } 19751 } 19752 19753 // Track unmatched elements for set filters 19754 if ( bySet ) { 19755 19756 // They will have gone through all possible matchers 19757 if ( ( elem = !matcher && elem ) ) { 19758 matchedCount--; 19759 } 19760 19761 // Lengthen the array for every element, matched or not 19762 if ( seed ) { 19763 unmatched.push( elem ); 19764 } 19765 } 19766 } 19767 19768 // `i` is now the count of elements visited above, and adding it to `matchedCount` 19769 // makes the latter nonnegative. 19770 matchedCount += i; 19771 19772 // Apply set filters to unmatched elements 19773 // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` 19774 // equals `i`), unless we didn't visit _any_ elements in the above loop because we have 19775 // no element matchers and no seed. 19776 // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that 19777 // case, which will result in a "00" `matchedCount` that differs from `i` but is also 19778 // numerically zero. 19779 if ( bySet && i !== matchedCount ) { 19780 j = 0; 19781 while ( ( matcher = setMatchers[ j++ ] ) ) { 19782 matcher( unmatched, setMatched, context, xml ); 19783 } 19784 19785 if ( seed ) { 19786 19787 // Reintegrate element matches to eliminate the need for sorting 19788 if ( matchedCount > 0 ) { 19789 while ( i-- ) { 19790 if ( !( unmatched[ i ] || setMatched[ i ] ) ) { 19791 setMatched[ i ] = pop.call( results ); 19792 } 19793 } 19794 } 19795 19796 // Discard index placeholder values to get only actual matches 19797 setMatched = condense( setMatched ); 19798 } 19799 19800 // Add matches to results 19801 push.apply( results, setMatched ); 19802 19803 // Seedless set matches succeeding multiple successful matchers stipulate sorting 19804 if ( outermost && !seed && setMatched.length > 0 && 19805 ( matchedCount + setMatchers.length ) > 1 ) { 19806 19807 Sizzle.uniqueSort( results ); 19808 } 19809 } 19810 19811 // Override manipulation of globals by nested matchers 19812 if ( outermost ) { 19813 dirruns = dirrunsUnique; 19814 outermostContext = contextBackup; 19815 } 19816 19817 return unmatched; 19818 }; 19819 19820 return bySet ? 19821 markFunction( superMatcher ) : 19822 superMatcher; 19823} 19824 19825compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { 19826 var i, 19827 setMatchers = [], 19828 elementMatchers = [], 19829 cached = compilerCache[ selector + " " ]; 19830 19831 if ( !cached ) { 19832 19833 // Generate a function of recursive functions that can be used to check each element 19834 if ( !match ) { 19835 match = tokenize( selector ); 19836 } 19837 i = match.length; 19838 while ( i-- ) { 19839 cached = matcherFromTokens( match[ i ] ); 19840 if ( cached[ expando ] ) { 19841 setMatchers.push( cached ); 19842 } else { 19843 elementMatchers.push( cached ); 19844 } 19845 } 19846 19847 // Cache the compiled function 19848 cached = compilerCache( 19849 selector, 19850 matcherFromGroupMatchers( elementMatchers, setMatchers ) 19851 ); 19852 19853 // Save selector and tokenization 19854 cached.selector = selector; 19855 } 19856 return cached; 19857}; 19858 19859/** 19860 * A low-level selection function that works with Sizzle's compiled 19861 * selector functions 19862 * @param {String|Function} selector A selector or a pre-compiled 19863 * selector function built with Sizzle.compile 19864 * @param {Element} context 19865 * @param {Array} [results] 19866 * @param {Array} [seed] A set of elements to match against 19867 */ 19868select = Sizzle.select = function( selector, context, results, seed ) { 19869 var i, tokens, token, type, find, 19870 compiled = typeof selector === "function" && selector, 19871 match = !seed && tokenize( ( selector = compiled.selector || selector ) ); 19872 19873 results = results || []; 19874 19875 // Try to minimize operations if there is only one selector in the list and no seed 19876 // (the latter of which guarantees us context) 19877 if ( match.length === 1 ) { 19878 19879 // Reduce context if the leading compound selector is an ID 19880 tokens = match[ 0 ] = match[ 0 ].slice( 0 ); 19881 if ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === "ID" && 19882 context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[ 1 ].type ] ) { 19883 19884 context = ( Expr.find[ "ID" ]( token.matches[ 0 ] 19885 .replace( runescape, funescape ), context ) || [] )[ 0 ]; 19886 if ( !context ) { 19887 return results; 19888 19889 // Precompiled matchers will still verify ancestry, so step up a level 19890 } else if ( compiled ) { 19891 context = context.parentNode; 19892 } 19893 19894 selector = selector.slice( tokens.shift().value.length ); 19895 } 19896 19897 // Fetch a seed set for right-to-left matching 19898 i = matchExpr[ "needsContext" ].test( selector ) ? 0 : tokens.length; 19899 while ( i-- ) { 19900 token = tokens[ i ]; 19901 19902 // Abort if we hit a combinator 19903 if ( Expr.relative[ ( type = token.type ) ] ) { 19904 break; 19905 } 19906 if ( ( find = Expr.find[ type ] ) ) { 19907 19908 // Search, expanding context for leading sibling combinators 19909 if ( ( seed = find( 19910 token.matches[ 0 ].replace( runescape, funescape ), 19911 rsibling.test( tokens[ 0 ].type ) && testContext( context.parentNode ) || 19912 context 19913 ) ) ) { 19914 19915 // If seed is empty or no tokens remain, we can return early 19916 tokens.splice( i, 1 ); 19917 selector = seed.length && toSelector( tokens ); 19918 if ( !selector ) { 19919 push.apply( results, seed ); 19920 return results; 19921 } 19922 19923 break; 19924 } 19925 } 19926 } 19927 } 19928 19929 // Compile and execute a filtering function if one is not provided 19930 // Provide `match` to avoid retokenization if we modified the selector above 19931 ( compiled || compile( selector, match ) )( 19932 seed, 19933 context, 19934 !documentIsHTML, 19935 results, 19936 !context || rsibling.test( selector ) && testContext( context.parentNode ) || context 19937 ); 19938 return results; 19939}; 19940 19941// One-time assignments 19942 19943// Sort stability 19944support.sortStable = expando.split( "" ).sort( sortOrder ).join( "" ) === expando; 19945 19946// Support: Chrome 14-35+ 19947// Always assume duplicates if they aren't passed to the comparison function 19948support.detectDuplicates = !!hasDuplicate; 19949 19950// Initialize against the default document 19951setDocument(); 19952 19953// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) 19954// Detached nodes confoundingly follow *each other* 19955support.sortDetached = assert( function( el ) { 19956 19957 // Should return 1, but returns 4 (following) 19958 return el.compareDocumentPosition( document.createElement( "fieldset" ) ) & 1; 19959} ); 19960 19961// Support: IE<8 19962// Prevent attribute/property "interpolation" 19963// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx 19964if ( !assert( function( el ) { 19965 el.innerHTML = "<a href='#'></a>"; 19966 return el.firstChild.getAttribute( "href" ) === "#"; 19967} ) ) { 19968 addHandle( "type|href|height|width", function( elem, name, isXML ) { 19969 if ( !isXML ) { 19970 return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); 19971 } 19972 } ); 19973} 19974 19975// Support: IE<9 19976// Use defaultValue in place of getAttribute("value") 19977if ( !support.attributes || !assert( function( el ) { 19978 el.innerHTML = "<input/>"; 19979 el.firstChild.setAttribute( "value", "" ); 19980 return el.firstChild.getAttribute( "value" ) === ""; 19981} ) ) { 19982 addHandle( "value", function( elem, _name, isXML ) { 19983 if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { 19984 return elem.defaultValue; 19985 } 19986 } ); 19987} 19988 19989// Support: IE<9 19990// Use getAttributeNode to fetch booleans when getAttribute lies 19991if ( !assert( function( el ) { 19992 return el.getAttribute( "disabled" ) == null; 19993} ) ) { 19994 addHandle( booleans, function( elem, name, isXML ) { 19995 var val; 19996 if ( !isXML ) { 19997 return elem[ name ] === true ? name.toLowerCase() : 19998 ( val = elem.getAttributeNode( name ) ) && val.specified ? 19999 val.value : 20000 null; 20001 } 20002 } ); 20003} 20004 20005return Sizzle; 20006 20007} )( window ); 20008 20009 20010 20011jQuery.find = Sizzle; 20012jQuery.expr = Sizzle.selectors; 20013 20014// Deprecated 20015jQuery.expr[ ":" ] = jQuery.expr.pseudos; 20016jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; 20017jQuery.text = Sizzle.getText; 20018jQuery.isXMLDoc = Sizzle.isXML; 20019jQuery.contains = Sizzle.contains; 20020jQuery.escapeSelector = Sizzle.escape; 20021 20022 20023 20024 20025var dir = function( elem, dir, until ) { 20026 var matched = [], 20027 truncate = until !== undefined; 20028 20029 while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { 20030 if ( elem.nodeType === 1 ) { 20031 if ( truncate && jQuery( elem ).is( until ) ) { 20032 break; 20033 } 20034 matched.push( elem ); 20035 } 20036 } 20037 return matched; 20038}; 20039 20040 20041var siblings = function( n, elem ) { 20042 var matched = []; 20043 20044 for ( ; n; n = n.nextSibling ) { 20045 if ( n.nodeType === 1 && n !== elem ) { 20046 matched.push( n ); 20047 } 20048 } 20049 20050 return matched; 20051}; 20052 20053 20054var rneedsContext = jQuery.expr.match.needsContext; 20055 20056 20057 20058function nodeName( elem, name ) { 20059 20060 return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); 20061 20062} 20063var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); 20064 20065 20066 20067// Implement the identical functionality for filter and not 20068function winnow( elements, qualifier, not ) { 20069 if ( isFunction( qualifier ) ) { 20070 return jQuery.grep( elements, function( elem, i ) { 20071 return !!qualifier.call( elem, i, elem ) !== not; 20072 } ); 20073 } 20074 20075 // Single element 20076 if ( qualifier.nodeType ) { 20077 return jQuery.grep( elements, function( elem ) { 20078 return ( elem === qualifier ) !== not; 20079 } ); 20080 } 20081 20082 // Arraylike of elements (jQuery, arguments, Array) 20083 if ( typeof qualifier !== "string" ) { 20084 return jQuery.grep( elements, function( elem ) { 20085 return ( indexOf.call( qualifier, elem ) > -1 ) !== not; 20086 } ); 20087 } 20088 20089 // Filtered directly for both simple and complex selectors 20090 return jQuery.filter( qualifier, elements, not ); 20091} 20092 20093jQuery.filter = function( expr, elems, not ) { 20094 var elem = elems[ 0 ]; 20095 20096 if ( not ) { 20097 expr = ":not(" + expr + ")"; 20098 } 20099 20100 if ( elems.length === 1 && elem.nodeType === 1 ) { 20101 return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; 20102 } 20103 20104 return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { 20105 return elem.nodeType === 1; 20106 } ) ); 20107}; 20108 20109jQuery.fn.extend( { 20110 find: function( selector ) { 20111 var i, ret, 20112 len = this.length, 20113 self = this; 20114 20115 if ( typeof selector !== "string" ) { 20116 return this.pushStack( jQuery( selector ).filter( function() { 20117 for ( i = 0; i < len; i++ ) { 20118 if ( jQuery.contains( self[ i ], this ) ) { 20119 return true; 20120 } 20121 } 20122 } ) ); 20123 } 20124 20125 ret = this.pushStack( [] ); 20126 20127 for ( i = 0; i < len; i++ ) { 20128 jQuery.find( selector, self[ i ], ret ); 20129 } 20130 20131 return len > 1 ? jQuery.uniqueSort( ret ) : ret; 20132 }, 20133 filter: function( selector ) { 20134 return this.pushStack( winnow( this, selector || [], false ) ); 20135 }, 20136 not: function( selector ) { 20137 return this.pushStack( winnow( this, selector || [], true ) ); 20138 }, 20139 is: function( selector ) { 20140 return !!winnow( 20141 this, 20142 20143 // If this is a positional/relative selector, check membership in the returned set 20144 // so $("p:first").is("p:last") won't return true for a doc with two "p". 20145 typeof selector === "string" && rneedsContext.test( selector ) ? 20146 jQuery( selector ) : 20147 selector || [], 20148 false 20149 ).length; 20150 } 20151} ); 20152 20153 20154// Initialize a jQuery object 20155 20156 20157// A central reference to the root jQuery(document) 20158var rootjQuery, 20159 20160 // A simple way to check for HTML strings 20161 // Prioritize #id over <tag> to avoid XSS via location.hash (#9521) 20162 // Strict HTML recognition (#11290: must start with <) 20163 // Shortcut simple #id case for speed 20164 rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, 20165 20166 init = jQuery.fn.init = function( selector, context, root ) { 20167 var match, elem; 20168 20169 // HANDLE: $(""), $(null), $(undefined), $(false) 20170 if ( !selector ) { 20171 return this; 20172 } 20173 20174 // Method init() accepts an alternate rootjQuery 20175 // so migrate can support jQuery.sub (gh-2101) 20176 root = root || rootjQuery; 20177 20178 // Handle HTML strings 20179 if ( typeof selector === "string" ) { 20180 if ( selector[ 0 ] === "<" && 20181 selector[ selector.length - 1 ] === ">" && 20182 selector.length >= 3 ) { 20183 20184 // Assume that strings that start and end with <> are HTML and skip the regex check 20185 match = [ null, selector, null ]; 20186 20187 } else { 20188 match = rquickExpr.exec( selector ); 20189 } 20190 20191 // Match html or make sure no context is specified for #id 20192 if ( match && ( match[ 1 ] || !context ) ) { 20193 20194 // HANDLE: $(html) -> $(array) 20195 if ( match[ 1 ] ) { 20196 context = context instanceof jQuery ? context[ 0 ] : context; 20197 20198 // Option to run scripts is true for back-compat 20199 // Intentionally let the error be thrown if parseHTML is not present 20200 jQuery.merge( this, jQuery.parseHTML( 20201 match[ 1 ], 20202 context && context.nodeType ? context.ownerDocument || context : document, 20203 true 20204 ) ); 20205 20206 // HANDLE: $(html, props) 20207 if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { 20208 for ( match in context ) { 20209 20210 // Properties of context are called as methods if possible 20211 if ( isFunction( this[ match ] ) ) { 20212 this[ match ]( context[ match ] ); 20213 20214 // ...and otherwise set as attributes 20215 } else { 20216 this.attr( match, context[ match ] ); 20217 } 20218 } 20219 } 20220 20221 return this; 20222 20223 // HANDLE: $(#id) 20224 } else { 20225 elem = document.getElementById( match[ 2 ] ); 20226 20227 if ( elem ) { 20228 20229 // Inject the element directly into the jQuery object 20230 this[ 0 ] = elem; 20231 this.length = 1; 20232 } 20233 return this; 20234 } 20235 20236 // HANDLE: $(expr, $(...)) 20237 } else if ( !context || context.jquery ) { 20238 return ( context || root ).find( selector ); 20239 20240 // HANDLE: $(expr, context) 20241 // (which is just equivalent to: $(context).find(expr) 20242 } else { 20243 return this.constructor( context ).find( selector ); 20244 } 20245 20246 // HANDLE: $(DOMElement) 20247 } else if ( selector.nodeType ) { 20248 this[ 0 ] = selector; 20249 this.length = 1; 20250 return this; 20251 20252 // HANDLE: $(function) 20253 // Shortcut for document ready 20254 } else if ( isFunction( selector ) ) { 20255 return root.ready !== undefined ? 20256 root.ready( selector ) : 20257 20258 // Execute immediately if ready is not present 20259 selector( jQuery ); 20260 } 20261 20262 return jQuery.makeArray( selector, this ); 20263 }; 20264 20265// Give the init function the jQuery prototype for later instantiation 20266init.prototype = jQuery.fn; 20267 20268// Initialize central reference 20269rootjQuery = jQuery( document ); 20270 20271 20272var rparentsprev = /^(?:parents|prev(?:Until|All))/, 20273 20274 // Methods guaranteed to produce a unique set when starting from a unique set 20275 guaranteedUnique = { 20276 children: true, 20277 contents: true, 20278 next: true, 20279 prev: true 20280 }; 20281 20282jQuery.fn.extend( { 20283 has: function( target ) { 20284 var targets = jQuery( target, this ), 20285 l = targets.length; 20286 20287 return this.filter( function() { 20288 var i = 0; 20289 for ( ; i < l; i++ ) { 20290 if ( jQuery.contains( this, targets[ i ] ) ) { 20291 return true; 20292 } 20293 } 20294 } ); 20295 }, 20296 20297 closest: function( selectors, context ) { 20298 var cur, 20299 i = 0, 20300 l = this.length, 20301 matched = [], 20302 targets = typeof selectors !== "string" && jQuery( selectors ); 20303 20304 // Positional selectors never match, since there's no _selection_ context 20305 if ( !rneedsContext.test( selectors ) ) { 20306 for ( ; i < l; i++ ) { 20307 for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { 20308 20309 // Always skip document fragments 20310 if ( cur.nodeType < 11 && ( targets ? 20311 targets.index( cur ) > -1 : 20312 20313 // Don't pass non-elements to Sizzle 20314 cur.nodeType === 1 && 20315 jQuery.find.matchesSelector( cur, selectors ) ) ) { 20316 20317 matched.push( cur ); 20318 break; 20319 } 20320 } 20321 } 20322 } 20323 20324 return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); 20325 }, 20326 20327 // Determine the position of an element within the set 20328 index: function( elem ) { 20329 20330 // No argument, return index in parent 20331 if ( !elem ) { 20332 return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; 20333 } 20334 20335 // Index in selector 20336 if ( typeof elem === "string" ) { 20337 return indexOf.call( jQuery( elem ), this[ 0 ] ); 20338 } 20339 20340 // Locate the position of the desired element 20341 return indexOf.call( this, 20342 20343 // If it receives a jQuery object, the first element is used 20344 elem.jquery ? elem[ 0 ] : elem 20345 ); 20346 }, 20347 20348 add: function( selector, context ) { 20349 return this.pushStack( 20350 jQuery.uniqueSort( 20351 jQuery.merge( this.get(), jQuery( selector, context ) ) 20352 ) 20353 ); 20354 }, 20355 20356 addBack: function( selector ) { 20357 return this.add( selector == null ? 20358 this.prevObject : this.prevObject.filter( selector ) 20359 ); 20360 } 20361} ); 20362 20363function sibling( cur, dir ) { 20364 while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} 20365 return cur; 20366} 20367 20368jQuery.each( { 20369 parent: function( elem ) { 20370 var parent = elem.parentNode; 20371 return parent && parent.nodeType !== 11 ? parent : null; 20372 }, 20373 parents: function( elem ) { 20374 return dir( elem, "parentNode" ); 20375 }, 20376 parentsUntil: function( elem, _i, until ) { 20377 return dir( elem, "parentNode", until ); 20378 }, 20379 next: function( elem ) { 20380 return sibling( elem, "nextSibling" ); 20381 }, 20382 prev: function( elem ) { 20383 return sibling( elem, "previousSibling" ); 20384 }, 20385 nextAll: function( elem ) { 20386 return dir( elem, "nextSibling" ); 20387 }, 20388 prevAll: function( elem ) { 20389 return dir( elem, "previousSibling" ); 20390 }, 20391 nextUntil: function( elem, _i, until ) { 20392 return dir( elem, "nextSibling", until ); 20393 }, 20394 prevUntil: function( elem, _i, until ) { 20395 return dir( elem, "previousSibling", until ); 20396 }, 20397 siblings: function( elem ) { 20398 return siblings( ( elem.parentNode || {} ).firstChild, elem ); 20399 }, 20400 children: function( elem ) { 20401 return siblings( elem.firstChild ); 20402 }, 20403 contents: function( elem ) { 20404 if ( elem.contentDocument != null && 20405 20406 // Support: IE 11+ 20407 // <object> elements with no `data` attribute has an object 20408 // `contentDocument` with a `null` prototype. 20409 getProto( elem.contentDocument ) ) { 20410 20411 return elem.contentDocument; 20412 } 20413 20414 // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only 20415 // Treat the template element as a regular one in browsers that 20416 // don't support it. 20417 if ( nodeName( elem, "template" ) ) { 20418 elem = elem.content || elem; 20419 } 20420 20421 return jQuery.merge( [], elem.childNodes ); 20422 } 20423}, function( name, fn ) { 20424 jQuery.fn[ name ] = function( until, selector ) { 20425 var matched = jQuery.map( this, fn, until ); 20426 20427 if ( name.slice( -5 ) !== "Until" ) { 20428 selector = until; 20429 } 20430 20431 if ( selector && typeof selector === "string" ) { 20432 matched = jQuery.filter( selector, matched ); 20433 } 20434 20435 if ( this.length > 1 ) { 20436 20437 // Remove duplicates 20438 if ( !guaranteedUnique[ name ] ) { 20439 jQuery.uniqueSort( matched ); 20440 } 20441 20442 // Reverse order for parents* and prev-derivatives 20443 if ( rparentsprev.test( name ) ) { 20444 matched.reverse(); 20445 } 20446 } 20447 20448 return this.pushStack( matched ); 20449 }; 20450} ); 20451var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); 20452 20453 20454 20455// Convert String-formatted options into Object-formatted ones 20456function createOptions( options ) { 20457 var object = {}; 20458 jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { 20459 object[ flag ] = true; 20460 } ); 20461 return object; 20462} 20463 20464/* 20465 * Create a callback list using the following parameters: 20466 * 20467 * options: an optional list of space-separated options that will change how 20468 * the callback list behaves or a more traditional option object 20469 * 20470 * By default a callback list will act like an event callback list and can be 20471 * "fired" multiple times. 20472 * 20473 * Possible options: 20474 * 20475 * once: will ensure the callback list can only be fired once (like a Deferred) 20476 * 20477 * memory: will keep track of previous values and will call any callback added 20478 * after the list has been fired right away with the latest "memorized" 20479 * values (like a Deferred) 20480 * 20481 * unique: will ensure a callback can only be added once (no duplicate in the list) 20482 * 20483 * stopOnFalse: interrupt callings when a callback returns false 20484 * 20485 */ 20486jQuery.Callbacks = function( options ) { 20487 20488 // Convert options from String-formatted to Object-formatted if needed 20489 // (we check in cache first) 20490 options = typeof options === "string" ? 20491 createOptions( options ) : 20492 jQuery.extend( {}, options ); 20493 20494 var // Flag to know if list is currently firing 20495 firing, 20496 20497 // Last fire value for non-forgettable lists 20498 memory, 20499 20500 // Flag to know if list was already fired 20501 fired, 20502 20503 // Flag to prevent firing 20504 locked, 20505 20506 // Actual callback list 20507 list = [], 20508 20509 // Queue of execution data for repeatable lists 20510 queue = [], 20511 20512 // Index of currently firing callback (modified by add/remove as needed) 20513 firingIndex = -1, 20514 20515 // Fire callbacks 20516 fire = function() { 20517 20518 // Enforce single-firing 20519 locked = locked || options.once; 20520 20521 // Execute callbacks for all pending executions, 20522 // respecting firingIndex overrides and runtime changes 20523 fired = firing = true; 20524 for ( ; queue.length; firingIndex = -1 ) { 20525 memory = queue.shift(); 20526 while ( ++firingIndex < list.length ) { 20527 20528 // Run callback and check for early termination 20529 if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && 20530 options.stopOnFalse ) { 20531 20532 // Jump to end and forget the data so .add doesn't re-fire 20533 firingIndex = list.length; 20534 memory = false; 20535 } 20536 } 20537 } 20538 20539 // Forget the data if we're done with it 20540 if ( !options.memory ) { 20541 memory = false; 20542 } 20543 20544 firing = false; 20545 20546 // Clean up if we're done firing for good 20547 if ( locked ) { 20548 20549 // Keep an empty list if we have data for future add calls 20550 if ( memory ) { 20551 list = []; 20552 20553 // Otherwise, this object is spent 20554 } else { 20555 list = ""; 20556 } 20557 } 20558 }, 20559 20560 // Actual Callbacks object 20561 self = { 20562 20563 // Add a callback or a collection of callbacks to the list 20564 add: function() { 20565 if ( list ) { 20566 20567 // If we have memory from a past run, we should fire after adding 20568 if ( memory && !firing ) { 20569 firingIndex = list.length - 1; 20570 queue.push( memory ); 20571 } 20572 20573 ( function add( args ) { 20574 jQuery.each( args, function( _, arg ) { 20575 if ( isFunction( arg ) ) { 20576 if ( !options.unique || !self.has( arg ) ) { 20577 list.push( arg ); 20578 } 20579 } else if ( arg && arg.length && toType( arg ) !== "string" ) { 20580 20581 // Inspect recursively 20582 add( arg ); 20583 } 20584 } ); 20585 } )( arguments ); 20586 20587 if ( memory && !firing ) { 20588 fire(); 20589 } 20590 } 20591 return this; 20592 }, 20593 20594 // Remove a callback from the list 20595 remove: function() { 20596 jQuery.each( arguments, function( _, arg ) { 20597 var index; 20598 while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { 20599 list.splice( index, 1 ); 20600 20601 // Handle firing indexes 20602 if ( index <= firingIndex ) { 20603 firingIndex--; 20604 } 20605 } 20606 } ); 20607 return this; 20608 }, 20609 20610 // Check if a given callback is in the list. 20611 // If no argument is given, return whether or not list has callbacks attached. 20612 has: function( fn ) { 20613 return fn ? 20614 jQuery.inArray( fn, list ) > -1 : 20615 list.length > 0; 20616 }, 20617 20618 // Remove all callbacks from the list 20619 empty: function() { 20620 if ( list ) { 20621 list = []; 20622 } 20623 return this; 20624 }, 20625 20626 // Disable .fire and .add 20627 // Abort any current/pending executions 20628 // Clear all callbacks and values 20629 disable: function() { 20630 locked = queue = []; 20631 list = memory = ""; 20632 return this; 20633 }, 20634 disabled: function() { 20635 return !list; 20636 }, 20637 20638 // Disable .fire 20639 // Also disable .add unless we have memory (since it would have no effect) 20640 // Abort any pending executions 20641 lock: function() { 20642 locked = queue = []; 20643 if ( !memory && !firing ) { 20644 list = memory = ""; 20645 } 20646 return this; 20647 }, 20648 locked: function() { 20649 return !!locked; 20650 }, 20651 20652 // Call all callbacks with the given context and arguments 20653 fireWith: function( context, args ) { 20654 if ( !locked ) { 20655 args = args || []; 20656 args = [ context, args.slice ? args.slice() : args ]; 20657 queue.push( args ); 20658 if ( !firing ) { 20659 fire(); 20660 } 20661 } 20662 return this; 20663 }, 20664 20665 // Call all the callbacks with the given arguments 20666 fire: function() { 20667 self.fireWith( this, arguments ); 20668 return this; 20669 }, 20670 20671 // To know if the callbacks have already been called at least once 20672 fired: function() { 20673 return !!fired; 20674 } 20675 }; 20676 20677 return self; 20678}; 20679 20680 20681function Identity( v ) { 20682 return v; 20683} 20684function Thrower( ex ) { 20685 throw ex; 20686} 20687 20688function adoptValue( value, resolve, reject, noValue ) { 20689 var method; 20690 20691 try { 20692 20693 // Check for promise aspect first to privilege synchronous behavior 20694 if ( value && isFunction( ( method = value.promise ) ) ) { 20695 method.call( value ).done( resolve ).fail( reject ); 20696 20697 // Other thenables 20698 } else if ( value && isFunction( ( method = value.then ) ) ) { 20699 method.call( value, resolve, reject ); 20700 20701 // Other non-thenables 20702 } else { 20703 20704 // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: 20705 // * false: [ value ].slice( 0 ) => resolve( value ) 20706 // * true: [ value ].slice( 1 ) => resolve() 20707 resolve.apply( undefined, [ value ].slice( noValue ) ); 20708 } 20709 20710 // For Promises/A+, convert exceptions into rejections 20711 // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in 20712 // Deferred#then to conditionally suppress rejection. 20713 } catch ( value ) { 20714 20715 // Support: Android 4.0 only 20716 // Strict mode functions invoked without .call/.apply get global-object context 20717 reject.apply( undefined, [ value ] ); 20718 } 20719} 20720 20721jQuery.extend( { 20722 20723 Deferred: function( func ) { 20724 var tuples = [ 20725 20726 // action, add listener, callbacks, 20727 // ... .then handlers, argument index, [final state] 20728 [ "notify", "progress", jQuery.Callbacks( "memory" ), 20729 jQuery.Callbacks( "memory" ), 2 ], 20730 [ "resolve", "done", jQuery.Callbacks( "once memory" ), 20731 jQuery.Callbacks( "once memory" ), 0, "resolved" ], 20732 [ "reject", "fail", jQuery.Callbacks( "once memory" ), 20733 jQuery.Callbacks( "once memory" ), 1, "rejected" ] 20734 ], 20735 state = "pending", 20736 promise = { 20737 state: function() { 20738 return state; 20739 }, 20740 always: function() { 20741 deferred.done( arguments ).fail( arguments ); 20742 return this; 20743 }, 20744 "catch": function( fn ) { 20745 return promise.then( null, fn ); 20746 }, 20747 20748 // Keep pipe for back-compat 20749 pipe: function( /* fnDone, fnFail, fnProgress */ ) { 20750 var fns = arguments; 20751 20752 return jQuery.Deferred( function( newDefer ) { 20753 jQuery.each( tuples, function( _i, tuple ) { 20754 20755 // Map tuples (progress, done, fail) to arguments (done, fail, progress) 20756 var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; 20757 20758 // deferred.progress(function() { bind to newDefer or newDefer.notify }) 20759 // deferred.done(function() { bind to newDefer or newDefer.resolve }) 20760 // deferred.fail(function() { bind to newDefer or newDefer.reject }) 20761 deferred[ tuple[ 1 ] ]( function() { 20762 var returned = fn && fn.apply( this, arguments ); 20763 if ( returned && isFunction( returned.promise ) ) { 20764 returned.promise() 20765 .progress( newDefer.notify ) 20766 .done( newDefer.resolve ) 20767 .fail( newDefer.reject ); 20768 } else { 20769 newDefer[ tuple[ 0 ] + "With" ]( 20770 this, 20771 fn ? [ returned ] : arguments 20772 ); 20773 } 20774 } ); 20775 } ); 20776 fns = null; 20777 } ).promise(); 20778 }, 20779 then: function( onFulfilled, onRejected, onProgress ) { 20780 var maxDepth = 0; 20781 function resolve( depth, deferred, handler, special ) { 20782 return function() { 20783 var that = this, 20784 args = arguments, 20785 mightThrow = function() { 20786 var returned, then; 20787 20788 // Support: Promises/A+ section 2.3.3.3.3 20789 // https://promisesaplus.com/#point-59 20790 // Ignore double-resolution attempts 20791 if ( depth < maxDepth ) { 20792 return; 20793 } 20794 20795 returned = handler.apply( that, args ); 20796 20797 // Support: Promises/A+ section 2.3.1 20798 // https://promisesaplus.com/#point-48 20799 if ( returned === deferred.promise() ) { 20800 throw new TypeError( "Thenable self-resolution" ); 20801 } 20802 20803 // Support: Promises/A+ sections 2.3.3.1, 3.5 20804 // https://promisesaplus.com/#point-54 20805 // https://promisesaplus.com/#point-75 20806 // Retrieve `then` only once 20807 then = returned && 20808 20809 // Support: Promises/A+ section 2.3.4 20810 // https://promisesaplus.com/#point-64 20811 // Only check objects and functions for thenability 20812 ( typeof returned === "object" || 20813 typeof returned === "function" ) && 20814 returned.then; 20815 20816 // Handle a returned thenable 20817 if ( isFunction( then ) ) { 20818 20819 // Special processors (notify) just wait for resolution 20820 if ( special ) { 20821 then.call( 20822 returned, 20823 resolve( maxDepth, deferred, Identity, special ), 20824 resolve( maxDepth, deferred, Thrower, special ) 20825 ); 20826 20827 // Normal processors (resolve) also hook into progress 20828 } else { 20829 20830 // ...and disregard older resolution values 20831 maxDepth++; 20832 20833 then.call( 20834 returned, 20835 resolve( maxDepth, deferred, Identity, special ), 20836 resolve( maxDepth, deferred, Thrower, special ), 20837 resolve( maxDepth, deferred, Identity, 20838 deferred.notifyWith ) 20839 ); 20840 } 20841 20842 // Handle all other returned values 20843 } else { 20844 20845 // Only substitute handlers pass on context 20846 // and multiple values (non-spec behavior) 20847 if ( handler !== Identity ) { 20848 that = undefined; 20849 args = [ returned ]; 20850 } 20851 20852 // Process the value(s) 20853 // Default process is resolve 20854 ( special || deferred.resolveWith )( that, args ); 20855 } 20856 }, 20857 20858 // Only normal processors (resolve) catch and reject exceptions 20859 process = special ? 20860 mightThrow : 20861 function() { 20862 try { 20863 mightThrow(); 20864 } catch ( e ) { 20865 20866 if ( jQuery.Deferred.exceptionHook ) { 20867 jQuery.Deferred.exceptionHook( e, 20868 process.stackTrace ); 20869 } 20870 20871 // Support: Promises/A+ section 2.3.3.3.4.1 20872 // https://promisesaplus.com/#point-61 20873 // Ignore post-resolution exceptions 20874 if ( depth + 1 >= maxDepth ) { 20875 20876 // Only substitute handlers pass on context 20877 // and multiple values (non-spec behavior) 20878 if ( handler !== Thrower ) { 20879 that = undefined; 20880 args = [ e ]; 20881 } 20882 20883 deferred.rejectWith( that, args ); 20884 } 20885 } 20886 }; 20887 20888 // Support: Promises/A+ section 2.3.3.3.1 20889 // https://promisesaplus.com/#point-57 20890 // Re-resolve promises immediately to dodge false rejection from 20891 // subsequent errors 20892 if ( depth ) { 20893 process(); 20894 } else { 20895 20896 // Call an optional hook to record the stack, in case of exception 20897 // since it's otherwise lost when execution goes async 20898 if ( jQuery.Deferred.getStackHook ) { 20899 process.stackTrace = jQuery.Deferred.getStackHook(); 20900 } 20901 window.setTimeout( process ); 20902 } 20903 }; 20904 } 20905 20906 return jQuery.Deferred( function( newDefer ) { 20907 20908 // progress_handlers.add( ... ) 20909 tuples[ 0 ][ 3 ].add( 20910 resolve( 20911 0, 20912 newDefer, 20913 isFunction( onProgress ) ? 20914 onProgress : 20915 Identity, 20916 newDefer.notifyWith 20917 ) 20918 ); 20919 20920 // fulfilled_handlers.add( ... ) 20921 tuples[ 1 ][ 3 ].add( 20922 resolve( 20923 0, 20924 newDefer, 20925 isFunction( onFulfilled ) ? 20926 onFulfilled : 20927 Identity 20928 ) 20929 ); 20930 20931 // rejected_handlers.add( ... ) 20932 tuples[ 2 ][ 3 ].add( 20933 resolve( 20934 0, 20935 newDefer, 20936 isFunction( onRejected ) ? 20937 onRejected : 20938 Thrower 20939 ) 20940 ); 20941 } ).promise(); 20942 }, 20943 20944 // Get a promise for this deferred 20945 // If obj is provided, the promise aspect is added to the object 20946 promise: function( obj ) { 20947 return obj != null ? jQuery.extend( obj, promise ) : promise; 20948 } 20949 }, 20950 deferred = {}; 20951 20952 // Add list-specific methods 20953 jQuery.each( tuples, function( i, tuple ) { 20954 var list = tuple[ 2 ], 20955 stateString = tuple[ 5 ]; 20956 20957 // promise.progress = list.add 20958 // promise.done = list.add 20959 // promise.fail = list.add 20960 promise[ tuple[ 1 ] ] = list.add; 20961 20962 // Handle state 20963 if ( stateString ) { 20964 list.add( 20965 function() { 20966 20967 // state = "resolved" (i.e., fulfilled) 20968 // state = "rejected" 20969 state = stateString; 20970 }, 20971 20972 // rejected_callbacks.disable 20973 // fulfilled_callbacks.disable 20974 tuples[ 3 - i ][ 2 ].disable, 20975 20976 // rejected_handlers.disable 20977 // fulfilled_handlers.disable 20978 tuples[ 3 - i ][ 3 ].disable, 20979 20980 // progress_callbacks.lock 20981 tuples[ 0 ][ 2 ].lock, 20982 20983 // progress_handlers.lock 20984 tuples[ 0 ][ 3 ].lock 20985 ); 20986 } 20987 20988 // progress_handlers.fire 20989 // fulfilled_handlers.fire 20990 // rejected_handlers.fire 20991 list.add( tuple[ 3 ].fire ); 20992 20993 // deferred.notify = function() { deferred.notifyWith(...) } 20994 // deferred.resolve = function() { deferred.resolveWith(...) } 20995 // deferred.reject = function() { deferred.rejectWith(...) } 20996 deferred[ tuple[ 0 ] ] = function() { 20997 deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); 20998 return this; 20999 }; 21000 21001 // deferred.notifyWith = list.fireWith 21002 // deferred.resolveWith = list.fireWith 21003 // deferred.rejectWith = list.fireWith 21004 deferred[ tuple[ 0 ] + "With" ] = list.fireWith; 21005 } ); 21006 21007 // Make the deferred a promise 21008 promise.promise( deferred ); 21009 21010 // Call given func if any 21011 if ( func ) { 21012 func.call( deferred, deferred ); 21013 } 21014 21015 // All done! 21016 return deferred; 21017 }, 21018 21019 // Deferred helper 21020 when: function( singleValue ) { 21021 var 21022 21023 // count of uncompleted subordinates 21024 remaining = arguments.length, 21025 21026 // count of unprocessed arguments 21027 i = remaining, 21028 21029 // subordinate fulfillment data 21030 resolveContexts = Array( i ), 21031 resolveValues = slice.call( arguments ), 21032 21033 // the primary Deferred 21034 primary = jQuery.Deferred(), 21035 21036 // subordinate callback factory 21037 updateFunc = function( i ) { 21038 return function( value ) { 21039 resolveContexts[ i ] = this; 21040 resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; 21041 if ( !( --remaining ) ) { 21042 primary.resolveWith( resolveContexts, resolveValues ); 21043 } 21044 }; 21045 }; 21046 21047 // Single- and empty arguments are adopted like Promise.resolve 21048 if ( remaining <= 1 ) { 21049 adoptValue( singleValue, primary.done( updateFunc( i ) ).resolve, primary.reject, 21050 !remaining ); 21051 21052 // Use .then() to unwrap secondary thenables (cf. gh-3000) 21053 if ( primary.state() === "pending" || 21054 isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { 21055 21056 return primary.then(); 21057 } 21058 } 21059 21060 // Multiple arguments are aggregated like Promise.all array elements 21061 while ( i-- ) { 21062 adoptValue( resolveValues[ i ], updateFunc( i ), primary.reject ); 21063 } 21064 21065 return primary.promise(); 21066 } 21067} ); 21068 21069 21070// These usually indicate a programmer mistake during development, 21071// warn about them ASAP rather than swallowing them by default. 21072var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; 21073 21074jQuery.Deferred.exceptionHook = function( error, stack ) { 21075 21076 // Support: IE 8 - 9 only 21077 // Console exists when dev tools are open, which can happen at any time 21078 if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { 21079 window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); 21080 } 21081}; 21082 21083 21084 21085 21086jQuery.readyException = function( error ) { 21087 window.setTimeout( function() { 21088 throw error; 21089 } ); 21090}; 21091 21092 21093 21094 21095// The deferred used on DOM ready 21096var readyList = jQuery.Deferred(); 21097 21098jQuery.fn.ready = function( fn ) { 21099 21100 readyList 21101 .then( fn ) 21102 21103 // Wrap jQuery.readyException in a function so that the lookup 21104 // happens at the time of error handling instead of callback 21105 // registration. 21106 .catch( function( error ) { 21107 jQuery.readyException( error ); 21108 } ); 21109 21110 return this; 21111}; 21112 21113jQuery.extend( { 21114 21115 // Is the DOM ready to be used? Set to true once it occurs. 21116 isReady: false, 21117 21118 // A counter to track how many items to wait for before 21119 // the ready event fires. See #6781 21120 readyWait: 1, 21121 21122 // Handle when the DOM is ready 21123 ready: function( wait ) { 21124 21125 // Abort if there are pending holds or we're already ready 21126 if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { 21127 return; 21128 } 21129 21130 // Remember that the DOM is ready 21131 jQuery.isReady = true; 21132 21133 // If a normal DOM Ready event fired, decrement, and wait if need be 21134 if ( wait !== true && --jQuery.readyWait > 0 ) { 21135 return; 21136 } 21137 21138 // If there are functions bound, to execute 21139 readyList.resolveWith( document, [ jQuery ] ); 21140 } 21141} ); 21142 21143jQuery.ready.then = readyList.then; 21144 21145// The ready event handler and self cleanup method 21146function completed() { 21147 document.removeEventListener( "DOMContentLoaded", completed ); 21148 window.removeEventListener( "load", completed ); 21149 jQuery.ready(); 21150} 21151 21152// Catch cases where $(document).ready() is called 21153// after the browser event has already occurred. 21154// Support: IE <=9 - 10 only 21155// Older IE sometimes signals "interactive" too soon 21156if ( document.readyState === "complete" || 21157 ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { 21158 21159 // Handle it asynchronously to allow scripts the opportunity to delay ready 21160 window.setTimeout( jQuery.ready ); 21161 21162} else { 21163 21164 // Use the handy event callback 21165 document.addEventListener( "DOMContentLoaded", completed ); 21166 21167 // A fallback to window.onload, that will always work 21168 window.addEventListener( "load", completed ); 21169} 21170 21171 21172 21173 21174// Multifunctional method to get and set values of a collection 21175// The value/s can optionally be executed if it's a function 21176var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { 21177 var i = 0, 21178 len = elems.length, 21179 bulk = key == null; 21180 21181 // Sets many values 21182 if ( toType( key ) === "object" ) { 21183 chainable = true; 21184 for ( i in key ) { 21185 access( elems, fn, i, key[ i ], true, emptyGet, raw ); 21186 } 21187 21188 // Sets one value 21189 } else if ( value !== undefined ) { 21190 chainable = true; 21191 21192 if ( !isFunction( value ) ) { 21193 raw = true; 21194 } 21195 21196 if ( bulk ) { 21197 21198 // Bulk operations run against the entire set 21199 if ( raw ) { 21200 fn.call( elems, value ); 21201 fn = null; 21202 21203 // ...except when executing function values 21204 } else { 21205 bulk = fn; 21206 fn = function( elem, _key, value ) { 21207 return bulk.call( jQuery( elem ), value ); 21208 }; 21209 } 21210 } 21211 21212 if ( fn ) { 21213 for ( ; i < len; i++ ) { 21214 fn( 21215 elems[ i ], key, raw ? 21216 value : 21217 value.call( elems[ i ], i, fn( elems[ i ], key ) ) 21218 ); 21219 } 21220 } 21221 } 21222 21223 if ( chainable ) { 21224 return elems; 21225 } 21226 21227 // Gets 21228 if ( bulk ) { 21229 return fn.call( elems ); 21230 } 21231 21232 return len ? fn( elems[ 0 ], key ) : emptyGet; 21233}; 21234 21235 21236// Matches dashed string for camelizing 21237var rmsPrefix = /^-ms-/, 21238 rdashAlpha = /-([a-z])/g; 21239 21240// Used by camelCase as callback to replace() 21241function fcamelCase( _all, letter ) { 21242 return letter.toUpperCase(); 21243} 21244 21245// Convert dashed to camelCase; used by the css and data modules 21246// Support: IE <=9 - 11, Edge 12 - 15 21247// Microsoft forgot to hump their vendor prefix (#9572) 21248function camelCase( string ) { 21249 return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); 21250} 21251var acceptData = function( owner ) { 21252 21253 // Accepts only: 21254 // - Node 21255 // - Node.ELEMENT_NODE 21256 // - Node.DOCUMENT_NODE 21257 // - Object 21258 // - Any 21259 return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); 21260}; 21261 21262 21263 21264 21265function Data() { 21266 this.expando = jQuery.expando + Data.uid++; 21267} 21268 21269Data.uid = 1; 21270 21271Data.prototype = { 21272 21273 cache: function( owner ) { 21274 21275 // Check if the owner object already has a cache 21276 var value = owner[ this.expando ]; 21277 21278 // If not, create one 21279 if ( !value ) { 21280 value = {}; 21281 21282 // We can accept data for non-element nodes in modern browsers, 21283 // but we should not, see #8335. 21284 // Always return an empty object. 21285 if ( acceptData( owner ) ) { 21286 21287 // If it is a node unlikely to be stringify-ed or looped over 21288 // use plain assignment 21289 if ( owner.nodeType ) { 21290 owner[ this.expando ] = value; 21291 21292 // Otherwise secure it in a non-enumerable property 21293 // configurable must be true to allow the property to be 21294 // deleted when data is removed 21295 } else { 21296 Object.defineProperty( owner, this.expando, { 21297 value: value, 21298 configurable: true 21299 } ); 21300 } 21301 } 21302 } 21303 21304 return value; 21305 }, 21306 set: function( owner, data, value ) { 21307 var prop, 21308 cache = this.cache( owner ); 21309 21310 // Handle: [ owner, key, value ] args 21311 // Always use camelCase key (gh-2257) 21312 if ( typeof data === "string" ) { 21313 cache[ camelCase( data ) ] = value; 21314 21315 // Handle: [ owner, { properties } ] args 21316 } else { 21317 21318 // Copy the properties one-by-one to the cache object 21319 for ( prop in data ) { 21320 cache[ camelCase( prop ) ] = data[ prop ]; 21321 } 21322 } 21323 return cache; 21324 }, 21325 get: function( owner, key ) { 21326 return key === undefined ? 21327 this.cache( owner ) : 21328 21329 // Always use camelCase key (gh-2257) 21330 owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ]; 21331 }, 21332 access: function( owner, key, value ) { 21333 21334 // In cases where either: 21335 // 21336 // 1. No key was specified 21337 // 2. A string key was specified, but no value provided 21338 // 21339 // Take the "read" path and allow the get method to determine 21340 // which value to return, respectively either: 21341 // 21342 // 1. The entire cache object 21343 // 2. The data stored at the key 21344 // 21345 if ( key === undefined || 21346 ( ( key && typeof key === "string" ) && value === undefined ) ) { 21347 21348 return this.get( owner, key ); 21349 } 21350 21351 // When the key is not a string, or both a key and value 21352 // are specified, set or extend (existing objects) with either: 21353 // 21354 // 1. An object of properties 21355 // 2. A key and value 21356 // 21357 this.set( owner, key, value ); 21358 21359 // Since the "set" path can have two possible entry points 21360 // return the expected data based on which path was taken[*] 21361 return value !== undefined ? value : key; 21362 }, 21363 remove: function( owner, key ) { 21364 var i, 21365 cache = owner[ this.expando ]; 21366 21367 if ( cache === undefined ) { 21368 return; 21369 } 21370 21371 if ( key !== undefined ) { 21372 21373 // Support array or space separated string of keys 21374 if ( Array.isArray( key ) ) { 21375 21376 // If key is an array of keys... 21377 // We always set camelCase keys, so remove that. 21378 key = key.map( camelCase ); 21379 } else { 21380 key = camelCase( key ); 21381 21382 // If a key with the spaces exists, use it. 21383 // Otherwise, create an array by matching non-whitespace 21384 key = key in cache ? 21385 [ key ] : 21386 ( key.match( rnothtmlwhite ) || [] ); 21387 } 21388 21389 i = key.length; 21390 21391 while ( i-- ) { 21392 delete cache[ key[ i ] ]; 21393 } 21394 } 21395 21396 // Remove the expando if there's no more data 21397 if ( key === undefined || jQuery.isEmptyObject( cache ) ) { 21398 21399 // Support: Chrome <=35 - 45 21400 // Webkit & Blink performance suffers when deleting properties 21401 // from DOM nodes, so set to undefined instead 21402 // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) 21403 if ( owner.nodeType ) { 21404 owner[ this.expando ] = undefined; 21405 } else { 21406 delete owner[ this.expando ]; 21407 } 21408 } 21409 }, 21410 hasData: function( owner ) { 21411 var cache = owner[ this.expando ]; 21412 return cache !== undefined && !jQuery.isEmptyObject( cache ); 21413 } 21414}; 21415var dataPriv = new Data(); 21416 21417var dataUser = new Data(); 21418 21419 21420 21421// Implementation Summary 21422// 21423// 1. Enforce API surface and semantic compatibility with 1.9.x branch 21424// 2. Improve the module's maintainability by reducing the storage 21425// paths to a single mechanism. 21426// 3. Use the same single mechanism to support "private" and "user" data. 21427// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) 21428// 5. Avoid exposing implementation details on user objects (eg. expando properties) 21429// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 21430 21431var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, 21432 rmultiDash = /[A-Z]/g; 21433 21434function getData( data ) { 21435 if ( data === "true" ) { 21436 return true; 21437 } 21438 21439 if ( data === "false" ) { 21440 return false; 21441 } 21442 21443 if ( data === "null" ) { 21444 return null; 21445 } 21446 21447 // Only convert to a number if it doesn't change the string 21448 if ( data === +data + "" ) { 21449 return +data; 21450 } 21451 21452 if ( rbrace.test( data ) ) { 21453 return JSON.parse( data ); 21454 } 21455 21456 return data; 21457} 21458 21459function dataAttr( elem, key, data ) { 21460 var name; 21461 21462 // If nothing was found internally, try to fetch any 21463 // data from the HTML5 data-* attribute 21464 if ( data === undefined && elem.nodeType === 1 ) { 21465 name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); 21466 data = elem.getAttribute( name ); 21467 21468 if ( typeof data === "string" ) { 21469 try { 21470 data = getData( data ); 21471 } catch ( e ) {} 21472 21473 // Make sure we set the data so it isn't changed later 21474 dataUser.set( elem, key, data ); 21475 } else { 21476 data = undefined; 21477 } 21478 } 21479 return data; 21480} 21481 21482jQuery.extend( { 21483 hasData: function( elem ) { 21484 return dataUser.hasData( elem ) || dataPriv.hasData( elem ); 21485 }, 21486 21487 data: function( elem, name, data ) { 21488 return dataUser.access( elem, name, data ); 21489 }, 21490 21491 removeData: function( elem, name ) { 21492 dataUser.remove( elem, name ); 21493 }, 21494 21495 // TODO: Now that all calls to _data and _removeData have been replaced 21496 // with direct calls to dataPriv methods, these can be deprecated. 21497 _data: function( elem, name, data ) { 21498 return dataPriv.access( elem, name, data ); 21499 }, 21500 21501 _removeData: function( elem, name ) { 21502 dataPriv.remove( elem, name ); 21503 } 21504} ); 21505 21506jQuery.fn.extend( { 21507 data: function( key, value ) { 21508 var i, name, data, 21509 elem = this[ 0 ], 21510 attrs = elem && elem.attributes; 21511 21512 // Gets all values 21513 if ( key === undefined ) { 21514 if ( this.length ) { 21515 data = dataUser.get( elem ); 21516 21517 if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { 21518 i = attrs.length; 21519 while ( i-- ) { 21520 21521 // Support: IE 11 only 21522 // The attrs elements can be null (#14894) 21523 if ( attrs[ i ] ) { 21524 name = attrs[ i ].name; 21525 if ( name.indexOf( "data-" ) === 0 ) { 21526 name = camelCase( name.slice( 5 ) ); 21527 dataAttr( elem, name, data[ name ] ); 21528 } 21529 } 21530 } 21531 dataPriv.set( elem, "hasDataAttrs", true ); 21532 } 21533 } 21534 21535 return data; 21536 } 21537 21538 // Sets multiple values 21539 if ( typeof key === "object" ) { 21540 return this.each( function() { 21541 dataUser.set( this, key ); 21542 } ); 21543 } 21544 21545 return access( this, function( value ) { 21546 var data; 21547 21548 // The calling jQuery object (element matches) is not empty 21549 // (and therefore has an element appears at this[ 0 ]) and the 21550 // `value` parameter was not undefined. An empty jQuery object 21551 // will result in `undefined` for elem = this[ 0 ] which will 21552 // throw an exception if an attempt to read a data cache is made. 21553 if ( elem && value === undefined ) { 21554 21555 // Attempt to get data from the cache 21556 // The key will always be camelCased in Data 21557 data = dataUser.get( elem, key ); 21558 if ( data !== undefined ) { 21559 return data; 21560 } 21561 21562 // Attempt to "discover" the data in 21563 // HTML5 custom data-* attrs 21564 data = dataAttr( elem, key ); 21565 if ( data !== undefined ) { 21566 return data; 21567 } 21568 21569 // We tried really hard, but the data doesn't exist. 21570 return; 21571 } 21572 21573 // Set the data... 21574 this.each( function() { 21575 21576 // We always store the camelCased key 21577 dataUser.set( this, key, value ); 21578 } ); 21579 }, null, value, arguments.length > 1, null, true ); 21580 }, 21581 21582 removeData: function( key ) { 21583 return this.each( function() { 21584 dataUser.remove( this, key ); 21585 } ); 21586 } 21587} ); 21588 21589 21590jQuery.extend( { 21591 queue: function( elem, type, data ) { 21592 var queue; 21593 21594 if ( elem ) { 21595 type = ( type || "fx" ) + "queue"; 21596 queue = dataPriv.get( elem, type ); 21597 21598 // Speed up dequeue by getting out quickly if this is just a lookup 21599 if ( data ) { 21600 if ( !queue || Array.isArray( data ) ) { 21601 queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); 21602 } else { 21603 queue.push( data ); 21604 } 21605 } 21606 return queue || []; 21607 } 21608 }, 21609 21610 dequeue: function( elem, type ) { 21611 type = type || "fx"; 21612 21613 var queue = jQuery.queue( elem, type ), 21614 startLength = queue.length, 21615 fn = queue.shift(), 21616 hooks = jQuery._queueHooks( elem, type ), 21617 next = function() { 21618 jQuery.dequeue( elem, type ); 21619 }; 21620 21621 // If the fx queue is dequeued, always remove the progress sentinel 21622 if ( fn === "inprogress" ) { 21623 fn = queue.shift(); 21624 startLength--; 21625 } 21626 21627 if ( fn ) { 21628 21629 // Add a progress sentinel to prevent the fx queue from being 21630 // automatically dequeued 21631 if ( type === "fx" ) { 21632 queue.unshift( "inprogress" ); 21633 } 21634 21635 // Clear up the last queue stop function 21636 delete hooks.stop; 21637 fn.call( elem, next, hooks ); 21638 } 21639 21640 if ( !startLength && hooks ) { 21641 hooks.empty.fire(); 21642 } 21643 }, 21644 21645 // Not public - generate a queueHooks object, or return the current one 21646 _queueHooks: function( elem, type ) { 21647 var key = type + "queueHooks"; 21648 return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { 21649 empty: jQuery.Callbacks( "once memory" ).add( function() { 21650 dataPriv.remove( elem, [ type + "queue", key ] ); 21651 } ) 21652 } ); 21653 } 21654} ); 21655 21656jQuery.fn.extend( { 21657 queue: function( type, data ) { 21658 var setter = 2; 21659 21660 if ( typeof type !== "string" ) { 21661 data = type; 21662 type = "fx"; 21663 setter--; 21664 } 21665 21666 if ( arguments.length < setter ) { 21667 return jQuery.queue( this[ 0 ], type ); 21668 } 21669 21670 return data === undefined ? 21671 this : 21672 this.each( function() { 21673 var queue = jQuery.queue( this, type, data ); 21674 21675 // Ensure a hooks for this queue 21676 jQuery._queueHooks( this, type ); 21677 21678 if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { 21679 jQuery.dequeue( this, type ); 21680 } 21681 } ); 21682 }, 21683 dequeue: function( type ) { 21684 return this.each( function() { 21685 jQuery.dequeue( this, type ); 21686 } ); 21687 }, 21688 clearQueue: function( type ) { 21689 return this.queue( type || "fx", [] ); 21690 }, 21691 21692 // Get a promise resolved when queues of a certain type 21693 // are emptied (fx is the type by default) 21694 promise: function( type, obj ) { 21695 var tmp, 21696 count = 1, 21697 defer = jQuery.Deferred(), 21698 elements = this, 21699 i = this.length, 21700 resolve = function() { 21701 if ( !( --count ) ) { 21702 defer.resolveWith( elements, [ elements ] ); 21703 } 21704 }; 21705 21706 if ( typeof type !== "string" ) { 21707 obj = type; 21708 type = undefined; 21709 } 21710 type = type || "fx"; 21711 21712 while ( i-- ) { 21713 tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); 21714 if ( tmp && tmp.empty ) { 21715 count++; 21716 tmp.empty.add( resolve ); 21717 } 21718 } 21719 resolve(); 21720 return defer.promise( obj ); 21721 } 21722} ); 21723var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; 21724 21725var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); 21726 21727 21728var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; 21729 21730var documentElement = document.documentElement; 21731 21732 21733 21734 var isAttached = function( elem ) { 21735 return jQuery.contains( elem.ownerDocument, elem ); 21736 }, 21737 composed = { composed: true }; 21738 21739 // Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only 21740 // Check attachment across shadow DOM boundaries when possible (gh-3504) 21741 // Support: iOS 10.0-10.2 only 21742 // Early iOS 10 versions support `attachShadow` but not `getRootNode`, 21743 // leading to errors. We need to check for `getRootNode`. 21744 if ( documentElement.getRootNode ) { 21745 isAttached = function( elem ) { 21746 return jQuery.contains( elem.ownerDocument, elem ) || 21747 elem.getRootNode( composed ) === elem.ownerDocument; 21748 }; 21749 } 21750var isHiddenWithinTree = function( elem, el ) { 21751 21752 // isHiddenWithinTree might be called from jQuery#filter function; 21753 // in that case, element will be second argument 21754 elem = el || elem; 21755 21756 // Inline style trumps all 21757 return elem.style.display === "none" || 21758 elem.style.display === "" && 21759 21760 // Otherwise, check computed style 21761 // Support: Firefox <=43 - 45 21762 // Disconnected elements can have computed display: none, so first confirm that elem is 21763 // in the document. 21764 isAttached( elem ) && 21765 21766 jQuery.css( elem, "display" ) === "none"; 21767 }; 21768 21769 21770 21771function adjustCSS( elem, prop, valueParts, tween ) { 21772 var adjusted, scale, 21773 maxIterations = 20, 21774 currentValue = tween ? 21775 function() { 21776 return tween.cur(); 21777 } : 21778 function() { 21779 return jQuery.css( elem, prop, "" ); 21780 }, 21781 initial = currentValue(), 21782 unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), 21783 21784 // Starting value computation is required for potential unit mismatches 21785 initialInUnit = elem.nodeType && 21786 ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && 21787 rcssNum.exec( jQuery.css( elem, prop ) ); 21788 21789 if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { 21790 21791 // Support: Firefox <=54 21792 // Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144) 21793 initial = initial / 2; 21794 21795 // Trust units reported by jQuery.css 21796 unit = unit || initialInUnit[ 3 ]; 21797 21798 // Iteratively approximate from a nonzero starting point 21799 initialInUnit = +initial || 1; 21800 21801 while ( maxIterations-- ) { 21802 21803 // Evaluate and update our best guess (doubling guesses that zero out). 21804 // Finish if the scale equals or crosses 1 (making the old*new product non-positive). 21805 jQuery.style( elem, prop, initialInUnit + unit ); 21806 if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) { 21807 maxIterations = 0; 21808 } 21809 initialInUnit = initialInUnit / scale; 21810 21811 } 21812 21813 initialInUnit = initialInUnit * 2; 21814 jQuery.style( elem, prop, initialInUnit + unit ); 21815 21816 // Make sure we update the tween properties later on 21817 valueParts = valueParts || []; 21818 } 21819 21820 if ( valueParts ) { 21821 initialInUnit = +initialInUnit || +initial || 0; 21822 21823 // Apply relative offset (+=/-=) if specified 21824 adjusted = valueParts[ 1 ] ? 21825 initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : 21826 +valueParts[ 2 ]; 21827 if ( tween ) { 21828 tween.unit = unit; 21829 tween.start = initialInUnit; 21830 tween.end = adjusted; 21831 } 21832 } 21833 return adjusted; 21834} 21835 21836 21837var defaultDisplayMap = {}; 21838 21839function getDefaultDisplay( elem ) { 21840 var temp, 21841 doc = elem.ownerDocument, 21842 nodeName = elem.nodeName, 21843 display = defaultDisplayMap[ nodeName ]; 21844 21845 if ( display ) { 21846 return display; 21847 } 21848 21849 temp = doc.body.appendChild( doc.createElement( nodeName ) ); 21850 display = jQuery.css( temp, "display" ); 21851 21852 temp.parentNode.removeChild( temp ); 21853 21854 if ( display === "none" ) { 21855 display = "block"; 21856 } 21857 defaultDisplayMap[ nodeName ] = display; 21858 21859 return display; 21860} 21861 21862function showHide( elements, show ) { 21863 var display, elem, 21864 values = [], 21865 index = 0, 21866 length = elements.length; 21867 21868 // Determine new display value for elements that need to change 21869 for ( ; index < length; index++ ) { 21870 elem = elements[ index ]; 21871 if ( !elem.style ) { 21872 continue; 21873 } 21874 21875 display = elem.style.display; 21876 if ( show ) { 21877 21878 // Since we force visibility upon cascade-hidden elements, an immediate (and slow) 21879 // check is required in this first loop unless we have a nonempty display value (either 21880 // inline or about-to-be-restored) 21881 if ( display === "none" ) { 21882 values[ index ] = dataPriv.get( elem, "display" ) || null; 21883 if ( !values[ index ] ) { 21884 elem.style.display = ""; 21885 } 21886 } 21887 if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { 21888 values[ index ] = getDefaultDisplay( elem ); 21889 } 21890 } else { 21891 if ( display !== "none" ) { 21892 values[ index ] = "none"; 21893 21894 // Remember what we're overwriting 21895 dataPriv.set( elem, "display", display ); 21896 } 21897 } 21898 } 21899 21900 // Set the display of the elements in a second loop to avoid constant reflow 21901 for ( index = 0; index < length; index++ ) { 21902 if ( values[ index ] != null ) { 21903 elements[ index ].style.display = values[ index ]; 21904 } 21905 } 21906 21907 return elements; 21908} 21909 21910jQuery.fn.extend( { 21911 show: function() { 21912 return showHide( this, true ); 21913 }, 21914 hide: function() { 21915 return showHide( this ); 21916 }, 21917 toggle: function( state ) { 21918 if ( typeof state === "boolean" ) { 21919 return state ? this.show() : this.hide(); 21920 } 21921 21922 return this.each( function() { 21923 if ( isHiddenWithinTree( this ) ) { 21924 jQuery( this ).show(); 21925 } else { 21926 jQuery( this ).hide(); 21927 } 21928 } ); 21929 } 21930} ); 21931var rcheckableType = ( /^(?:checkbox|radio)$/i ); 21932 21933var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]*)/i ); 21934 21935var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i ); 21936 21937 21938 21939( function() { 21940 var fragment = document.createDocumentFragment(), 21941 div = fragment.appendChild( document.createElement( "div" ) ), 21942 input = document.createElement( "input" ); 21943 21944 // Support: Android 4.0 - 4.3 only 21945 // Check state lost if the name is set (#11217) 21946 // Support: Windows Web Apps (WWA) 21947 // `name` and `type` must use .setAttribute for WWA (#14901) 21948 input.setAttribute( "type", "radio" ); 21949 input.setAttribute( "checked", "checked" ); 21950 input.setAttribute( "name", "t" ); 21951 21952 div.appendChild( input ); 21953 21954 // Support: Android <=4.1 only 21955 // Older WebKit doesn't clone checked state correctly in fragments 21956 support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; 21957 21958 // Support: IE <=11 only 21959 // Make sure textarea (and checkbox) defaultValue is properly cloned 21960 div.innerHTML = "<textarea>x</textarea>"; 21961 support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; 21962 21963 // Support: IE <=9 only 21964 // IE <=9 replaces <option> tags with their contents when inserted outside of 21965 // the select element. 21966 div.innerHTML = "<option></option>"; 21967 support.option = !!div.lastChild; 21968} )(); 21969 21970 21971// We have to close these tags to support XHTML (#13200) 21972var wrapMap = { 21973 21974 // XHTML parsers do not magically insert elements in the 21975 // same way that tag soup parsers do. So we cannot shorten 21976 // this by omitting <tbody> or other required elements. 21977 thead: [ 1, "<table>", "</table>" ], 21978 col: [ 2, "<table><colgroup>", "</colgroup></table>" ], 21979 tr: [ 2, "<table><tbody>", "</tbody></table>" ], 21980 td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ], 21981 21982 _default: [ 0, "", "" ] 21983}; 21984 21985wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; 21986wrapMap.th = wrapMap.td; 21987 21988// Support: IE <=9 only 21989if ( !support.option ) { 21990 wrapMap.optgroup = wrapMap.option = [ 1, "<select multiple='multiple'>", "</select>" ]; 21991} 21992 21993 21994function getAll( context, tag ) { 21995 21996 // Support: IE <=9 - 11 only 21997 // Use typeof to avoid zero-argument method invocation on host objects (#15151) 21998 var ret; 21999 22000 if ( typeof context.getElementsByTagName !== "undefined" ) { 22001 ret = context.getElementsByTagName( tag || "*" ); 22002 22003 } else if ( typeof context.querySelectorAll !== "undefined" ) { 22004 ret = context.querySelectorAll( tag || "*" ); 22005 22006 } else { 22007 ret = []; 22008 } 22009 22010 if ( tag === undefined || tag && nodeName( context, tag ) ) { 22011 return jQuery.merge( [ context ], ret ); 22012 } 22013 22014 return ret; 22015} 22016 22017 22018// Mark scripts as having already been evaluated 22019function setGlobalEval( elems, refElements ) { 22020 var i = 0, 22021 l = elems.length; 22022 22023 for ( ; i < l; i++ ) { 22024 dataPriv.set( 22025 elems[ i ], 22026 "globalEval", 22027 !refElements || dataPriv.get( refElements[ i ], "globalEval" ) 22028 ); 22029 } 22030} 22031 22032 22033var rhtml = /<|&#?\w+;/; 22034 22035function buildFragment( elems, context, scripts, selection, ignored ) { 22036 var elem, tmp, tag, wrap, attached, j, 22037 fragment = context.createDocumentFragment(), 22038 nodes = [], 22039 i = 0, 22040 l = elems.length; 22041 22042 for ( ; i < l; i++ ) { 22043 elem = elems[ i ]; 22044 22045 if ( elem || elem === 0 ) { 22046 22047 // Add nodes directly 22048 if ( toType( elem ) === "object" ) { 22049 22050 // Support: Android <=4.0 only, PhantomJS 1 only 22051 // push.apply(_, arraylike) throws on ancient WebKit 22052 jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); 22053 22054 // Convert non-html into a text node 22055 } else if ( !rhtml.test( elem ) ) { 22056 nodes.push( context.createTextNode( elem ) ); 22057 22058 // Convert html into DOM nodes 22059 } else { 22060 tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); 22061 22062 // Deserialize a standard representation 22063 tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); 22064 wrap = wrapMap[ tag ] || wrapMap._default; 22065 tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; 22066 22067 // Descend through wrappers to the right content 22068 j = wrap[ 0 ]; 22069 while ( j-- ) { 22070 tmp = tmp.lastChild; 22071 } 22072 22073 // Support: Android <=4.0 only, PhantomJS 1 only 22074 // push.apply(_, arraylike) throws on ancient WebKit 22075 jQuery.merge( nodes, tmp.childNodes ); 22076 22077 // Remember the top-level container 22078 tmp = fragment.firstChild; 22079 22080 // Ensure the created nodes are orphaned (#12392) 22081 tmp.textContent = ""; 22082 } 22083 } 22084 } 22085 22086 // Remove wrapper from fragment 22087 fragment.textContent = ""; 22088 22089 i = 0; 22090 while ( ( elem = nodes[ i++ ] ) ) { 22091 22092 // Skip elements already in the context collection (trac-4087) 22093 if ( selection && jQuery.inArray( elem, selection ) > -1 ) { 22094 if ( ignored ) { 22095 ignored.push( elem ); 22096 } 22097 continue; 22098 } 22099 22100 attached = isAttached( elem ); 22101 22102 // Append to fragment 22103 tmp = getAll( fragment.appendChild( elem ), "script" ); 22104 22105 // Preserve script evaluation history 22106 if ( attached ) { 22107 setGlobalEval( tmp ); 22108 } 22109 22110 // Capture executables 22111 if ( scripts ) { 22112 j = 0; 22113 while ( ( elem = tmp[ j++ ] ) ) { 22114 if ( rscriptType.test( elem.type || "" ) ) { 22115 scripts.push( elem ); 22116 } 22117 } 22118 } 22119 } 22120 22121 return fragment; 22122} 22123 22124 22125var rtypenamespace = /^([^.]*)(?:\.(.+)|)/; 22126 22127function returnTrue() { 22128 return true; 22129} 22130 22131function returnFalse() { 22132 return false; 22133} 22134 22135// Support: IE <=9 - 11+ 22136// focus() and blur() are asynchronous, except when they are no-op. 22137// So expect focus to be synchronous when the element is already active, 22138// and blur to be synchronous when the element is not already active. 22139// (focus and blur are always synchronous in other supported browsers, 22140// this just defines when we can count on it). 22141function expectSync( elem, type ) { 22142 return ( elem === safeActiveElement() ) === ( type === "focus" ); 22143} 22144 22145// Support: IE <=9 only 22146// Accessing document.activeElement can throw unexpectedly 22147// https://bugs.jquery.com/ticket/13393 22148function safeActiveElement() { 22149 try { 22150 return document.activeElement; 22151 } catch ( err ) { } 22152} 22153 22154function on( elem, types, selector, data, fn, one ) { 22155 var origFn, type; 22156 22157 // Types can be a map of types/handlers 22158 if ( typeof types === "object" ) { 22159 22160 // ( types-Object, selector, data ) 22161 if ( typeof selector !== "string" ) { 22162 22163 // ( types-Object, data ) 22164 data = data || selector; 22165 selector = undefined; 22166 } 22167 for ( type in types ) { 22168 on( elem, type, selector, data, types[ type ], one ); 22169 } 22170 return elem; 22171 } 22172 22173 if ( data == null && fn == null ) { 22174 22175 // ( types, fn ) 22176 fn = selector; 22177 data = selector = undefined; 22178 } else if ( fn == null ) { 22179 if ( typeof selector === "string" ) { 22180 22181 // ( types, selector, fn ) 22182 fn = data; 22183 data = undefined; 22184 } else { 22185 22186 // ( types, data, fn ) 22187 fn = data; 22188 data = selector; 22189 selector = undefined; 22190 } 22191 } 22192 if ( fn === false ) { 22193 fn = returnFalse; 22194 } else if ( !fn ) { 22195 return elem; 22196 } 22197 22198 if ( one === 1 ) { 22199 origFn = fn; 22200 fn = function( event ) { 22201 22202 // Can use an empty set, since event contains the info 22203 jQuery().off( event ); 22204 return origFn.apply( this, arguments ); 22205 }; 22206 22207 // Use same guid so caller can remove using origFn 22208 fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); 22209 } 22210 return elem.each( function() { 22211 jQuery.event.add( this, types, fn, data, selector ); 22212 } ); 22213} 22214 22215/* 22216 * Helper functions for managing events -- not part of the public interface. 22217 * Props to Dean Edwards' addEvent library for many of the ideas. 22218 */ 22219jQuery.event = { 22220 22221 global: {}, 22222 22223 add: function( elem, types, handler, data, selector ) { 22224 22225 var handleObjIn, eventHandle, tmp, 22226 events, t, handleObj, 22227 special, handlers, type, namespaces, origType, 22228 elemData = dataPriv.get( elem ); 22229 22230 // Only attach events to objects that accept data 22231 if ( !acceptData( elem ) ) { 22232 return; 22233 } 22234 22235 // Caller can pass in an object of custom data in lieu of the handler 22236 if ( handler.handler ) { 22237 handleObjIn = handler; 22238 handler = handleObjIn.handler; 22239 selector = handleObjIn.selector; 22240 } 22241 22242 // Ensure that invalid selectors throw exceptions at attach time 22243 // Evaluate against documentElement in case elem is a non-element node (e.g., document) 22244 if ( selector ) { 22245 jQuery.find.matchesSelector( documentElement, selector ); 22246 } 22247 22248 // Make sure that the handler has a unique ID, used to find/remove it later 22249 if ( !handler.guid ) { 22250 handler.guid = jQuery.guid++; 22251 } 22252 22253 // Init the element's event structure and main handler, if this is the first 22254 if ( !( events = elemData.events ) ) { 22255 events = elemData.events = Object.create( null ); 22256 } 22257 if ( !( eventHandle = elemData.handle ) ) { 22258 eventHandle = elemData.handle = function( e ) { 22259 22260 // Discard the second event of a jQuery.event.trigger() and 22261 // when an event is called after a page has unloaded 22262 return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? 22263 jQuery.event.dispatch.apply( elem, arguments ) : undefined; 22264 }; 22265 } 22266 22267 // Handle multiple events separated by a space 22268 types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; 22269 t = types.length; 22270 while ( t-- ) { 22271 tmp = rtypenamespace.exec( types[ t ] ) || []; 22272 type = origType = tmp[ 1 ]; 22273 namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); 22274 22275 // There *must* be a type, no attaching namespace-only handlers 22276 if ( !type ) { 22277 continue; 22278 } 22279 22280 // If event changes its type, use the special event handlers for the changed type 22281 special = jQuery.event.special[ type ] || {}; 22282 22283 // If selector defined, determine special event api type, otherwise given type 22284 type = ( selector ? special.delegateType : special.bindType ) || type; 22285 22286 // Update special based on newly reset type 22287 special = jQuery.event.special[ type ] || {}; 22288 22289 // handleObj is passed to all event handlers 22290 handleObj = jQuery.extend( { 22291 type: type, 22292 origType: origType, 22293 data: data, 22294 handler: handler, 22295 guid: handler.guid, 22296 selector: selector, 22297 needsContext: selector && jQuery.expr.match.needsContext.test( selector ), 22298 namespace: namespaces.join( "." ) 22299 }, handleObjIn ); 22300 22301 // Init the event handler queue if we're the first 22302 if ( !( handlers = events[ type ] ) ) { 22303 handlers = events[ type ] = []; 22304 handlers.delegateCount = 0; 22305 22306 // Only use addEventListener if the special events handler returns false 22307 if ( !special.setup || 22308 special.setup.call( elem, data, namespaces, eventHandle ) === false ) { 22309 22310 if ( elem.addEventListener ) { 22311 elem.addEventListener( type, eventHandle ); 22312 } 22313 } 22314 } 22315 22316 if ( special.add ) { 22317 special.add.call( elem, handleObj ); 22318 22319 if ( !handleObj.handler.guid ) { 22320 handleObj.handler.guid = handler.guid; 22321 } 22322 } 22323 22324 // Add to the element's handler list, delegates in front 22325 if ( selector ) { 22326 handlers.splice( handlers.delegateCount++, 0, handleObj ); 22327 } else { 22328 handlers.push( handleObj ); 22329 } 22330 22331 // Keep track of which events have ever been used, for event optimization 22332 jQuery.event.global[ type ] = true; 22333 } 22334 22335 }, 22336 22337 // Detach an event or set of events from an element 22338 remove: function( elem, types, handler, selector, mappedTypes ) { 22339 22340 var j, origCount, tmp, 22341 events, t, handleObj, 22342 special, handlers, type, namespaces, origType, 22343 elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); 22344 22345 if ( !elemData || !( events = elemData.events ) ) { 22346 return; 22347 } 22348 22349 // Once for each type.namespace in types; type may be omitted 22350 types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; 22351 t = types.length; 22352 while ( t-- ) { 22353 tmp = rtypenamespace.exec( types[ t ] ) || []; 22354 type = origType = tmp[ 1 ]; 22355 namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); 22356 22357 // Unbind all events (on this namespace, if provided) for the element 22358 if ( !type ) { 22359 for ( type in events ) { 22360 jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); 22361 } 22362 continue; 22363 } 22364 22365 special = jQuery.event.special[ type ] || {}; 22366 type = ( selector ? special.delegateType : special.bindType ) || type; 22367 handlers = events[ type ] || []; 22368 tmp = tmp[ 2 ] && 22369 new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); 22370 22371 // Remove matching events 22372 origCount = j = handlers.length; 22373 while ( j-- ) { 22374 handleObj = handlers[ j ]; 22375 22376 if ( ( mappedTypes || origType === handleObj.origType ) && 22377 ( !handler || handler.guid === handleObj.guid ) && 22378 ( !tmp || tmp.test( handleObj.namespace ) ) && 22379 ( !selector || selector === handleObj.selector || 22380 selector === "**" && handleObj.selector ) ) { 22381 handlers.splice( j, 1 ); 22382 22383 if ( handleObj.selector ) { 22384 handlers.delegateCount--; 22385 } 22386 if ( special.remove ) { 22387 special.remove.call( elem, handleObj ); 22388 } 22389 } 22390 } 22391 22392 // Remove generic event handler if we removed something and no more handlers exist 22393 // (avoids potential for endless recursion during removal of special event handlers) 22394 if ( origCount && !handlers.length ) { 22395 if ( !special.teardown || 22396 special.teardown.call( elem, namespaces, elemData.handle ) === false ) { 22397 22398 jQuery.removeEvent( elem, type, elemData.handle ); 22399 } 22400 22401 delete events[ type ]; 22402 } 22403 } 22404 22405 // Remove data and the expando if it's no longer used 22406 if ( jQuery.isEmptyObject( events ) ) { 22407 dataPriv.remove( elem, "handle events" ); 22408 } 22409 }, 22410 22411 dispatch: function( nativeEvent ) { 22412 22413 var i, j, ret, matched, handleObj, handlerQueue, 22414 args = new Array( arguments.length ), 22415 22416 // Make a writable jQuery.Event from the native event object 22417 event = jQuery.event.fix( nativeEvent ), 22418 22419 handlers = ( 22420 dataPriv.get( this, "events" ) || Object.create( null ) 22421 )[ event.type ] || [], 22422 special = jQuery.event.special[ event.type ] || {}; 22423 22424 // Use the fix-ed jQuery.Event rather than the (read-only) native event 22425 args[ 0 ] = event; 22426 22427 for ( i = 1; i < arguments.length; i++ ) { 22428 args[ i ] = arguments[ i ]; 22429 } 22430 22431 event.delegateTarget = this; 22432 22433 // Call the preDispatch hook for the mapped type, and let it bail if desired 22434 if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { 22435 return; 22436 } 22437 22438 // Determine handlers 22439 handlerQueue = jQuery.event.handlers.call( this, event, handlers ); 22440 22441 // Run delegates first; they may want to stop propagation beneath us 22442 i = 0; 22443 while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { 22444 event.currentTarget = matched.elem; 22445 22446 j = 0; 22447 while ( ( handleObj = matched.handlers[ j++ ] ) && 22448 !event.isImmediatePropagationStopped() ) { 22449 22450 // If the event is namespaced, then each handler is only invoked if it is 22451 // specially universal or its namespaces are a superset of the event's. 22452 if ( !event.rnamespace || handleObj.namespace === false || 22453 event.rnamespace.test( handleObj.namespace ) ) { 22454 22455 event.handleObj = handleObj; 22456 event.data = handleObj.data; 22457 22458 ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || 22459 handleObj.handler ).apply( matched.elem, args ); 22460 22461 if ( ret !== undefined ) { 22462 if ( ( event.result = ret ) === false ) { 22463 event.preventDefault(); 22464 event.stopPropagation(); 22465 } 22466 } 22467 } 22468 } 22469 } 22470 22471 // Call the postDispatch hook for the mapped type 22472 if ( special.postDispatch ) { 22473 special.postDispatch.call( this, event ); 22474 } 22475 22476 return event.result; 22477 }, 22478 22479 handlers: function( event, handlers ) { 22480 var i, handleObj, sel, matchedHandlers, matchedSelectors, 22481 handlerQueue = [], 22482 delegateCount = handlers.delegateCount, 22483 cur = event.target; 22484 22485 // Find delegate handlers 22486 if ( delegateCount && 22487 22488 // Support: IE <=9 22489 // Black-hole SVG <use> instance trees (trac-13180) 22490 cur.nodeType && 22491 22492 // Support: Firefox <=42 22493 // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) 22494 // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click 22495 // Support: IE 11 only 22496 // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) 22497 !( event.type === "click" && event.button >= 1 ) ) { 22498 22499 for ( ; cur !== this; cur = cur.parentNode || this ) { 22500 22501 // Don't check non-elements (#13208) 22502 // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) 22503 if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { 22504 matchedHandlers = []; 22505 matchedSelectors = {}; 22506 for ( i = 0; i < delegateCount; i++ ) { 22507 handleObj = handlers[ i ]; 22508 22509 // Don't conflict with Object.prototype properties (#13203) 22510 sel = handleObj.selector + " "; 22511 22512 if ( matchedSelectors[ sel ] === undefined ) { 22513 matchedSelectors[ sel ] = handleObj.needsContext ? 22514 jQuery( sel, this ).index( cur ) > -1 : 22515 jQuery.find( sel, this, null, [ cur ] ).length; 22516 } 22517 if ( matchedSelectors[ sel ] ) { 22518 matchedHandlers.push( handleObj ); 22519 } 22520 } 22521 if ( matchedHandlers.length ) { 22522 handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); 22523 } 22524 } 22525 } 22526 } 22527 22528 // Add the remaining (directly-bound) handlers 22529 cur = this; 22530 if ( delegateCount < handlers.length ) { 22531 handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); 22532 } 22533 22534 return handlerQueue; 22535 }, 22536 22537 addProp: function( name, hook ) { 22538 Object.defineProperty( jQuery.Event.prototype, name, { 22539 enumerable: true, 22540 configurable: true, 22541 22542 get: isFunction( hook ) ? 22543 function() { 22544 if ( this.originalEvent ) { 22545 return hook( this.originalEvent ); 22546 } 22547 } : 22548 function() { 22549 if ( this.originalEvent ) { 22550 return this.originalEvent[ name ]; 22551 } 22552 }, 22553 22554 set: function( value ) { 22555 Object.defineProperty( this, name, { 22556 enumerable: true, 22557 configurable: true, 22558 writable: true, 22559 value: value 22560 } ); 22561 } 22562 } ); 22563 }, 22564 22565 fix: function( originalEvent ) { 22566 return originalEvent[ jQuery.expando ] ? 22567 originalEvent : 22568 new jQuery.Event( originalEvent ); 22569 }, 22570 22571 special: { 22572 load: { 22573 22574 // Prevent triggered image.load events from bubbling to window.load 22575 noBubble: true 22576 }, 22577 click: { 22578 22579 // Utilize native event to ensure correct state for checkable inputs 22580 setup: function( data ) { 22581 22582 // For mutual compressibility with _default, replace `this` access with a local var. 22583 // `|| data` is dead code meant only to preserve the variable through minification. 22584 var el = this || data; 22585 22586 // Claim the first handler 22587 if ( rcheckableType.test( el.type ) && 22588 el.click && nodeName( el, "input" ) ) { 22589 22590 // dataPriv.set( el, "click", ... ) 22591 leverageNative( el, "click", returnTrue ); 22592 } 22593 22594 // Return false to allow normal processing in the caller 22595 return false; 22596 }, 22597 trigger: function( data ) { 22598 22599 // For mutual compressibility with _default, replace `this` access with a local var. 22600 // `|| data` is dead code meant only to preserve the variable through minification. 22601 var el = this || data; 22602 22603 // Force setup before triggering a click 22604 if ( rcheckableType.test( el.type ) && 22605 el.click && nodeName( el, "input" ) ) { 22606 22607 leverageNative( el, "click" ); 22608 } 22609 22610 // Return non-false to allow normal event-path propagation 22611 return true; 22612 }, 22613 22614 // For cross-browser consistency, suppress native .click() on links 22615 // Also prevent it if we're currently inside a leveraged native-event stack 22616 _default: function( event ) { 22617 var target = event.target; 22618 return rcheckableType.test( target.type ) && 22619 target.click && nodeName( target, "input" ) && 22620 dataPriv.get( target, "click" ) || 22621 nodeName( target, "a" ); 22622 } 22623 }, 22624 22625 beforeunload: { 22626 postDispatch: function( event ) { 22627 22628 // Support: Firefox 20+ 22629 // Firefox doesn't alert if the returnValue field is not set. 22630 if ( event.result !== undefined && event.originalEvent ) { 22631 event.originalEvent.returnValue = event.result; 22632 } 22633 } 22634 } 22635 } 22636}; 22637 22638// Ensure the presence of an event listener that handles manually-triggered 22639// synthetic events by interrupting progress until reinvoked in response to 22640// *native* events that it fires directly, ensuring that state changes have 22641// already occurred before other listeners are invoked. 22642function leverageNative( el, type, expectSync ) { 22643 22644 // Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add 22645 if ( !expectSync ) { 22646 if ( dataPriv.get( el, type ) === undefined ) { 22647 jQuery.event.add( el, type, returnTrue ); 22648 } 22649 return; 22650 } 22651 22652 // Register the controller as a special universal handler for all event namespaces 22653 dataPriv.set( el, type, false ); 22654 jQuery.event.add( el, type, { 22655 namespace: false, 22656 handler: function( event ) { 22657 var notAsync, result, 22658 saved = dataPriv.get( this, type ); 22659 22660 if ( ( event.isTrigger & 1 ) && this[ type ] ) { 22661 22662 // Interrupt processing of the outer synthetic .trigger()ed event 22663 // Saved data should be false in such cases, but might be a leftover capture object 22664 // from an async native handler (gh-4350) 22665 if ( !saved.length ) { 22666 22667 // Store arguments for use when handling the inner native event 22668 // There will always be at least one argument (an event object), so this array 22669 // will not be confused with a leftover capture object. 22670 saved = slice.call( arguments ); 22671 dataPriv.set( this, type, saved ); 22672 22673 // Trigger the native event and capture its result 22674 // Support: IE <=9 - 11+ 22675 // focus() and blur() are asynchronous 22676 notAsync = expectSync( this, type ); 22677 this[ type ](); 22678 result = dataPriv.get( this, type ); 22679 if ( saved !== result || notAsync ) { 22680 dataPriv.set( this, type, false ); 22681 } else { 22682 result = {}; 22683 } 22684 if ( saved !== result ) { 22685 22686 // Cancel the outer synthetic event 22687 event.stopImmediatePropagation(); 22688 event.preventDefault(); 22689 22690 // Support: Chrome 86+ 22691 // In Chrome, if an element having a focusout handler is blurred by 22692 // clicking outside of it, it invokes the handler synchronously. If 22693 // that handler calls `.remove()` on the element, the data is cleared, 22694 // leaving `result` undefined. We need to guard against this. 22695 return result && result.value; 22696 } 22697 22698 // If this is an inner synthetic event for an event with a bubbling surrogate 22699 // (focus or blur), assume that the surrogate already propagated from triggering the 22700 // native event and prevent that from happening again here. 22701 // This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the 22702 // bubbling surrogate propagates *after* the non-bubbling base), but that seems 22703 // less bad than duplication. 22704 } else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) { 22705 event.stopPropagation(); 22706 } 22707 22708 // If this is a native event triggered above, everything is now in order 22709 // Fire an inner synthetic event with the original arguments 22710 } else if ( saved.length ) { 22711 22712 // ...and capture the result 22713 dataPriv.set( this, type, { 22714 value: jQuery.event.trigger( 22715 22716 // Support: IE <=9 - 11+ 22717 // Extend with the prototype to reset the above stopImmediatePropagation() 22718 jQuery.extend( saved[ 0 ], jQuery.Event.prototype ), 22719 saved.slice( 1 ), 22720 this 22721 ) 22722 } ); 22723 22724 // Abort handling of the native event 22725 event.stopImmediatePropagation(); 22726 } 22727 } 22728 } ); 22729} 22730 22731jQuery.removeEvent = function( elem, type, handle ) { 22732 22733 // This "if" is needed for plain objects 22734 if ( elem.removeEventListener ) { 22735 elem.removeEventListener( type, handle ); 22736 } 22737}; 22738 22739jQuery.Event = function( src, props ) { 22740 22741 // Allow instantiation without the 'new' keyword 22742 if ( !( this instanceof jQuery.Event ) ) { 22743 return new jQuery.Event( src, props ); 22744 } 22745 22746 // Event object 22747 if ( src && src.type ) { 22748 this.originalEvent = src; 22749 this.type = src.type; 22750 22751 // Events bubbling up the document may have been marked as prevented 22752 // by a handler lower down the tree; reflect the correct value. 22753 this.isDefaultPrevented = src.defaultPrevented || 22754 src.defaultPrevented === undefined && 22755 22756 // Support: Android <=2.3 only 22757 src.returnValue === false ? 22758 returnTrue : 22759 returnFalse; 22760 22761 // Create target properties 22762 // Support: Safari <=6 - 7 only 22763 // Target should not be a text node (#504, #13143) 22764 this.target = ( src.target && src.target.nodeType === 3 ) ? 22765 src.target.parentNode : 22766 src.target; 22767 22768 this.currentTarget = src.currentTarget; 22769 this.relatedTarget = src.relatedTarget; 22770 22771 // Event type 22772 } else { 22773 this.type = src; 22774 } 22775 22776 // Put explicitly provided properties onto the event object 22777 if ( props ) { 22778 jQuery.extend( this, props ); 22779 } 22780 22781 // Create a timestamp if incoming event doesn't have one 22782 this.timeStamp = src && src.timeStamp || Date.now(); 22783 22784 // Mark it as fixed 22785 this[ jQuery.expando ] = true; 22786}; 22787 22788// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding 22789// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html 22790jQuery.Event.prototype = { 22791 constructor: jQuery.Event, 22792 isDefaultPrevented: returnFalse, 22793 isPropagationStopped: returnFalse, 22794 isImmediatePropagationStopped: returnFalse, 22795 isSimulated: false, 22796 22797 preventDefault: function() { 22798 var e = this.originalEvent; 22799 22800 this.isDefaultPrevented = returnTrue; 22801 22802 if ( e && !this.isSimulated ) { 22803 e.preventDefault(); 22804 } 22805 }, 22806 stopPropagation: function() { 22807 var e = this.originalEvent; 22808 22809 this.isPropagationStopped = returnTrue; 22810 22811 if ( e && !this.isSimulated ) { 22812 e.stopPropagation(); 22813 } 22814 }, 22815 stopImmediatePropagation: function() { 22816 var e = this.originalEvent; 22817 22818 this.isImmediatePropagationStopped = returnTrue; 22819 22820 if ( e && !this.isSimulated ) { 22821 e.stopImmediatePropagation(); 22822 } 22823 22824 this.stopPropagation(); 22825 } 22826}; 22827 22828// Includes all common event props including KeyEvent and MouseEvent specific props 22829jQuery.each( { 22830 altKey: true, 22831 bubbles: true, 22832 cancelable: true, 22833 changedTouches: true, 22834 ctrlKey: true, 22835 detail: true, 22836 eventPhase: true, 22837 metaKey: true, 22838 pageX: true, 22839 pageY: true, 22840 shiftKey: true, 22841 view: true, 22842 "char": true, 22843 code: true, 22844 charCode: true, 22845 key: true, 22846 keyCode: true, 22847 button: true, 22848 buttons: true, 22849 clientX: true, 22850 clientY: true, 22851 offsetX: true, 22852 offsetY: true, 22853 pointerId: true, 22854 pointerType: true, 22855 screenX: true, 22856 screenY: true, 22857 targetTouches: true, 22858 toElement: true, 22859 touches: true, 22860 which: true 22861}, jQuery.event.addProp ); 22862 22863jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) { 22864 jQuery.event.special[ type ] = { 22865 22866 // Utilize native event if possible so blur/focus sequence is correct 22867 setup: function() { 22868 22869 // Claim the first handler 22870 // dataPriv.set( this, "focus", ... ) 22871 // dataPriv.set( this, "blur", ... ) 22872 leverageNative( this, type, expectSync ); 22873 22874 // Return false to allow normal processing in the caller 22875 return false; 22876 }, 22877 trigger: function() { 22878 22879 // Force setup before trigger 22880 leverageNative( this, type ); 22881 22882 // Return non-false to allow normal event-path propagation 22883 return true; 22884 }, 22885 22886 // Suppress native focus or blur as it's already being fired 22887 // in leverageNative. 22888 _default: function() { 22889 return true; 22890 }, 22891 22892 delegateType: delegateType 22893 }; 22894} ); 22895 22896// Create mouseenter/leave events using mouseover/out and event-time checks 22897// so that event delegation works in jQuery. 22898// Do the same for pointerenter/pointerleave and pointerover/pointerout 22899// 22900// Support: Safari 7 only 22901// Safari sends mouseenter too often; see: 22902// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 22903// for the description of the bug (it existed in older Chrome versions as well). 22904jQuery.each( { 22905 mouseenter: "mouseover", 22906 mouseleave: "mouseout", 22907 pointerenter: "pointerover", 22908 pointerleave: "pointerout" 22909}, function( orig, fix ) { 22910 jQuery.event.special[ orig ] = { 22911 delegateType: fix, 22912 bindType: fix, 22913 22914 handle: function( event ) { 22915 var ret, 22916 target = this, 22917 related = event.relatedTarget, 22918 handleObj = event.handleObj; 22919 22920 // For mouseenter/leave call the handler if related is outside the target. 22921 // NB: No relatedTarget if the mouse left/entered the browser window 22922 if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { 22923 event.type = handleObj.origType; 22924 ret = handleObj.handler.apply( this, arguments ); 22925 event.type = fix; 22926 } 22927 return ret; 22928 } 22929 }; 22930} ); 22931 22932jQuery.fn.extend( { 22933 22934 on: function( types, selector, data, fn ) { 22935 return on( this, types, selector, data, fn ); 22936 }, 22937 one: function( types, selector, data, fn ) { 22938 return on( this, types, selector, data, fn, 1 ); 22939 }, 22940 off: function( types, selector, fn ) { 22941 var handleObj, type; 22942 if ( types && types.preventDefault && types.handleObj ) { 22943 22944 // ( event ) dispatched jQuery.Event 22945 handleObj = types.handleObj; 22946 jQuery( types.delegateTarget ).off( 22947 handleObj.namespace ? 22948 handleObj.origType + "." + handleObj.namespace : 22949 handleObj.origType, 22950 handleObj.selector, 22951 handleObj.handler 22952 ); 22953 return this; 22954 } 22955 if ( typeof types === "object" ) { 22956 22957 // ( types-object [, selector] ) 22958 for ( type in types ) { 22959 this.off( type, selector, types[ type ] ); 22960 } 22961 return this; 22962 } 22963 if ( selector === false || typeof selector === "function" ) { 22964 22965 // ( types [, fn] ) 22966 fn = selector; 22967 selector = undefined; 22968 } 22969 if ( fn === false ) { 22970 fn = returnFalse; 22971 } 22972 return this.each( function() { 22973 jQuery.event.remove( this, types, fn, selector ); 22974 } ); 22975 } 22976} ); 22977 22978 22979var 22980 22981 // Support: IE <=10 - 11, Edge 12 - 13 only 22982 // In IE/Edge using regex groups here causes severe slowdowns. 22983 // See https://connect.microsoft.com/IE/feedback/details/1736512/ 22984 rnoInnerhtml = /<script|<style|<link/i, 22985 22986 // checked="checked" or checked 22987 rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, 22988 rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g; 22989 22990// Prefer a tbody over its parent table for containing new rows 22991function manipulationTarget( elem, content ) { 22992 if ( nodeName( elem, "table" ) && 22993 nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { 22994 22995 return jQuery( elem ).children( "tbody" )[ 0 ] || elem; 22996 } 22997 22998 return elem; 22999} 23000 23001// Replace/restore the type attribute of script elements for safe DOM manipulation 23002function disableScript( elem ) { 23003 elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; 23004 return elem; 23005} 23006function restoreScript( elem ) { 23007 if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) { 23008 elem.type = elem.type.slice( 5 ); 23009 } else { 23010 elem.removeAttribute( "type" ); 23011 } 23012 23013 return elem; 23014} 23015 23016function cloneCopyEvent( src, dest ) { 23017 var i, l, type, pdataOld, udataOld, udataCur, events; 23018 23019 if ( dest.nodeType !== 1 ) { 23020 return; 23021 } 23022 23023 // 1. Copy private data: events, handlers, etc. 23024 if ( dataPriv.hasData( src ) ) { 23025 pdataOld = dataPriv.get( src ); 23026 events = pdataOld.events; 23027 23028 if ( events ) { 23029 dataPriv.remove( dest, "handle events" ); 23030 23031 for ( type in events ) { 23032 for ( i = 0, l = events[ type ].length; i < l; i++ ) { 23033 jQuery.event.add( dest, type, events[ type ][ i ] ); 23034 } 23035 } 23036 } 23037 } 23038 23039 // 2. Copy user data 23040 if ( dataUser.hasData( src ) ) { 23041 udataOld = dataUser.access( src ); 23042 udataCur = jQuery.extend( {}, udataOld ); 23043 23044 dataUser.set( dest, udataCur ); 23045 } 23046} 23047 23048// Fix IE bugs, see support tests 23049function fixInput( src, dest ) { 23050 var nodeName = dest.nodeName.toLowerCase(); 23051 23052 // Fails to persist the checked state of a cloned checkbox or radio button. 23053 if ( nodeName === "input" && rcheckableType.test( src.type ) ) { 23054 dest.checked = src.checked; 23055 23056 // Fails to return the selected option to the default selected state when cloning options 23057 } else if ( nodeName === "input" || nodeName === "textarea" ) { 23058 dest.defaultValue = src.defaultValue; 23059 } 23060} 23061 23062function domManip( collection, args, callback, ignored ) { 23063 23064 // Flatten any nested arrays 23065 args = flat( args ); 23066 23067 var fragment, first, scripts, hasScripts, node, doc, 23068 i = 0, 23069 l = collection.length, 23070 iNoClone = l - 1, 23071 value = args[ 0 ], 23072 valueIsFunction = isFunction( value ); 23073 23074 // We can't cloneNode fragments that contain checked, in WebKit 23075 if ( valueIsFunction || 23076 ( l > 1 && typeof value === "string" && 23077 !support.checkClone && rchecked.test( value ) ) ) { 23078 return collection.each( function( index ) { 23079 var self = collection.eq( index ); 23080 if ( valueIsFunction ) { 23081 args[ 0 ] = value.call( this, index, self.html() ); 23082 } 23083 domManip( self, args, callback, ignored ); 23084 } ); 23085 } 23086 23087 if ( l ) { 23088 fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); 23089 first = fragment.firstChild; 23090 23091 if ( fragment.childNodes.length === 1 ) { 23092 fragment = first; 23093 } 23094 23095 // Require either new content or an interest in ignored elements to invoke the callback 23096 if ( first || ignored ) { 23097 scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); 23098 hasScripts = scripts.length; 23099 23100 // Use the original fragment for the last item 23101 // instead of the first because it can end up 23102 // being emptied incorrectly in certain situations (#8070). 23103 for ( ; i < l; i++ ) { 23104 node = fragment; 23105 23106 if ( i !== iNoClone ) { 23107 node = jQuery.clone( node, true, true ); 23108 23109 // Keep references to cloned scripts for later restoration 23110 if ( hasScripts ) { 23111 23112 // Support: Android <=4.0 only, PhantomJS 1 only 23113 // push.apply(_, arraylike) throws on ancient WebKit 23114 jQuery.merge( scripts, getAll( node, "script" ) ); 23115 } 23116 } 23117 23118 callback.call( collection[ i ], node, i ); 23119 } 23120 23121 if ( hasScripts ) { 23122 doc = scripts[ scripts.length - 1 ].ownerDocument; 23123 23124 // Reenable scripts 23125 jQuery.map( scripts, restoreScript ); 23126 23127 // Evaluate executable scripts on first document insertion 23128 for ( i = 0; i < hasScripts; i++ ) { 23129 node = scripts[ i ]; 23130 if ( rscriptType.test( node.type || "" ) && 23131 !dataPriv.access( node, "globalEval" ) && 23132 jQuery.contains( doc, node ) ) { 23133 23134 if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) { 23135 23136 // Optional AJAX dependency, but won't run scripts if not present 23137 if ( jQuery._evalUrl && !node.noModule ) { 23138 jQuery._evalUrl( node.src, { 23139 nonce: node.nonce || node.getAttribute( "nonce" ) 23140 }, doc ); 23141 } 23142 } else { 23143 DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc ); 23144 } 23145 } 23146 } 23147 } 23148 } 23149 } 23150 23151 return collection; 23152} 23153 23154function remove( elem, selector, keepData ) { 23155 var node, 23156 nodes = selector ? jQuery.filter( selector, elem ) : elem, 23157 i = 0; 23158 23159 for ( ; ( node = nodes[ i ] ) != null; i++ ) { 23160 if ( !keepData && node.nodeType === 1 ) { 23161 jQuery.cleanData( getAll( node ) ); 23162 } 23163 23164 if ( node.parentNode ) { 23165 if ( keepData && isAttached( node ) ) { 23166 setGlobalEval( getAll( node, "script" ) ); 23167 } 23168 node.parentNode.removeChild( node ); 23169 } 23170 } 23171 23172 return elem; 23173} 23174 23175jQuery.extend( { 23176 htmlPrefilter: function( html ) { 23177 return html; 23178 }, 23179 23180 clone: function( elem, dataAndEvents, deepDataAndEvents ) { 23181 var i, l, srcElements, destElements, 23182 clone = elem.cloneNode( true ), 23183 inPage = isAttached( elem ); 23184 23185 // Fix IE cloning issues 23186 if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && 23187 !jQuery.isXMLDoc( elem ) ) { 23188 23189 // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 23190 destElements = getAll( clone ); 23191 srcElements = getAll( elem ); 23192 23193 for ( i = 0, l = srcElements.length; i < l; i++ ) { 23194 fixInput( srcElements[ i ], destElements[ i ] ); 23195 } 23196 } 23197 23198 // Copy the events from the original to the clone 23199 if ( dataAndEvents ) { 23200 if ( deepDataAndEvents ) { 23201 srcElements = srcElements || getAll( elem ); 23202 destElements = destElements || getAll( clone ); 23203 23204 for ( i = 0, l = srcElements.length; i < l; i++ ) { 23205 cloneCopyEvent( srcElements[ i ], destElements[ i ] ); 23206 } 23207 } else { 23208 cloneCopyEvent( elem, clone ); 23209 } 23210 } 23211 23212 // Preserve script evaluation history 23213 destElements = getAll( clone, "script" ); 23214 if ( destElements.length > 0 ) { 23215 setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); 23216 } 23217 23218 // Return the cloned set 23219 return clone; 23220 }, 23221 23222 cleanData: function( elems ) { 23223 var data, elem, type, 23224 special = jQuery.event.special, 23225 i = 0; 23226 23227 for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { 23228 if ( acceptData( elem ) ) { 23229 if ( ( data = elem[ dataPriv.expando ] ) ) { 23230 if ( data.events ) { 23231 for ( type in data.events ) { 23232 if ( special[ type ] ) { 23233 jQuery.event.remove( elem, type ); 23234 23235 // This is a shortcut to avoid jQuery.event.remove's overhead 23236 } else { 23237 jQuery.removeEvent( elem, type, data.handle ); 23238 } 23239 } 23240 } 23241 23242 // Support: Chrome <=35 - 45+ 23243 // Assign undefined instead of using delete, see Data#remove 23244 elem[ dataPriv.expando ] = undefined; 23245 } 23246 if ( elem[ dataUser.expando ] ) { 23247 23248 // Support: Chrome <=35 - 45+ 23249 // Assign undefined instead of using delete, see Data#remove 23250 elem[ dataUser.expando ] = undefined; 23251 } 23252 } 23253 } 23254 } 23255} ); 23256 23257jQuery.fn.extend( { 23258 detach: function( selector ) { 23259 return remove( this, selector, true ); 23260 }, 23261 23262 remove: function( selector ) { 23263 return remove( this, selector ); 23264 }, 23265 23266 text: function( value ) { 23267 return access( this, function( value ) { 23268 return value === undefined ? 23269 jQuery.text( this ) : 23270 this.empty().each( function() { 23271 if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { 23272 this.textContent = value; 23273 } 23274 } ); 23275 }, null, value, arguments.length ); 23276 }, 23277 23278 append: function() { 23279 return domManip( this, arguments, function( elem ) { 23280 if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { 23281 var target = manipulationTarget( this, elem ); 23282 target.appendChild( elem ); 23283 } 23284 } ); 23285 }, 23286 23287 prepend: function() { 23288 return domManip( this, arguments, function( elem ) { 23289 if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { 23290 var target = manipulationTarget( this, elem ); 23291 target.insertBefore( elem, target.firstChild ); 23292 } 23293 } ); 23294 }, 23295 23296 before: function() { 23297 return domManip( this, arguments, function( elem ) { 23298 if ( this.parentNode ) { 23299 this.parentNode.insertBefore( elem, this ); 23300 } 23301 } ); 23302 }, 23303 23304 after: function() { 23305 return domManip( this, arguments, function( elem ) { 23306 if ( this.parentNode ) { 23307 this.parentNode.insertBefore( elem, this.nextSibling ); 23308 } 23309 } ); 23310 }, 23311 23312 empty: function() { 23313 var elem, 23314 i = 0; 23315 23316 for ( ; ( elem = this[ i ] ) != null; i++ ) { 23317 if ( elem.nodeType === 1 ) { 23318 23319 // Prevent memory leaks 23320 jQuery.cleanData( getAll( elem, false ) ); 23321 23322 // Remove any remaining nodes 23323 elem.textContent = ""; 23324 } 23325 } 23326 23327 return this; 23328 }, 23329 23330 clone: function( dataAndEvents, deepDataAndEvents ) { 23331 dataAndEvents = dataAndEvents == null ? false : dataAndEvents; 23332 deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; 23333 23334 return this.map( function() { 23335 return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); 23336 } ); 23337 }, 23338 23339 html: function( value ) { 23340 return access( this, function( value ) { 23341 var elem = this[ 0 ] || {}, 23342 i = 0, 23343 l = this.length; 23344 23345 if ( value === undefined && elem.nodeType === 1 ) { 23346 return elem.innerHTML; 23347 } 23348 23349 // See if we can take a shortcut and just use innerHTML 23350 if ( typeof value === "string" && !rnoInnerhtml.test( value ) && 23351 !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { 23352 23353 value = jQuery.htmlPrefilter( value ); 23354 23355 try { 23356 for ( ; i < l; i++ ) { 23357 elem = this[ i ] || {}; 23358 23359 // Remove element nodes and prevent memory leaks 23360 if ( elem.nodeType === 1 ) { 23361 jQuery.cleanData( getAll( elem, false ) ); 23362 elem.innerHTML = value; 23363 } 23364 } 23365 23366 elem = 0; 23367 23368 // If using innerHTML throws an exception, use the fallback method 23369 } catch ( e ) {} 23370 } 23371 23372 if ( elem ) { 23373 this.empty().append( value ); 23374 } 23375 }, null, value, arguments.length ); 23376 }, 23377 23378 replaceWith: function() { 23379 var ignored = []; 23380 23381 // Make the changes, replacing each non-ignored context element with the new content 23382 return domManip( this, arguments, function( elem ) { 23383 var parent = this.parentNode; 23384 23385 if ( jQuery.inArray( this, ignored ) < 0 ) { 23386 jQuery.cleanData( getAll( this ) ); 23387 if ( parent ) { 23388 parent.replaceChild( elem, this ); 23389 } 23390 } 23391 23392 // Force callback invocation 23393 }, ignored ); 23394 } 23395} ); 23396 23397jQuery.each( { 23398 appendTo: "append", 23399 prependTo: "prepend", 23400 insertBefore: "before", 23401 insertAfter: "after", 23402 replaceAll: "replaceWith" 23403}, function( name, original ) { 23404 jQuery.fn[ name ] = function( selector ) { 23405 var elems, 23406 ret = [], 23407 insert = jQuery( selector ), 23408 last = insert.length - 1, 23409 i = 0; 23410 23411 for ( ; i <= last; i++ ) { 23412 elems = i === last ? this : this.clone( true ); 23413 jQuery( insert[ i ] )[ original ]( elems ); 23414 23415 // Support: Android <=4.0 only, PhantomJS 1 only 23416 // .get() because push.apply(_, arraylike) throws on ancient WebKit 23417 push.apply( ret, elems.get() ); 23418 } 23419 23420 return this.pushStack( ret ); 23421 }; 23422} ); 23423var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); 23424 23425var getStyles = function( elem ) { 23426 23427 // Support: IE <=11 only, Firefox <=30 (#15098, #14150) 23428 // IE throws on elements created in popups 23429 // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" 23430 var view = elem.ownerDocument.defaultView; 23431 23432 if ( !view || !view.opener ) { 23433 view = window; 23434 } 23435 23436 return view.getComputedStyle( elem ); 23437 }; 23438 23439var swap = function( elem, options, callback ) { 23440 var ret, name, 23441 old = {}; 23442 23443 // Remember the old values, and insert the new ones 23444 for ( name in options ) { 23445 old[ name ] = elem.style[ name ]; 23446 elem.style[ name ] = options[ name ]; 23447 } 23448 23449 ret = callback.call( elem ); 23450 23451 // Revert the old values 23452 for ( name in options ) { 23453 elem.style[ name ] = old[ name ]; 23454 } 23455 23456 return ret; 23457}; 23458 23459 23460var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); 23461 23462 23463 23464( function() { 23465 23466 // Executing both pixelPosition & boxSizingReliable tests require only one layout 23467 // so they're executed at the same time to save the second computation. 23468 function computeStyleTests() { 23469 23470 // This is a singleton, we need to execute it only once 23471 if ( !div ) { 23472 return; 23473 } 23474 23475 container.style.cssText = "position:absolute;left:-11111px;width:60px;" + 23476 "margin-top:1px;padding:0;border:0"; 23477 div.style.cssText = 23478 "position:relative;display:block;box-sizing:border-box;overflow:scroll;" + 23479 "margin:auto;border:1px;padding:1px;" + 23480 "width:60%;top:1%"; 23481 documentElement.appendChild( container ).appendChild( div ); 23482 23483 var divStyle = window.getComputedStyle( div ); 23484 pixelPositionVal = divStyle.top !== "1%"; 23485 23486 // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 23487 reliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12; 23488 23489 // Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3 23490 // Some styles come back with percentage values, even though they shouldn't 23491 div.style.right = "60%"; 23492 pixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36; 23493 23494 // Support: IE 9 - 11 only 23495 // Detect misreporting of content dimensions for box-sizing:border-box elements 23496 boxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36; 23497 23498 // Support: IE 9 only 23499 // Detect overflow:scroll screwiness (gh-3699) 23500 // Support: Chrome <=64 23501 // Don't get tricked when zoom affects offsetWidth (gh-4029) 23502 div.style.position = "absolute"; 23503 scrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12; 23504 23505 documentElement.removeChild( container ); 23506 23507 // Nullify the div so it wouldn't be stored in the memory and 23508 // it will also be a sign that checks already performed 23509 div = null; 23510 } 23511 23512 function roundPixelMeasures( measure ) { 23513 return Math.round( parseFloat( measure ) ); 23514 } 23515 23516 var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal, 23517 reliableTrDimensionsVal, reliableMarginLeftVal, 23518 container = document.createElement( "div" ), 23519 div = document.createElement( "div" ); 23520 23521 // Finish early in limited (non-browser) environments 23522 if ( !div.style ) { 23523 return; 23524 } 23525 23526 // Support: IE <=9 - 11 only 23527 // Style of cloned element affects source element cloned (#8908) 23528 div.style.backgroundClip = "content-box"; 23529 div.cloneNode( true ).style.backgroundClip = ""; 23530 support.clearCloneStyle = div.style.backgroundClip === "content-box"; 23531 23532 jQuery.extend( support, { 23533 boxSizingReliable: function() { 23534 computeStyleTests(); 23535 return boxSizingReliableVal; 23536 }, 23537 pixelBoxStyles: function() { 23538 computeStyleTests(); 23539 return pixelBoxStylesVal; 23540 }, 23541 pixelPosition: function() { 23542 computeStyleTests(); 23543 return pixelPositionVal; 23544 }, 23545 reliableMarginLeft: function() { 23546 computeStyleTests(); 23547 return reliableMarginLeftVal; 23548 }, 23549 scrollboxSize: function() { 23550 computeStyleTests(); 23551 return scrollboxSizeVal; 23552 }, 23553 23554 // Support: IE 9 - 11+, Edge 15 - 18+ 23555 // IE/Edge misreport `getComputedStyle` of table rows with width/height 23556 // set in CSS while `offset*` properties report correct values. 23557 // Behavior in IE 9 is more subtle than in newer versions & it passes 23558 // some versions of this test; make sure not to make it pass there! 23559 // 23560 // Support: Firefox 70+ 23561 // Only Firefox includes border widths 23562 // in computed dimensions. (gh-4529) 23563 reliableTrDimensions: function() { 23564 var table, tr, trChild, trStyle; 23565 if ( reliableTrDimensionsVal == null ) { 23566 table = document.createElement( "table" ); 23567 tr = document.createElement( "tr" ); 23568 trChild = document.createElement( "div" ); 23569 23570 table.style.cssText = "position:absolute;left:-11111px;border-collapse:separate"; 23571 tr.style.cssText = "border:1px solid"; 23572 23573 // Support: Chrome 86+ 23574 // Height set through cssText does not get applied. 23575 // Computed height then comes back as 0. 23576 tr.style.height = "1px"; 23577 trChild.style.height = "9px"; 23578 23579 // Support: Android 8 Chrome 86+ 23580 // In our bodyBackground.html iframe, 23581 // display for all div elements is set to "inline", 23582 // which causes a problem only in Android 8 Chrome 86. 23583 // Ensuring the div is display: block 23584 // gets around this issue. 23585 trChild.style.display = "block"; 23586 23587 documentElement 23588 .appendChild( table ) 23589 .appendChild( tr ) 23590 .appendChild( trChild ); 23591 23592 trStyle = window.getComputedStyle( tr ); 23593 reliableTrDimensionsVal = ( parseInt( trStyle.height, 10 ) + 23594 parseInt( trStyle.borderTopWidth, 10 ) + 23595 parseInt( trStyle.borderBottomWidth, 10 ) ) === tr.offsetHeight; 23596 23597 documentElement.removeChild( table ); 23598 } 23599 return reliableTrDimensionsVal; 23600 } 23601 } ); 23602} )(); 23603 23604 23605function curCSS( elem, name, computed ) { 23606 var width, minWidth, maxWidth, ret, 23607 23608 // Support: Firefox 51+ 23609 // Retrieving style before computed somehow 23610 // fixes an issue with getting wrong values 23611 // on detached elements 23612 style = elem.style; 23613 23614 computed = computed || getStyles( elem ); 23615 23616 // getPropertyValue is needed for: 23617 // .css('filter') (IE 9 only, #12537) 23618 // .css('--customProperty) (#3144) 23619 if ( computed ) { 23620 ret = computed.getPropertyValue( name ) || computed[ name ]; 23621 23622 if ( ret === "" && !isAttached( elem ) ) { 23623 ret = jQuery.style( elem, name ); 23624 } 23625 23626 // A tribute to the "awesome hack by Dean Edwards" 23627 // Android Browser returns percentage for some values, 23628 // but width seems to be reliably pixels. 23629 // This is against the CSSOM draft spec: 23630 // https://drafts.csswg.org/cssom/#resolved-values 23631 if ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) { 23632 23633 // Remember the original values 23634 width = style.width; 23635 minWidth = style.minWidth; 23636 maxWidth = style.maxWidth; 23637 23638 // Put in the new values to get a computed value out 23639 style.minWidth = style.maxWidth = style.width = ret; 23640 ret = computed.width; 23641 23642 // Revert the changed values 23643 style.width = width; 23644 style.minWidth = minWidth; 23645 style.maxWidth = maxWidth; 23646 } 23647 } 23648 23649 return ret !== undefined ? 23650 23651 // Support: IE <=9 - 11 only 23652 // IE returns zIndex value as an integer. 23653 ret + "" : 23654 ret; 23655} 23656 23657 23658function addGetHookIf( conditionFn, hookFn ) { 23659 23660 // Define the hook, we'll check on the first run if it's really needed. 23661 return { 23662 get: function() { 23663 if ( conditionFn() ) { 23664 23665 // Hook not needed (or it's not possible to use it due 23666 // to missing dependency), remove it. 23667 delete this.get; 23668 return; 23669 } 23670 23671 // Hook needed; redefine it so that the support test is not executed again. 23672 return ( this.get = hookFn ).apply( this, arguments ); 23673 } 23674 }; 23675} 23676 23677 23678var cssPrefixes = [ "Webkit", "Moz", "ms" ], 23679 emptyStyle = document.createElement( "div" ).style, 23680 vendorProps = {}; 23681 23682// Return a vendor-prefixed property or undefined 23683function vendorPropName( name ) { 23684 23685 // Check for vendor prefixed names 23686 var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), 23687 i = cssPrefixes.length; 23688 23689 while ( i-- ) { 23690 name = cssPrefixes[ i ] + capName; 23691 if ( name in emptyStyle ) { 23692 return name; 23693 } 23694 } 23695} 23696 23697// Return a potentially-mapped jQuery.cssProps or vendor prefixed property 23698function finalPropName( name ) { 23699 var final = jQuery.cssProps[ name ] || vendorProps[ name ]; 23700 23701 if ( final ) { 23702 return final; 23703 } 23704 if ( name in emptyStyle ) { 23705 return name; 23706 } 23707 return vendorProps[ name ] = vendorPropName( name ) || name; 23708} 23709 23710 23711var 23712 23713 // Swappable if display is none or starts with table 23714 // except "table", "table-cell", or "table-caption" 23715 // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display 23716 rdisplayswap = /^(none|table(?!-c[ea]).+)/, 23717 rcustomProp = /^--/, 23718 cssShow = { position: "absolute", visibility: "hidden", display: "block" }, 23719 cssNormalTransform = { 23720 letterSpacing: "0", 23721 fontWeight: "400" 23722 }; 23723 23724function setPositiveNumber( _elem, value, subtract ) { 23725 23726 // Any relative (+/-) values have already been 23727 // normalized at this point 23728 var matches = rcssNum.exec( value ); 23729 return matches ? 23730 23731 // Guard against undefined "subtract", e.g., when used as in cssHooks 23732 Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : 23733 value; 23734} 23735 23736function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) { 23737 var i = dimension === "width" ? 1 : 0, 23738 extra = 0, 23739 delta = 0; 23740 23741 // Adjustment may not be necessary 23742 if ( box === ( isBorderBox ? "border" : "content" ) ) { 23743 return 0; 23744 } 23745 23746 for ( ; i < 4; i += 2 ) { 23747 23748 // Both box models exclude margin 23749 if ( box === "margin" ) { 23750 delta += jQuery.css( elem, box + cssExpand[ i ], true, styles ); 23751 } 23752 23753 // If we get here with a content-box, we're seeking "padding" or "border" or "margin" 23754 if ( !isBorderBox ) { 23755 23756 // Add padding 23757 delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); 23758 23759 // For "border" or "margin", add border 23760 if ( box !== "padding" ) { 23761 delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); 23762 23763 // But still keep track of it otherwise 23764 } else { 23765 extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); 23766 } 23767 23768 // If we get here with a border-box (content + padding + border), we're seeking "content" or 23769 // "padding" or "margin" 23770 } else { 23771 23772 // For "content", subtract padding 23773 if ( box === "content" ) { 23774 delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); 23775 } 23776 23777 // For "content" or "padding", subtract border 23778 if ( box !== "margin" ) { 23779 delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); 23780 } 23781 } 23782 } 23783 23784 // Account for positive content-box scroll gutter when requested by providing computedVal 23785 if ( !isBorderBox && computedVal >= 0 ) { 23786 23787 // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border 23788 // Assuming integer scroll gutter, subtract the rest and round down 23789 delta += Math.max( 0, Math.ceil( 23790 elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - 23791 computedVal - 23792 delta - 23793 extra - 23794 0.5 23795 23796 // If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter 23797 // Use an explicit zero to avoid NaN (gh-3964) 23798 ) ) || 0; 23799 } 23800 23801 return delta; 23802} 23803 23804function getWidthOrHeight( elem, dimension, extra ) { 23805 23806 // Start with computed style 23807 var styles = getStyles( elem ), 23808 23809 // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322). 23810 // Fake content-box until we know it's needed to know the true value. 23811 boxSizingNeeded = !support.boxSizingReliable() || extra, 23812 isBorderBox = boxSizingNeeded && 23813 jQuery.css( elem, "boxSizing", false, styles ) === "border-box", 23814 valueIsBorderBox = isBorderBox, 23815 23816 val = curCSS( elem, dimension, styles ), 23817 offsetProp = "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ); 23818 23819 // Support: Firefox <=54 23820 // Return a confounding non-pixel value or feign ignorance, as appropriate. 23821 if ( rnumnonpx.test( val ) ) { 23822 if ( !extra ) { 23823 return val; 23824 } 23825 val = "auto"; 23826 } 23827 23828 23829 // Support: IE 9 - 11 only 23830 // Use offsetWidth/offsetHeight for when box sizing is unreliable. 23831 // In those cases, the computed value can be trusted to be border-box. 23832 if ( ( !support.boxSizingReliable() && isBorderBox || 23833 23834 // Support: IE 10 - 11+, Edge 15 - 18+ 23835 // IE/Edge misreport `getComputedStyle` of table rows with width/height 23836 // set in CSS while `offset*` properties report correct values. 23837 // Interestingly, in some cases IE 9 doesn't suffer from this issue. 23838 !support.reliableTrDimensions() && nodeName( elem, "tr" ) || 23839 23840 // Fall back to offsetWidth/offsetHeight when value is "auto" 23841 // This happens for inline elements with no explicit setting (gh-3571) 23842 val === "auto" || 23843 23844 // Support: Android <=4.1 - 4.3 only 23845 // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602) 23846 !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) && 23847 23848 // Make sure the element is visible & connected 23849 elem.getClientRects().length ) { 23850 23851 isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; 23852 23853 // Where available, offsetWidth/offsetHeight approximate border box dimensions. 23854 // Where not available (e.g., SVG), assume unreliable box-sizing and interpret the 23855 // retrieved value as a content box dimension. 23856 valueIsBorderBox = offsetProp in elem; 23857 if ( valueIsBorderBox ) { 23858 val = elem[ offsetProp ]; 23859 } 23860 } 23861 23862 // Normalize "" and auto 23863 val = parseFloat( val ) || 0; 23864 23865 // Adjust for the element's box model 23866 return ( val + 23867 boxModelAdjustment( 23868 elem, 23869 dimension, 23870 extra || ( isBorderBox ? "border" : "content" ), 23871 valueIsBorderBox, 23872 styles, 23873 23874 // Provide the current computed size to request scroll gutter calculation (gh-3589) 23875 val 23876 ) 23877 ) + "px"; 23878} 23879 23880jQuery.extend( { 23881 23882 // Add in style property hooks for overriding the default 23883 // behavior of getting and setting a style property 23884 cssHooks: { 23885 opacity: { 23886 get: function( elem, computed ) { 23887 if ( computed ) { 23888 23889 // We should always get a number back from opacity 23890 var ret = curCSS( elem, "opacity" ); 23891 return ret === "" ? "1" : ret; 23892 } 23893 } 23894 } 23895 }, 23896 23897 // Don't automatically add "px" to these possibly-unitless properties 23898 cssNumber: { 23899 "animationIterationCount": true, 23900 "columnCount": true, 23901 "fillOpacity": true, 23902 "flexGrow": true, 23903 "flexShrink": true, 23904 "fontWeight": true, 23905 "gridArea": true, 23906 "gridColumn": true, 23907 "gridColumnEnd": true, 23908 "gridColumnStart": true, 23909 "gridRow": true, 23910 "gridRowEnd": true, 23911 "gridRowStart": true, 23912 "lineHeight": true, 23913 "opacity": true, 23914 "order": true, 23915 "orphans": true, 23916 "widows": true, 23917 "zIndex": true, 23918 "zoom": true 23919 }, 23920 23921 // Add in properties whose names you wish to fix before 23922 // setting or getting the value 23923 cssProps: {}, 23924 23925 // Get and set the style property on a DOM Node 23926 style: function( elem, name, value, extra ) { 23927 23928 // Don't set styles on text and comment nodes 23929 if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { 23930 return; 23931 } 23932 23933 // Make sure that we're working with the right name 23934 var ret, type, hooks, 23935 origName = camelCase( name ), 23936 isCustomProp = rcustomProp.test( name ), 23937 style = elem.style; 23938 23939 // Make sure that we're working with the right name. We don't 23940 // want to query the value if it is a CSS custom property 23941 // since they are user-defined. 23942 if ( !isCustomProp ) { 23943 name = finalPropName( origName ); 23944 } 23945 23946 // Gets hook for the prefixed version, then unprefixed version 23947 hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; 23948 23949 // Check if we're setting a value 23950 if ( value !== undefined ) { 23951 type = typeof value; 23952 23953 // Convert "+=" or "-=" to relative numbers (#7345) 23954 if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { 23955 value = adjustCSS( elem, name, ret ); 23956 23957 // Fixes bug #9237 23958 type = "number"; 23959 } 23960 23961 // Make sure that null and NaN values aren't set (#7116) 23962 if ( value == null || value !== value ) { 23963 return; 23964 } 23965 23966 // If a number was passed in, add the unit (except for certain CSS properties) 23967 // The isCustomProp check can be removed in jQuery 4.0 when we only auto-append 23968 // "px" to a few hardcoded values. 23969 if ( type === "number" && !isCustomProp ) { 23970 value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); 23971 } 23972 23973 // background-* props affect original clone's values 23974 if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { 23975 style[ name ] = "inherit"; 23976 } 23977 23978 // If a hook was provided, use that value, otherwise just set the specified value 23979 if ( !hooks || !( "set" in hooks ) || 23980 ( value = hooks.set( elem, value, extra ) ) !== undefined ) { 23981 23982 if ( isCustomProp ) { 23983 style.setProperty( name, value ); 23984 } else { 23985 style[ name ] = value; 23986 } 23987 } 23988 23989 } else { 23990 23991 // If a hook was provided get the non-computed value from there 23992 if ( hooks && "get" in hooks && 23993 ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { 23994 23995 return ret; 23996 } 23997 23998 // Otherwise just get the value from the style object 23999 return style[ name ]; 24000 } 24001 }, 24002 24003 css: function( elem, name, extra, styles ) { 24004 var val, num, hooks, 24005 origName = camelCase( name ), 24006 isCustomProp = rcustomProp.test( name ); 24007 24008 // Make sure that we're working with the right name. We don't 24009 // want to modify the value if it is a CSS custom property 24010 // since they are user-defined. 24011 if ( !isCustomProp ) { 24012 name = finalPropName( origName ); 24013 } 24014 24015 // Try prefixed name followed by the unprefixed name 24016 hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; 24017 24018 // If a hook was provided get the computed value from there 24019 if ( hooks && "get" in hooks ) { 24020 val = hooks.get( elem, true, extra ); 24021 } 24022 24023 // Otherwise, if a way to get the computed value exists, use that 24024 if ( val === undefined ) { 24025 val = curCSS( elem, name, styles ); 24026 } 24027 24028 // Convert "normal" to computed value 24029 if ( val === "normal" && name in cssNormalTransform ) { 24030 val = cssNormalTransform[ name ]; 24031 } 24032 24033 // Make numeric if forced or a qualifier was provided and val looks numeric 24034 if ( extra === "" || extra ) { 24035 num = parseFloat( val ); 24036 return extra === true || isFinite( num ) ? num || 0 : val; 24037 } 24038 24039 return val; 24040 } 24041} ); 24042 24043jQuery.each( [ "height", "width" ], function( _i, dimension ) { 24044 jQuery.cssHooks[ dimension ] = { 24045 get: function( elem, computed, extra ) { 24046 if ( computed ) { 24047 24048 // Certain elements can have dimension info if we invisibly show them 24049 // but it must have a current display style that would benefit 24050 return rdisplayswap.test( jQuery.css( elem, "display" ) ) && 24051 24052 // Support: Safari 8+ 24053 // Table columns in Safari have non-zero offsetWidth & zero 24054 // getBoundingClientRect().width unless display is changed. 24055 // Support: IE <=11 only 24056 // Running getBoundingClientRect on a disconnected node 24057 // in IE throws an error. 24058 ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? 24059 swap( elem, cssShow, function() { 24060 return getWidthOrHeight( elem, dimension, extra ); 24061 } ) : 24062 getWidthOrHeight( elem, dimension, extra ); 24063 } 24064 }, 24065 24066 set: function( elem, value, extra ) { 24067 var matches, 24068 styles = getStyles( elem ), 24069 24070 // Only read styles.position if the test has a chance to fail 24071 // to avoid forcing a reflow. 24072 scrollboxSizeBuggy = !support.scrollboxSize() && 24073 styles.position === "absolute", 24074 24075 // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991) 24076 boxSizingNeeded = scrollboxSizeBuggy || extra, 24077 isBorderBox = boxSizingNeeded && 24078 jQuery.css( elem, "boxSizing", false, styles ) === "border-box", 24079 subtract = extra ? 24080 boxModelAdjustment( 24081 elem, 24082 dimension, 24083 extra, 24084 isBorderBox, 24085 styles 24086 ) : 24087 0; 24088 24089 // Account for unreliable border-box dimensions by comparing offset* to computed and 24090 // faking a content-box to get border and padding (gh-3699) 24091 if ( isBorderBox && scrollboxSizeBuggy ) { 24092 subtract -= Math.ceil( 24093 elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - 24094 parseFloat( styles[ dimension ] ) - 24095 boxModelAdjustment( elem, dimension, "border", false, styles ) - 24096 0.5 24097 ); 24098 } 24099 24100 // Convert to pixels if value adjustment is needed 24101 if ( subtract && ( matches = rcssNum.exec( value ) ) && 24102 ( matches[ 3 ] || "px" ) !== "px" ) { 24103 24104 elem.style[ dimension ] = value; 24105 value = jQuery.css( elem, dimension ); 24106 } 24107 24108 return setPositiveNumber( elem, value, subtract ); 24109 } 24110 }; 24111} ); 24112 24113jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, 24114 function( elem, computed ) { 24115 if ( computed ) { 24116 return ( parseFloat( curCSS( elem, "marginLeft" ) ) || 24117 elem.getBoundingClientRect().left - 24118 swap( elem, { marginLeft: 0 }, function() { 24119 return elem.getBoundingClientRect().left; 24120 } ) 24121 ) + "px"; 24122 } 24123 } 24124); 24125 24126// These hooks are used by animate to expand properties 24127jQuery.each( { 24128 margin: "", 24129 padding: "", 24130 border: "Width" 24131}, function( prefix, suffix ) { 24132 jQuery.cssHooks[ prefix + suffix ] = { 24133 expand: function( value ) { 24134 var i = 0, 24135 expanded = {}, 24136 24137 // Assumes a single number if not a string 24138 parts = typeof value === "string" ? value.split( " " ) : [ value ]; 24139 24140 for ( ; i < 4; i++ ) { 24141 expanded[ prefix + cssExpand[ i ] + suffix ] = 24142 parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; 24143 } 24144 24145 return expanded; 24146 } 24147 }; 24148 24149 if ( prefix !== "margin" ) { 24150 jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; 24151 } 24152} ); 24153 24154jQuery.fn.extend( { 24155 css: function( name, value ) { 24156 return access( this, function( elem, name, value ) { 24157 var styles, len, 24158 map = {}, 24159 i = 0; 24160 24161 if ( Array.isArray( name ) ) { 24162 styles = getStyles( elem ); 24163 len = name.length; 24164 24165 for ( ; i < len; i++ ) { 24166 map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); 24167 } 24168 24169 return map; 24170 } 24171 24172 return value !== undefined ? 24173 jQuery.style( elem, name, value ) : 24174 jQuery.css( elem, name ); 24175 }, name, value, arguments.length > 1 ); 24176 } 24177} ); 24178 24179 24180function Tween( elem, options, prop, end, easing ) { 24181 return new Tween.prototype.init( elem, options, prop, end, easing ); 24182} 24183jQuery.Tween = Tween; 24184 24185Tween.prototype = { 24186 constructor: Tween, 24187 init: function( elem, options, prop, end, easing, unit ) { 24188 this.elem = elem; 24189 this.prop = prop; 24190 this.easing = easing || jQuery.easing._default; 24191 this.options = options; 24192 this.start = this.now = this.cur(); 24193 this.end = end; 24194 this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); 24195 }, 24196 cur: function() { 24197 var hooks = Tween.propHooks[ this.prop ]; 24198 24199 return hooks && hooks.get ? 24200 hooks.get( this ) : 24201 Tween.propHooks._default.get( this ); 24202 }, 24203 run: function( percent ) { 24204 var eased, 24205 hooks = Tween.propHooks[ this.prop ]; 24206 24207 if ( this.options.duration ) { 24208 this.pos = eased = jQuery.easing[ this.easing ]( 24209 percent, this.options.duration * percent, 0, 1, this.options.duration 24210 ); 24211 } else { 24212 this.pos = eased = percent; 24213 } 24214 this.now = ( this.end - this.start ) * eased + this.start; 24215 24216 if ( this.options.step ) { 24217 this.options.step.call( this.elem, this.now, this ); 24218 } 24219 24220 if ( hooks && hooks.set ) { 24221 hooks.set( this ); 24222 } else { 24223 Tween.propHooks._default.set( this ); 24224 } 24225 return this; 24226 } 24227}; 24228 24229Tween.prototype.init.prototype = Tween.prototype; 24230 24231Tween.propHooks = { 24232 _default: { 24233 get: function( tween ) { 24234 var result; 24235 24236 // Use a property on the element directly when it is not a DOM element, 24237 // or when there is no matching style property that exists. 24238 if ( tween.elem.nodeType !== 1 || 24239 tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { 24240 return tween.elem[ tween.prop ]; 24241 } 24242 24243 // Passing an empty string as a 3rd parameter to .css will automatically 24244 // attempt a parseFloat and fallback to a string if the parse fails. 24245 // Simple values such as "10px" are parsed to Float; 24246 // complex values such as "rotate(1rad)" are returned as-is. 24247 result = jQuery.css( tween.elem, tween.prop, "" ); 24248 24249 // Empty strings, null, undefined and "auto" are converted to 0. 24250 return !result || result === "auto" ? 0 : result; 24251 }, 24252 set: function( tween ) { 24253 24254 // Use step hook for back compat. 24255 // Use cssHook if its there. 24256 // Use .style if available and use plain properties where available. 24257 if ( jQuery.fx.step[ tween.prop ] ) { 24258 jQuery.fx.step[ tween.prop ]( tween ); 24259 } else if ( tween.elem.nodeType === 1 && ( 24260 jQuery.cssHooks[ tween.prop ] || 24261 tween.elem.style[ finalPropName( tween.prop ) ] != null ) ) { 24262 jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); 24263 } else { 24264 tween.elem[ tween.prop ] = tween.now; 24265 } 24266 } 24267 } 24268}; 24269 24270// Support: IE <=9 only 24271// Panic based approach to setting things on disconnected nodes 24272Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { 24273 set: function( tween ) { 24274 if ( tween.elem.nodeType && tween.elem.parentNode ) { 24275 tween.elem[ tween.prop ] = tween.now; 24276 } 24277 } 24278}; 24279 24280jQuery.easing = { 24281 linear: function( p ) { 24282 return p; 24283 }, 24284 swing: function( p ) { 24285 return 0.5 - Math.cos( p * Math.PI ) / 2; 24286 }, 24287 _default: "swing" 24288}; 24289 24290jQuery.fx = Tween.prototype.init; 24291 24292// Back compat <1.8 extension point 24293jQuery.fx.step = {}; 24294 24295 24296 24297 24298var 24299 fxNow, inProgress, 24300 rfxtypes = /^(?:toggle|show|hide)$/, 24301 rrun = /queueHooks$/; 24302 24303function schedule() { 24304 if ( inProgress ) { 24305 if ( document.hidden === false && window.requestAnimationFrame ) { 24306 window.requestAnimationFrame( schedule ); 24307 } else { 24308 window.setTimeout( schedule, jQuery.fx.interval ); 24309 } 24310 24311 jQuery.fx.tick(); 24312 } 24313} 24314 24315// Animations created synchronously will run synchronously 24316function createFxNow() { 24317 window.setTimeout( function() { 24318 fxNow = undefined; 24319 } ); 24320 return ( fxNow = Date.now() ); 24321} 24322 24323// Generate parameters to create a standard animation 24324function genFx( type, includeWidth ) { 24325 var which, 24326 i = 0, 24327 attrs = { height: type }; 24328 24329 // If we include width, step value is 1 to do all cssExpand values, 24330 // otherwise step value is 2 to skip over Left and Right 24331 includeWidth = includeWidth ? 1 : 0; 24332 for ( ; i < 4; i += 2 - includeWidth ) { 24333 which = cssExpand[ i ]; 24334 attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; 24335 } 24336 24337 if ( includeWidth ) { 24338 attrs.opacity = attrs.width = type; 24339 } 24340 24341 return attrs; 24342} 24343 24344function createTween( value, prop, animation ) { 24345 var tween, 24346 collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), 24347 index = 0, 24348 length = collection.length; 24349 for ( ; index < length; index++ ) { 24350 if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { 24351 24352 // We're done with this property 24353 return tween; 24354 } 24355 } 24356} 24357 24358function defaultPrefilter( elem, props, opts ) { 24359 var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, 24360 isBox = "width" in props || "height" in props, 24361 anim = this, 24362 orig = {}, 24363 style = elem.style, 24364 hidden = elem.nodeType && isHiddenWithinTree( elem ), 24365 dataShow = dataPriv.get( elem, "fxshow" ); 24366 24367 // Queue-skipping animations hijack the fx hooks 24368 if ( !opts.queue ) { 24369 hooks = jQuery._queueHooks( elem, "fx" ); 24370 if ( hooks.unqueued == null ) { 24371 hooks.unqueued = 0; 24372 oldfire = hooks.empty.fire; 24373 hooks.empty.fire = function() { 24374 if ( !hooks.unqueued ) { 24375 oldfire(); 24376 } 24377 }; 24378 } 24379 hooks.unqueued++; 24380 24381 anim.always( function() { 24382 24383 // Ensure the complete handler is called before this completes 24384 anim.always( function() { 24385 hooks.unqueued--; 24386 if ( !jQuery.queue( elem, "fx" ).length ) { 24387 hooks.empty.fire(); 24388 } 24389 } ); 24390 } ); 24391 } 24392 24393 // Detect show/hide animations 24394 for ( prop in props ) { 24395 value = props[ prop ]; 24396 if ( rfxtypes.test( value ) ) { 24397 delete props[ prop ]; 24398 toggle = toggle || value === "toggle"; 24399 if ( value === ( hidden ? "hide" : "show" ) ) { 24400 24401 // Pretend to be hidden if this is a "show" and 24402 // there is still data from a stopped show/hide 24403 if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { 24404 hidden = true; 24405 24406 // Ignore all other no-op show/hide data 24407 } else { 24408 continue; 24409 } 24410 } 24411 orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); 24412 } 24413 } 24414 24415 // Bail out if this is a no-op like .hide().hide() 24416 propTween = !jQuery.isEmptyObject( props ); 24417 if ( !propTween && jQuery.isEmptyObject( orig ) ) { 24418 return; 24419 } 24420 24421 // Restrict "overflow" and "display" styles during box animations 24422 if ( isBox && elem.nodeType === 1 ) { 24423 24424 // Support: IE <=9 - 11, Edge 12 - 15 24425 // Record all 3 overflow attributes because IE does not infer the shorthand 24426 // from identically-valued overflowX and overflowY and Edge just mirrors 24427 // the overflowX value there. 24428 opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; 24429 24430 // Identify a display type, preferring old show/hide data over the CSS cascade 24431 restoreDisplay = dataShow && dataShow.display; 24432 if ( restoreDisplay == null ) { 24433 restoreDisplay = dataPriv.get( elem, "display" ); 24434 } 24435 display = jQuery.css( elem, "display" ); 24436 if ( display === "none" ) { 24437 if ( restoreDisplay ) { 24438 display = restoreDisplay; 24439 } else { 24440 24441 // Get nonempty value(s) by temporarily forcing visibility 24442 showHide( [ elem ], true ); 24443 restoreDisplay = elem.style.display || restoreDisplay; 24444 display = jQuery.css( elem, "display" ); 24445 showHide( [ elem ] ); 24446 } 24447 } 24448 24449 // Animate inline elements as inline-block 24450 if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { 24451 if ( jQuery.css( elem, "float" ) === "none" ) { 24452 24453 // Restore the original display value at the end of pure show/hide animations 24454 if ( !propTween ) { 24455 anim.done( function() { 24456 style.display = restoreDisplay; 24457 } ); 24458 if ( restoreDisplay == null ) { 24459 display = style.display; 24460 restoreDisplay = display === "none" ? "" : display; 24461 } 24462 } 24463 style.display = "inline-block"; 24464 } 24465 } 24466 } 24467 24468 if ( opts.overflow ) { 24469 style.overflow = "hidden"; 24470 anim.always( function() { 24471 style.overflow = opts.overflow[ 0 ]; 24472 style.overflowX = opts.overflow[ 1 ]; 24473 style.overflowY = opts.overflow[ 2 ]; 24474 } ); 24475 } 24476 24477 // Implement show/hide animations 24478 propTween = false; 24479 for ( prop in orig ) { 24480 24481 // General show/hide setup for this element animation 24482 if ( !propTween ) { 24483 if ( dataShow ) { 24484 if ( "hidden" in dataShow ) { 24485 hidden = dataShow.hidden; 24486 } 24487 } else { 24488 dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); 24489 } 24490 24491 // Store hidden/visible for toggle so `.stop().toggle()` "reverses" 24492 if ( toggle ) { 24493 dataShow.hidden = !hidden; 24494 } 24495 24496 // Show elements before animating them 24497 if ( hidden ) { 24498 showHide( [ elem ], true ); 24499 } 24500 24501 /* eslint-disable no-loop-func */ 24502 24503 anim.done( function() { 24504 24505 /* eslint-enable no-loop-func */ 24506 24507 // The final step of a "hide" animation is actually hiding the element 24508 if ( !hidden ) { 24509 showHide( [ elem ] ); 24510 } 24511 dataPriv.remove( elem, "fxshow" ); 24512 for ( prop in orig ) { 24513 jQuery.style( elem, prop, orig[ prop ] ); 24514 } 24515 } ); 24516 } 24517 24518 // Per-property setup 24519 propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); 24520 if ( !( prop in dataShow ) ) { 24521 dataShow[ prop ] = propTween.start; 24522 if ( hidden ) { 24523 propTween.end = propTween.start; 24524 propTween.start = 0; 24525 } 24526 } 24527 } 24528} 24529 24530function propFilter( props, specialEasing ) { 24531 var index, name, easing, value, hooks; 24532 24533 // camelCase, specialEasing and expand cssHook pass 24534 for ( index in props ) { 24535 name = camelCase( index ); 24536 easing = specialEasing[ name ]; 24537 value = props[ index ]; 24538 if ( Array.isArray( value ) ) { 24539 easing = value[ 1 ]; 24540 value = props[ index ] = value[ 0 ]; 24541 } 24542 24543 if ( index !== name ) { 24544 props[ name ] = value; 24545 delete props[ index ]; 24546 } 24547 24548 hooks = jQuery.cssHooks[ name ]; 24549 if ( hooks && "expand" in hooks ) { 24550 value = hooks.expand( value ); 24551 delete props[ name ]; 24552 24553 // Not quite $.extend, this won't overwrite existing keys. 24554 // Reusing 'index' because we have the correct "name" 24555 for ( index in value ) { 24556 if ( !( index in props ) ) { 24557 props[ index ] = value[ index ]; 24558 specialEasing[ index ] = easing; 24559 } 24560 } 24561 } else { 24562 specialEasing[ name ] = easing; 24563 } 24564 } 24565} 24566 24567function Animation( elem, properties, options ) { 24568 var result, 24569 stopped, 24570 index = 0, 24571 length = Animation.prefilters.length, 24572 deferred = jQuery.Deferred().always( function() { 24573 24574 // Don't match elem in the :animated selector 24575 delete tick.elem; 24576 } ), 24577 tick = function() { 24578 if ( stopped ) { 24579 return false; 24580 } 24581 var currentTime = fxNow || createFxNow(), 24582 remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), 24583 24584 // Support: Android 2.3 only 24585 // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) 24586 temp = remaining / animation.duration || 0, 24587 percent = 1 - temp, 24588 index = 0, 24589 length = animation.tweens.length; 24590 24591 for ( ; index < length; index++ ) { 24592 animation.tweens[ index ].run( percent ); 24593 } 24594 24595 deferred.notifyWith( elem, [ animation, percent, remaining ] ); 24596 24597 // If there's more to do, yield 24598 if ( percent < 1 && length ) { 24599 return remaining; 24600 } 24601 24602 // If this was an empty animation, synthesize a final progress notification 24603 if ( !length ) { 24604 deferred.notifyWith( elem, [ animation, 1, 0 ] ); 24605 } 24606 24607 // Resolve the animation and report its conclusion 24608 deferred.resolveWith( elem, [ animation ] ); 24609 return false; 24610 }, 24611 animation = deferred.promise( { 24612 elem: elem, 24613 props: jQuery.extend( {}, properties ), 24614 opts: jQuery.extend( true, { 24615 specialEasing: {}, 24616 easing: jQuery.easing._default 24617 }, options ), 24618 originalProperties: properties, 24619 originalOptions: options, 24620 startTime: fxNow || createFxNow(), 24621 duration: options.duration, 24622 tweens: [], 24623 createTween: function( prop, end ) { 24624 var tween = jQuery.Tween( elem, animation.opts, prop, end, 24625 animation.opts.specialEasing[ prop ] || animation.opts.easing ); 24626 animation.tweens.push( tween ); 24627 return tween; 24628 }, 24629 stop: function( gotoEnd ) { 24630 var index = 0, 24631 24632 // If we are going to the end, we want to run all the tweens 24633 // otherwise we skip this part 24634 length = gotoEnd ? animation.tweens.length : 0; 24635 if ( stopped ) { 24636 return this; 24637 } 24638 stopped = true; 24639 for ( ; index < length; index++ ) { 24640 animation.tweens[ index ].run( 1 ); 24641 } 24642 24643 // Resolve when we played the last frame; otherwise, reject 24644 if ( gotoEnd ) { 24645 deferred.notifyWith( elem, [ animation, 1, 0 ] ); 24646 deferred.resolveWith( elem, [ animation, gotoEnd ] ); 24647 } else { 24648 deferred.rejectWith( elem, [ animation, gotoEnd ] ); 24649 } 24650 return this; 24651 } 24652 } ), 24653 props = animation.props; 24654 24655 propFilter( props, animation.opts.specialEasing ); 24656 24657 for ( ; index < length; index++ ) { 24658 result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); 24659 if ( result ) { 24660 if ( isFunction( result.stop ) ) { 24661 jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = 24662 result.stop.bind( result ); 24663 } 24664 return result; 24665 } 24666 } 24667 24668 jQuery.map( props, createTween, animation ); 24669 24670 if ( isFunction( animation.opts.start ) ) { 24671 animation.opts.start.call( elem, animation ); 24672 } 24673 24674 // Attach callbacks from options 24675 animation 24676 .progress( animation.opts.progress ) 24677 .done( animation.opts.done, animation.opts.complete ) 24678 .fail( animation.opts.fail ) 24679 .always( animation.opts.always ); 24680 24681 jQuery.fx.timer( 24682 jQuery.extend( tick, { 24683 elem: elem, 24684 anim: animation, 24685 queue: animation.opts.queue 24686 } ) 24687 ); 24688 24689 return animation; 24690} 24691 24692jQuery.Animation = jQuery.extend( Animation, { 24693 24694 tweeners: { 24695 "*": [ function( prop, value ) { 24696 var tween = this.createTween( prop, value ); 24697 adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); 24698 return tween; 24699 } ] 24700 }, 24701 24702 tweener: function( props, callback ) { 24703 if ( isFunction( props ) ) { 24704 callback = props; 24705 props = [ "*" ]; 24706 } else { 24707 props = props.match( rnothtmlwhite ); 24708 } 24709 24710 var prop, 24711 index = 0, 24712 length = props.length; 24713 24714 for ( ; index < length; index++ ) { 24715 prop = props[ index ]; 24716 Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; 24717 Animation.tweeners[ prop ].unshift( callback ); 24718 } 24719 }, 24720 24721 prefilters: [ defaultPrefilter ], 24722 24723 prefilter: function( callback, prepend ) { 24724 if ( prepend ) { 24725 Animation.prefilters.unshift( callback ); 24726 } else { 24727 Animation.prefilters.push( callback ); 24728 } 24729 } 24730} ); 24731 24732jQuery.speed = function( speed, easing, fn ) { 24733 var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { 24734 complete: fn || !fn && easing || 24735 isFunction( speed ) && speed, 24736 duration: speed, 24737 easing: fn && easing || easing && !isFunction( easing ) && easing 24738 }; 24739 24740 // Go to the end state if fx are off 24741 if ( jQuery.fx.off ) { 24742 opt.duration = 0; 24743 24744 } else { 24745 if ( typeof opt.duration !== "number" ) { 24746 if ( opt.duration in jQuery.fx.speeds ) { 24747 opt.duration = jQuery.fx.speeds[ opt.duration ]; 24748 24749 } else { 24750 opt.duration = jQuery.fx.speeds._default; 24751 } 24752 } 24753 } 24754 24755 // Normalize opt.queue - true/undefined/null -> "fx" 24756 if ( opt.queue == null || opt.queue === true ) { 24757 opt.queue = "fx"; 24758 } 24759 24760 // Queueing 24761 opt.old = opt.complete; 24762 24763 opt.complete = function() { 24764 if ( isFunction( opt.old ) ) { 24765 opt.old.call( this ); 24766 } 24767 24768 if ( opt.queue ) { 24769 jQuery.dequeue( this, opt.queue ); 24770 } 24771 }; 24772 24773 return opt; 24774}; 24775 24776jQuery.fn.extend( { 24777 fadeTo: function( speed, to, easing, callback ) { 24778 24779 // Show any hidden elements after setting opacity to 0 24780 return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() 24781 24782 // Animate to the value specified 24783 .end().animate( { opacity: to }, speed, easing, callback ); 24784 }, 24785 animate: function( prop, speed, easing, callback ) { 24786 var empty = jQuery.isEmptyObject( prop ), 24787 optall = jQuery.speed( speed, easing, callback ), 24788 doAnimation = function() { 24789 24790 // Operate on a copy of prop so per-property easing won't be lost 24791 var anim = Animation( this, jQuery.extend( {}, prop ), optall ); 24792 24793 // Empty animations, or finishing resolves immediately 24794 if ( empty || dataPriv.get( this, "finish" ) ) { 24795 anim.stop( true ); 24796 } 24797 }; 24798 24799 doAnimation.finish = doAnimation; 24800 24801 return empty || optall.queue === false ? 24802 this.each( doAnimation ) : 24803 this.queue( optall.queue, doAnimation ); 24804 }, 24805 stop: function( type, clearQueue, gotoEnd ) { 24806 var stopQueue = function( hooks ) { 24807 var stop = hooks.stop; 24808 delete hooks.stop; 24809 stop( gotoEnd ); 24810 }; 24811 24812 if ( typeof type !== "string" ) { 24813 gotoEnd = clearQueue; 24814 clearQueue = type; 24815 type = undefined; 24816 } 24817 if ( clearQueue ) { 24818 this.queue( type || "fx", [] ); 24819 } 24820 24821 return this.each( function() { 24822 var dequeue = true, 24823 index = type != null && type + "queueHooks", 24824 timers = jQuery.timers, 24825 data = dataPriv.get( this ); 24826 24827 if ( index ) { 24828 if ( data[ index ] && data[ index ].stop ) { 24829 stopQueue( data[ index ] ); 24830 } 24831 } else { 24832 for ( index in data ) { 24833 if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { 24834 stopQueue( data[ index ] ); 24835 } 24836 } 24837 } 24838 24839 for ( index = timers.length; index--; ) { 24840 if ( timers[ index ].elem === this && 24841 ( type == null || timers[ index ].queue === type ) ) { 24842 24843 timers[ index ].anim.stop( gotoEnd ); 24844 dequeue = false; 24845 timers.splice( index, 1 ); 24846 } 24847 } 24848 24849 // Start the next in the queue if the last step wasn't forced. 24850 // Timers currently will call their complete callbacks, which 24851 // will dequeue but only if they were gotoEnd. 24852 if ( dequeue || !gotoEnd ) { 24853 jQuery.dequeue( this, type ); 24854 } 24855 } ); 24856 }, 24857 finish: function( type ) { 24858 if ( type !== false ) { 24859 type = type || "fx"; 24860 } 24861 return this.each( function() { 24862 var index, 24863 data = dataPriv.get( this ), 24864 queue = data[ type + "queue" ], 24865 hooks = data[ type + "queueHooks" ], 24866 timers = jQuery.timers, 24867 length = queue ? queue.length : 0; 24868 24869 // Enable finishing flag on private data 24870 data.finish = true; 24871 24872 // Empty the queue first 24873 jQuery.queue( this, type, [] ); 24874 24875 if ( hooks && hooks.stop ) { 24876 hooks.stop.call( this, true ); 24877 } 24878 24879 // Look for any active animations, and finish them 24880 for ( index = timers.length; index--; ) { 24881 if ( timers[ index ].elem === this && timers[ index ].queue === type ) { 24882 timers[ index ].anim.stop( true ); 24883 timers.splice( index, 1 ); 24884 } 24885 } 24886 24887 // Look for any animations in the old queue and finish them 24888 for ( index = 0; index < length; index++ ) { 24889 if ( queue[ index ] && queue[ index ].finish ) { 24890 queue[ index ].finish.call( this ); 24891 } 24892 } 24893 24894 // Turn off finishing flag 24895 delete data.finish; 24896 } ); 24897 } 24898} ); 24899 24900jQuery.each( [ "toggle", "show", "hide" ], function( _i, name ) { 24901 var cssFn = jQuery.fn[ name ]; 24902 jQuery.fn[ name ] = function( speed, easing, callback ) { 24903 return speed == null || typeof speed === "boolean" ? 24904 cssFn.apply( this, arguments ) : 24905 this.animate( genFx( name, true ), speed, easing, callback ); 24906 }; 24907} ); 24908 24909// Generate shortcuts for custom animations 24910jQuery.each( { 24911 slideDown: genFx( "show" ), 24912 slideUp: genFx( "hide" ), 24913 slideToggle: genFx( "toggle" ), 24914 fadeIn: { opacity: "show" }, 24915 fadeOut: { opacity: "hide" }, 24916 fadeToggle: { opacity: "toggle" } 24917}, function( name, props ) { 24918 jQuery.fn[ name ] = function( speed, easing, callback ) { 24919 return this.animate( props, speed, easing, callback ); 24920 }; 24921} ); 24922 24923jQuery.timers = []; 24924jQuery.fx.tick = function() { 24925 var timer, 24926 i = 0, 24927 timers = jQuery.timers; 24928 24929 fxNow = Date.now(); 24930 24931 for ( ; i < timers.length; i++ ) { 24932 timer = timers[ i ]; 24933 24934 // Run the timer and safely remove it when done (allowing for external removal) 24935 if ( !timer() && timers[ i ] === timer ) { 24936 timers.splice( i--, 1 ); 24937 } 24938 } 24939 24940 if ( !timers.length ) { 24941 jQuery.fx.stop(); 24942 } 24943 fxNow = undefined; 24944}; 24945 24946jQuery.fx.timer = function( timer ) { 24947 jQuery.timers.push( timer ); 24948 jQuery.fx.start(); 24949}; 24950 24951jQuery.fx.interval = 13; 24952jQuery.fx.start = function() { 24953 if ( inProgress ) { 24954 return; 24955 } 24956 24957 inProgress = true; 24958 schedule(); 24959}; 24960 24961jQuery.fx.stop = function() { 24962 inProgress = null; 24963}; 24964 24965jQuery.fx.speeds = { 24966 slow: 600, 24967 fast: 200, 24968 24969 // Default speed 24970 _default: 400 24971}; 24972 24973 24974// Based off of the plugin by Clint Helfers, with permission. 24975// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ 24976jQuery.fn.delay = function( time, type ) { 24977 time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; 24978 type = type || "fx"; 24979 24980 return this.queue( type, function( next, hooks ) { 24981 var timeout = window.setTimeout( next, time ); 24982 hooks.stop = function() { 24983 window.clearTimeout( timeout ); 24984 }; 24985 } ); 24986}; 24987 24988 24989( function() { 24990 var input = document.createElement( "input" ), 24991 select = document.createElement( "select" ), 24992 opt = select.appendChild( document.createElement( "option" ) ); 24993 24994 input.type = "checkbox"; 24995 24996 // Support: Android <=4.3 only 24997 // Default value for a checkbox should be "on" 24998 support.checkOn = input.value !== ""; 24999 25000 // Support: IE <=11 only 25001 // Must access selectedIndex to make default options select 25002 support.optSelected = opt.selected; 25003 25004 // Support: IE <=11 only 25005 // An input loses its value after becoming a radio 25006 input = document.createElement( "input" ); 25007 input.value = "t"; 25008 input.type = "radio"; 25009 support.radioValue = input.value === "t"; 25010} )(); 25011 25012 25013var boolHook, 25014 attrHandle = jQuery.expr.attrHandle; 25015 25016jQuery.fn.extend( { 25017 attr: function( name, value ) { 25018 return access( this, jQuery.attr, name, value, arguments.length > 1 ); 25019 }, 25020 25021 removeAttr: function( name ) { 25022 return this.each( function() { 25023 jQuery.removeAttr( this, name ); 25024 } ); 25025 } 25026} ); 25027 25028jQuery.extend( { 25029 attr: function( elem, name, value ) { 25030 var ret, hooks, 25031 nType = elem.nodeType; 25032 25033 // Don't get/set attributes on text, comment and attribute nodes 25034 if ( nType === 3 || nType === 8 || nType === 2 ) { 25035 return; 25036 } 25037 25038 // Fallback to prop when attributes are not supported 25039 if ( typeof elem.getAttribute === "undefined" ) { 25040 return jQuery.prop( elem, name, value ); 25041 } 25042 25043 // Attribute hooks are determined by the lowercase version 25044 // Grab necessary hook if one is defined 25045 if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { 25046 hooks = jQuery.attrHooks[ name.toLowerCase() ] || 25047 ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); 25048 } 25049 25050 if ( value !== undefined ) { 25051 if ( value === null ) { 25052 jQuery.removeAttr( elem, name ); 25053 return; 25054 } 25055 25056 if ( hooks && "set" in hooks && 25057 ( ret = hooks.set( elem, value, name ) ) !== undefined ) { 25058 return ret; 25059 } 25060 25061 elem.setAttribute( name, value + "" ); 25062 return value; 25063 } 25064 25065 if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { 25066 return ret; 25067 } 25068 25069 ret = jQuery.find.attr( elem, name ); 25070 25071 // Non-existent attributes return null, we normalize to undefined 25072 return ret == null ? undefined : ret; 25073 }, 25074 25075 attrHooks: { 25076 type: { 25077 set: function( elem, value ) { 25078 if ( !support.radioValue && value === "radio" && 25079 nodeName( elem, "input" ) ) { 25080 var val = elem.value; 25081 elem.setAttribute( "type", value ); 25082 if ( val ) { 25083 elem.value = val; 25084 } 25085 return value; 25086 } 25087 } 25088 } 25089 }, 25090 25091 removeAttr: function( elem, value ) { 25092 var name, 25093 i = 0, 25094 25095 // Attribute names can contain non-HTML whitespace characters 25096 // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 25097 attrNames = value && value.match( rnothtmlwhite ); 25098 25099 if ( attrNames && elem.nodeType === 1 ) { 25100 while ( ( name = attrNames[ i++ ] ) ) { 25101 elem.removeAttribute( name ); 25102 } 25103 } 25104 } 25105} ); 25106 25107// Hooks for boolean attributes 25108boolHook = { 25109 set: function( elem, value, name ) { 25110 if ( value === false ) { 25111 25112 // Remove boolean attributes when set to false 25113 jQuery.removeAttr( elem, name ); 25114 } else { 25115 elem.setAttribute( name, name ); 25116 } 25117 return name; 25118 } 25119}; 25120 25121jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( _i, name ) { 25122 var getter = attrHandle[ name ] || jQuery.find.attr; 25123 25124 attrHandle[ name ] = function( elem, name, isXML ) { 25125 var ret, handle, 25126 lowercaseName = name.toLowerCase(); 25127 25128 if ( !isXML ) { 25129 25130 // Avoid an infinite loop by temporarily removing this function from the getter 25131 handle = attrHandle[ lowercaseName ]; 25132 attrHandle[ lowercaseName ] = ret; 25133 ret = getter( elem, name, isXML ) != null ? 25134 lowercaseName : 25135 null; 25136 attrHandle[ lowercaseName ] = handle; 25137 } 25138 return ret; 25139 }; 25140} ); 25141 25142 25143 25144 25145var rfocusable = /^(?:input|select|textarea|button)$/i, 25146 rclickable = /^(?:a|area)$/i; 25147 25148jQuery.fn.extend( { 25149 prop: function( name, value ) { 25150 return access( this, jQuery.prop, name, value, arguments.length > 1 ); 25151 }, 25152 25153 removeProp: function( name ) { 25154 return this.each( function() { 25155 delete this[ jQuery.propFix[ name ] || name ]; 25156 } ); 25157 } 25158} ); 25159 25160jQuery.extend( { 25161 prop: function( elem, name, value ) { 25162 var ret, hooks, 25163 nType = elem.nodeType; 25164 25165 // Don't get/set properties on text, comment and attribute nodes 25166 if ( nType === 3 || nType === 8 || nType === 2 ) { 25167 return; 25168 } 25169 25170 if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { 25171 25172 // Fix name and attach hooks 25173 name = jQuery.propFix[ name ] || name; 25174 hooks = jQuery.propHooks[ name ]; 25175 } 25176 25177 if ( value !== undefined ) { 25178 if ( hooks && "set" in hooks && 25179 ( ret = hooks.set( elem, value, name ) ) !== undefined ) { 25180 return ret; 25181 } 25182 25183 return ( elem[ name ] = value ); 25184 } 25185 25186 if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { 25187 return ret; 25188 } 25189 25190 return elem[ name ]; 25191 }, 25192 25193 propHooks: { 25194 tabIndex: { 25195 get: function( elem ) { 25196 25197 // Support: IE <=9 - 11 only 25198 // elem.tabIndex doesn't always return the 25199 // correct value when it hasn't been explicitly set 25200 // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ 25201 // Use proper attribute retrieval(#12072) 25202 var tabindex = jQuery.find.attr( elem, "tabindex" ); 25203 25204 if ( tabindex ) { 25205 return parseInt( tabindex, 10 ); 25206 } 25207 25208 if ( 25209 rfocusable.test( elem.nodeName ) || 25210 rclickable.test( elem.nodeName ) && 25211 elem.href 25212 ) { 25213 return 0; 25214 } 25215 25216 return -1; 25217 } 25218 } 25219 }, 25220 25221 propFix: { 25222 "for": "htmlFor", 25223 "class": "className" 25224 } 25225} ); 25226 25227// Support: IE <=11 only 25228// Accessing the selectedIndex property 25229// forces the browser to respect setting selected 25230// on the option 25231// The getter ensures a default option is selected 25232// when in an optgroup 25233// eslint rule "no-unused-expressions" is disabled for this code 25234// since it considers such accessions noop 25235if ( !support.optSelected ) { 25236 jQuery.propHooks.selected = { 25237 get: function( elem ) { 25238 25239 /* eslint no-unused-expressions: "off" */ 25240 25241 var parent = elem.parentNode; 25242 if ( parent && parent.parentNode ) { 25243 parent.parentNode.selectedIndex; 25244 } 25245 return null; 25246 }, 25247 set: function( elem ) { 25248 25249 /* eslint no-unused-expressions: "off" */ 25250 25251 var parent = elem.parentNode; 25252 if ( parent ) { 25253 parent.selectedIndex; 25254 25255 if ( parent.parentNode ) { 25256 parent.parentNode.selectedIndex; 25257 } 25258 } 25259 } 25260 }; 25261} 25262 25263jQuery.each( [ 25264 "tabIndex", 25265 "readOnly", 25266 "maxLength", 25267 "cellSpacing", 25268 "cellPadding", 25269 "rowSpan", 25270 "colSpan", 25271 "useMap", 25272 "frameBorder", 25273 "contentEditable" 25274], function() { 25275 jQuery.propFix[ this.toLowerCase() ] = this; 25276} ); 25277 25278 25279 25280 25281 // Strip and collapse whitespace according to HTML spec 25282 // https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace 25283 function stripAndCollapse( value ) { 25284 var tokens = value.match( rnothtmlwhite ) || []; 25285 return tokens.join( " " ); 25286 } 25287 25288 25289function getClass( elem ) { 25290 return elem.getAttribute && elem.getAttribute( "class" ) || ""; 25291} 25292 25293function classesToArray( value ) { 25294 if ( Array.isArray( value ) ) { 25295 return value; 25296 } 25297 if ( typeof value === "string" ) { 25298 return value.match( rnothtmlwhite ) || []; 25299 } 25300 return []; 25301} 25302 25303jQuery.fn.extend( { 25304 addClass: function( value ) { 25305 var classes, elem, cur, curValue, clazz, j, finalValue, 25306 i = 0; 25307 25308 if ( isFunction( value ) ) { 25309 return this.each( function( j ) { 25310 jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); 25311 } ); 25312 } 25313 25314 classes = classesToArray( value ); 25315 25316 if ( classes.length ) { 25317 while ( ( elem = this[ i++ ] ) ) { 25318 curValue = getClass( elem ); 25319 cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); 25320 25321 if ( cur ) { 25322 j = 0; 25323 while ( ( clazz = classes[ j++ ] ) ) { 25324 if ( cur.indexOf( " " + clazz + " " ) < 0 ) { 25325 cur += clazz + " "; 25326 } 25327 } 25328 25329 // Only assign if different to avoid unneeded rendering. 25330 finalValue = stripAndCollapse( cur ); 25331 if ( curValue !== finalValue ) { 25332 elem.setAttribute( "class", finalValue ); 25333 } 25334 } 25335 } 25336 } 25337 25338 return this; 25339 }, 25340 25341 removeClass: function( value ) { 25342 var classes, elem, cur, curValue, clazz, j, finalValue, 25343 i = 0; 25344 25345 if ( isFunction( value ) ) { 25346 return this.each( function( j ) { 25347 jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); 25348 } ); 25349 } 25350 25351 if ( !arguments.length ) { 25352 return this.attr( "class", "" ); 25353 } 25354 25355 classes = classesToArray( value ); 25356 25357 if ( classes.length ) { 25358 while ( ( elem = this[ i++ ] ) ) { 25359 curValue = getClass( elem ); 25360 25361 // This expression is here for better compressibility (see addClass) 25362 cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); 25363 25364 if ( cur ) { 25365 j = 0; 25366 while ( ( clazz = classes[ j++ ] ) ) { 25367 25368 // Remove *all* instances 25369 while ( cur.indexOf( " " + clazz + " " ) > -1 ) { 25370 cur = cur.replace( " " + clazz + " ", " " ); 25371 } 25372 } 25373 25374 // Only assign if different to avoid unneeded rendering. 25375 finalValue = stripAndCollapse( cur ); 25376 if ( curValue !== finalValue ) { 25377 elem.setAttribute( "class", finalValue ); 25378 } 25379 } 25380 } 25381 } 25382 25383 return this; 25384 }, 25385 25386 toggleClass: function( value, stateVal ) { 25387 var type = typeof value, 25388 isValidValue = type === "string" || Array.isArray( value ); 25389 25390 if ( typeof stateVal === "boolean" && isValidValue ) { 25391 return stateVal ? this.addClass( value ) : this.removeClass( value ); 25392 } 25393 25394 if ( isFunction( value ) ) { 25395 return this.each( function( i ) { 25396 jQuery( this ).toggleClass( 25397 value.call( this, i, getClass( this ), stateVal ), 25398 stateVal 25399 ); 25400 } ); 25401 } 25402 25403 return this.each( function() { 25404 var className, i, self, classNames; 25405 25406 if ( isValidValue ) { 25407 25408 // Toggle individual class names 25409 i = 0; 25410 self = jQuery( this ); 25411 classNames = classesToArray( value ); 25412 25413 while ( ( className = classNames[ i++ ] ) ) { 25414 25415 // Check each className given, space separated list 25416 if ( self.hasClass( className ) ) { 25417 self.removeClass( className ); 25418 } else { 25419 self.addClass( className ); 25420 } 25421 } 25422 25423 // Toggle whole class name 25424 } else if ( value === undefined || type === "boolean" ) { 25425 className = getClass( this ); 25426 if ( className ) { 25427 25428 // Store className if set 25429 dataPriv.set( this, "__className__", className ); 25430 } 25431 25432 // If the element has a class name or if we're passed `false`, 25433 // then remove the whole classname (if there was one, the above saved it). 25434 // Otherwise bring back whatever was previously saved (if anything), 25435 // falling back to the empty string if nothing was stored. 25436 if ( this.setAttribute ) { 25437 this.setAttribute( "class", 25438 className || value === false ? 25439 "" : 25440 dataPriv.get( this, "__className__" ) || "" 25441 ); 25442 } 25443 } 25444 } ); 25445 }, 25446 25447 hasClass: function( selector ) { 25448 var className, elem, 25449 i = 0; 25450 25451 className = " " + selector + " "; 25452 while ( ( elem = this[ i++ ] ) ) { 25453 if ( elem.nodeType === 1 && 25454 ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { 25455 return true; 25456 } 25457 } 25458 25459 return false; 25460 } 25461} ); 25462 25463 25464 25465 25466var rreturn = /\r/g; 25467 25468jQuery.fn.extend( { 25469 val: function( value ) { 25470 var hooks, ret, valueIsFunction, 25471 elem = this[ 0 ]; 25472 25473 if ( !arguments.length ) { 25474 if ( elem ) { 25475 hooks = jQuery.valHooks[ elem.type ] || 25476 jQuery.valHooks[ elem.nodeName.toLowerCase() ]; 25477 25478 if ( hooks && 25479 "get" in hooks && 25480 ( ret = hooks.get( elem, "value" ) ) !== undefined 25481 ) { 25482 return ret; 25483 } 25484 25485 ret = elem.value; 25486 25487 // Handle most common string cases 25488 if ( typeof ret === "string" ) { 25489 return ret.replace( rreturn, "" ); 25490 } 25491 25492 // Handle cases where value is null/undef or number 25493 return ret == null ? "" : ret; 25494 } 25495 25496 return; 25497 } 25498 25499 valueIsFunction = isFunction( value ); 25500 25501 return this.each( function( i ) { 25502 var val; 25503 25504 if ( this.nodeType !== 1 ) { 25505 return; 25506 } 25507 25508 if ( valueIsFunction ) { 25509 val = value.call( this, i, jQuery( this ).val() ); 25510 } else { 25511 val = value; 25512 } 25513 25514 // Treat null/undefined as ""; convert numbers to string 25515 if ( val == null ) { 25516 val = ""; 25517 25518 } else if ( typeof val === "number" ) { 25519 val += ""; 25520 25521 } else if ( Array.isArray( val ) ) { 25522 val = jQuery.map( val, function( value ) { 25523 return value == null ? "" : value + ""; 25524 } ); 25525 } 25526 25527 hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; 25528 25529 // If set returns undefined, fall back to normal setting 25530 if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { 25531 this.value = val; 25532 } 25533 } ); 25534 } 25535} ); 25536 25537jQuery.extend( { 25538 valHooks: { 25539 option: { 25540 get: function( elem ) { 25541 25542 var val = jQuery.find.attr( elem, "value" ); 25543 return val != null ? 25544 val : 25545 25546 // Support: IE <=10 - 11 only 25547 // option.text throws exceptions (#14686, #14858) 25548 // Strip and collapse whitespace 25549 // https://html.spec.whatwg.org/#strip-and-collapse-whitespace 25550 stripAndCollapse( jQuery.text( elem ) ); 25551 } 25552 }, 25553 select: { 25554 get: function( elem ) { 25555 var value, option, i, 25556 options = elem.options, 25557 index = elem.selectedIndex, 25558 one = elem.type === "select-one", 25559 values = one ? null : [], 25560 max = one ? index + 1 : options.length; 25561 25562 if ( index < 0 ) { 25563 i = max; 25564 25565 } else { 25566 i = one ? index : 0; 25567 } 25568 25569 // Loop through all the selected options 25570 for ( ; i < max; i++ ) { 25571 option = options[ i ]; 25572 25573 // Support: IE <=9 only 25574 // IE8-9 doesn't update selected after form reset (#2551) 25575 if ( ( option.selected || i === index ) && 25576 25577 // Don't return options that are disabled or in a disabled optgroup 25578 !option.disabled && 25579 ( !option.parentNode.disabled || 25580 !nodeName( option.parentNode, "optgroup" ) ) ) { 25581 25582 // Get the specific value for the option 25583 value = jQuery( option ).val(); 25584 25585 // We don't need an array for one selects 25586 if ( one ) { 25587 return value; 25588 } 25589 25590 // Multi-Selects return an array 25591 values.push( value ); 25592 } 25593 } 25594 25595 return values; 25596 }, 25597 25598 set: function( elem, value ) { 25599 var optionSet, option, 25600 options = elem.options, 25601 values = jQuery.makeArray( value ), 25602 i = options.length; 25603 25604 while ( i-- ) { 25605 option = options[ i ]; 25606 25607 /* eslint-disable no-cond-assign */ 25608 25609 if ( option.selected = 25610 jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 25611 ) { 25612 optionSet = true; 25613 } 25614 25615 /* eslint-enable no-cond-assign */ 25616 } 25617 25618 // Force browsers to behave consistently when non-matching value is set 25619 if ( !optionSet ) { 25620 elem.selectedIndex = -1; 25621 } 25622 return values; 25623 } 25624 } 25625 } 25626} ); 25627 25628// Radios and checkboxes getter/setter 25629jQuery.each( [ "radio", "checkbox" ], function() { 25630 jQuery.valHooks[ this ] = { 25631 set: function( elem, value ) { 25632 if ( Array.isArray( value ) ) { 25633 return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); 25634 } 25635 } 25636 }; 25637 if ( !support.checkOn ) { 25638 jQuery.valHooks[ this ].get = function( elem ) { 25639 return elem.getAttribute( "value" ) === null ? "on" : elem.value; 25640 }; 25641 } 25642} ); 25643 25644 25645 25646 25647// Return jQuery for attributes-only inclusion 25648 25649 25650support.focusin = "onfocusin" in window; 25651 25652 25653var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, 25654 stopPropagationCallback = function( e ) { 25655 e.stopPropagation(); 25656 }; 25657 25658jQuery.extend( jQuery.event, { 25659 25660 trigger: function( event, data, elem, onlyHandlers ) { 25661 25662 var i, cur, tmp, bubbleType, ontype, handle, special, lastElement, 25663 eventPath = [ elem || document ], 25664 type = hasOwn.call( event, "type" ) ? event.type : event, 25665 namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; 25666 25667 cur = lastElement = tmp = elem = elem || document; 25668 25669 // Don't do events on text and comment nodes 25670 if ( elem.nodeType === 3 || elem.nodeType === 8 ) { 25671 return; 25672 } 25673 25674 // focus/blur morphs to focusin/out; ensure we're not firing them right now 25675 if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { 25676 return; 25677 } 25678 25679 if ( type.indexOf( "." ) > -1 ) { 25680 25681 // Namespaced trigger; create a regexp to match event type in handle() 25682 namespaces = type.split( "." ); 25683 type = namespaces.shift(); 25684 namespaces.sort(); 25685 } 25686 ontype = type.indexOf( ":" ) < 0 && "on" + type; 25687 25688 // Caller can pass in a jQuery.Event object, Object, or just an event type string 25689 event = event[ jQuery.expando ] ? 25690 event : 25691 new jQuery.Event( type, typeof event === "object" && event ); 25692 25693 // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) 25694 event.isTrigger = onlyHandlers ? 2 : 3; 25695 event.namespace = namespaces.join( "." ); 25696 event.rnamespace = event.namespace ? 25697 new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : 25698 null; 25699 25700 // Clean up the event in case it is being reused 25701 event.result = undefined; 25702 if ( !event.target ) { 25703 event.target = elem; 25704 } 25705 25706 // Clone any incoming data and prepend the event, creating the handler arg list 25707 data = data == null ? 25708 [ event ] : 25709 jQuery.makeArray( data, [ event ] ); 25710 25711 // Allow special events to draw outside the lines 25712 special = jQuery.event.special[ type ] || {}; 25713 if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { 25714 return; 25715 } 25716 25717 // Determine event propagation path in advance, per W3C events spec (#9951) 25718 // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) 25719 if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) { 25720 25721 bubbleType = special.delegateType || type; 25722 if ( !rfocusMorph.test( bubbleType + type ) ) { 25723 cur = cur.parentNode; 25724 } 25725 for ( ; cur; cur = cur.parentNode ) { 25726 eventPath.push( cur ); 25727 tmp = cur; 25728 } 25729 25730 // Only add window if we got to document (e.g., not plain obj or detached DOM) 25731 if ( tmp === ( elem.ownerDocument || document ) ) { 25732 eventPath.push( tmp.defaultView || tmp.parentWindow || window ); 25733 } 25734 } 25735 25736 // Fire handlers on the event path 25737 i = 0; 25738 while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { 25739 lastElement = cur; 25740 event.type = i > 1 ? 25741 bubbleType : 25742 special.bindType || type; 25743 25744 // jQuery handler 25745 handle = ( dataPriv.get( cur, "events" ) || Object.create( null ) )[ event.type ] && 25746 dataPriv.get( cur, "handle" ); 25747 if ( handle ) { 25748 handle.apply( cur, data ); 25749 } 25750 25751 // Native handler 25752 handle = ontype && cur[ ontype ]; 25753 if ( handle && handle.apply && acceptData( cur ) ) { 25754 event.result = handle.apply( cur, data ); 25755 if ( event.result === false ) { 25756 event.preventDefault(); 25757 } 25758 } 25759 } 25760 event.type = type; 25761 25762 // If nobody prevented the default action, do it now 25763 if ( !onlyHandlers && !event.isDefaultPrevented() ) { 25764 25765 if ( ( !special._default || 25766 special._default.apply( eventPath.pop(), data ) === false ) && 25767 acceptData( elem ) ) { 25768 25769 // Call a native DOM method on the target with the same name as the event. 25770 // Don't do default actions on window, that's where global variables be (#6170) 25771 if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) { 25772 25773 // Don't re-trigger an onFOO event when we call its FOO() method 25774 tmp = elem[ ontype ]; 25775 25776 if ( tmp ) { 25777 elem[ ontype ] = null; 25778 } 25779 25780 // Prevent re-triggering of the same event, since we already bubbled it above 25781 jQuery.event.triggered = type; 25782 25783 if ( event.isPropagationStopped() ) { 25784 lastElement.addEventListener( type, stopPropagationCallback ); 25785 } 25786 25787 elem[ type ](); 25788 25789 if ( event.isPropagationStopped() ) { 25790 lastElement.removeEventListener( type, stopPropagationCallback ); 25791 } 25792 25793 jQuery.event.triggered = undefined; 25794 25795 if ( tmp ) { 25796 elem[ ontype ] = tmp; 25797 } 25798 } 25799 } 25800 } 25801 25802 return event.result; 25803 }, 25804 25805 // Piggyback on a donor event to simulate a different one 25806 // Used only for `focus(in | out)` events 25807 simulate: function( type, elem, event ) { 25808 var e = jQuery.extend( 25809 new jQuery.Event(), 25810 event, 25811 { 25812 type: type, 25813 isSimulated: true 25814 } 25815 ); 25816 25817 jQuery.event.trigger( e, null, elem ); 25818 } 25819 25820} ); 25821 25822jQuery.fn.extend( { 25823 25824 trigger: function( type, data ) { 25825 return this.each( function() { 25826 jQuery.event.trigger( type, data, this ); 25827 } ); 25828 }, 25829 triggerHandler: function( type, data ) { 25830 var elem = this[ 0 ]; 25831 if ( elem ) { 25832 return jQuery.event.trigger( type, data, elem, true ); 25833 } 25834 } 25835} ); 25836 25837 25838// Support: Firefox <=44 25839// Firefox doesn't have focus(in | out) events 25840// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 25841// 25842// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 25843// focus(in | out) events fire after focus & blur events, 25844// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order 25845// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 25846if ( !support.focusin ) { 25847 jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { 25848 25849 // Attach a single capturing handler on the document while someone wants focusin/focusout 25850 var handler = function( event ) { 25851 jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); 25852 }; 25853 25854 jQuery.event.special[ fix ] = { 25855 setup: function() { 25856 25857 // Handle: regular nodes (via `this.ownerDocument`), window 25858 // (via `this.document`) & document (via `this`). 25859 var doc = this.ownerDocument || this.document || this, 25860 attaches = dataPriv.access( doc, fix ); 25861 25862 if ( !attaches ) { 25863 doc.addEventListener( orig, handler, true ); 25864 } 25865 dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); 25866 }, 25867 teardown: function() { 25868 var doc = this.ownerDocument || this.document || this, 25869 attaches = dataPriv.access( doc, fix ) - 1; 25870 25871 if ( !attaches ) { 25872 doc.removeEventListener( orig, handler, true ); 25873 dataPriv.remove( doc, fix ); 25874 25875 } else { 25876 dataPriv.access( doc, fix, attaches ); 25877 } 25878 } 25879 }; 25880 } ); 25881} 25882var location = window.location; 25883 25884var nonce = { guid: Date.now() }; 25885 25886var rquery = ( /\?/ ); 25887 25888 25889 25890// Cross-browser xml parsing 25891jQuery.parseXML = function( data ) { 25892 var xml, parserErrorElem; 25893 if ( !data || typeof data !== "string" ) { 25894 return null; 25895 } 25896 25897 // Support: IE 9 - 11 only 25898 // IE throws on parseFromString with invalid input. 25899 try { 25900 xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); 25901 } catch ( e ) {} 25902 25903 parserErrorElem = xml && xml.getElementsByTagName( "parsererror" )[ 0 ]; 25904 if ( !xml || parserErrorElem ) { 25905 jQuery.error( "Invalid XML: " + ( 25906 parserErrorElem ? 25907 jQuery.map( parserErrorElem.childNodes, function( el ) { 25908 return el.textContent; 25909 } ).join( "\n" ) : 25910 data 25911 ) ); 25912 } 25913 return xml; 25914}; 25915 25916 25917var 25918 rbracket = /\[\]$/, 25919 rCRLF = /\r?\n/g, 25920 rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, 25921 rsubmittable = /^(?:input|select|textarea|keygen)/i; 25922 25923function buildParams( prefix, obj, traditional, add ) { 25924 var name; 25925 25926 if ( Array.isArray( obj ) ) { 25927 25928 // Serialize array item. 25929 jQuery.each( obj, function( i, v ) { 25930 if ( traditional || rbracket.test( prefix ) ) { 25931 25932 // Treat each array item as a scalar. 25933 add( prefix, v ); 25934 25935 } else { 25936 25937 // Item is non-scalar (array or object), encode its numeric index. 25938 buildParams( 25939 prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", 25940 v, 25941 traditional, 25942 add 25943 ); 25944 } 25945 } ); 25946 25947 } else if ( !traditional && toType( obj ) === "object" ) { 25948 25949 // Serialize object item. 25950 for ( name in obj ) { 25951 buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); 25952 } 25953 25954 } else { 25955 25956 // Serialize scalar item. 25957 add( prefix, obj ); 25958 } 25959} 25960 25961// Serialize an array of form elements or a set of 25962// key/values into a query string 25963jQuery.param = function( a, traditional ) { 25964 var prefix, 25965 s = [], 25966 add = function( key, valueOrFunction ) { 25967 25968 // If value is a function, invoke it and use its return value 25969 var value = isFunction( valueOrFunction ) ? 25970 valueOrFunction() : 25971 valueOrFunction; 25972 25973 s[ s.length ] = encodeURIComponent( key ) + "=" + 25974 encodeURIComponent( value == null ? "" : value ); 25975 }; 25976 25977 if ( a == null ) { 25978 return ""; 25979 } 25980 25981 // If an array was passed in, assume that it is an array of form elements. 25982 if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { 25983 25984 // Serialize the form elements 25985 jQuery.each( a, function() { 25986 add( this.name, this.value ); 25987 } ); 25988 25989 } else { 25990 25991 // If traditional, encode the "old" way (the way 1.3.2 or older 25992 // did it), otherwise encode params recursively. 25993 for ( prefix in a ) { 25994 buildParams( prefix, a[ prefix ], traditional, add ); 25995 } 25996 } 25997 25998 // Return the resulting serialization 25999 return s.join( "&" ); 26000}; 26001 26002jQuery.fn.extend( { 26003 serialize: function() { 26004 return jQuery.param( this.serializeArray() ); 26005 }, 26006 serializeArray: function() { 26007 return this.map( function() { 26008 26009 // Can add propHook for "elements" to filter or add form elements 26010 var elements = jQuery.prop( this, "elements" ); 26011 return elements ? jQuery.makeArray( elements ) : this; 26012 } ).filter( function() { 26013 var type = this.type; 26014 26015 // Use .is( ":disabled" ) so that fieldset[disabled] works 26016 return this.name && !jQuery( this ).is( ":disabled" ) && 26017 rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && 26018 ( this.checked || !rcheckableType.test( type ) ); 26019 } ).map( function( _i, elem ) { 26020 var val = jQuery( this ).val(); 26021 26022 if ( val == null ) { 26023 return null; 26024 } 26025 26026 if ( Array.isArray( val ) ) { 26027 return jQuery.map( val, function( val ) { 26028 return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; 26029 } ); 26030 } 26031 26032 return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; 26033 } ).get(); 26034 } 26035} ); 26036 26037 26038var 26039 r20 = /%20/g, 26040 rhash = /#.*$/, 26041 rantiCache = /([?&])_=[^&]*/, 26042 rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, 26043 26044 // #7653, #8125, #8152: local protocol detection 26045 rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, 26046 rnoContent = /^(?:GET|HEAD)$/, 26047 rprotocol = /^\/\//, 26048 26049 /* Prefilters 26050 * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) 26051 * 2) These are called: 26052 * - BEFORE asking for a transport 26053 * - AFTER param serialization (s.data is a string if s.processData is true) 26054 * 3) key is the dataType 26055 * 4) the catchall symbol "*" can be used 26056 * 5) execution will start with transport dataType and THEN continue down to "*" if needed 26057 */ 26058 prefilters = {}, 26059 26060 /* Transports bindings 26061 * 1) key is the dataType 26062 * 2) the catchall symbol "*" can be used 26063 * 3) selection will start with transport dataType and THEN go to "*" if needed 26064 */ 26065 transports = {}, 26066 26067 // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression 26068 allTypes = "*/".concat( "*" ), 26069 26070 // Anchor tag for parsing the document origin 26071 originAnchor = document.createElement( "a" ); 26072 26073originAnchor.href = location.href; 26074 26075// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport 26076function addToPrefiltersOrTransports( structure ) { 26077 26078 // dataTypeExpression is optional and defaults to "*" 26079 return function( dataTypeExpression, func ) { 26080 26081 if ( typeof dataTypeExpression !== "string" ) { 26082 func = dataTypeExpression; 26083 dataTypeExpression = "*"; 26084 } 26085 26086 var dataType, 26087 i = 0, 26088 dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; 26089 26090 if ( isFunction( func ) ) { 26091 26092 // For each dataType in the dataTypeExpression 26093 while ( ( dataType = dataTypes[ i++ ] ) ) { 26094 26095 // Prepend if requested 26096 if ( dataType[ 0 ] === "+" ) { 26097 dataType = dataType.slice( 1 ) || "*"; 26098 ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); 26099 26100 // Otherwise append 26101 } else { 26102 ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); 26103 } 26104 } 26105 } 26106 }; 26107} 26108 26109// Base inspection function for prefilters and transports 26110function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { 26111 26112 var inspected = {}, 26113 seekingTransport = ( structure === transports ); 26114 26115 function inspect( dataType ) { 26116 var selected; 26117 inspected[ dataType ] = true; 26118 jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { 26119 var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); 26120 if ( typeof dataTypeOrTransport === "string" && 26121 !seekingTransport && !inspected[ dataTypeOrTransport ] ) { 26122 26123 options.dataTypes.unshift( dataTypeOrTransport ); 26124 inspect( dataTypeOrTransport ); 26125 return false; 26126 } else if ( seekingTransport ) { 26127 return !( selected = dataTypeOrTransport ); 26128 } 26129 } ); 26130 return selected; 26131 } 26132 26133 return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); 26134} 26135 26136// A special extend for ajax options 26137// that takes "flat" options (not to be deep extended) 26138// Fixes #9887 26139function ajaxExtend( target, src ) { 26140 var key, deep, 26141 flatOptions = jQuery.ajaxSettings.flatOptions || {}; 26142 26143 for ( key in src ) { 26144 if ( src[ key ] !== undefined ) { 26145 ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; 26146 } 26147 } 26148 if ( deep ) { 26149 jQuery.extend( true, target, deep ); 26150 } 26151 26152 return target; 26153} 26154 26155/* Handles responses to an ajax request: 26156 * - finds the right dataType (mediates between content-type and expected dataType) 26157 * - returns the corresponding response 26158 */ 26159function ajaxHandleResponses( s, jqXHR, responses ) { 26160 26161 var ct, type, finalDataType, firstDataType, 26162 contents = s.contents, 26163 dataTypes = s.dataTypes; 26164 26165 // Remove auto dataType and get content-type in the process 26166 while ( dataTypes[ 0 ] === "*" ) { 26167 dataTypes.shift(); 26168 if ( ct === undefined ) { 26169 ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); 26170 } 26171 } 26172 26173 // Check if we're dealing with a known content-type 26174 if ( ct ) { 26175 for ( type in contents ) { 26176 if ( contents[ type ] && contents[ type ].test( ct ) ) { 26177 dataTypes.unshift( type ); 26178 break; 26179 } 26180 } 26181 } 26182 26183 // Check to see if we have a response for the expected dataType 26184 if ( dataTypes[ 0 ] in responses ) { 26185 finalDataType = dataTypes[ 0 ]; 26186 } else { 26187 26188 // Try convertible dataTypes 26189 for ( type in responses ) { 26190 if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { 26191 finalDataType = type; 26192 break; 26193 } 26194 if ( !firstDataType ) { 26195 firstDataType = type; 26196 } 26197 } 26198 26199 // Or just use first one 26200 finalDataType = finalDataType || firstDataType; 26201 } 26202 26203 // If we found a dataType 26204 // We add the dataType to the list if needed 26205 // and return the corresponding response 26206 if ( finalDataType ) { 26207 if ( finalDataType !== dataTypes[ 0 ] ) { 26208 dataTypes.unshift( finalDataType ); 26209 } 26210 return responses[ finalDataType ]; 26211 } 26212} 26213 26214/* Chain conversions given the request and the original response 26215 * Also sets the responseXXX fields on the jqXHR instance 26216 */ 26217function ajaxConvert( s, response, jqXHR, isSuccess ) { 26218 var conv2, current, conv, tmp, prev, 26219 converters = {}, 26220 26221 // Work with a copy of dataTypes in case we need to modify it for conversion 26222 dataTypes = s.dataTypes.slice(); 26223 26224 // Create converters map with lowercased keys 26225 if ( dataTypes[ 1 ] ) { 26226 for ( conv in s.converters ) { 26227 converters[ conv.toLowerCase() ] = s.converters[ conv ]; 26228 } 26229 } 26230 26231 current = dataTypes.shift(); 26232 26233 // Convert to each sequential dataType 26234 while ( current ) { 26235 26236 if ( s.responseFields[ current ] ) { 26237 jqXHR[ s.responseFields[ current ] ] = response; 26238 } 26239 26240 // Apply the dataFilter if provided 26241 if ( !prev && isSuccess && s.dataFilter ) { 26242 response = s.dataFilter( response, s.dataType ); 26243 } 26244 26245 prev = current; 26246 current = dataTypes.shift(); 26247 26248 if ( current ) { 26249 26250 // There's only work to do if current dataType is non-auto 26251 if ( current === "*" ) { 26252 26253 current = prev; 26254 26255 // Convert response if prev dataType is non-auto and differs from current 26256 } else if ( prev !== "*" && prev !== current ) { 26257 26258 // Seek a direct converter 26259 conv = converters[ prev + " " + current ] || converters[ "* " + current ]; 26260 26261 // If none found, seek a pair 26262 if ( !conv ) { 26263 for ( conv2 in converters ) { 26264 26265 // If conv2 outputs current 26266 tmp = conv2.split( " " ); 26267 if ( tmp[ 1 ] === current ) { 26268 26269 // If prev can be converted to accepted input 26270 conv = converters[ prev + " " + tmp[ 0 ] ] || 26271 converters[ "* " + tmp[ 0 ] ]; 26272 if ( conv ) { 26273 26274 // Condense equivalence converters 26275 if ( conv === true ) { 26276 conv = converters[ conv2 ]; 26277 26278 // Otherwise, insert the intermediate dataType 26279 } else if ( converters[ conv2 ] !== true ) { 26280 current = tmp[ 0 ]; 26281 dataTypes.unshift( tmp[ 1 ] ); 26282 } 26283 break; 26284 } 26285 } 26286 } 26287 } 26288 26289 // Apply converter (if not an equivalence) 26290 if ( conv !== true ) { 26291 26292 // Unless errors are allowed to bubble, catch and return them 26293 if ( conv && s.throws ) { 26294 response = conv( response ); 26295 } else { 26296 try { 26297 response = conv( response ); 26298 } catch ( e ) { 26299 return { 26300 state: "parsererror", 26301 error: conv ? e : "No conversion from " + prev + " to " + current 26302 }; 26303 } 26304 } 26305 } 26306 } 26307 } 26308 } 26309 26310 return { state: "success", data: response }; 26311} 26312 26313jQuery.extend( { 26314 26315 // Counter for holding the number of active queries 26316 active: 0, 26317 26318 // Last-Modified header cache for next request 26319 lastModified: {}, 26320 etag: {}, 26321 26322 ajaxSettings: { 26323 url: location.href, 26324 type: "GET", 26325 isLocal: rlocalProtocol.test( location.protocol ), 26326 global: true, 26327 processData: true, 26328 async: true, 26329 contentType: "application/x-www-form-urlencoded; charset=UTF-8", 26330 26331 /* 26332 timeout: 0, 26333 data: null, 26334 dataType: null, 26335 username: null, 26336 password: null, 26337 cache: null, 26338 throws: false, 26339 traditional: false, 26340 headers: {}, 26341 */ 26342 26343 accepts: { 26344 "*": allTypes, 26345 text: "text/plain", 26346 html: "text/html", 26347 xml: "application/xml, text/xml", 26348 json: "application/json, text/javascript" 26349 }, 26350 26351 contents: { 26352 xml: /\bxml\b/, 26353 html: /\bhtml/, 26354 json: /\bjson\b/ 26355 }, 26356 26357 responseFields: { 26358 xml: "responseXML", 26359 text: "responseText", 26360 json: "responseJSON" 26361 }, 26362 26363 // Data converters 26364 // Keys separate source (or catchall "*") and destination types with a single space 26365 converters: { 26366 26367 // Convert anything to text 26368 "* text": String, 26369 26370 // Text to html (true = no transformation) 26371 "text html": true, 26372 26373 // Evaluate text as a json expression 26374 "text json": JSON.parse, 26375 26376 // Parse text as xml 26377 "text xml": jQuery.parseXML 26378 }, 26379 26380 // For options that shouldn't be deep extended: 26381 // you can add your own custom options here if 26382 // and when you create one that shouldn't be 26383 // deep extended (see ajaxExtend) 26384 flatOptions: { 26385 url: true, 26386 context: true 26387 } 26388 }, 26389 26390 // Creates a full fledged settings object into target 26391 // with both ajaxSettings and settings fields. 26392 // If target is omitted, writes into ajaxSettings. 26393 ajaxSetup: function( target, settings ) { 26394 return settings ? 26395 26396 // Building a settings object 26397 ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : 26398 26399 // Extending ajaxSettings 26400 ajaxExtend( jQuery.ajaxSettings, target ); 26401 }, 26402 26403 ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), 26404 ajaxTransport: addToPrefiltersOrTransports( transports ), 26405 26406 // Main method 26407 ajax: function( url, options ) { 26408 26409 // If url is an object, simulate pre-1.5 signature 26410 if ( typeof url === "object" ) { 26411 options = url; 26412 url = undefined; 26413 } 26414 26415 // Force options to be an object 26416 options = options || {}; 26417 26418 var transport, 26419 26420 // URL without anti-cache param 26421 cacheURL, 26422 26423 // Response headers 26424 responseHeadersString, 26425 responseHeaders, 26426 26427 // timeout handle 26428 timeoutTimer, 26429 26430 // Url cleanup var 26431 urlAnchor, 26432 26433 // Request state (becomes false upon send and true upon completion) 26434 completed, 26435 26436 // To know if global events are to be dispatched 26437 fireGlobals, 26438 26439 // Loop variable 26440 i, 26441 26442 // uncached part of the url 26443 uncached, 26444 26445 // Create the final options object 26446 s = jQuery.ajaxSetup( {}, options ), 26447 26448 // Callbacks context 26449 callbackContext = s.context || s, 26450 26451 // Context for global events is callbackContext if it is a DOM node or jQuery collection 26452 globalEventContext = s.context && 26453 ( callbackContext.nodeType || callbackContext.jquery ) ? 26454 jQuery( callbackContext ) : 26455 jQuery.event, 26456 26457 // Deferreds 26458 deferred = jQuery.Deferred(), 26459 completeDeferred = jQuery.Callbacks( "once memory" ), 26460 26461 // Status-dependent callbacks 26462 statusCode = s.statusCode || {}, 26463 26464 // Headers (they are sent all at once) 26465 requestHeaders = {}, 26466 requestHeadersNames = {}, 26467 26468 // Default abort message 26469 strAbort = "canceled", 26470 26471 // Fake xhr 26472 jqXHR = { 26473 readyState: 0, 26474 26475 // Builds headers hashtable if needed 26476 getResponseHeader: function( key ) { 26477 var match; 26478 if ( completed ) { 26479 if ( !responseHeaders ) { 26480 responseHeaders = {}; 26481 while ( ( match = rheaders.exec( responseHeadersString ) ) ) { 26482 responseHeaders[ match[ 1 ].toLowerCase() + " " ] = 26483 ( responseHeaders[ match[ 1 ].toLowerCase() + " " ] || [] ) 26484 .concat( match[ 2 ] ); 26485 } 26486 } 26487 match = responseHeaders[ key.toLowerCase() + " " ]; 26488 } 26489 return match == null ? null : match.join( ", " ); 26490 }, 26491 26492 // Raw string 26493 getAllResponseHeaders: function() { 26494 return completed ? responseHeadersString : null; 26495 }, 26496 26497 // Caches the header 26498 setRequestHeader: function( name, value ) { 26499 if ( completed == null ) { 26500 name = requestHeadersNames[ name.toLowerCase() ] = 26501 requestHeadersNames[ name.toLowerCase() ] || name; 26502 requestHeaders[ name ] = value; 26503 } 26504 return this; 26505 }, 26506 26507 // Overrides response content-type header 26508 overrideMimeType: function( type ) { 26509 if ( completed == null ) { 26510 s.mimeType = type; 26511 } 26512 return this; 26513 }, 26514 26515 // Status-dependent callbacks 26516 statusCode: function( map ) { 26517 var code; 26518 if ( map ) { 26519 if ( completed ) { 26520 26521 // Execute the appropriate callbacks 26522 jqXHR.always( map[ jqXHR.status ] ); 26523 } else { 26524 26525 // Lazy-add the new callbacks in a way that preserves old ones 26526 for ( code in map ) { 26527 statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; 26528 } 26529 } 26530 } 26531 return this; 26532 }, 26533 26534 // Cancel the request 26535 abort: function( statusText ) { 26536 var finalText = statusText || strAbort; 26537 if ( transport ) { 26538 transport.abort( finalText ); 26539 } 26540 done( 0, finalText ); 26541 return this; 26542 } 26543 }; 26544 26545 // Attach deferreds 26546 deferred.promise( jqXHR ); 26547 26548 // Add protocol if not provided (prefilters might expect it) 26549 // Handle falsy url in the settings object (#10093: consistency with old signature) 26550 // We also use the url parameter if available 26551 s.url = ( ( url || s.url || location.href ) + "" ) 26552 .replace( rprotocol, location.protocol + "//" ); 26553 26554 // Alias method option to type as per ticket #12004 26555 s.type = options.method || options.type || s.method || s.type; 26556 26557 // Extract dataTypes list 26558 s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; 26559 26560 // A cross-domain request is in order when the origin doesn't match the current origin. 26561 if ( s.crossDomain == null ) { 26562 urlAnchor = document.createElement( "a" ); 26563 26564 // Support: IE <=8 - 11, Edge 12 - 15 26565 // IE throws exception on accessing the href property if url is malformed, 26566 // e.g. http://example.com:80x/ 26567 try { 26568 urlAnchor.href = s.url; 26569 26570 // Support: IE <=8 - 11 only 26571 // Anchor's host property isn't correctly set when s.url is relative 26572 urlAnchor.href = urlAnchor.href; 26573 s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== 26574 urlAnchor.protocol + "//" + urlAnchor.host; 26575 } catch ( e ) { 26576 26577 // If there is an error parsing the URL, assume it is crossDomain, 26578 // it can be rejected by the transport if it is invalid 26579 s.crossDomain = true; 26580 } 26581 } 26582 26583 // Convert data if not already a string 26584 if ( s.data && s.processData && typeof s.data !== "string" ) { 26585 s.data = jQuery.param( s.data, s.traditional ); 26586 } 26587 26588 // Apply prefilters 26589 inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); 26590 26591 // If request was aborted inside a prefilter, stop there 26592 if ( completed ) { 26593 return jqXHR; 26594 } 26595 26596 // We can fire global events as of now if asked to 26597 // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) 26598 fireGlobals = jQuery.event && s.global; 26599 26600 // Watch for a new set of requests 26601 if ( fireGlobals && jQuery.active++ === 0 ) { 26602 jQuery.event.trigger( "ajaxStart" ); 26603 } 26604 26605 // Uppercase the type 26606 s.type = s.type.toUpperCase(); 26607 26608 // Determine if request has content 26609 s.hasContent = !rnoContent.test( s.type ); 26610 26611 // Save the URL in case we're toying with the If-Modified-Since 26612 // and/or If-None-Match header later on 26613 // Remove hash to simplify url manipulation 26614 cacheURL = s.url.replace( rhash, "" ); 26615 26616 // More options handling for requests with no content 26617 if ( !s.hasContent ) { 26618 26619 // Remember the hash so we can put it back 26620 uncached = s.url.slice( cacheURL.length ); 26621 26622 // If data is available and should be processed, append data to url 26623 if ( s.data && ( s.processData || typeof s.data === "string" ) ) { 26624 cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; 26625 26626 // #9682: remove data so that it's not used in an eventual retry 26627 delete s.data; 26628 } 26629 26630 // Add or update anti-cache param if needed 26631 if ( s.cache === false ) { 26632 cacheURL = cacheURL.replace( rantiCache, "$1" ); 26633 uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce.guid++ ) + 26634 uncached; 26635 } 26636 26637 // Put hash and anti-cache on the URL that will be requested (gh-1732) 26638 s.url = cacheURL + uncached; 26639 26640 // Change '%20' to '+' if this is encoded form body content (gh-2658) 26641 } else if ( s.data && s.processData && 26642 ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { 26643 s.data = s.data.replace( r20, "+" ); 26644 } 26645 26646 // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. 26647 if ( s.ifModified ) { 26648 if ( jQuery.lastModified[ cacheURL ] ) { 26649 jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); 26650 } 26651 if ( jQuery.etag[ cacheURL ] ) { 26652 jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); 26653 } 26654 } 26655 26656 // Set the correct header, if data is being sent 26657 if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { 26658 jqXHR.setRequestHeader( "Content-Type", s.contentType ); 26659 } 26660 26661 // Set the Accepts header for the server, depending on the dataType 26662 jqXHR.setRequestHeader( 26663 "Accept", 26664 s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? 26665 s.accepts[ s.dataTypes[ 0 ] ] + 26666 ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : 26667 s.accepts[ "*" ] 26668 ); 26669 26670 // Check for headers option 26671 for ( i in s.headers ) { 26672 jqXHR.setRequestHeader( i, s.headers[ i ] ); 26673 } 26674 26675 // Allow custom headers/mimetypes and early abort 26676 if ( s.beforeSend && 26677 ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { 26678 26679 // Abort if not done already and return 26680 return jqXHR.abort(); 26681 } 26682 26683 // Aborting is no longer a cancellation 26684 strAbort = "abort"; 26685 26686 // Install callbacks on deferreds 26687 completeDeferred.add( s.complete ); 26688 jqXHR.done( s.success ); 26689 jqXHR.fail( s.error ); 26690 26691 // Get transport 26692 transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); 26693 26694 // If no transport, we auto-abort 26695 if ( !transport ) { 26696 done( -1, "No Transport" ); 26697 } else { 26698 jqXHR.readyState = 1; 26699 26700 // Send global event 26701 if ( fireGlobals ) { 26702 globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); 26703 } 26704 26705 // If request was aborted inside ajaxSend, stop there 26706 if ( completed ) { 26707 return jqXHR; 26708 } 26709 26710 // Timeout 26711 if ( s.async && s.timeout > 0 ) { 26712 timeoutTimer = window.setTimeout( function() { 26713 jqXHR.abort( "timeout" ); 26714 }, s.timeout ); 26715 } 26716 26717 try { 26718 completed = false; 26719 transport.send( requestHeaders, done ); 26720 } catch ( e ) { 26721 26722 // Rethrow post-completion exceptions 26723 if ( completed ) { 26724 throw e; 26725 } 26726 26727 // Propagate others as results 26728 done( -1, e ); 26729 } 26730 } 26731 26732 // Callback for when everything is done 26733 function done( status, nativeStatusText, responses, headers ) { 26734 var isSuccess, success, error, response, modified, 26735 statusText = nativeStatusText; 26736 26737 // Ignore repeat invocations 26738 if ( completed ) { 26739 return; 26740 } 26741 26742 completed = true; 26743 26744 // Clear timeout if it exists 26745 if ( timeoutTimer ) { 26746 window.clearTimeout( timeoutTimer ); 26747 } 26748 26749 // Dereference transport for early garbage collection 26750 // (no matter how long the jqXHR object will be used) 26751 transport = undefined; 26752 26753 // Cache response headers 26754 responseHeadersString = headers || ""; 26755 26756 // Set readyState 26757 jqXHR.readyState = status > 0 ? 4 : 0; 26758 26759 // Determine if successful 26760 isSuccess = status >= 200 && status < 300 || status === 304; 26761 26762 // Get response data 26763 if ( responses ) { 26764 response = ajaxHandleResponses( s, jqXHR, responses ); 26765 } 26766 26767 // Use a noop converter for missing script but not if jsonp 26768 if ( !isSuccess && 26769 jQuery.inArray( "script", s.dataTypes ) > -1 && 26770 jQuery.inArray( "json", s.dataTypes ) < 0 ) { 26771 s.converters[ "text script" ] = function() {}; 26772 } 26773 26774 // Convert no matter what (that way responseXXX fields are always set) 26775 response = ajaxConvert( s, response, jqXHR, isSuccess ); 26776 26777 // If successful, handle type chaining 26778 if ( isSuccess ) { 26779 26780 // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. 26781 if ( s.ifModified ) { 26782 modified = jqXHR.getResponseHeader( "Last-Modified" ); 26783 if ( modified ) { 26784 jQuery.lastModified[ cacheURL ] = modified; 26785 } 26786 modified = jqXHR.getResponseHeader( "etag" ); 26787 if ( modified ) { 26788 jQuery.etag[ cacheURL ] = modified; 26789 } 26790 } 26791 26792 // if no content 26793 if ( status === 204 || s.type === "HEAD" ) { 26794 statusText = "nocontent"; 26795 26796 // if not modified 26797 } else if ( status === 304 ) { 26798 statusText = "notmodified"; 26799 26800 // If we have data, let's convert it 26801 } else { 26802 statusText = response.state; 26803 success = response.data; 26804 error = response.error; 26805 isSuccess = !error; 26806 } 26807 } else { 26808 26809 // Extract error from statusText and normalize for non-aborts 26810 error = statusText; 26811 if ( status || !statusText ) { 26812 statusText = "error"; 26813 if ( status < 0 ) { 26814 status = 0; 26815 } 26816 } 26817 } 26818 26819 // Set data for the fake xhr object 26820 jqXHR.status = status; 26821 jqXHR.statusText = ( nativeStatusText || statusText ) + ""; 26822 26823 // Success/Error 26824 if ( isSuccess ) { 26825 deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); 26826 } else { 26827 deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); 26828 } 26829 26830 // Status-dependent callbacks 26831 jqXHR.statusCode( statusCode ); 26832 statusCode = undefined; 26833 26834 if ( fireGlobals ) { 26835 globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", 26836 [ jqXHR, s, isSuccess ? success : error ] ); 26837 } 26838 26839 // Complete 26840 completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); 26841 26842 if ( fireGlobals ) { 26843 globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); 26844 26845 // Handle the global AJAX counter 26846 if ( !( --jQuery.active ) ) { 26847 jQuery.event.trigger( "ajaxStop" ); 26848 } 26849 } 26850 } 26851 26852 return jqXHR; 26853 }, 26854 26855 getJSON: function( url, data, callback ) { 26856 return jQuery.get( url, data, callback, "json" ); 26857 }, 26858 26859 getScript: function( url, callback ) { 26860 return jQuery.get( url, undefined, callback, "script" ); 26861 } 26862} ); 26863 26864jQuery.each( [ "get", "post" ], function( _i, method ) { 26865 jQuery[ method ] = function( url, data, callback, type ) { 26866 26867 // Shift arguments if data argument was omitted 26868 if ( isFunction( data ) ) { 26869 type = type || callback; 26870 callback = data; 26871 data = undefined; 26872 } 26873 26874 // The url can be an options object (which then must have .url) 26875 return jQuery.ajax( jQuery.extend( { 26876 url: url, 26877 type: method, 26878 dataType: type, 26879 data: data, 26880 success: callback 26881 }, jQuery.isPlainObject( url ) && url ) ); 26882 }; 26883} ); 26884 26885jQuery.ajaxPrefilter( function( s ) { 26886 var i; 26887 for ( i in s.headers ) { 26888 if ( i.toLowerCase() === "content-type" ) { 26889 s.contentType = s.headers[ i ] || ""; 26890 } 26891 } 26892} ); 26893 26894 26895jQuery._evalUrl = function( url, options, doc ) { 26896 return jQuery.ajax( { 26897 url: url, 26898 26899 // Make this explicit, since user can override this through ajaxSetup (#11264) 26900 type: "GET", 26901 dataType: "script", 26902 cache: true, 26903 async: false, 26904 global: false, 26905 26906 // Only evaluate the response if it is successful (gh-4126) 26907 // dataFilter is not invoked for failure responses, so using it instead 26908 // of the default converter is kludgy but it works. 26909 converters: { 26910 "text script": function() {} 26911 }, 26912 dataFilter: function( response ) { 26913 jQuery.globalEval( response, options, doc ); 26914 } 26915 } ); 26916}; 26917 26918 26919jQuery.fn.extend( { 26920 wrapAll: function( html ) { 26921 var wrap; 26922 26923 if ( this[ 0 ] ) { 26924 if ( isFunction( html ) ) { 26925 html = html.call( this[ 0 ] ); 26926 } 26927 26928 // The elements to wrap the target around 26929 wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); 26930 26931 if ( this[ 0 ].parentNode ) { 26932 wrap.insertBefore( this[ 0 ] ); 26933 } 26934 26935 wrap.map( function() { 26936 var elem = this; 26937 26938 while ( elem.firstElementChild ) { 26939 elem = elem.firstElementChild; 26940 } 26941 26942 return elem; 26943 } ).append( this ); 26944 } 26945 26946 return this; 26947 }, 26948 26949 wrapInner: function( html ) { 26950 if ( isFunction( html ) ) { 26951 return this.each( function( i ) { 26952 jQuery( this ).wrapInner( html.call( this, i ) ); 26953 } ); 26954 } 26955 26956 return this.each( function() { 26957 var self = jQuery( this ), 26958 contents = self.contents(); 26959 26960 if ( contents.length ) { 26961 contents.wrapAll( html ); 26962 26963 } else { 26964 self.append( html ); 26965 } 26966 } ); 26967 }, 26968 26969 wrap: function( html ) { 26970 var htmlIsFunction = isFunction( html ); 26971 26972 return this.each( function( i ) { 26973 jQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html ); 26974 } ); 26975 }, 26976 26977 unwrap: function( selector ) { 26978 this.parent( selector ).not( "body" ).each( function() { 26979 jQuery( this ).replaceWith( this.childNodes ); 26980 } ); 26981 return this; 26982 } 26983} ); 26984 26985 26986jQuery.expr.pseudos.hidden = function( elem ) { 26987 return !jQuery.expr.pseudos.visible( elem ); 26988}; 26989jQuery.expr.pseudos.visible = function( elem ) { 26990 return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); 26991}; 26992 26993 26994 26995 26996jQuery.ajaxSettings.xhr = function() { 26997 try { 26998 return new window.XMLHttpRequest(); 26999 } catch ( e ) {} 27000}; 27001 27002var xhrSuccessStatus = { 27003 27004 // File protocol always yields status code 0, assume 200 27005 0: 200, 27006 27007 // Support: IE <=9 only 27008 // #1450: sometimes IE returns 1223 when it should be 204 27009 1223: 204 27010 }, 27011 xhrSupported = jQuery.ajaxSettings.xhr(); 27012 27013support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); 27014support.ajax = xhrSupported = !!xhrSupported; 27015 27016jQuery.ajaxTransport( function( options ) { 27017 var callback, errorCallback; 27018 27019 // Cross domain only allowed if supported through XMLHttpRequest 27020 if ( support.cors || xhrSupported && !options.crossDomain ) { 27021 return { 27022 send: function( headers, complete ) { 27023 var i, 27024 xhr = options.xhr(); 27025 27026 xhr.open( 27027 options.type, 27028 options.url, 27029 options.async, 27030 options.username, 27031 options.password 27032 ); 27033 27034 // Apply custom fields if provided 27035 if ( options.xhrFields ) { 27036 for ( i in options.xhrFields ) { 27037 xhr[ i ] = options.xhrFields[ i ]; 27038 } 27039 } 27040 27041 // Override mime type if needed 27042 if ( options.mimeType && xhr.overrideMimeType ) { 27043 xhr.overrideMimeType( options.mimeType ); 27044 } 27045 27046 // X-Requested-With header 27047 // For cross-domain requests, seeing as conditions for a preflight are 27048 // akin to a jigsaw puzzle, we simply never set it to be sure. 27049 // (it can always be set on a per-request basis or even using ajaxSetup) 27050 // For same-domain requests, won't change header if already provided. 27051 if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { 27052 headers[ "X-Requested-With" ] = "XMLHttpRequest"; 27053 } 27054 27055 // Set headers 27056 for ( i in headers ) { 27057 xhr.setRequestHeader( i, headers[ i ] ); 27058 } 27059 27060 // Callback 27061 callback = function( type ) { 27062 return function() { 27063 if ( callback ) { 27064 callback = errorCallback = xhr.onload = 27065 xhr.onerror = xhr.onabort = xhr.ontimeout = 27066 xhr.onreadystatechange = null; 27067 27068 if ( type === "abort" ) { 27069 xhr.abort(); 27070 } else if ( type === "error" ) { 27071 27072 // Support: IE <=9 only 27073 // On a manual native abort, IE9 throws 27074 // errors on any property access that is not readyState 27075 if ( typeof xhr.status !== "number" ) { 27076 complete( 0, "error" ); 27077 } else { 27078 complete( 27079 27080 // File: protocol always yields status 0; see #8605, #14207 27081 xhr.status, 27082 xhr.statusText 27083 ); 27084 } 27085 } else { 27086 complete( 27087 xhrSuccessStatus[ xhr.status ] || xhr.status, 27088 xhr.statusText, 27089 27090 // Support: IE <=9 only 27091 // IE9 has no XHR2 but throws on binary (trac-11426) 27092 // For XHR2 non-text, let the caller handle it (gh-2498) 27093 ( xhr.responseType || "text" ) !== "text" || 27094 typeof xhr.responseText !== "string" ? 27095 { binary: xhr.response } : 27096 { text: xhr.responseText }, 27097 xhr.getAllResponseHeaders() 27098 ); 27099 } 27100 } 27101 }; 27102 }; 27103 27104 // Listen to events 27105 xhr.onload = callback(); 27106 errorCallback = xhr.onerror = xhr.ontimeout = callback( "error" ); 27107 27108 // Support: IE 9 only 27109 // Use onreadystatechange to replace onabort 27110 // to handle uncaught aborts 27111 if ( xhr.onabort !== undefined ) { 27112 xhr.onabort = errorCallback; 27113 } else { 27114 xhr.onreadystatechange = function() { 27115 27116 // Check readyState before timeout as it changes 27117 if ( xhr.readyState === 4 ) { 27118 27119 // Allow onerror to be called first, 27120 // but that will not handle a native abort 27121 // Also, save errorCallback to a variable 27122 // as xhr.onerror cannot be accessed 27123 window.setTimeout( function() { 27124 if ( callback ) { 27125 errorCallback(); 27126 } 27127 } ); 27128 } 27129 }; 27130 } 27131 27132 // Create the abort callback 27133 callback = callback( "abort" ); 27134 27135 try { 27136 27137 // Do send the request (this may raise an exception) 27138 xhr.send( options.hasContent && options.data || null ); 27139 } catch ( e ) { 27140 27141 // #14683: Only rethrow if this hasn't been notified as an error yet 27142 if ( callback ) { 27143 throw e; 27144 } 27145 } 27146 }, 27147 27148 abort: function() { 27149 if ( callback ) { 27150 callback(); 27151 } 27152 } 27153 }; 27154 } 27155} ); 27156 27157 27158 27159 27160// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) 27161jQuery.ajaxPrefilter( function( s ) { 27162 if ( s.crossDomain ) { 27163 s.contents.script = false; 27164 } 27165} ); 27166 27167// Install script dataType 27168jQuery.ajaxSetup( { 27169 accepts: { 27170 script: "text/javascript, application/javascript, " + 27171 "application/ecmascript, application/x-ecmascript" 27172 }, 27173 contents: { 27174 script: /\b(?:java|ecma)script\b/ 27175 }, 27176 converters: { 27177 "text script": function( text ) { 27178 jQuery.globalEval( text ); 27179 return text; 27180 } 27181 } 27182} ); 27183 27184// Handle cache's special case and crossDomain 27185jQuery.ajaxPrefilter( "script", function( s ) { 27186 if ( s.cache === undefined ) { 27187 s.cache = false; 27188 } 27189 if ( s.crossDomain ) { 27190 s.type = "GET"; 27191 } 27192} ); 27193 27194// Bind script tag hack transport 27195jQuery.ajaxTransport( "script", function( s ) { 27196 27197 // This transport only deals with cross domain or forced-by-attrs requests 27198 if ( s.crossDomain || s.scriptAttrs ) { 27199 var script, callback; 27200 return { 27201 send: function( _, complete ) { 27202 script = jQuery( "<script>" ) 27203 .attr( s.scriptAttrs || {} ) 27204 .prop( { charset: s.scriptCharset, src: s.url } ) 27205 .on( "load error", callback = function( evt ) { 27206 script.remove(); 27207 callback = null; 27208 if ( evt ) { 27209 complete( evt.type === "error" ? 404 : 200, evt.type ); 27210 } 27211 } ); 27212 27213 // Use native DOM manipulation to avoid our domManip AJAX trickery 27214 document.head.appendChild( script[ 0 ] ); 27215 }, 27216 abort: function() { 27217 if ( callback ) { 27218 callback(); 27219 } 27220 } 27221 }; 27222 } 27223} ); 27224 27225 27226 27227 27228var oldCallbacks = [], 27229 rjsonp = /(=)\?(?=&|$)|\?\?/; 27230 27231// Default jsonp settings 27232jQuery.ajaxSetup( { 27233 jsonp: "callback", 27234 jsonpCallback: function() { 27235 var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce.guid++ ) ); 27236 this[ callback ] = true; 27237 return callback; 27238 } 27239} ); 27240 27241// Detect, normalize options and install callbacks for jsonp requests 27242jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { 27243 27244 var callbackName, overwritten, responseContainer, 27245 jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ? 27246 "url" : 27247 typeof s.data === "string" && 27248 ( s.contentType || "" ) 27249 .indexOf( "application/x-www-form-urlencoded" ) === 0 && 27250 rjsonp.test( s.data ) && "data" 27251 ); 27252 27253 // Handle iff the expected data type is "jsonp" or we have a parameter to set 27254 if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) { 27255 27256 // Get callback name, remembering preexisting value associated with it 27257 callbackName = s.jsonpCallback = isFunction( s.jsonpCallback ) ? 27258 s.jsonpCallback() : 27259 s.jsonpCallback; 27260 27261 // Insert callback into url or form data 27262 if ( jsonProp ) { 27263 s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName ); 27264 } else if ( s.jsonp !== false ) { 27265 s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName; 27266 } 27267 27268 // Use data converter to retrieve json after script execution 27269 s.converters[ "script json" ] = function() { 27270 if ( !responseContainer ) { 27271 jQuery.error( callbackName + " was not called" ); 27272 } 27273 return responseContainer[ 0 ]; 27274 }; 27275 27276 // Force json dataType 27277 s.dataTypes[ 0 ] = "json"; 27278 27279 // Install callback 27280 overwritten = window[ callbackName ]; 27281 window[ callbackName ] = function() { 27282 responseContainer = arguments; 27283 }; 27284 27285 // Clean-up function (fires after converters) 27286 jqXHR.always( function() { 27287 27288 // If previous value didn't exist - remove it 27289 if ( overwritten === undefined ) { 27290 jQuery( window ).removeProp( callbackName ); 27291 27292 // Otherwise restore preexisting value 27293 } else { 27294 window[ callbackName ] = overwritten; 27295 } 27296 27297 // Save back as free 27298 if ( s[ callbackName ] ) { 27299 27300 // Make sure that re-using the options doesn't screw things around 27301 s.jsonpCallback = originalSettings.jsonpCallback; 27302 27303 // Save the callback name for future use 27304 oldCallbacks.push( callbackName ); 27305 } 27306 27307 // Call if it was a function and we have a response 27308 if ( responseContainer && isFunction( overwritten ) ) { 27309 overwritten( responseContainer[ 0 ] ); 27310 } 27311 27312 responseContainer = overwritten = undefined; 27313 } ); 27314 27315 // Delegate to script 27316 return "script"; 27317 } 27318} ); 27319 27320 27321 27322 27323// Support: Safari 8 only 27324// In Safari 8 documents created via document.implementation.createHTMLDocument 27325// collapse sibling forms: the second one becomes a child of the first one. 27326// Because of that, this security measure has to be disabled in Safari 8. 27327// https://bugs.webkit.org/show_bug.cgi?id=137337 27328support.createHTMLDocument = ( function() { 27329 var body = document.implementation.createHTMLDocument( "" ).body; 27330 body.innerHTML = "<form></form><form></form>"; 27331 return body.childNodes.length === 2; 27332} )(); 27333 27334 27335// Argument "data" should be string of html 27336// context (optional): If specified, the fragment will be created in this context, 27337// defaults to document 27338// keepScripts (optional): If true, will include scripts passed in the html string 27339jQuery.parseHTML = function( data, context, keepScripts ) { 27340 if ( typeof data !== "string" ) { 27341 return []; 27342 } 27343 if ( typeof context === "boolean" ) { 27344 keepScripts = context; 27345 context = false; 27346 } 27347 27348 var base, parsed, scripts; 27349 27350 if ( !context ) { 27351 27352 // Stop scripts or inline event handlers from being executed immediately 27353 // by using document.implementation 27354 if ( support.createHTMLDocument ) { 27355 context = document.implementation.createHTMLDocument( "" ); 27356 27357 // Set the base href for the created document 27358 // so any parsed elements with URLs 27359 // are based on the document's URL (gh-2965) 27360 base = context.createElement( "base" ); 27361 base.href = document.location.href; 27362 context.head.appendChild( base ); 27363 } else { 27364 context = document; 27365 } 27366 } 27367 27368 parsed = rsingleTag.exec( data ); 27369 scripts = !keepScripts && []; 27370 27371 // Single tag 27372 if ( parsed ) { 27373 return [ context.createElement( parsed[ 1 ] ) ]; 27374 } 27375 27376 parsed = buildFragment( [ data ], context, scripts ); 27377 27378 if ( scripts && scripts.length ) { 27379 jQuery( scripts ).remove(); 27380 } 27381 27382 return jQuery.merge( [], parsed.childNodes ); 27383}; 27384 27385 27386/** 27387 * Load a url into a page 27388 */ 27389jQuery.fn.load = function( url, params, callback ) { 27390 var selector, type, response, 27391 self = this, 27392 off = url.indexOf( " " ); 27393 27394 if ( off > -1 ) { 27395 selector = stripAndCollapse( url.slice( off ) ); 27396 url = url.slice( 0, off ); 27397 } 27398 27399 // If it's a function 27400 if ( isFunction( params ) ) { 27401 27402 // We assume that it's the callback 27403 callback = params; 27404 params = undefined; 27405 27406 // Otherwise, build a param string 27407 } else if ( params && typeof params === "object" ) { 27408 type = "POST"; 27409 } 27410 27411 // If we have elements to modify, make the request 27412 if ( self.length > 0 ) { 27413 jQuery.ajax( { 27414 url: url, 27415 27416 // If "type" variable is undefined, then "GET" method will be used. 27417 // Make value of this field explicit since 27418 // user can override it through ajaxSetup method 27419 type: type || "GET", 27420 dataType: "html", 27421 data: params 27422 } ).done( function( responseText ) { 27423 27424 // Save response for use in complete callback 27425 response = arguments; 27426 27427 self.html( selector ? 27428 27429 // If a selector was specified, locate the right elements in a dummy div 27430 // Exclude scripts to avoid IE 'Permission Denied' errors 27431 jQuery( "<div>" ).append( jQuery.parseHTML( responseText ) ).find( selector ) : 27432 27433 // Otherwise use the full result 27434 responseText ); 27435 27436 // If the request succeeds, this function gets "data", "status", "jqXHR" 27437 // but they are ignored because response was set above. 27438 // If it fails, this function gets "jqXHR", "status", "error" 27439 } ).always( callback && function( jqXHR, status ) { 27440 self.each( function() { 27441 callback.apply( this, response || [ jqXHR.responseText, status, jqXHR ] ); 27442 } ); 27443 } ); 27444 } 27445 27446 return this; 27447}; 27448 27449 27450 27451 27452jQuery.expr.pseudos.animated = function( elem ) { 27453 return jQuery.grep( jQuery.timers, function( fn ) { 27454 return elem === fn.elem; 27455 } ).length; 27456}; 27457 27458 27459 27460 27461jQuery.offset = { 27462 setOffset: function( elem, options, i ) { 27463 var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition, 27464 position = jQuery.css( elem, "position" ), 27465 curElem = jQuery( elem ), 27466 props = {}; 27467 27468 // Set position first, in-case top/left are set even on static elem 27469 if ( position === "static" ) { 27470 elem.style.position = "relative"; 27471 } 27472 27473 curOffset = curElem.offset(); 27474 curCSSTop = jQuery.css( elem, "top" ); 27475 curCSSLeft = jQuery.css( elem, "left" ); 27476 calculatePosition = ( position === "absolute" || position === "fixed" ) && 27477 ( curCSSTop + curCSSLeft ).indexOf( "auto" ) > -1; 27478 27479 // Need to be able to calculate position if either 27480 // top or left is auto and position is either absolute or fixed 27481 if ( calculatePosition ) { 27482 curPosition = curElem.position(); 27483 curTop = curPosition.top; 27484 curLeft = curPosition.left; 27485 27486 } else { 27487 curTop = parseFloat( curCSSTop ) || 0; 27488 curLeft = parseFloat( curCSSLeft ) || 0; 27489 } 27490 27491 if ( isFunction( options ) ) { 27492 27493 // Use jQuery.extend here to allow modification of coordinates argument (gh-1848) 27494 options = options.call( elem, i, jQuery.extend( {}, curOffset ) ); 27495 } 27496 27497 if ( options.top != null ) { 27498 props.top = ( options.top - curOffset.top ) + curTop; 27499 } 27500 if ( options.left != null ) { 27501 props.left = ( options.left - curOffset.left ) + curLeft; 27502 } 27503 27504 if ( "using" in options ) { 27505 options.using.call( elem, props ); 27506 27507 } else { 27508 curElem.css( props ); 27509 } 27510 } 27511}; 27512 27513jQuery.fn.extend( { 27514 27515 // offset() relates an element's border box to the document origin 27516 offset: function( options ) { 27517 27518 // Preserve chaining for setter 27519 if ( arguments.length ) { 27520 return options === undefined ? 27521 this : 27522 this.each( function( i ) { 27523 jQuery.offset.setOffset( this, options, i ); 27524 } ); 27525 } 27526 27527 var rect, win, 27528 elem = this[ 0 ]; 27529 27530 if ( !elem ) { 27531 return; 27532 } 27533 27534 // Return zeros for disconnected and hidden (display: none) elements (gh-2310) 27535 // Support: IE <=11 only 27536 // Running getBoundingClientRect on a 27537 // disconnected node in IE throws an error 27538 if ( !elem.getClientRects().length ) { 27539 return { top: 0, left: 0 }; 27540 } 27541 27542 // Get document-relative position by adding viewport scroll to viewport-relative gBCR 27543 rect = elem.getBoundingClientRect(); 27544 win = elem.ownerDocument.defaultView; 27545 return { 27546 top: rect.top + win.pageYOffset, 27547 left: rect.left + win.pageXOffset 27548 }; 27549 }, 27550 27551 // position() relates an element's margin box to its offset parent's padding box 27552 // This corresponds to the behavior of CSS absolute positioning 27553 position: function() { 27554 if ( !this[ 0 ] ) { 27555 return; 27556 } 27557 27558 var offsetParent, offset, doc, 27559 elem = this[ 0 ], 27560 parentOffset = { top: 0, left: 0 }; 27561 27562 // position:fixed elements are offset from the viewport, which itself always has zero offset 27563 if ( jQuery.css( elem, "position" ) === "fixed" ) { 27564 27565 // Assume position:fixed implies availability of getBoundingClientRect 27566 offset = elem.getBoundingClientRect(); 27567 27568 } else { 27569 offset = this.offset(); 27570 27571 // Account for the *real* offset parent, which can be the document or its root element 27572 // when a statically positioned element is identified 27573 doc = elem.ownerDocument; 27574 offsetParent = elem.offsetParent || doc.documentElement; 27575 while ( offsetParent && 27576 ( offsetParent === doc.body || offsetParent === doc.documentElement ) && 27577 jQuery.css( offsetParent, "position" ) === "static" ) { 27578 27579 offsetParent = offsetParent.parentNode; 27580 } 27581 if ( offsetParent && offsetParent !== elem && offsetParent.nodeType === 1 ) { 27582 27583 // Incorporate borders into its offset, since they are outside its content origin 27584 parentOffset = jQuery( offsetParent ).offset(); 27585 parentOffset.top += jQuery.css( offsetParent, "borderTopWidth", true ); 27586 parentOffset.left += jQuery.css( offsetParent, "borderLeftWidth", true ); 27587 } 27588 } 27589 27590 // Subtract parent offsets and element margins 27591 return { 27592 top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ), 27593 left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true ) 27594 }; 27595 }, 27596 27597 // This method will return documentElement in the following cases: 27598 // 1) For the element inside the iframe without offsetParent, this method will return 27599 // documentElement of the parent window 27600 // 2) For the hidden or detached element 27601 // 3) For body or html element, i.e. in case of the html node - it will return itself 27602 // 27603 // but those exceptions were never presented as a real life use-cases 27604 // and might be considered as more preferable results. 27605 // 27606 // This logic, however, is not guaranteed and can change at any point in the future 27607 offsetParent: function() { 27608 return this.map( function() { 27609 var offsetParent = this.offsetParent; 27610 27611 while ( offsetParent && jQuery.css( offsetParent, "position" ) === "static" ) { 27612 offsetParent = offsetParent.offsetParent; 27613 } 27614 27615 return offsetParent || documentElement; 27616 } ); 27617 } 27618} ); 27619 27620// Create scrollLeft and scrollTop methods 27621jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( method, prop ) { 27622 var top = "pageYOffset" === prop; 27623 27624 jQuery.fn[ method ] = function( val ) { 27625 return access( this, function( elem, method, val ) { 27626 27627 // Coalesce documents and windows 27628 var win; 27629 if ( isWindow( elem ) ) { 27630 win = elem; 27631 } else if ( elem.nodeType === 9 ) { 27632 win = elem.defaultView; 27633 } 27634 27635 if ( val === undefined ) { 27636 return win ? win[ prop ] : elem[ method ]; 27637 } 27638 27639 if ( win ) { 27640 win.scrollTo( 27641 !top ? val : win.pageXOffset, 27642 top ? val : win.pageYOffset 27643 ); 27644 27645 } else { 27646 elem[ method ] = val; 27647 } 27648 }, method, val, arguments.length ); 27649 }; 27650} ); 27651 27652// Support: Safari <=7 - 9.1, Chrome <=37 - 49 27653// Add the top/left cssHooks using jQuery.fn.position 27654// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084 27655// Blink bug: https://bugs.chromium.org/p/chromium/issues/detail?id=589347 27656// getComputedStyle returns percent when specified for top/left/bottom/right; 27657// rather than make the css module depend on the offset module, just check for it here 27658jQuery.each( [ "top", "left" ], function( _i, prop ) { 27659 jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition, 27660 function( elem, computed ) { 27661 if ( computed ) { 27662 computed = curCSS( elem, prop ); 27663 27664 // If curCSS returns percentage, fallback to offset 27665 return rnumnonpx.test( computed ) ? 27666 jQuery( elem ).position()[ prop ] + "px" : 27667 computed; 27668 } 27669 } 27670 ); 27671} ); 27672 27673 27674// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods 27675jQuery.each( { Height: "height", Width: "width" }, function( name, type ) { 27676 jQuery.each( { 27677 padding: "inner" + name, 27678 content: type, 27679 "": "outer" + name 27680 }, function( defaultExtra, funcName ) { 27681 27682 // Margin is only for outerHeight, outerWidth 27683 jQuery.fn[ funcName ] = function( margin, value ) { 27684 var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ), 27685 extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" ); 27686 27687 return access( this, function( elem, type, value ) { 27688 var doc; 27689 27690 if ( isWindow( elem ) ) { 27691 27692 // $( window ).outerWidth/Height return w/h including scrollbars (gh-1729) 27693 return funcName.indexOf( "outer" ) === 0 ? 27694 elem[ "inner" + name ] : 27695 elem.document.documentElement[ "client" + name ]; 27696 } 27697 27698 // Get document width or height 27699 if ( elem.nodeType === 9 ) { 27700 doc = elem.documentElement; 27701 27702 // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], 27703 // whichever is greatest 27704 return Math.max( 27705 elem.body[ "scroll" + name ], doc[ "scroll" + name ], 27706 elem.body[ "offset" + name ], doc[ "offset" + name ], 27707 doc[ "client" + name ] 27708 ); 27709 } 27710 27711 return value === undefined ? 27712 27713 // Get width or height on the element, requesting but not forcing parseFloat 27714 jQuery.css( elem, type, extra ) : 27715 27716 // Set width or height on the element 27717 jQuery.style( elem, type, value, extra ); 27718 }, type, chainable ? margin : undefined, chainable ); 27719 }; 27720 } ); 27721} ); 27722 27723 27724jQuery.each( [ 27725 "ajaxStart", 27726 "ajaxStop", 27727 "ajaxComplete", 27728 "ajaxError", 27729 "ajaxSuccess", 27730 "ajaxSend" 27731], function( _i, type ) { 27732 jQuery.fn[ type ] = function( fn ) { 27733 return this.on( type, fn ); 27734 }; 27735} ); 27736 27737 27738 27739 27740jQuery.fn.extend( { 27741 27742 bind: function( types, data, fn ) { 27743 return this.on( types, null, data, fn ); 27744 }, 27745 unbind: function( types, fn ) { 27746 return this.off( types, null, fn ); 27747 }, 27748 27749 delegate: function( selector, types, data, fn ) { 27750 return this.on( types, selector, data, fn ); 27751 }, 27752 undelegate: function( selector, types, fn ) { 27753 27754 // ( namespace ) or ( selector, types [, fn] ) 27755 return arguments.length === 1 ? 27756 this.off( selector, "**" ) : 27757 this.off( types, selector || "**", fn ); 27758 }, 27759 27760 hover: function( fnOver, fnOut ) { 27761 return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); 27762 } 27763} ); 27764 27765jQuery.each( 27766 ( "blur focus focusin focusout resize scroll click dblclick " + 27767 "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + 27768 "change select submit keydown keypress keyup contextmenu" ).split( " " ), 27769 function( _i, name ) { 27770 27771 // Handle event binding 27772 jQuery.fn[ name ] = function( data, fn ) { 27773 return arguments.length > 0 ? 27774 this.on( name, null, data, fn ) : 27775 this.trigger( name ); 27776 }; 27777 } 27778); 27779 27780 27781 27782 27783// Support: Android <=4.0 only 27784// Make sure we trim BOM and NBSP 27785var rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g; 27786 27787// Bind a function to a context, optionally partially applying any 27788// arguments. 27789// jQuery.proxy is deprecated to promote standards (specifically Function#bind) 27790// However, it is not slated for removal any time soon 27791jQuery.proxy = function( fn, context ) { 27792 var tmp, args, proxy; 27793 27794 if ( typeof context === "string" ) { 27795 tmp = fn[ context ]; 27796 context = fn; 27797 fn = tmp; 27798 } 27799 27800 // Quick check to determine if target is callable, in the spec 27801 // this throws a TypeError, but we will just return undefined. 27802 if ( !isFunction( fn ) ) { 27803 return undefined; 27804 } 27805 27806 // Simulated bind 27807 args = slice.call( arguments, 2 ); 27808 proxy = function() { 27809 return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); 27810 }; 27811 27812 // Set the guid of unique handler to the same of original handler, so it can be removed 27813 proxy.guid = fn.guid = fn.guid || jQuery.guid++; 27814 27815 return proxy; 27816}; 27817 27818jQuery.holdReady = function( hold ) { 27819 if ( hold ) { 27820 jQuery.readyWait++; 27821 } else { 27822 jQuery.ready( true ); 27823 } 27824}; 27825jQuery.isArray = Array.isArray; 27826jQuery.parseJSON = JSON.parse; 27827jQuery.nodeName = nodeName; 27828jQuery.isFunction = isFunction; 27829jQuery.isWindow = isWindow; 27830jQuery.camelCase = camelCase; 27831jQuery.type = toType; 27832 27833jQuery.now = Date.now; 27834 27835jQuery.isNumeric = function( obj ) { 27836 27837 // As of jQuery 3.0, isNumeric is limited to 27838 // strings and numbers (primitives or objects) 27839 // that can be coerced to finite numbers (gh-2662) 27840 var type = jQuery.type( obj ); 27841 return ( type === "number" || type === "string" ) && 27842 27843 // parseFloat NaNs numeric-cast false positives ("") 27844 // ...but misinterprets leading-number strings, particularly hex literals ("0x...") 27845 // subtraction forces infinities to NaN 27846 !isNaN( obj - parseFloat( obj ) ); 27847}; 27848 27849jQuery.trim = function( text ) { 27850 return text == null ? 27851 "" : 27852 ( text + "" ).replace( rtrim, "" ); 27853}; 27854 27855 27856 27857// Register as a named AMD module, since jQuery can be concatenated with other 27858// files that may use define, but not via a proper concatenation script that 27859// understands anonymous AMD modules. A named AMD is safest and most robust 27860// way to register. Lowercase jquery is used because AMD module names are 27861// derived from file names, and jQuery is normally delivered in a lowercase 27862// file name. Do this after creating the global so that if an AMD module wants 27863// to call noConflict to hide this version of jQuery, it will work. 27864 27865// Note that for maximum portability, libraries that are not jQuery should 27866// declare themselves as anonymous modules, and avoid setting a global if an 27867// AMD loader is present. jQuery is a special case. For more information, see 27868// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon 27869 27870if ( true ) { 27871 !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = (function() { 27872 return jQuery; 27873 }).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), 27874 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); 27875} 27876 27877 27878 27879 27880var 27881 27882 // Map over jQuery in case of overwrite 27883 _jQuery = window.jQuery, 27884 27885 // Map over the $ in case of overwrite 27886 _$ = window.$; 27887 27888jQuery.noConflict = function( deep ) { 27889 if ( window.$ === jQuery ) { 27890 window.$ = _$; 27891 } 27892 27893 if ( deep && window.jQuery === jQuery ) { 27894 window.jQuery = _jQuery; 27895 } 27896 27897 return jQuery; 27898}; 27899 27900// Expose jQuery and $ identifiers, even in AMD 27901// (#7102#comment:10, https://github.com/jquery/jquery/pull/557) 27902// and CommonJS for browser emulators (#13566) 27903if ( typeof noGlobal === "undefined" ) { 27904 window.jQuery = window.$ = jQuery; 27905} 27906 27907 27908 27909 27910return jQuery; 27911} ); 27912 27913 27914/***/ }), 27915 27916/***/ "./node_modules/mini-css-extract-plugin/dist/loader.js!./node_modules/css-loader/dist/cjs.js?!./node_modules/postcss-loader/src/index.js?!./node_modules/sass-loader/dist/cjs.js?!./Frontend/SCSS/main.scss": 27917/*!************************************************************************************************************************************************************************************************************************************!*\ 27918 !*** ./node_modules/mini-css-extract-plugin/dist/loader.js!./node_modules/css-loader/dist/cjs.js??ref--6-2!./node_modules/postcss-loader/src??ref--6-3!./node_modules/sass-loader/dist/cjs.js??ref--6-4!./Frontend/SCSS/main.scss ***! 27919 \************************************************************************************************************************************************************************************************************************************/ 27920/*! no static exports found */ 27921/***/ (function(module, exports, __webpack_require__) { 27922 27923// extracted by mini-css-extract-plugin 27924 27925/***/ }), 27926
vendor: 7,080 bytes, lines 27927-28204
27927/***/ "./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js": 27928/*!****************************************************************************!*\ 27929 !*** ./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js ***! 27930 \****************************************************************************/ 27931/*! no static exports found */ 27932/***/ (function(module, exports, __webpack_require__) { 27933 27934"use strict"; 27935 27936 27937var isOldIE = function isOldIE() { 27938 var memo; 27939 return function memorize() { 27940 if (typeof memo === 'undefined') { 27941 // Test for IE <= 9 as proposed by Browserhacks 27942 // @see http://browserhacks.com/#hack-e71d8692f65334173fee715c222cb805 27943 // Tests for existence of standard globals is to allow style-loader 27944 // to operate correctly into non-standard environments 27945 // @see https://github.com/webpack-contrib/style-loader/issues/177 27946 memo = Boolean(window && document && document.all && !window.atob); 27947 } 27948 27949 return memo; 27950 }; 27951}(); 27952 27953var getTarget = function getTarget() { 27954 var memo = {}; 27955 return function memorize(target) { 27956 if (typeof memo[target] === 'undefined') { 27957 var styleTarget = document.querySelector(target); // Special case to return head of iframe instead of iframe itself 27958 27959 if (window.HTMLIFrameElement && styleTarget instanceof window.HTMLIFrameElement) { 27960 try { 27961 // This will throw an exception if access to iframe is blocked 27962 // due to cross-origin restrictions 27963 styleTarget = styleTarget.contentDocument.head; 27964 } catch (e) { 27965 // istanbul ignore next 27966 styleTarget = null; 27967 } 27968 } 27969 27970 memo[target] = styleTarget; 27971 } 27972 27973 return memo[target]; 27974 }; 27975}(); 27976 27977var stylesInDom = []; 27978 27979function getIndexByIdentifier(identifier) { 27980 var result = -1; 27981 27982 for (var i = 0; i < stylesInDom.length; i++) { 27983 if (stylesInDom[i].identifier === identifier) { 27984 result = i; 27985 break; 27986 } 27987 } 27988 27989 return result; 27990} 27991 27992function modulesToDom(list, options) { 27993 var idCountMap = {}; 27994 var identifiers = []; 27995 27996 for (var i = 0; i < list.length; i++) { 27997 var item = list[i]; 27998 var id = options.base ? item[0] + options.base : item[0]; 27999 var count = idCountMap[id] || 0; 28000 var identifier = "".concat(id, " ").concat(count); 28001 idCountMap[id] = count + 1; 28002 var index = getIndexByIdentifier(identifier); 28003 var obj = { 28004 css: item[1], 28005 media: item[2], 28006 sourceMap: item[3] 28007 }; 28008 28009 if (index !== -1) { 28010 stylesInDom[index].references++; 28011 stylesInDom[index].updater(obj); 28012 } else { 28013 stylesInDom.push({ 28014 identifier: identifier, 28015 updater: addStyle(obj, options), 28016 references: 1 28017 }); 28018 } 28019 28020 identifiers.push(identifier); 28021 } 28022 28023 return identifiers; 28024} 28025 28026function insertStyleElement(options) { 28027 var style = document.createElement('style'); 28028 var attributes = options.attributes || {}; 28029 28030 if (typeof attributes.nonce === 'undefined') { 28031 var nonce = true ? __webpack_require__.nc : undefined; 28032 28033 if (nonce) { 28034 attributes.nonce = nonce; 28035 } 28036 } 28037 28038 Object.keys(attributes).forEach(function (key) { 28039 style.setAttribute(key, attributes[key]); 28040 }); 28041 28042 if (typeof options.insert === 'function') { 28043 options.insert(style); 28044 } else { 28045 var target = getTarget(options.insert || 'head'); 28046 28047 if (!target) { 28048 throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid."); 28049 } 28050 28051 target.appendChild(style); 28052 } 28053 28054 return style; 28055} 28056 28057function removeStyleElement(style) { 28058 // istanbul ignore if 28059 if (style.parentNode === null) { 28060 return false; 28061 } 28062 28063 style.parentNode.removeChild(style); 28064} 28065/* istanbul ignore next */ 28066 28067 28068var replaceText = function replaceText() { 28069 var textStore = []; 28070 return function replace(index, replacement) { 28071 textStore[index] = replacement; 28072 return textStore.filter(Boolean).join('\n'); 28073 }; 28074}(); 28075 28076function applyToSingletonTag(style, index, remove, obj) { 28077 var css = remove ? '' : obj.media ? "@media ".concat(obj.media, " {").concat(obj.css, "}") : obj.css; // For old IE 28078 28079 /* istanbul ignore if */ 28080 28081 if (style.styleSheet) { 28082 style.styleSheet.cssText = replaceText(index, css); 28083 } else { 28084 var cssNode = document.createTextNode(css); 28085 var childNodes = style.childNodes; 28086 28087 if (childNodes[index]) { 28088 style.removeChild(childNodes[index]); 28089 } 28090 28091 if (childNodes.length) { 28092 style.insertBefore(cssNode, childNodes[index]); 28093 } else { 28094 style.appendChild(cssNode); 28095 } 28096 } 28097} 28098 28099function applyToTag(style, options, obj) { 28100 var css = obj.css; 28101 var media = obj.media; 28102 var sourceMap = obj.sourceMap; 28103 28104 if (media) { 28105 style.setAttribute('media', media); 28106 } else { 28107 style.removeAttribute('media'); 28108 } 28109 28110 if (sourceMap && typeof btoa !== 'undefined') { 28111 } // For old IE 28112 28113 /* istanbul ignore if */ 28114 28115 28116 if (style.styleSheet) { 28117 style.styleSheet.cssText = css; 28118 } else { 28119 while (style.firstChild) { 28120 style.removeChild(style.firstChild); 28121 } 28122 28123 style.appendChild(document.createTextNode(css)); 28124 } 28125} 28126 28127var singleton = null; 28128var singletonCounter = 0; 28129 28130function addStyle(obj, options) { 28131 var style; 28132 var update; 28133 var remove; 28134 28135 if (options.singleton) { 28136 var styleIndex = singletonCounter++; 28137 style = singleton || (singleton = insertStyleElement(options)); 28138 update = applyToSingletonTag.bind(null, style, styleIndex, false); 28139 remove = applyToSingletonTag.bind(null, style, styleIndex, true); 28140 } else { 28141 style = insertStyleElement(options); 28142 update = applyToTag.bind(null, style, options); 28143 28144 remove = function remove() { 28145 removeStyleElement(style); 28146 }; 28147 } 28148 28149 update(obj); 28150 return function updateStyle(newObj) { 28151 if (newObj) { 28152 if (newObj.css === obj.css && newObj.media === obj.media && newObj.sourceMap === obj.sourceMap) { 28153 return; 28154 } 28155 28156 update(obj = newObj); 28157 } else { 28158 remove(); 28159 } 28160 }; 28161} 28162 28163module.exports = function (list, options) { 28164 options = options || {}; // Force single-tag solution on IE6-9, which has a hard limit on the # of <style> 28165 // tags it will allow on a page 28166 28167 if (!options.singleton && typeof options.singleton !== 'boolean') { 28168 options.singleton = isOldIE(); 28169 } 28170 28171 list = list || []; 28172 var lastIdentifiers = modulesToDom(list, options); 28173 return function update(newList) { 28174 newList = newList || []; 28175 28176 if (Object.prototype.toString.call(newList) !== '[object Array]') { 28177 return; 28178 } 28179 28180 for (var i = 0; i < lastIdentifiers.length; i++) { 28181 var identifier = lastIdentifiers[i]; 28182 var index = getIndexByIdentifier(identifier); 28183 stylesInDom[index].references--; 28184 } 28185 28186 var newLastIdentifiers = modulesToDom(newList, options); 28187 28188 for (var _i = 0; _i < lastIdentifiers.length; _i++) { 28189 var _identifier = lastIdentifiers[_i]; 28190 28191 var _index = getIndexByIdentifier(_identifier); 28192 28193 if (stylesInDom[_index].references === 0) { 28194 stylesInDom[_index].updater(); 28195 28196 stylesInDom.splice(_index, 1); 28197 } 28198 } 28199 28200 lastIdentifiers = newLastIdentifiers; 28201 }; 28202}; 28203 28204/***/ })
28204, 28205 28206/***/ 0: 28207/*!********************************************************************************!*\ 28208 !*** multi ./Frontend/JavaScript/src/public/main.js ./Frontend/SCSS/main.scss ***! 28209 \********************************************************************************/ 28210/*! no static exports found */ 28211/***/ (function(module, exports, __webpack_require__) { 28212 28213__webpack_require__(/*! ./Frontend/JavaScript/src/public/main.js */"./Frontend/JavaScript/src/public/main.js"); 28214module.exports = __webpack_require__(/*! ./Frontend/SCSS/main.scss */"./Frontend/SCSS/main.scss"); 28215 28216 28217/***/ }) 28218 28219/******/ });
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.