1/*! Responsive 3.0.4 2 * © SpryMedia Ltd - datatables.net/license 3 */ 4 5(function( factory ){ 6 if ( typeof define === 'function' && define.amd ) { 7 // AMD 8 define( ['jquery', 'datatables.net'], function ( $ ) { 9 return factory( $, window, document ); 10 } ); 11 } 12 else if ( typeof exports === 'object' ) { 13 // CommonJS 14 var jq = require('jquery'); 15 var cjsRequires = function (root, $) { 16 if ( ! $.fn.dataTable ) { 17 require('datatables.net')(root, $); 18 } 19 }; 20 21 if (typeof window === 'undefined') { 22 module.exports = function (root, $) { 23 if ( ! root ) { 24 // CommonJS environments without a window global must pass a 25 // root. This will give an error otherwise 26 root = window; 27 } 28 29 if ( ! $ ) { 30 $ = jq( root ); 31 } 32 33 cjsRequires( root, $ ); 34 return factory( $, root, root.document ); 35 }; 36 } 37 else { 38 cjsRequires( window, jq ); 39 module.exports = factory( jq, window, window.document ); 40 } 41 } 42 else { 43 // Browser 44 factory( jQuery, window, document ); 45 } 46}(function( $, window, document ) { 47'use strict'; 48var DataTable = $.fn.dataTable; 49 50 51 52/** 53 * @summary Responsive 54 * @description Responsive tables plug-in for DataTables 55 * @version 3.0.4 56 * @author SpryMedia Ltd 57 * @copyright SpryMedia Ltd. 58 * 59 * This source file is free software, available under the following license: 60 * MIT license - http://datatables.net/license/mit 61 * 62 * This source file is distributed in the hope that it will be useful, but 63 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 64 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. 65 * 66 * For details please refer to: http://www.datatables.net 67 */ 68 69/** 70 * Responsive is a plug-in for the DataTables library that makes use of 71 * DataTables' ability to change the visibility of columns, changing the 72 * visibility of columns so the displayed columns fit into the table container. 73 * The end result is that complex tables will be dynamically adjusted to fit 74 * into the viewport, be it on a desktop, tablet or mobile browser. 75 * 76 * Responsive for DataTables has two modes of operation, which can used 77 * individually or combined: 78 * 79 * * Class name based control - columns assigned class names that match the 80 * breakpoint logic can be shown / hidden as required for each breakpoint. 81 * * Automatic control - columns are automatically hidden when there is no 82 * room left to display them. Columns removed from the right. 83 * 84 * In additional to column visibility control, Responsive also has built into 85 * options to use DataTables' child row display to show / hide the information 86 * from the table that has been hidden. There are also two modes of operation 87 * for this child row display: 88 * 89 * * Inline - when the control element that the user can use to show / hide 90 * child rows is displayed inside the first column of the table. 91 * * Column - where a whole column is dedicated to be the show / hide control. 92 * 93 * Initialisation of Responsive is performed by: 94 * 95 * * Adding the class `responsive` or `dt-responsive` to the table. In this case 96 * Responsive will automatically be initialised with the default configuration 97 * options when the DataTable is created. 98 * * Using the `responsive` option in the DataTables configuration options. This 99 * can also be used to specify the configuration options, or simply set to 100 * `true` to use the defaults. 101 * 102 * @class 103 * @param {object} settings DataTables settings object for the host table 104 * @param {object} [opts] Configuration options 105 * @requires jQuery 1.7+ 106 * @requires DataTables 2.0.0+ 107 * 108 * @example 109 * $('#example').DataTable( { 110 * responsive: true 111 * } ); 112 * } ); 113 */ 114var Responsive = function (settings, opts) { 115 // Sanity check that we are using DataTables 2.0.0 or newer 116 if (!DataTable.versionCheck || !DataTable.versionCheck('2')) { 117 throw 'DataTables Responsive requires DataTables 2 or newer'; 118 } 119 120 this.s = { 121 childNodeStore: {}, 122 columns: [], 123 current: [], 124 dt: new DataTable.Api(settings) 125 }; 126 127 // Check if responsive has already been initialised on this table 128 if (this.s.dt.settings()[0].responsive) { 129 return; 130 } 131 132 // details is an object, but for simplicity the user can give it as a string 133 // or a boolean 134 if (opts && typeof opts.details === 'string') { 135 opts.details = { type: opts.details }; 136 } 137 else if (opts && opts.details === false) { 138 opts.details = { type: false }; 139 } 140 else if (opts && opts.details === true) { 141 opts.details = { type: 'inline' }; 142 } 143 144 this.c = $.extend( 145 true, 146 {}, 147 Responsive.defaults, 148 DataTable.defaults.responsive, 149 opts 150 ); 151 settings.responsive = this; 152 this._constructor(); 153}; 154 155$.extend(Responsive.prototype, { 156 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 157 * Constructor 158 */ 159 160 /** 161 * Initialise the Responsive instance 162 * 163 * @private 164 */ 165 _constructor: function () { 166 var that = this; 167 var dt = this.s.dt; 168 var oldWindowWidth = $(window).innerWidth(); 169 170 dt.settings()[0]._responsive = this; 171 172 // Use DataTables' throttle function to avoid processor thrashing 173 $(window).on( 174 'orientationchange.dtr', 175 DataTable.util.throttle(function () { 176 // iOS has a bug whereby resize can fire when only scrolling 177 // See: http://stackoverflow.com/questions/8898412 178 var width = $(window).innerWidth(); 179 180 if (width !== oldWindowWidth) { 181 that._resize(); 182 oldWindowWidth = width; 183 } 184 }) 185 ); 186 187 // Handle new rows being dynamically added - needed as responsive
188 // updates all rows (shown or not) a responsive change, rather than 189 // per draw. 190 dt.on('row-created.dtr', function (e, tr, data, idx) { 191 if ($.inArray(false, that.s.current) !== -1) { 192 $('>td, >th', tr).each(function (i) { 193 var idx = dt.column.index('toData', i); 194 195 if (that.s.current[idx] === false) { 196 $(this) 197 .css('display', 'none') 198 .addClass('dtr-hidden'); 199 } 200 }); 201 } 202 }); 203 204 // Destroy event handler 205 dt.on('destroy.dtr', function () { 206 dt.off('.dtr'); 207 $(dt.table().body()).off('.dtr'); 208 $(window).off('resize.dtr orientationchange.dtr'); 209 dt.cells('.dtr-control').nodes().to$().removeClass('dtr-control'); 210 $(dt.table().node()).removeClass('dtr-inline collapsed'); 211 212 // Restore the columns that we've hidden 213 $.each(that.s.current, function (i, val) { 214 if (val === false) { 215 that._setColumnVis(i, true); 216 } 217 }); 218 }); 219 220 // Reorder the breakpoints array here in case they have been added out 221 // of order 222 this.c.breakpoints.sort(function (a, b) { 223 return a.width < b.width ? 1 : a.width > b.width ? -1 : 0; 224 }); 225 226 this._classLogic(); 227 228 // Details handler 229 var details = this.c.details; 230 231 if (details.type !== false) { 232 that._detailsInit(); 233 234 // DataTables will trigger this event on every column it shows and 235 // hides individually 236 dt.on('column-visibility.dtr', function () { 237 // Use a small debounce to allow multiple columns to be set together 238 if (that._timer) { 239 clearTimeout(that._timer); 240 } 241 242 that._timer = setTimeout(function () { 243 that._timer = null; 244 245 that._classLogic(); 246 that._resizeAuto(); 247 that._resize(true); 248 249 that._redrawChildren(); 250 }, 100); 251 }); 252 253 // Redraw the details box on each draw which will happen if the data 254 // has changed. This is used until DataTables implements a native 255 // `updated` event for rows 256 dt.on('draw.dtr', function () { 257 that._redrawChildren(); 258 }); 259 260 $(dt.table().node()).addClass('dtr-' + details.type); 261 } 262 263 // DT2 let's us tell it if we are hiding columns 264 dt.on('column-calc.dt', function (e, d) { 265 var curr = that.s.current; 266 267 for (var i = 0; i < curr.length; i++) { 268 var idx = d.visible.indexOf(i); 269 270 if (curr[i] === false && idx >= 0) { 271 d.visible.splice(idx, 1); 272 } 273 } 274 }); 275 276 // On Ajax reload we want to reopen any child rows which are displayed 277 // by responsive 278 dt.on('preXhr.dtr', function () { 279 var rowIds = []; 280 dt.rows().every(function () { 281 if (this.child.isShown()) { 282 rowIds.push(this.id(true)); 283 } 284 }); 285 286 dt.one('draw.dtr', function () { 287 that._resizeAuto(); 288 that._resize(); 289 290 dt.rows(rowIds).every(function () { 291 that._detailsDisplay(this, false); 292 }); 293 }); 294 }); 295 296 // First pass when the table is ready 297 dt 298 .on('draw.dtr', function () { 299 that._controlClass(); 300 }) 301 .ready(function () { 302 that._resizeAuto(); 303 that._resize(); 304 305 // Attach listeners after first pass 306 dt.on('column-reorder.dtr', function (e, settings, details) { 307 that._classLogic(); 308 that._resizeAuto(); 309 that._resize(true); 310 }); 311 312 // Change in column sizes means we need to calc 313 dt.on('column-sizing.dtr', function () { 314 that._resizeAuto(); 315 that._resize(); 316 }); 317 }); 318 }, 319 320 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 321 * Private methods 322 */ 323 324 /** 325 * Insert a `col` tag into the correct location in a `colgroup`. 326 * 327 * @param {jQuery} colGroup The `colgroup` tag 328 * @param {jQuery} colEl The `col` tag 329 */ 330 _colGroupAttach: function (colGroup, colEls, idx) { 331 var found = null; 332 333 // No need to do anything if already attached 334 if (colEls[idx].get(0).parentNode === colGroup[0]) { 335 return; 336 } 337 338 // Find the first `col` after our own which is already attached 339 for (var i = idx+1; i < colEls.length; i++) { 340 if (colGroup[0] === colEls[i].get(0).parentNode) { 341 found = i; 342 break; 343 } 344 } 345 346 if (found !== null) { 347 // Insert before 348 colEls[idx].insertBefore(colEls[found][0]); 349 } 350 else { 351 // If wasn't found, insert at the end 352 colGroup.append(colEls[idx]); 353 } 354 }, 355 356 /** 357 * Get and store nodes from a cell - use for node moving renderers 358 * 359 * @param {*} dt DT instance 360 * @param {*} row Row index 361 * @param {*} col Column index 362 */ 363 _childNodes: function (dt, row, col) { 364 var name = row + '-' + col; 365 366 if (this.s.childNodeStore[name]) { 367 return this.s.childNodeStore[name]; 368 } 369 370 // https://jsperf.com/childnodes-array-slice-vs-loop 371 var nodes = []; 372 var children = dt.cell(row, col).node().childNodes; 373 for (var i = 0, ien = children.length; i < ien; i++) { 374 nodes.push(children[i]); 375 } 376 377 this.s.childNodeStore[name] = nodes; 378 379 return nodes; 380 }, 381 382 /** 383 * Restore nodes from the cache to a table cell 384 * 385 * @param {*} dt DT instance 386 * @param {*} row Row index 387 * @param {*} col Column index 388 */ 389 _childNodesRestore: function (dt, row, col) { 390 var name = row + '-' + col; 391 392 if (!this.s.childNodeStore[name]) { 393 return; 394 } 395 396 var node = dt.cell(row, col).node(); 397 var store = this.s.childNodeStore[name]; 398 if (store.length > 0) { 399 var parent = store[0].parentNode; 400 var parentChildren = parent.childNodes; 401 var a = []; 402 403 for (var i = 0, ien = parentChildren.length; i < ien; i++) { 404 a.push(parentChildren[i]); 405 } 406 407 for (var j = 0, jen = a.length; j < jen; j++) { 408 node.appendChild(a[j]); 409 } 410 } 411 412 this.s.childNodeStore[name] = undefined; 413 }, 414 415 /** 416 * Calculate the visibility for the columns in a table for a given 417 * breakpoint. The result is pre-determined based on the class logic if 418 * class names are used to control all columns, but the width of the table 419 * is also used if there are columns which are to be automatically shown 420 * and hidden. 421 * 422 * @param {string} breakpoint Breakpoint name to use for the calculation 423 * @return {array} Array of boolean values initiating the visibility of each 424 * column. 425 * @private 426 */ 427 _columnsVisiblity: function (breakpoint) { 428 var dt = this.s.dt; 429 var columns = this.s.columns; 430 var i, ien; 431 432 // Create an array that defines the column ordering based first on the 433 // column's priority, and secondly the column index. This allows the 434 // columns to be removed from the right if the priority matches 435 var order = columns 436 .map(function (col, idx) { 437 return { 438 columnIdx: idx, 439 priority: col.priority 440 }; 441 }) 442 .sort(function (a, b) { 443 if (a.priority !== b.priority) { 444 return a.priority - b.priority; 445 } 446 return a.columnIdx - b.columnIdx; 447 }); 448 449 // Class logic - determine which columns are in this breakpoint based 450 // on the classes. If no class control (i.e. `auto`) then `-` is used 451 // to indicate this to the rest of the function 452 var display = $.map(columns, function (col, i) { 453 if (dt.column(i).visible() === false) { 454 return 'not-visible'; 455 } 456 return col.auto && col.minWidth === null 457 ? false 458 : col.auto === true 459 ? '-' 460 : $.inArray(breakpoint, col.includeIn) !== -1; 461 }); 462 463 // Auto column control - first pass: how much width is taken by the 464 // ones that must be included from the non-auto columns 465 var requiredWidth = 0; 466 for (i = 0, ien = display.length; i < ien; i++) { 467 if (display[i] === true) { 468 requiredWidth += columns[i].minWidth; 469 } 470 } 471 472 // Second pass, use up any remaining width for other columns. For 473 // scrolling tables we need to subtract the width of the scrollbar. It
474 // may not be requires which makes this sub-optimal, but it would 475 // require another full redraw to make complete use of those extra few 476 // pixels 477 var scrolling = dt.settings()[0].oScroll; 478 var bar = scrolling.sY || scrolling.sX ? scrolling.iBarWidth : 0; 479 var widthAvailable = dt.table().container().offsetWidth - bar; 480 var usedWidth = widthAvailable - requiredWidth; 481 482 // Control column needs to always be included. This makes it sub- 483 // optimal in terms of using the available with, but to stop layout 484 // thrashing or overflow. Also we need to account for the control column 485 // width first so we know how much width is available for the other 486 // columns, since the control column might not be the first one shown 487 for (i = 0, ien = display.length; i < ien; i++) { 488 if (columns[i].control) { 489 usedWidth -= columns[i].minWidth; 490 } 491 } 492 493 // Allow columns to be shown (counting by priority and then right to 494 // left) until we run out of room 495 var empty = false; 496 for (i = 0, ien = order.length; i < ien; i++) { 497 var colIdx = order[i].columnIdx; 498 499 if ( 500 display[colIdx] === '-' && 501 !columns[colIdx].control && 502 columns[colIdx].minWidth 503 ) { 504 // Once we've found a column that won't fit we don't let any 505 // others display either, or columns might disappear in the 506 // middle of the table 507 if (empty || usedWidth - columns[colIdx].minWidth < 0) { 508 empty = true; 509 display[colIdx] = false; 510 } 511 else { 512 display[colIdx] = true; 513 } 514 515 usedWidth -= columns[colIdx].minWidth; 516 } 517 } 518 519 // Determine if the 'control' column should be shown (if there is one). 520 // This is the case when there is a hidden column (that is not the 521 // control column). The two loops look inefficient here, but they are 522 // trivial and will fly through. We need to know the outcome from the 523 // first , before the action in the second can be taken 524 var showControl = false; 525 526 for (i = 0, ien = columns.length; i < ien; i++) { 527 if ( 528 !columns[i].control && 529 !columns[i].never && 530 display[i] === false 531 ) { 532 showControl = true; 533 break; 534 } 535 } 536 537 for (i = 0, ien = columns.length; i < ien; i++) { 538 if (columns[i].control) { 539 display[i] = showControl; 540 } 541 542 // Replace not visible string with false from the control column detection above 543 if (display[i] === 'not-visible') { 544 display[i] = false; 545 } 546 } 547 548 // Finally we need to make sure that there is at least one column that 549 // is visible 550 if ($.inArray(true, display) === -1) { 551 display[0] = true; 552 } 553
554 return display; 555 }, 556 557 /** 558 * Create the internal `columns` array with information about the columns 559 * for the table. This includes determining which breakpoints the column 560 * will appear in, based upon class names in the column, which makes up the 561 * vast majority of this method. 562 * 563 * @private 564 */ 565 _classLogic: function () { 566 var that = this; 567 var breakpoints = this.c.breakpoints; 568 var dt = this.s.dt; 569 var columns = dt 570 .columns() 571 .eq(0) 572 .map(function (i) { 573 var column = this.column(i); 574 var className = column.header().className; 575 var priority = column.init().responsivePriority; 576 var dataPriority = column 577 .header() 578 .getAttribute('data-priority'); 579 580 if (priority === undefined) { 581 priority = 582 dataPriority === undefined || dataPriority === null 583 ? 10000 584 : dataPriority * 1; 585 } 586 587 return { 588 className: className, 589 includeIn: [], 590 auto: false, 591 control: false, 592 never: className.match(/\b(dtr\-)?never\b/) ? true : false, 593 priority: priority 594 }; 595 }); 596 597 // Simply add a breakpoint to `includeIn` array, ensuring that there are 598 // no duplicates 599 var add = function (colIdx, name) { 600 var includeIn = columns[colIdx].includeIn; 601 602 if ($.inArray(name, includeIn) === -1) { 603 includeIn.push(name); 604 } 605 }; 606 607 var column = function (colIdx, name, operator, matched) { 608 var size, i, ien; 609 610 if (!operator) { 611 columns[colIdx].includeIn.push(name); 612 } 613 else if (operator === 'max-') { 614 // Add this breakpoint and all smaller 615 size = that._find(name).width; 616 617 for (i = 0, ien = breakpoints.length; i < ien; i++) { 618 if (breakpoints[i].width <= size) { 619 add(colIdx, breakpoints[i].name); 620 } 621 } 622 } 623 else if (operator === 'min-') { 624 // Add this breakpoint and all larger 625 size = that._find(name).width; 626 627 for (i = 0, ien = breakpoints.length; i < ien; i++) { 628 if (breakpoints[i].width >= size) { 629 add(colIdx, breakpoints[i].name); 630 } 631 } 632 } 633 else if (operator === 'not-') { 634 // Add all but this breakpoint 635 for (i = 0, ien = breakpoints.length; i < ien; i++) { 636 if (breakpoints[i].name.indexOf(matched) === -1) { 637 add(colIdx, breakpoints[i].name); 638 } 639 } 640 } 641 }; 642 643 // Loop over each column and determine if it has a responsive control 644 // class 645 columns.each(function (col, i) { 646 var classNames = col.className.split(' '); 647 var hasClass = false; 648 649 // Split the class name up so multiple rules can be applied if needed 650 for (var k = 0, ken = classNames.length; k < ken; k++) { 651 var className = classNames[k].trim(); 652 653 if (className === 'all' || className === 'dtr-all') { 654 // Include in all 655 hasClass = true; 656 col.includeIn = $.map(breakpoints, function (a) { 657 return a.name; 658 }); 659 return; 660 } 661 else if ( 662 className === 'none' || 663 className === 'dtr-none' || 664 col.never 665 ) { 666 // Include in none (default) and no auto 667 hasClass = true; 668 return; 669 } 670 else if ( 671 className === 'control' || 672 className === 'dtr-control' 673 ) { 674 // Special column that is only visible, when one of the other 675 // columns is hidden. This is used for the details control 676 hasClass = true; 677 col.control = true; 678 return; 679 } 680 681 $.each(breakpoints, function (j, breakpoint) { 682 // Does this column have a class that matches this breakpoint? 683 var brokenPoint = breakpoint.name.split('-'); 684 var re = new RegExp( 685 '(min\\-|max\\-|not\\-)?(' + 686 brokenPoint[0] + 687 ')(\\-[_a-zA-Z0-9])?' 688 ); 689 var match = className.match(re); 690 691 if (match) { 692 hasClass = true; 693 694 if ( 695 match[2] === brokenPoint[0] && 696 match[3] === '-' + brokenPoint[1] 697 ) { 698 // Class name matches breakpoint name fully 699 column( 700 i, 701 breakpoint.name, 702 match[1], 703 match[2] + match[3] 704 ); 705 } 706 else if (match[2] === brokenPoint[0] && !match[3]) { 707 // Class name matched primary breakpoint name with no qualifier 708 column(i, breakpoint.name, match[1], match[2]); 709 } 710 } 711 }); 712 } 713 714 // If there was no control class, then automatic sizing is used 715 if (!hasClass) { 716 col.auto = true; 717 } 718 }); 719 720 this.s.columns = columns; 721 }, 722 723 /** 724 * Update the cells to show the correct control class / button 725 * @private 726 */ 727 _controlClass: function () { 728 if (this.c.details.type === 'inline') { 729 var dt = this.s.dt; 730 var columnsVis = this.s.current; 731 var firstVisible = $.inArray(true, columnsVis); 732 733 // Remove from any cells which shouldn't have it 734 dt.cells( 735 null, 736 function (idx) { 737 return idx !== firstVisible; 738 }, 739 { page: 'current' } 740 ) 741 .nodes() 742 .to$() 743 .filter('.dtr-control') 744 .removeClass('dtr-control'); 745 746 if (firstVisible >= 0) { 747 dt.cells(null, firstVisible, { page: 'current' }) 748 .nodes() 749 .to$() 750 .addClass('dtr-control'); 751 } 752 } 753 754 this._tabIndexes(); 755 }, 756 757 /** 758 * Show the details for the child row 759 * 760 * @param {DataTables.Api} row API instance for the row 761 * @param {boolean} update Update flag 762 * @private 763 */ 764 _detailsDisplay: function (row, update) { 765 var that = this; 766 var dt = this.s.dt; 767 var details = this.c.details; 768 var event = function (res) { 769 $(row.node()).toggleClass('dtr-expanded', res !== false); 770 $(dt.table().node()).triggerHandler('responsive-display.dt', [ 771 dt, 772 row, 773 res, 774 update 775 ]); 776 }; 777 778 if (details && details.type !== false) { 779 var renderer = 780 typeof details.renderer === 'string' 781 ? Responsive.renderer[details.renderer]() 782 : details.renderer; 783 784 var res = details.display( 785 row, 786 update, 787 function () { 788 return renderer.call( 789 that, 790 dt, 791 row[0][0], 792 that._detailsObj(row[0]) 793 ); 794 }, 795 function () { 796 event(false); 797 } 798 ); 799 800 if (typeof res === 'boolean') { 801 event(res); 802 } 803 } 804 }, 805 806 /** 807 * Initialisation for the details handler 808 * 809 * @private 810 */ 811 _detailsInit: function () { 812 var that = this; 813 var dt = this.s.dt; 814 var details = this.c.details; 815 816 // The inline type always uses the first child as the target 817 if (details.type === 'inline') { 818 details.target = 'td.dtr-control, th.dtr-control'; 819 } 820 821 $(dt.table().body()).on('keyup.dtr', 'td, th', function (e) { 822 if (e.keyCode === 13 && $(this).data('dtr-keyboard')) { 823 $(this).click(); 824 } 825 }); 826 827 // type.target can be a string jQuery selector or a column index 828 var target = details.target; 829 var selector = typeof target === 'string' ? target : 'td, th'; 830 831 if (target !== undefined || target !== null) { 832 // Click handler to show / hide the details rows when they are available 833 $(dt.table().body()).on( 834 'click.dtr mousedown.dtr mouseup.dtr', 835 selector, 836 function (e) { 837 // If the table is not collapsed (i.e. there is no hidden columns) 838 // then take no action 839 if (!$(dt.table().node()).hasClass('collapsed')) { 840 return; 841 } 842 843 // Check that the row is actually a DataTable's controlled node 844 if ( 845 $.inArray( 846 $(this).closest('tr').get(0), 847 dt.rows().nodes().toArray() 848 ) === -1 849 ) { 850 return; 851 } 852 853 // For column index, we determine if we should act or not in the 854 // handler - otherwise it is already okay 855 if (typeof target === 'number') { 856 var targetIdx = 857 target < 0 858 ? dt.columns().eq(0).length + target 859 : target; 860 861 if (dt.cell(this).index().column !== targetIdx) { 862 return; 863 } 864 } 865
866 // $().closest() includes itself in its check 867 var row = dt.row($(this).closest('tr')); 868 869 // Check event type to do an action 870 if (e.type === 'click') { 871 // The renderer is given as a function so the caller can execute it 872 // only when they need (i.e. if hiding there is no point is running 873 // the renderer) 874 that._detailsDisplay(row, false); 875 } 876 else if (e.type === 'mousedown') { 877 // For mouse users, prevent the focus ring from showing 878 $(this).css('outline', 'none'); 879 } 880 else if (e.type === 'mouseup') { 881 // And then re-allow at the end of the click 882 $(this).trigger('blur').css('outline', ''); 883 } 884 } 885 ); 886 } 887 }, 888 889 /** 890 * Get the details to pass to a renderer for a row 891 * @param {int} rowIdx Row index 892 * @private 893 */ 894 _detailsObj: function (rowIdx) { 895 var that = this; 896 var dt = this.s.dt; 897 898 return $.map(this.s.columns, function (col, i) { 899 // Never and control columns should not be passed to the renderer 900 if (col.never || col.control) { 901 return; 902 } 903 904 var dtCol = dt.settings()[0].aoColumns[i]; 905 906 return { 907 className: dtCol.sClass, 908 columnIndex: i, 909 data: dt.cell(rowIdx, i).render(that.c.orthogonal), 910 hidden: dt.column(i).visible() && !that.s.current[i], 911 rowIndex: rowIdx, 912 title: dt.column(i).title() 913 }; 914 }); 915 }, 916 917 /** 918 * Find a breakpoint object from a name 919 * 920 * @param {string} name Breakpoint name to find 921 * @return {object} Breakpoint description object 922 * @private 923 */ 924 _find: function (name) { 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 * Re-create the contents of the child rows as the display has changed in 936 * some way. 937 * 938 * @private 939 */ 940 _redrawChildren: function () { 941 var that = this; 942 var dt = this.s.dt; 943 944 dt.rows({ page: 'current' }).iterator('row', function (settings, idx) { 945 that._detailsDisplay(dt.row(idx), true); 946 }); 947 }, 948 949 /** 950 * Alter the table display for a resized viewport. This involves first 951 * determining what breakpoint the window currently is in, getting the 952 * column visibilities to apply and then setting them. 953 * 954 * @param {boolean} forceRedraw Force a redraw 955 * @private 956 */ 957 _resize: function (forceRedraw) { 958 var that = this; 959 var dt = this.s.dt; 960 var width = $(window).innerWidth(); 961 var breakpoints = this.c.breakpoints; 962 var breakpoint = breakpoints[0].name; 963 var columns = this.s.columns; 964 var i, ien; 965 var oldVis = this.s.current.slice(); 966 967 // Determine what breakpoint we are currently at 968 for (i = breakpoints.length - 1; i >= 0; i--) { 969 if (width <= breakpoints[i].width) { 970 breakpoint = breakpoints[i].name; 971 break; 972 } 973 } 974 975 // Show the columns for that break point 976 var columnsVis = this._columnsVisiblity(breakpoint); 977 this.s.current = columnsVis; 978 979 // Set the class before the column visibility is changed so event 980 // listeners know what the state is. Need to determine if there are 981 // any columns that are not visible but can be shown 982 var collapsedClass = false; 983 984 for (i = 0, ien = columns.length; i < ien; i++) { 985 if ( 986 columnsVis[i] === false && 987 !columns[i].never && 988 !columns[i].control && 989 !dt.column(i).visible() === false 990 ) { 991 collapsedClass = true; 992 break; 993 } 994 } 995 996 $(dt.table().node()).toggleClass('collapsed', collapsedClass); 997 998 var changed = false; 999 var visible = 0; 1000 var dtSettings = dt.settings()[0]; 1001 var colGroup = $(dt.table().node()).children('colgroup'); 1002 var colEls = dtSettings.aoColumns.map(function (col) { 1003 return col.colEl; 1004 }); 1005 1006 dt.columns() 1007 .eq(0) 1008 .each(function (colIdx, i) { 1009 // Do nothing on DataTables' hidden column - DT removes it from the table 1010 // so we need to slide back 1011 if (! dt.column(colIdx).visible()) { 1012 return; 1013 } 1014 1015 if (columnsVis[i] === true) { 1016 visible++; 1017 } 1018 1019 if (forceRedraw || columnsVis[i] !== oldVis[i]) { 1020 changed = true; 1021 that._setColumnVis(colIdx, columnsVis[i]); 1022 } 1023 1024 // DataTables 2 uses `col` to define the width for a column 1025 // and this needs to run each time, as DataTables will change 1026 // the column width. We may need to reattach if we've removed 1027 // an element previously. 1028 if (! columnsVis[i]) { 1029 colEls[i].detach(); 1030 } 1031 else { 1032 that._colGroupAttach(colGroup, colEls, i); 1033 } 1034 }); 1035 1036 if (changed) { 1037 dt.columns.adjust(); 1038 1039 this._redrawChildren();
1040 1041 // Inform listeners of the change 1042 $(dt.table().node()).trigger('responsive-resize.dt', [ 1043 dt, 1044 this._responsiveOnlyHidden() 1045 ]); 1046 1047 // If no records, update the "No records" display element 1048 if (dt.page.info().recordsDisplay === 0) { 1049 $('td', dt.table().body()).eq(0).attr('colspan', visible); 1050 } 1051 } 1052 1053 that._controlClass(); 1054 }, 1055 1056 /** 1057 * Determine the width of each column in the table so the auto column hiding 1058 * has that information to work with. This method is never going to be 100% 1059 * perfect since column widths can change slightly per page, but without 1060 * seriously compromising performance this is quite effective. 1061 * 1062 * @private 1063 */ 1064 _resizeAuto: function () { 1065 var dt = this.s.dt; 1066 var columns = this.s.columns; 1067 var that = this; 1068 var visibleColumns = dt 1069 .columns() 1070 .indexes() 1071 .filter(function (idx) { 1072 return dt.column(idx).visible(); 1073 }); 1074 1075 // Are we allowed to do auto sizing? 1076 if (!this.c.auto) { 1077 return; 1078 } 1079 1080 // Are there any columns that actually need auto-sizing, or do they all 1081 // have classes defined 1082 if ( 1083 $.inArray( 1084 true, 1085 $.map(columns, function (c) { 1086 return c.auto; 1087 }) 1088 ) === -1 1089 ) { 1090 return; 1091 } 1092 1093 // Clone the table with the current data in it 1094 var clonedTable = dt.table().node().cloneNode(false); 1095 var clonedHeader = $(dt.table().header().cloneNode(false)).appendTo( 1096 clonedTable 1097 ); 1098 var clonedFooter = $(dt.table().footer().cloneNode(false)).appendTo( 1099 clonedTable 1100 ); 1101 var clonedBody = $(dt.table().body()) 1102 .clone(false, false) 1103 .empty() 1104 .appendTo(clonedTable); // use jQuery because of IE8 1105 1106 clonedTable.style.width = 'auto'; 1107 1108 // Header 1109 dt.table() 1110 .header.structure(visibleColumns) 1111 .forEach((row) => { 1112 var cells = row 1113 .filter(function (el) { 1114 return el ? true : false; 1115 }) 1116 .map(function (el) { 1117 return $(el.cell) 1118 .clone(false) 1119 .css('display', 'table-cell') 1120 .css('width', 'auto') 1121 .css('min-width', 0); 1122 }); 1123 1124 $('<tr/>').append(cells).appendTo(clonedHeader); 1125 }); 1126 1127 // Always need an empty row that we can read widths from 1128 var emptyRow = $('<tr/>').appendTo(clonedBody); 1129 1130 for (var i = 0; i < visibleColumns.count(); i++) { 1131 emptyRow.append('<td/>'); 1132 } 1133 1134 // Body rows 1135 if (this.c.details.renderer._responsiveMovesNodes) { 1136 // Slow but it allows for moving elements around the document 1137 dt.rows({ page: 'current' }).every(function (rowIdx) { 1138 var node = this.node(); 1139 1140 if (! node) { 1141 return; 1142 } 1143 1144 // We clone the table's rows and cells to create the sizing table 1145 var tr = node.cloneNode(false); 1146 1147 dt.cells(rowIdx, visibleColumns).every(function (rowIdx2, colIdx) { 1148 // If nodes have been moved out (listHiddenNodes), we need to 1149 // clone from the store 1150 var store = that.s.childNodeStore[rowIdx + '-' + colIdx]; 1151 1152 if (store) { 1153 $(this.node().cloneNode(false)) 1154 .append($(store).clone()) 1155 .appendTo(tr); 1156 } 1157 else { 1158 $(this.node()).clone(false).appendTo(tr); 1159 } 1160 }); 1161 1162 clonedBody.append(tr); 1163 }); 1164 } 1165 else { 1166 // This is much faster, but it doesn't account for moving nodes around 1167 $(clonedBody) 1168 .append( $(dt.rows( { page: 'current' } ).nodes()).clone( false ) ) 1169 .find( 'th, td' ).css( 'display', '' ); 1170 } 1171 1172 // Any cells which were hidden by Responsive in the host table, need to 1173 // be visible here for the calculations 1174 clonedBody.find('th, td').css('display', ''); 1175 1176 // Footer 1177 dt.table() 1178 .footer.structure(visibleColumns) 1179 .forEach((row) => { 1180 var cells = row 1181 .filter(function (el) { 1182 return el ? true : false; 1183 }) 1184 .map(function (el) { 1185 return $(el.cell) 1186 .clone(false) 1187 .css('display', 'table-cell') 1188 .css('width', 'auto') 1189 .css('min-width', 0); 1190 }); 1191 1192 $('<tr/>').append(cells).appendTo(clonedFooter); 1193 }); 1194 1195 // In the inline case extra padding is applied to the first column to 1196 // give space for the show / hide icon. We need to use this in the 1197 // calculation 1198 if (this.c.details.type === 'inline') { 1199 $(clonedTable).addClass('dtr-inline collapsed'); 1200 } 1201 1202 // It is unsafe to insert elements with the same name into the DOM 1203 // multiple times. For example, cloning and inserting a checked radio 1204 // clears the chcecked state of the original radio. 1205 $(clonedTable).find('[name]').removeAttr('name'); 1206 1207 // A position absolute table would take the table out of the flow of 1208 // our container element, bypassing the height and width (Scroller) 1209 $(clonedTable).css('position', 'relative'); 1210 1211 var inserted = $('<div/>') 1212 .css({ 1213 width: 1, 1214 height: 1, 1215 overflow: 'hidden', 1216 clear: 'both' 1217 }) 1218 .append(clonedTable); 1219 1220 inserted.insertBefore(dt.table().node()); 1221 1222 // The cloned table now contains the smallest that each column can be 1223 emptyRow.children().each(function (i) { 1224 var idx = dt.column.index('fromVisible', i); 1225 columns[idx].minWidth = this.offsetWidth || 0; 1226 }); 1227 1228 inserted.remove(); 1229 }, 1230 1231 /** 1232 * Get the state of the current hidden columns - controlled by Responsive only 1233 */ 1234 _responsiveOnlyHidden: function () { 1235 var dt = this.s.dt; 1236 1237 return $.map(this.s.current, function (v, i) { 1238 // If the column is hidden by DataTables then it can't be hidden by 1239 // Responsive! 1240 if (dt.column(i).visible() === false) { 1241 return true; 1242 } 1243 return v; 1244 }); 1245 }, 1246 1247 /** 1248 * Set a column's visibility. 1249 *
1250 * We don't use DataTables' column visibility controls in order to ensure 1251 * that column visibility can Responsive can no-exist. Since only IE8+ is 1252 * supported (and all evergreen browsers of course) the control of the 1253 * display attribute works well. 1254 * 1255 * @param {integer} col Column index 1256 * @param {boolean} showHide Show or hide (true or false) 1257 * @private 1258 */ 1259 _setColumnVis: function (col, showHide) { 1260 var that = this; 1261 var dt = this.s.dt; 1262 var display = showHide ? '' : 'none'; // empty string will remove the attr 1263 1264 this._setHeaderVis(col, showHide, dt.table().header.structure()); 1265 this._setHeaderVis(col, showHide, dt.table().footer.structure()); 1266 1267 dt.column(col) 1268 .nodes() 1269 .to$() 1270 .css('display', display) 1271 .toggleClass('dtr-hidden', !showHide); 1272 1273 // If the are child nodes stored, we might need to reinsert them 1274 if (!$.isEmptyObject(this.s.childNodeStore)) { 1275 dt.cells(null, col) 1276 .indexes() 1277 .each(function (idx) { 1278 that._childNodesRestore(dt, idx.row, idx.column); 1279 }); 1280 } 1281 }, 1282 1283 /** 1284 * Set the a column's visibility, taking into account multiple rows 1285 * in a header / footer and colspan attributes 1286 * @param {*} col 1287 * @param {*} showHide 1288 * @param {*} structure 1289 */ 1290 _setHeaderVis: function (col, showHide, structure) { 1291 var that = this; 1292 var display = showHide ? '' : 'none'; 1293 1294 // We use the `null`s in the structure array to indicate that a cell 1295 // should expand over that one if there is a colspan, but it might 1296 // also have been filled by a rowspan, so we need to expand the 1297 // rowspan cells down through the structure 1298 structure.forEach(function (row, rowIdx) { 1299 for (var col = 0; col < row.length; col++) { 1300 if (row[col] && row[col].rowspan > 1) { 1301 var span = row[col].rowspan; 1302 1303 for (var i=1 ; i<span ; i++) { 1304 structure[rowIdx + i][col] = {}; 1305 } 1306 } 1307 } 1308 }); 1309 1310 structure.forEach(function (row) { 1311 if (row[col] && row[col].cell) { 1312 $(row[col].cell) 1313 .css('display', display) 1314 .toggleClass('dtr-hidden', !showHide); 1315 } 1316 else { 1317 // In a colspan - need to rewind calc the new span since 1318 // display:none elements do not count as being spanned over 1319 var search = col; 1320 1321 while (search >= 0) { 1322 if (row[search] && row[search].cell) { 1323 row[search].cell.colSpan = that._colspan(row, search); 1324 break; 1325 } 1326 1327 search--; 1328 } 1329 } 1330 }); 1331 }, 1332 1333 /** 1334 * How many columns should this cell span 1335 * 1336 * @param {*} row Header structure row 1337 * @param {*} idx The column index of the cell to span 1338 */ 1339 _colspan: function (row, idx) { 1340 var colspan = 1; 1341 1342 for (var col = idx + 1; col < row.length; col++) { 1343 if (row[col] === null && this.s.current[col]) { 1344 // colspan and not hidden by Responsive 1345 colspan++; 1346 } 1347 else if (row[col]) { 1348 // Got the next cell, jump out 1349 break; 1350 } 1351 } 1352 1353 return colspan; 1354 }, 1355 1356 /** 1357 * Update the cell tab indexes for keyboard accessibility. This is called on 1358 * every table draw - that is potentially inefficient, but also the least 1359 * complex option given that column visibility can change on the fly. Its a 1360 * shame user-focus was removed from CSS 3 UI, as it would have solved this 1361 * issue with a single CSS statement. 1362 * 1363 * @private 1364 */ 1365 _tabIndexes: function () { 1366 var dt = this.s.dt; 1367 var cells = dt.cells({ page: 'current' }).nodes().to$(); 1368 var ctx = dt.settings()[0]; 1369 var target = this.c.details.target; 1370 1371 cells.filter('[data-dtr-keyboard]').removeData('[data-dtr-keyboard]'); 1372 1373 if (typeof target === 'number') { 1374 dt.cells(null, target, { page: 'current' }) 1375 .nodes() 1376 .to$() 1377 .attr('tabIndex', ctx.iTabIndex) 1378 .data('dtr-keyboard', 1); 1379 } 1380 else { 1381 // This is a bit of a hack - we need to limit the selected nodes to just 1382 // those of this table 1383 if (target === 'td:first-child, th:first-child') { 1384 target = '>td:first-child, >th:first-child'; 1385 } 1386 1387 var rows = dt.rows({ page: 'current' }).nodes(); 1388 var nodes = target === 'tr' 1389 ? $(rows) 1390 : $(target, rows); 1391 1392 nodes 1393 .attr('tabIndex', ctx.iTabIndex) 1394 .data('dtr-keyboard', 1); 1395 } 1396 } 1397}); 1398 1399/** 1400 * List of default breakpoints. Each item in the array is an object with two 1401 * properties: 1402 * 1403 * * `name` - the breakpoint name. 1404 * * `width` - the breakpoint width 1405 * 1406 * @name Responsive.breakpoints 1407 * @static 1408 */ 1409Responsive.breakpoints = [ 1410 { name: 'desktop', width: Infinity }, 1411 { name: 'tablet-l', width: 1024 }, 1412 { name: 'tablet-p', width: 768 }, 1413 { name: 'mobile-l', width: 480 }, 1414 { name: 'mobile-p', width: 320 } 1415]; 1416 1417/** 1418 * Display methods - functions which define how the hidden data should be shown 1419 * in the table. 1420 * 1421 * @namespace 1422 * @name Responsive.defaults 1423 * @static 1424 */ 1425Responsive.display = { 1426 childRow: function (row, update, render) { 1427 var rowNode = $(row.node()); 1428 1429 if (update) { 1430 if (rowNode.hasClass('dtr-expanded')) { 1431 row.child(render(), 'child').show(); 1432 1433 return true; 1434 } 1435 } 1436 else { 1437 if (!rowNode.hasClass('dtr-expanded')) { 1438 var rendered = render(); 1439 1440 if (rendered === false) { 1441 return false; 1442 } 1443 1444 row.child(rendered, 'child').show(); 1445 return true; 1446 } 1447 else { 1448 row.child(false); 1449 1450 return false; 1451 } 1452 } 1453 }, 1454 1455 childRowImmediate: function (row, update, render) { 1456 var rowNode = $(row.node()); 1457 1458 if ( 1459 (!update && rowNode.hasClass('dtr-expanded')) || 1460 !row.responsive.hasHidden() 1461 ) { 1462 // User interaction and the row is show, or nothing to show 1463 row.child(false); 1464 1465 return false; 1466 } 1467 else { 1468 // Display 1469 var rendered = render(); 1470 1471 if (rendered === false) { 1472 return false; 1473 } 1474 1475 row.child(rendered, 'child').show(); 1476 1477 return true; 1478 } 1479 }, 1480 1481 // This is a wrapper so the modal options for Bootstrap and jQuery UI can 1482 // have options passed into them. This specific one doesn't need to be a 1483 // function but it is for consistency in the `modal` name 1484 modal: function (options) { 1485 return function (row, update, render, closeCallback) { 1486 var modal; 1487 var rendered = render(); 1488 1489 if (rendered === false) { 1490 return false; 1491 } 1492 1493 if (!update) { 1494 // Show a modal 1495 var close = function () { 1496 modal.remove(); // will tidy events for us 1497 $(document).off('keypress.dtr'); 1498 $(row.node()).removeClass('dtr-expanded'); 1499 1500 closeCallback(); 1501 }; 1502
1503 modal = $('<div class="dtr-modal"/>') 1504 .append( 1505 $('<div class="dtr-modal-display"/>') 1506 .append( 1507 $('<div class="dtr-modal-content"/>') 1508 .data('dtr-row-idx', row.index()) 1509 .append(rendered) 1510 ) 1511 .append( 1512 $( 1513 '<div class="dtr-modal-close">×</div>' 1514 ).click(function () { 1515 close(); 1516 }) 1517 ) 1518 ) 1519 .append( 1520 $('<div class="dtr-modal-background"/>').click( 1521 function () { 1522 close(); 1523 } 1524 ) 1525 ) 1526 .appendTo('body'); 1527 1528 $(row.node()).addClass('dtr-expanded'); 1529 1530 $(document).on('keyup.dtr', function (e) { 1531 if (e.keyCode === 27) { 1532 e.stopPropagation(); 1533 1534 close(); 1535 } 1536 }); 1537 } 1538 else { 1539 modal = $('div.dtr-modal-content'); 1540 1541 if (modal.length && row.index() === modal.data('dtr-row-idx')) { 1542 modal.empty().append(rendered); 1543 } 1544 else { 1545 // Modal not shown, nothing to update 1546 return null; 1547 } 1548 } 1549 1550 if (options && options.header) { 1551 $('div.dtr-modal-content').prepend( 1552 '<h2>' + options.header(row) + '</h2>' 1553 ); 1554 } 1555 1556 return true; 1557 }; 1558 } 1559}; 1560 1561/** 1562 * Display methods - functions which define how the hidden data should be shown 1563 * in the table. 1564 * 1565 * @namespace 1566 * @name Responsive.defaults 1567 * @static 1568 */ 1569Responsive.renderer = { 1570 listHiddenNodes: function () { 1571 var fn = function (api, rowIdx, columns) { 1572 var that = this; 1573 var ul = $( 1574 '<ul data-dtr-index="' + rowIdx + '" class="dtr-details"/>' 1575 ); 1576 var found = false; 1577 1578 $.each(columns, function (i, col) { 1579 if (col.hidden) { 1580 var klass = col.className 1581 ? 'class="' + col.className + '"' 1582 : ''; 1583 1584 $( 1585 '<li ' + 1586 klass + 1587 ' data-dtr-index="' + 1588 col.columnIndex + 1589 '" data-dt-row="' + 1590 col.rowIndex + 1591 '" data-dt-column="' + 1592 col.columnIndex + 1593 '">' + 1594 '<span class="dtr-title">' + 1595 col.title + 1596 '</span> ' + 1597 '</li>' 1598 ) 1599 .append( 1600 $('<span class="dtr-data"/>').append( 1601 that._childNodes( 1602 api, 1603 col.rowIndex, 1604 col.columnIndex 1605 ) 1606 ) 1607 ) // api.cell( col.rowIndex, col.columnIndex ).node().childNodes ) ) 1608 .appendTo(ul); 1609 1610 found = true; 1611 } 1612 }); 1613 1614 return found ? ul : false; 1615 }; 1616 1617 fn._responsiveMovesNodes = true; 1618 1619 return fn; 1620 }, 1621 1622 listHidden: function () { 1623 return function (api, rowIdx, columns) { 1624 var data = $.map(columns, function (col) { 1625 var klass = col.className 1626 ? 'class="' + col.className + '"' 1627 : ''; 1628 1629 return col.hidden 1630 ? '<li ' + 1631 klass + 1632 ' data-dtr-index="' + 1633 col.columnIndex + 1634 '" data-dt-row="' + 1635 col.rowIndex + 1636 '" data-dt-column="' + 1637 col.columnIndex + 1638 '">' + 1639 '<span class="dtr-title">' + 1640 col.title + 1641 '</span> ' + 1642 '<span class="dtr-data">' + 1643 col.data + 1644 '</span>' + 1645 '</li>' 1646 : ''; 1647 }).join(''); 1648 1649 return data 1650 ? $( 1651 '<ul data-dtr-index="' + 1652 rowIdx + 1653 '" class="dtr-details"/>' 1654 ).append(data) 1655 : false; 1656 }; 1657 }, 1658 1659 tableAll: function (options) { 1660 options = $.extend( 1661 { 1662 tableClass: '' 1663 }, 1664 options 1665 ); 1666 1667 return function (api, rowIdx, columns) { 1668 var data = $.map(columns, function (col) { 1669 var klass = col.className 1670 ? 'class="' + col.className + '"' 1671 : ''; 1672 1673 return ( 1674 '<tr ' + 1675 klass + 1676 ' data-dt-row="' + 1677 col.rowIndex + 1678 '" data-dt-column="' + 1679 col.columnIndex + 1680 '">' + 1681 '<td>' + 1682 ( '' !== col.title 1683 ? col.title + ':' 1684 : '' 1685 ) + 1686 '</td> ' + 1687 '<td>' + 1688 col.data + 1689 '</td>' + 1690 '</tr>' 1691 ); 1692 }).join(''); 1693 1694 return $( 1695 '<table class="' + 1696 options.tableClass + 1697 ' dtr-details" width="100%"/>' 1698 ).append(data); 1699 }; 1700 } 1701}; 1702 1703/** 1704 * Responsive default settings for initialisation 1705 * 1706 * @namespace 1707 * @name Responsive.defaults 1708 * @static 1709 */ 1710Responsive.defaults = { 1711 /** 1712 * List of breakpoints for the instance. Note that this means that each 1713 * instance can have its own breakpoints. Additionally, the breakpoints 1714 * cannot be changed once an instance has been creased. 1715 * 1716 * @type {Array} 1717 * @default Takes the value of `Responsive.breakpoints` 1718 */ 1719 breakpoints: Responsive.breakpoints, 1720 1721 /** 1722 * Enable / disable auto hiding calculations. It can help to increase 1723 * performance slightly if you disable this option, but all columns would 1724 * need to have breakpoint classes assigned to them 1725 * 1726 * @type {Boolean} 1727 * @default `true` 1728 */ 1729 auto: true, 1730 1731 /** 1732 * Details control. If given as a string value, the `type` property of the 1733 * default object is set to that value, and the defaults used for the rest 1734 * of the object - this is for ease of implementation. 1735 *
1736 * The object consists of the following properties: 1737 * 1738 * * `display` - A function that is used to show and hide the hidden details 1739 * * `renderer` - function that is called for display of the child row data. 1740 * The default function will show the data from the hidden columns 1741 * * `target` - Used as the selector for what objects to attach the child 1742 * open / close to 1743 * * `type` - `false` to disable the details display, `inline` or `column` 1744 * for the two control types 1745 * 1746 * @type {Object|string} 1747 */ 1748 details: { 1749 display: Responsive.display.childRow, 1750 1751 renderer: Responsive.renderer.listHidden(), 1752 1753 target: 0, 1754 1755 type: 'inline' 1756 }, 1757 1758 /** 1759 * Orthogonal data request option. This is used to define the data type 1760 * requested when Responsive gets the data to show in the child row. 1761 * 1762 * @type {String} 1763 */ 1764 orthogonal: 'display' 1765}; 1766 1767/* 1768 * API 1769 */ 1770var Api = $.fn.dataTable.Api; 1771 1772// Doesn't do anything - work around for a bug in DT... Not documented 1773Api.register('responsive()', function () { 1774 return this; 1775}); 1776 1777Api.register('responsive.index()', function (li) { 1778 li = $(li); 1779 1780 return { 1781 column: li.data('dtr-index'), 1782 row: li.parent().data('dtr-index') 1783 }; 1784}); 1785 1786Api.register('responsive.rebuild()', function () { 1787 return this.iterator('table', function (ctx) { 1788 if (ctx._responsive) { 1789 ctx._responsive._classLogic(); 1790 } 1791 }); 1792}); 1793 1794Api.register('responsive.recalc()', function () { 1795 return this.iterator('table', function (ctx) { 1796 if (ctx._responsive) { 1797 ctx._responsive._resizeAuto(); 1798 ctx._responsive._resize(); 1799 } 1800 }); 1801}); 1802 1803Api.register('responsive.hasHidden()', function () { 1804 var ctx = this.context[0]; 1805 1806 return ctx._responsive 1807 ? $.inArray(false, ctx._responsive._responsiveOnlyHidden()) !== -1 1808 : false; 1809}); 1810 1811Api.registerPlural( 1812 'columns().responsiveHidden()', 1813 'column().responsiveHidden()', 1814 function () { 1815 return this.iterator( 1816 'column', 1817 function (settings, column) { 1818 return settings._responsive 1819 ? settings._responsive._responsiveOnlyHidden()[column] 1820 : false; 1821 }, 1822 1 1823 ); 1824 } 1825); 1826 1827/** 1828 * Version information 1829 * 1830 * @name Responsive.version 1831 * @static 1832 */ 1833Responsive.version = '3.0.4'; 1834 1835$.fn.dataTable.Responsive = Responsive; 1836$.fn.DataTable.Responsive = Responsive; 1837 1838// Attach a listener to the document which listens for DataTables initialisation 1839// events so we can automatically initialise 1840$(document).on('preInit.dt.dtr', function (e, settings, json) { 1841 if (e.namespace !== 'dt') { 1842 return; 1843 } 1844 1845 if ( 1846 $(settings.nTable).hasClass('responsive') || 1847 $(settings.nTable).hasClass('dt-responsive') || 1848 settings.oInit.responsive || 1849 DataTable.defaults.responsive 1850 ) { 1851 var init = settings.oInit.responsive; 1852 1853 if (init !== false) { 1854 new Responsive(settings, $.isPlainObject(init) ? init : {}); 1855 } 1856 } 1857}); 1858 1859 1860return DataTable; 1861}));
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.