META-INF.resources.bower_components.datatables.net-responsive.js.dataTables.responsive.js Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jwebmp-data-tables Show documentation
Show all versions of jwebmp-data-tables Show documentation
The JWebSwing implementation for Data Tables
/*! Responsive 2.2.3
* 2014-2018 SpryMedia Ltd - datatables.net/license
*/
/**
* @summary Responsive
* @description Responsive tables plug-in for DataTables
* @version 2.2.3
* @file dataTables.responsive.js
* @author SpryMedia Ltd (www.sprymedia.co.uk)
* @contact www.sprymedia.co.uk/contact
* @copyright Copyright 2014-2018 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
*/
(function( factory ){
if ( typeof define === 'function' && define.amd ) {
// AMD
define( ['jquery', 'datatables.net'], function ( $ ) {
return factory( $, window, document );
} );
}
else if ( typeof exports === 'object' ) {
// CommonJS
module.exports = function (root, $) {
if ( ! root ) {
root = window;
}
if ( ! $ || ! $.fn.dataTable ) {
$ = require('datatables.net')(root, $).$;
}
return factory( $, root, root.document );
};
}
else {
// Browser
factory( jQuery, window, document );
}
}(function( $, window, document, undefined ) {
'use strict';
var DataTable = $.fn.dataTable;
/**
* 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 = {
dt: new DataTable.Api( settings ),
columns: [],
current: []
};
// 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).width();
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).width();
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' );
// 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();
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();
} );
// Change in column sizes means we need to calc
dt.on( 'column-sizing.dtr', function () {
that._resizeAuto();
that._resize();
});
// 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( 'init.dtr', function (e, settings, details) {
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
*/
/**
* Calculate the visibility for the columns in a table for a given
* breakpoint. The result is pre-determined based on the class logic if
* class names are used to control all columns, but the width of the table
* is also used if there are columns which are to be automatically shown
* and hidden.
*
* @param {string} breakpoint Breakpoint name to use for the calculation
* @return {array} Array of boolean values initiating the visibility of each
* column.
* @private
*/
_columnsVisiblity: function ( breakpoint )
{
var dt = this.s.dt;
var columns = this.s.columns;
var i, ien;
// Create an array that defines the column ordering based first on the
// column's priority, and secondly the column index. This allows the
// columns to be removed from the right if the priority matches
var order = columns
.map( function ( col, idx ) {
return {
columnIdx: idx,
priority: col.priority
};
} )
.sort( function ( a, b ) {
if ( a.priority !== b.priority ) {
return a.priority - b.priority;
}
return a.columnIdx - b.columnIdx;
} );
// Class logic - determine which columns are in this breakpoint based
// on the classes. If no class control (i.e. `auto`) then `-` is used
// to indicate this to the rest of the function
var display = $.map( columns, function ( col, i ) {
if ( dt.column(i).visible() === false ) {
return 'not-visible';
}
return col.auto && col.minWidth === null ?
false :
col.auto === true ?
'-' :
$.inArray( breakpoint, col.includeIn ) !== -1;
} );
// Auto column control - first pass: how much width is taken by the
// ones that must be included from the non-auto columns
var requiredWidth = 0;
for ( i=0, ien=display.length ; i= size ) {
add( colIdx, breakpoints[i].name );
}
}
}
else if ( operator === 'not-' ) {
// Add all but this breakpoint
for ( i=0, ien=breakpoints.length ; i=0 ; i-- ) {
if ( width <= breakpoints[i].width ) {
breakpoint = breakpoints[i].name;
break;
}
}
// Show the columns for that break point
var columnsVis = this._columnsVisiblity( breakpoint );
this.s.current = columnsVis;
// Set the class before the column visibility is changed so event
// listeners know what the state is. Need to determine if there are
// any columns that are not visible but can be shown
var collapsedClass = false;
for ( i=0, ien=columns.length ; i ')
.append( footerCells )
.appendTo( clonedFooter );
}
$(' ')
.append( headerCells )
.appendTo( clonedHeader );
// In the inline case extra padding is applied to the first column to
// give space for the show / hide icon. We need to use this in the
// calculation
if ( this.c.details.type === 'inline' ) {
$(clonedTable).addClass( 'dtr-inline collapsed' );
}
// It is unsafe to insert elements with the same name into the DOM
// multiple times. For example, cloning and inserting a checked radio
// clears the chcecked state of the original radio.
$( clonedTable ).find( '[name]' ).removeAttr( 'name' );
// A position absolute table would take the table out of the flow of
// our container element, bypassing the height and width (Scroller)
$( clonedTable ).css( 'position', 'relative' )
var inserted = $('')
.css( {
width: 1,
height: 1,
overflow: 'hidden',
clear: 'both'
} )
.append( clonedTable );
inserted.insertBefore( dt.table().node() );
// The cloned header now contains the smallest that each column can be
headerCells.each( function (i) {
var idx = dt.column.index( 'fromVisible', i );
columns[ idx ].minWidth = this.offsetWidth || 0;
} );
inserted.remove();
},
/**
* Set a column's visibility.
*
* We don't use DataTables' column visibility controls in order to ensure
* that column visibility can Responsive can no-exist. Since only IE8+ is
* supported (and all evergreen browsers of course) the control of the
* display attribute works well.
*
* @param {integer} col Column index
* @param {boolean} showHide Show or hide (true or false)
* @private
*/
_setColumnVis: function ( col, showHide )
{
var dt = this.s.dt;
var display = showHide ? '' : 'none'; // empty string will remove the attr
$( dt.column( col ).header() ).css( 'display', display );
$( dt.column( col ).footer() ).css( 'display', display );
dt.column( col ).nodes().to$().css( 'display', display );
// If the are child nodes stored, we might need to reinsert them
if ( ! $.isEmptyObject( _childNodeStore ) ) {
dt.cells( null, col ).indexes().each( function (idx) {
_childNodesRestore( dt, idx.row, idx.column );
} );
}
},
/**
* Update the cell tab indexes for keyboard accessibility. This is called on
* every table draw - that is potentially inefficient, but also the least
* complex option given that column visibility can change on the fly. Its a
* shame user-focus was removed from CSS 3 UI, as it would have solved this
* issue with a single CSS statement.
*
* @private
*/
_tabIndexes: function ()
{
var dt = this.s.dt;
var cells = dt.cells( { page: 'current' } ).nodes().to$();
var ctx = dt.settings()[0];
var target = this.c.details.target;
cells.filter( '[data-dtr-keyboard]' ).removeData( '[data-dtr-keyboard]' );
if ( typeof target === 'number' ) {
dt.cells( null, target, { page: 'current' } ).nodes().to$()
.attr( 'tabIndex', ctx.iTabIndex )
.data( 'dtr-keyboard', 1 );
}
else {
// This is a bit of a hack - we need to limit the selected nodes to just
// those of this table
if ( target === 'td:first-child, th:first-child' ) {
target = '>td:first-child, >th:first-child';
}
$( target, dt.rows( { page: 'current' } ).nodes() )
.attr( 'tabIndex', ctx.iTabIndex )
.data( 'dtr-keyboard', 1 );
}
}
} );
/**
* List of default breakpoints. Each item in the array is an object with two
* properties:
*
* * `name` - the breakpoint name.
* * `width` - the breakpoint width
*
* @name Responsive.breakpoints
* @static
*/
Responsive.breakpoints = [
{ name: 'desktop', width: Infinity },
{ name: 'tablet-l', width: 1024 },
{ name: 'tablet-p', width: 768 },
{ name: 'mobile-l', width: 480 },
{ name: 'mobile-p', width: 320 }
];
/**
* Display methods - functions which define how the hidden data should be shown
* in the table.
*
* @namespace
* @name Responsive.defaults
* @static
*/
Responsive.display = {
childRow: function ( row, update, render ) {
if ( update ) {
if ( $(row.node()).hasClass('parent') ) {
row.child( render(), 'child' ).show();
return true;
}
}
else {
if ( ! row.child.isShown() ) {
row.child( render(), 'child' ).show();
$( row.node() ).addClass( 'parent' );
return true;
}
else {
row.child( false );
$( row.node() ).removeClass( 'parent' );
return false;
}
}
},
childRowImmediate: function ( row, update, render ) {
if ( (! update && row.child.isShown()) || ! row.responsive.hasHidden() ) {
// User interaction and the row is show, or nothing to show
row.child( false );
$( row.node() ).removeClass( 'parent' );
return false;
}
else {
// Display
row.child( render(), 'child' ).show();
$( row.node() ).addClass( 'parent' );
return true;
}
},
// This is a wrapper so the modal options for Bootstrap and jQuery UI can
// have options passed into them. This specific one doesn't need to be a
// function but it is for consistency in the `modal` name
modal: function ( options ) {
return function ( row, update, render ) {
if ( ! update ) {
// Show a modal
var close = function () {
modal.remove(); // will tidy events for us
$(document).off( 'keypress.dtr' );
};
var modal = $('')
.append( $('')
.append( $('')
.append( render() )
)
.append( $('×' )
.click( function () {
close();
} )
)
)
.append( $('')
.click( function () {
close();
} )
)
.appendTo( 'body' );
$(document).on( 'keyup.dtr', function (e) {
if ( e.keyCode === 27 ) {
e.stopPropagation();
close();
}
} );
}
else {
$('div.dtr-modal-content')
.empty()
.append( render() );
}
if ( options && options.header ) {
$('div.dtr-modal-content').prepend(
''+options.header( row )+'
'
);
}
};
}
};
var _childNodeStore = {};
function _childNodes( dt, row, col ) {
var name = row+'-'+col;
if ( _childNodeStore[ name ] ) {
return _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 ');
var found = false;
var data = $.each( columns, function ( i, col ) {
if ( col.hidden ) {
$(
''+
''+
col.title+
' '+
' '
)
.append( $('').append( _childNodes( api, col.rowIndex, col.columnIndex ) ) )// api.cell( col.rowIndex, col.columnIndex ).node().childNodes ) )
.appendTo( ul );
found = true;
}
} );
return found ?
ul :
false;
};
},
listHidden: function () {
return function ( api, rowIdx, columns ) {
var data = $.map( columns, function ( col ) {
return col.hidden ?
''+
''+
col.title+
' '+
''+
col.data+
''+
' ' :
'';
} ).join('');
return data ?
$('
').append( data ) :
false;
}
},
tableAll: function ( options ) {
options = $.extend( {
tableClass: ''
}, options );
return function ( api, rowIdx, columns ) {
var data = $.map( columns, function ( col ) {
return ''+
''+col.title+':'+' '+
''+col.data+' '+
' ';
} ).join('');
return $('
').append( data );
}
}
};
/**
* Responsive default settings for initialisation
*
* @namespace
* @name Responsive.defaults
* @static
*/
Responsive.defaults = {
/**
* List of breakpoints for the instance. Note that this means that each
* instance can have its own breakpoints. Additionally, the breakpoints
* cannot be changed once an instance has been creased.
*
* @type {Array}
* @default Takes the value of `Responsive.breakpoints`
*/
breakpoints: Responsive.breakpoints,
/**
* Enable / disable auto hiding calculations. It can help to increase
* performance slightly if you disable this option, but all columns would
* need to have breakpoint classes assigned to them
*
* @type {Boolean}
* @default `true`
*/
auto: true,
/**
* Details control. If given as a string value, the `type` property of the
* default object is set to that value, and the defaults used for the rest
* of the object - this is for ease of implementation.
*
* The object consists of the following properties:
*
* * `display` - A function that is used to show and hide the hidden details
* * `renderer` - function that is called for display of the child row data.
* The default function will show the data from the hidden columns
* * `target` - Used as the selector for what objects to attach the child
* open / close to
* * `type` - `false` to disable the details display, `inline` or `column`
* for the two control types
*
* @type {Object|string}
*/
details: {
display: Responsive.display.childRow,
renderer: Responsive.renderer.listHidden(),
target: 0,
type: 'inline'
},
/**
* Orthogonal data request option. This is used to define the data type
* requested when Responsive gets the data to show in the child row.
*
* @type {String}
*/
orthogonal: 'display'
};
/*
* API
*/
var Api = $.fn.dataTable.Api;
// Doesn't do anything - work around for a bug in DT... Not documented
Api.register( 'responsive()', function () {
return this;
} );
Api.register( 'responsive.index()', function ( li ) {
li = $(li);
return {
column: li.data('dtr-index'),
row: li.parent().data('dtr-index')
};
} );
Api.register( 'responsive.rebuild()', function () {
return this.iterator( 'table', function ( ctx ) {
if ( ctx._responsive ) {
ctx._responsive._classLogic();
}
} );
} );
Api.register( 'responsive.recalc()', function () {
return this.iterator( 'table', function ( ctx ) {
if ( ctx._responsive ) {
ctx._responsive._resizeAuto();
ctx._responsive._resize();
}
} );
} );
Api.register( 'responsive.hasHidden()', function () {
var ctx = this.context[0];
return ctx._responsive ?
$.inArray( false, ctx._responsive.s.current ) !== -1 :
false;
} );
Api.registerPlural( 'columns().responsiveHidden()', 'column().responsiveHidden()', function () {
return this.iterator( 'column', function ( settings, column ) {
return settings._responsive ?
settings._responsive.s.current[ column ] :
false;
}, 1 );
} );
/**
* Version information
*
* @name Responsive.version
* @static
*/
Responsive.version = '2.2.3';
$.fn.dataTable.Responsive = Responsive;
$.fn.DataTable.Responsive = Responsive;
// Attach a listener to the document which listens for DataTables initialisation
// events so we can automatically initialise
$(document).on( 'preInit.dt.dtr', function (e, settings, json) {
if ( e.namespace !== 'dt' ) {
return;
}
if ( $(settings.nTable).hasClass( 'responsive' ) ||
$(settings.nTable).hasClass( 'dt-responsive' ) ||
settings.oInit.responsive ||
DataTable.defaults.responsive
) {
var init = settings.oInit.responsive;
if ( init !== false ) {
new Responsive( settings, $.isPlainObject( init ) ? init : {} );
}
}
} );
return Responsive;
}));
© 2015 - 2025 Weber Informatics LLC | Privacy Policy