/*! Responsive 2.4.1 * © SpryMedia Ltd - datatables.net/license */ (function( factory ){ if ( typeof define === 'function' && define.amd ) { // AMD define( ['jquery', 'datatables.net'], function ( $ ) { return factory( $, window, document ); } ); } else if ( typeof exports === 'object' ) { // CommonJS var jq = require('jquery'); var cjsRequires = function (root, $) { if ( ! $.fn.dataTable ) { require('datatables.net')(root, $); } }; if (typeof window !== 'undefined') { module.exports = function (root, $) { if ( ! root ) { // CommonJS environments without a window global must pass a // root. This will give an error otherwise root = window; } if ( ! $ ) { $ = jq( root ); } cjsRequires( root, $ ); return factory( $, root, root.document ); }; } else { cjsRequires( window, jq ); module.exports = factory( jq, window, window.document ); } } else { // Browser factory( jQuery, window, document ); } }(function( $, window, document, undefined ) { 'use strict'; var DataTable = $.fn.dataTable; /** * @summary Responsive * @description Responsive tables plug-in for DataTables * @version 2.4.1 * @author SpryMedia Ltd (www.sprymedia.co.uk) * @contact www.sprymedia.co.uk/contact * @copyright SpryMedia Ltd. * * This source file is free software, available under the following license: * MIT license - http://datatables.net/license/mit * * This source file is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. * * For details please refer to: http://www.datatables.net */ /** * Responsive is a plug-in for the DataTables library that makes use of * DataTables' ability to change the visibility of columns, changing the * visibility of columns so the displayed columns fit into the table container. * The end result is that complex tables will be dynamically adjusted to fit * into the viewport, be it on a desktop, tablet or mobile browser. * * Responsive for DataTables has two modes of operation, which can used * individually or combined: * * * Class name based control - columns assigned class names that match the * breakpoint logic can be shown / hidden as required for each breakpoint. * * Automatic control - columns are automatically hidden when there is no * room left to display them. Columns removed from the right. * * In additional to column visibility control, Responsive also has built into * options to use DataTables' child row display to show / hide the information * from the table that has been hidden. There are also two modes of operation * for this child row display: * * * Inline - when the control element that the user can use to show / hide * child rows is displayed inside the first column of the table. * * Column - where a whole column is dedicated to be the show / hide control. * * Initialisation of Responsive is performed by: * * * Adding the class `responsive` or `dt-responsive` to the table. In this case * Responsive will automatically be initialised with the default configuration * options when the DataTable is created. * * Using the `responsive` option in the DataTables configuration options. This * can also be used to specify the configuration options, or simply set to * `true` to use the defaults. * * @class * @param {object} settings DataTables settings object for the host table * @param {object} [opts] Configuration options * @requires jQuery 1.7+ * @requires DataTables 1.10.3+ * * @example * $('#example').DataTable( { * responsive: true * } ); * } ); */ var Responsive = function ( settings, opts ) { // Sanity check that we are using DataTables 1.10 or newer if ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.10' ) ) { throw 'DataTables Responsive requires DataTables 1.10.10 or newer'; } this.s = { childNodeStore: {}, columns: [], current: [], dt: new DataTable.Api( settings ) }; // Check if responsive has already been initialised on this table if ( this.s.dt.settings()[0].responsive ) { return; } // details is an object, but for simplicity the user can give it as a string // or a boolean if ( opts && typeof opts.details === 'string' ) { opts.details = { type: opts.details }; } else if ( opts && opts.details === false ) { opts.details = { type: false }; } else if ( opts && opts.details === true ) { opts.details = { type: 'inline' }; } this.c = $.extend( true, {}, Responsive.defaults, DataTable.defaults.responsive, opts ); settings.responsive = this; this._constructor(); }; $.extend( Responsive.prototype, { /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Constructor */ /** * Initialise the Responsive instance * * @private */ _constructor: function () { var that = this; var dt = this.s.dt; var dtPrivateSettings = dt.settings()[0]; var oldWindowWidth = $(window).innerWidth(); dt.settings()[0]._responsive = this; // Use DataTables' throttle function to avoid processor thrashing on // resize $(window).on( 'resize.dtr orientationchange.dtr', DataTable.util.throttle( function () { // iOS has a bug whereby resize can fire when only scrolling // See: http://stackoverflow.com/questions/8898412 var width = $(window).innerWidth(); if ( width !== oldWindowWidth ) { that._resize(); oldWindowWidth = width; } } ) ); // DataTables doesn't currently trigger an event when a row is added, so // we need to hook into its private API to enforce the hidden rows when // new data is added dtPrivateSettings.oApi._fnCallbackReg( dtPrivateSettings, 'aoRowCreatedCallback', function (tr, data, idx) { if ( $.inArray( false, that.s.current ) !== -1 ) { $('>td, >th', tr).each( function ( i ) { var idx = dt.column.index( 'toData', i ); if ( that.s.current[idx] === false ) { $(this).css('display', 'none'); } } ); } } ); // Destroy event handler dt.on( 'destroy.dtr', function () { dt.off( '.dtr' ); $( dt.table().body() ).off( '.dtr' ); $(window).off( 'resize.dtr orientationchange.dtr' ); dt.cells('.dtr-control').nodes().to$().removeClass('dtr-control'); // Restore the columns that we've hidden $.each( that.s.current, function ( i, val ) { if ( val === false ) { that._setColumnVis( i, true ); } } ); } ); // Reorder the breakpoints array here in case they have been added out // of order this.c.breakpoints.sort( function (a, b) { return a.width < b.width ? 1 : a.width > b.width ? -1 : 0; } ); this._classLogic(); this._resizeAuto(); // Details handler var details = this.c.details; if ( details.type !== false ) { that._detailsInit(); // DataTables will trigger this event on every column it shows and // hides individually dt.on( 'column-visibility.dtr', function () { // Use a small debounce to allow multiple columns to be set together if ( that._timer ) { clearTimeout( that._timer ); } that._timer = setTimeout( function () { that._timer = null; that._classLogic(); that._resizeAuto(); that._resize(true); that._redrawChildren(); }, 100 ); } ); // Redraw the details box on each draw which will happen if the data // has changed. This is used until DataTables implements a native // `updated` event for rows dt.on( 'draw.dtr', function () { that._redrawChildren(); } ); $(dt.table().node()).addClass( 'dtr-'+details.type ); } dt.on( 'column-reorder.dtr', function (e, settings, details) { that._classLogic(); that._resizeAuto(); that._resize(true); } ); // Change in column sizes means we need to calc dt.on( 'column-sizing.dtr', function () { that._resizeAuto(); that._resize(); }); // DT2 let's us tell it if we are hiding columns dt.on( 'column-calc.dt', function (e, d) { var curr = that.s.current; for (var i=0 ; i= 0) { d.visible.splice(idx, 1); } } } ); // On Ajax reload we want to reopen any child rows which are displayed // by responsive dt.on( 'preXhr.dtr', function () { var rowIds = []; dt.rows().every( function () { if ( this.child.isShown() ) { rowIds.push( this.id(true) ); } } ); dt.one( 'draw.dtr', function () { that._resizeAuto(); that._resize(); dt.rows( rowIds ).every( function () { that._detailsDisplay( this, false ); } ); } ); }); dt .on( 'draw.dtr', function () { that._controlClass(); }) .on( 'init.dtr', function (e, settings, details) { if ( e.namespace !== 'dt' ) { return; } that._resizeAuto(); that._resize(); // If columns were hidden, then DataTables needs to adjust the // column sizing if ( $.inArray( false, that.s.current ) ) { dt.columns.adjust(); } } ); // First pass - draw the table for the current viewport size this._resize(); }, /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Private methods */ /** * Get and store nodes from a cell - use for node moving renderers * * @param {*} dt DT instance * @param {*} row Row index * @param {*} col Column index */ _childNodes: function( dt, row, col ) { var name = row+'-'+col; if ( this.s.childNodeStore[ name ] ) { return this.s.childNodeStore[ name ]; } // https://jsperf.com/childnodes-array-slice-vs-loop var nodes = []; var children = dt.cell( row, col ).node().childNodes; for ( var i=0, ien=children.length ; i