Show More
Commit Description:
select2, ace, moment now work....
Commit Description:
select2, ace, moment now work.
converting navbar
References:
File last commit:
Show/Diff file:
Action:
vendor/javascript/datatables/Responsive-2.3.0/js/dataTables.responsive.js
| 1498 lines
| 40.2 KiB
| application/javascript
| JavascriptLexer
|
r866 | /*! Responsive 2.3.0 | |||
* 2014-2022 SpryMedia Ltd - datatables.net/license | ||||
*/ | ||||
/** | ||||
* @summary Responsive | ||||
* @description Responsive tables plug-in for DataTables | ||||
* @version 2.3.0 | ||||
* @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 | ||||
*/ | ||||
(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).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<curr.length ; i++) { | ||||
var idx = d.visible.indexOf(i); | ||||
if (curr[i] === false && idx >= 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 | ||||
*/ | ||||
/** | ||||
* 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<ien ; i++ ) { | ||||
if ( display[i] === true ) { | ||||
requiredWidth += columns[i].minWidth; | ||||
} | ||||
} | ||||
// Second pass, use up any remaining width for other columns. For | ||||
// scrolling tables we need to subtract the width of the scrollbar. It | ||||
// may not be requires which makes this sub-optimal, but it would | ||||
// require another full redraw to make complete use of those extra few | ||||
// pixels | ||||
var scrolling = dt.settings()[0].oScroll; | ||||
var bar = scrolling.sY || scrolling.sX ? scrolling.iBarWidth : 0; | ||||
var widthAvailable = dt.table().container().offsetWidth - bar; | ||||
var usedWidth = widthAvailable - requiredWidth; | ||||
// Control column needs to always be included. This makes it sub- | ||||
// optimal in terms of using the available with, but to stop layout | ||||
// thrashing or overflow. Also we need to account for the control column | ||||
// width first so we know how much width is available for the other | ||||
// columns, since the control column might not be the first one shown | ||||
for ( i=0, ien=display.length ; i<ien ; i++ ) { | ||||
if ( columns[i].control ) { | ||||
usedWidth -= columns[i].minWidth; | ||||
} | ||||
} | ||||
// Allow columns to be shown (counting by priority and then right to | ||||
// left) until we run out of room | ||||
var empty = false; | ||||
for ( i=0, ien=order.length ; i<ien ; i++ ) { | ||||
var colIdx = order[i].columnIdx; | ||||
if ( display[colIdx] === '-' && ! columns[colIdx].control && columns[colIdx].minWidth ) { | ||||
// Once we've found a column that won't fit we don't let any | ||||
// others display either, or columns might disappear in the | ||||
// middle of the table | ||||
if ( empty || usedWidth - columns[colIdx].minWidth < 0 ) { | ||||
empty = true; | ||||
display[colIdx] = false; | ||||
} | ||||
else { | ||||
display[colIdx] = true; | ||||
} | ||||
usedWidth -= columns[colIdx].minWidth; | ||||
} | ||||
} | ||||
// Determine if the 'control' column should be shown (if there is one). | ||||
// This is the case when there is a hidden column (that is not the | ||||
// control column). The two loops look inefficient here, but they are | ||||
// trivial and will fly through. We need to know the outcome from the | ||||
// first , before the action in the second can be taken | ||||
var showControl = false; | ||||
for ( i=0, ien=columns.length ; i<ien ; i++ ) { | ||||
if ( ! columns[i].control && ! columns[i].never && display[i] === false ) { | ||||
showControl = true; | ||||
break; | ||||
} | ||||
} | ||||
for ( i=0, ien=columns.length ; i<ien ; i++ ) { | ||||
if ( columns[i].control ) { | ||||
display[i] = showControl; | ||||
} | ||||
// Replace not visible string with false from the control column detection above | ||||
if ( display[i] === 'not-visible' ) { | ||||
display[i] = false; | ||||
} | ||||
} | ||||
// Finally we need to make sure that there is at least one column that | ||||
// is visible | ||||
if ( $.inArray( true, display ) === -1 ) { | ||||
display[0] = true; | ||||
} | ||||
return display; | ||||
}, | ||||
/** | ||||
* Create the internal `columns` array with information about the columns | ||||
* for the table. This includes determining which breakpoints the column | ||||
* will appear in, based upon class names in the column, which makes up the | ||||
* vast majority of this method. | ||||
* | ||||
* @private | ||||
*/ | ||||
_classLogic: function () | ||||
{ | ||||
var that = this; | ||||
var calc = {}; | ||||
var breakpoints = this.c.breakpoints; | ||||
var dt = this.s.dt; | ||||
var columns = dt.columns().eq(0).map( function (i) { | ||||
var column = this.column(i); | ||||
var className = column.header().className; | ||||
var priority = dt.settings()[0].aoColumns[i].responsivePriority; | ||||
var dataPriority = column.header().getAttribute('data-priority'); | ||||
if ( priority === undefined ) { | ||||
priority = dataPriority === undefined || dataPriority === null? | ||||
10000 : | ||||
dataPriority * 1; | ||||
} | ||||
return { | ||||
className: className, | ||||
includeIn: [], | ||||
auto: false, | ||||
control: false, | ||||
never: className.match(/\b(dtr\-)?never\b/) ? true : false, | ||||
priority: priority | ||||
}; | ||||
} ); | ||||
// Simply add a breakpoint to `includeIn` array, ensuring that there are | ||||
// no duplicates | ||||
var add = function ( colIdx, name ) { | ||||
var includeIn = columns[ colIdx ].includeIn; | ||||
if ( $.inArray( name, includeIn ) === -1 ) { | ||||
includeIn.push( name ); | ||||
} | ||||
}; | ||||
var column = function ( colIdx, name, operator, matched ) { | ||||
var size, i, ien; | ||||
if ( ! operator ) { | ||||
columns[ colIdx ].includeIn.push( name ); | ||||
} | ||||
else if ( operator === 'max-' ) { | ||||
// Add this breakpoint and all smaller | ||||
size = that._find( name ).width; | ||||
for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) { | ||||
if ( breakpoints[i].width <= size ) { | ||||
add( colIdx, breakpoints[i].name ); | ||||
} | ||||
} | ||||
} | ||||
else if ( operator === 'min-' ) { | ||||
// Add this breakpoint and all larger | ||||
size = that._find( name ).width; | ||||
for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) { | ||||
if ( breakpoints[i].width >= size ) { | ||||
add( colIdx, breakpoints[i].name ); | ||||
} | ||||
} | ||||
} | ||||
else if ( operator === 'not-' ) { | ||||
// Add all but this breakpoint | ||||
for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) { | ||||
if ( breakpoints[i].name.indexOf( matched ) === -1 ) { | ||||
add( colIdx, breakpoints[i].name ); | ||||
} | ||||
} | ||||
} | ||||
}; | ||||
// Loop over each column and determine if it has a responsive control | ||||
// class | ||||
columns.each( function ( col, i ) { | ||||
var classNames = col.className.split(' '); | ||||
var hasClass = false; | ||||
// Split the class name up so multiple rules can be applied if needed | ||||
for ( var k=0, ken=classNames.length ; k<ken ; k++ ) { | ||||
var className = classNames[k].trim(); | ||||
if ( className === 'all' || className === 'dtr-all' ) { | ||||
// Include in all | ||||
hasClass = true; | ||||
col.includeIn = $.map( breakpoints, function (a) { | ||||
return a.name; | ||||
} ); | ||||
return; | ||||
} | ||||
else if ( className === 'none' || className === 'dtr-none' || col.never ) { | ||||
// Include in none (default) and no auto | ||||
hasClass = true; | ||||
return; | ||||
} | ||||
else if ( className === 'control' || className === 'dtr-control' ) { | ||||
// Special column that is only visible, when one of the other | ||||
// columns is hidden. This is used for the details control | ||||
hasClass = true; | ||||
col.control = true; | ||||
return; | ||||
} | ||||
$.each( breakpoints, function ( j, breakpoint ) { | ||||
// Does this column have a class that matches this breakpoint? | ||||
var brokenPoint = breakpoint.name.split('-'); | ||||
var re = new RegExp( '(min\\-|max\\-|not\\-)?('+brokenPoint[0]+')(\\-[_a-zA-Z0-9])?' ); | ||||
var match = className.match( re ); | ||||
if ( match ) { | ||||
hasClass = true; | ||||
if ( match[2] === brokenPoint[0] && match[3] === '-'+brokenPoint[1] ) { | ||||
// Class name matches breakpoint name fully | ||||
column( i, breakpoint.name, match[1], match[2]+match[3] ); | ||||
} | ||||
else if ( match[2] === brokenPoint[0] && ! match[3] ) { | ||||
// Class name matched primary breakpoint name with no qualifier | ||||
column( i, breakpoint.name, match[1], match[2] ); | ||||
} | ||||
} | ||||
} ); | ||||
} | ||||
// If there was no control class, then automatic sizing is used | ||||
if ( ! hasClass ) { | ||||
col.auto = true; | ||||
} | ||||
} ); | ||||
this.s.columns = columns; | ||||
}, | ||||
/** | ||||
* Update the cells to show the correct control class / button | ||||
* @private | ||||
*/ | ||||
_controlClass: function () | ||||
{ | ||||
if ( this.c.details.type === 'inline' ) { | ||||
var dt = this.s.dt; | ||||
var columnsVis = this.s.current; | ||||
var firstVisible = $.inArray(true, columnsVis); | ||||
// Remove from any cells which shouldn't have it | ||||
dt.cells( | ||||
null, | ||||
function(idx) { | ||||
return idx !== firstVisible; | ||||
}, | ||||
{page: 'current'} | ||||
) | ||||
.nodes() | ||||
.to$() | ||||
.filter('.dtr-control') | ||||
.removeClass('dtr-control'); | ||||
dt.cells(null, firstVisible, {page: 'current'}) | ||||
.nodes() | ||||
.to$() | ||||
.addClass('dtr-control'); | ||||
} | ||||
}, | ||||
/** | ||||
* Show the details for the child row | ||||
* | ||||
* @param {DataTables.Api} row API instance for the row | ||||
* @param {boolean} update Update flag | ||||
* @private | ||||
*/ | ||||
_detailsDisplay: function ( row, update ) | ||||
{ | ||||
var that = this; | ||||
var dt = this.s.dt; | ||||
var details = this.c.details; | ||||
if ( details && details.type !== false ) { | ||||
var renderer = typeof details.renderer === 'string' | ||||
? Responsive.renderer[details.renderer]() | ||||
: details.renderer; | ||||
var res = details.display( row, update, function () { | ||||
return renderer( | ||||
dt, row[0], that._detailsObj(row[0]) | ||||
); | ||||
} ); | ||||
if ( res === true || res === false ) { | ||||
$(dt.table().node()).triggerHandler( 'responsive-display.dt', [dt, row, res, update] ); | ||||
} | ||||
} | ||||
}, | ||||
/** | ||||
* Initialisation for the details handler | ||||
* | ||||
* @private | ||||
*/ | ||||
_detailsInit: function () | ||||
{ | ||||
var that = this; | ||||
var dt = this.s.dt; | ||||
var details = this.c.details; | ||||
// The inline type always uses the first child as the target | ||||
if ( details.type === 'inline' ) { | ||||
details.target = 'td.dtr-control, th.dtr-control'; | ||||
} | ||||
// Keyboard accessibility | ||||
dt.on( 'draw.dtr', function () { | ||||
that._tabIndexes(); | ||||
} ); | ||||
that._tabIndexes(); // Initial draw has already happened | ||||
$( dt.table().body() ).on( 'keyup.dtr', 'td, th', function (e) { | ||||
if ( e.keyCode === 13 && $(this).data('dtr-keyboard') ) { | ||||
$(this).click(); | ||||
} | ||||
} ); | ||||
// type.target can be a string jQuery selector or a column index | ||||
var target = details.target; | ||||
var selector = typeof target === 'string' ? target : 'td, th'; | ||||
if ( target !== undefined || target !== null ) { | ||||
// Click handler to show / hide the details rows when they are available | ||||
$( dt.table().body() ) | ||||
.on( 'click.dtr mousedown.dtr mouseup.dtr', selector, function (e) { | ||||
// If the table is not collapsed (i.e. there is no hidden columns) | ||||
// then take no action | ||||
if ( ! $(dt.table().node()).hasClass('collapsed' ) ) { | ||||
return; | ||||
} | ||||
// Check that the row is actually a DataTable's controlled node | ||||
if ( $.inArray( $(this).closest('tr').get(0), dt.rows().nodes().toArray() ) === -1 ) { | ||||
return; | ||||
} | ||||
// For column index, we determine if we should act or not in the | ||||
// handler - otherwise it is already okay | ||||
if ( typeof target === 'number' ) { | ||||
var targetIdx = target < 0 ? | ||||
dt.columns().eq(0).length + target : | ||||
target; | ||||
if ( dt.cell( this ).index().column !== targetIdx ) { | ||||
return; | ||||
} | ||||
} | ||||
// $().closest() includes itself in its check | ||||
var row = dt.row( $(this).closest('tr') ); | ||||
// Check event type to do an action | ||||
if ( e.type === 'click' ) { | ||||
// The renderer is given as a function so the caller can execute it | ||||
// only when they need (i.e. if hiding there is no point is running | ||||
// the renderer) | ||||
that._detailsDisplay( row, false ); | ||||
} | ||||
else if ( e.type === 'mousedown' ) { | ||||
// For mouse users, prevent the focus ring from showing | ||||
$(this).css('outline', 'none'); | ||||
} | ||||
else if ( e.type === 'mouseup' ) { | ||||
// And then re-allow at the end of the click | ||||
$(this).trigger('blur').css('outline', ''); | ||||
} | ||||
} ); | ||||
} | ||||
}, | ||||
/** | ||||
* Get the details to pass to a renderer for a row | ||||
* @param {int} rowIdx Row index | ||||
* @private | ||||
*/ | ||||
_detailsObj: function ( rowIdx ) | ||||
{ | ||||
var that = this; | ||||
var dt = this.s.dt; | ||||
return $.map( this.s.columns, function( col, i ) { | ||||
// Never and control columns should not be passed to the renderer | ||||
if ( col.never || col.control ) { | ||||
return; | ||||
} | ||||
var dtCol = dt.settings()[0].aoColumns[ i ]; | ||||
return { | ||||
className: dtCol.sClass, | ||||
columnIndex: i, | ||||
data: dt.cell( rowIdx, i ).render( that.c.orthogonal ), | ||||
hidden: dt.column( i ).visible() && !that.s.current[ i ], | ||||
rowIndex: rowIdx, | ||||
title: dtCol.sTitle !== null ? | ||||
dtCol.sTitle : | ||||
$(dt.column(i).header()).text() | ||||
}; | ||||
} ); | ||||
}, | ||||
/** | ||||
* Find a breakpoint object from a name | ||||
* | ||||
* @param {string} name Breakpoint name to find | ||||
* @return {object} Breakpoint description object | ||||
* @private | ||||
*/ | ||||
_find: function ( name ) | ||||
{ | ||||
var breakpoints = this.c.breakpoints; | ||||
for ( var i=0, ien=breakpoints.length ; i<ien ; i++ ) { | ||||
if ( breakpoints[i].name === name ) { | ||||
return breakpoints[i]; | ||||
} | ||||
} | ||||
}, | ||||
/** | ||||
* Re-create the contents of the child rows as the display has changed in | ||||
* some way. | ||||
* | ||||
* @private | ||||
*/ | ||||
_redrawChildren: function () | ||||
{ | ||||
var that = this; | ||||
var dt = this.s.dt; | ||||
dt.rows( {page: 'current'} ).iterator( 'row', function ( settings, idx ) { | ||||
var row = dt.row( idx ); | ||||
that._detailsDisplay( dt.row( idx ), true ); | ||||
} ); | ||||
}, | ||||
/** | ||||
* Alter the table display for a resized viewport. This involves first | ||||
* determining what breakpoint the window currently is in, getting the | ||||
* column visibilities to apply and then setting them. | ||||
* | ||||
* @param {boolean} forceRedraw Force a redraw | ||||
* @private | ||||
*/ | ||||
_resize: function (forceRedraw) | ||||
{ | ||||
var that = this; | ||||
var dt = this.s.dt; | ||||
var width = $(window).innerWidth(); | ||||
var breakpoints = this.c.breakpoints; | ||||
var breakpoint = breakpoints[0].name; | ||||
var columns = this.s.columns; | ||||
var i, ien; | ||||
var oldVis = this.s.current.slice(); | ||||
// Determine what breakpoint we are currently at | ||||
for ( i=breakpoints.length-1 ; 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<ien ; i++ ) { | ||||
if ( columnsVis[i] === false && ! columns[i].never && ! columns[i].control && ! dt.column(i).visible() === false ) { | ||||
collapsedClass = true; | ||||
break; | ||||
} | ||||
} | ||||
$( dt.table().node() ).toggleClass( 'collapsed', collapsedClass ); | ||||
var changed = false; | ||||
var visible = 0; | ||||
dt.columns().eq(0).each( function ( colIdx, i ) { | ||||
if ( columnsVis[i] === true ) { | ||||
visible++; | ||||
} | ||||
if ( forceRedraw || columnsVis[i] !== oldVis[i] ) { | ||||
changed = true; | ||||
that._setColumnVis( colIdx, columnsVis[i] ); | ||||
} | ||||
} ); | ||||
if ( changed ) { | ||||
this._redrawChildren(); | ||||
// Inform listeners of the change | ||||
$(dt.table().node()).trigger( 'responsive-resize.dt', [dt, this.s.current] ); | ||||
// If no records, update the "No records" display element | ||||
if ( dt.page.info().recordsDisplay === 0 ) { | ||||
$('td', dt.table().body()).eq(0).attr('colspan', visible); | ||||
} | ||||
} | ||||
that._controlClass(); | ||||
}, | ||||
/** | ||||
* Determine the width of each column in the table so the auto column hiding | ||||
* has that information to work with. This method is never going to be 100% | ||||
* perfect since column widths can change slightly per page, but without | ||||
* seriously compromising performance this is quite effective. | ||||
* | ||||
* @private | ||||
*/ | ||||
_resizeAuto: function () | ||||
{ | ||||
var dt = this.s.dt; | ||||
var columns = this.s.columns; | ||||
// Are we allowed to do auto sizing? | ||||
if ( ! this.c.auto ) { | ||||
return; | ||||
} | ||||
// Are there any columns that actually need auto-sizing, or do they all | ||||
// have classes defined | ||||
if ( $.inArray( true, $.map( columns, function (c) { return c.auto; } ) ) === -1 ) { | ||||
return; | ||||
} | ||||
// Need to restore all children. They will be reinstated by a re-render | ||||
if ( ! $.isEmptyObject( _childNodeStore ) ) { | ||||
$.each( _childNodeStore, function ( key ) { | ||||
var idx = key.split('-'); | ||||
_childNodesRestore( dt, idx[0]*1, idx[1]*1 ); | ||||
} ); | ||||
} | ||||
// Clone the table with the current data in it | ||||
var tableWidth = dt.table().node().offsetWidth; | ||||
var columnWidths = dt.columns; | ||||
var clonedTable = dt.table().node().cloneNode( false ); | ||||
var clonedHeader = $( dt.table().header().cloneNode( false ) ).appendTo( clonedTable ); | ||||
var clonedBody = $( dt.table().body() ).clone( false, false ).empty().appendTo( clonedTable ); // use jQuery because of IE8 | ||||
clonedTable.style.width = 'auto'; | ||||
// Header | ||||
var headerCells = dt.columns() | ||||
.header() | ||||
.filter( function (idx) { | ||||
return dt.column(idx).visible(); | ||||
} ) | ||||
.to$() | ||||
.clone( false ) | ||||
.css( 'display', 'table-cell' ) | ||||
.css( 'width', 'auto' ) | ||||
.css( 'min-width', 0 ); | ||||
// Body rows - we don't need to take account of DataTables' column | ||||
// visibility since we implement our own here (hence the `display` set) | ||||
$(clonedBody) | ||||
.append( $(dt.rows( { page: 'current' } ).nodes()).clone( false ) ) | ||||
.find( 'th, td' ).css( 'display', '' ); | ||||
// Footer | ||||
var footer = dt.table().footer(); | ||||
if ( footer ) { | ||||
var clonedFooter = $( footer.cloneNode( false ) ).appendTo( clonedTable ); | ||||
var footerCells = dt.columns() | ||||
.footer() | ||||
.filter( function (idx) { | ||||
return dt.column(idx).visible(); | ||||
} ) | ||||
.to$() | ||||
.clone( false ) | ||||
.css( 'display', 'table-cell' ); | ||||
$('<tr/>') | ||||
.append( footerCells ) | ||||
.appendTo( clonedFooter ); | ||||
} | ||||
$('<tr/>') | ||||
.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 = $('<div/>') | ||||
.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(); | ||||
}, | ||||
/** | ||||
* Get the state of the current hidden columns - controlled by Responsive only | ||||
*/ | ||||
_responsiveOnlyHidden: function () | ||||
{ | ||||
var dt = this.s.dt; | ||||
return $.map( this.s.current, function (v, i) { | ||||
// If the column is hidden by DataTables then it can't be hidden by | ||||
// Responsive! | ||||
if ( dt.column(i).visible() === false ) { | ||||
return true; | ||||
} | ||||
return v; | ||||
} ); | ||||
}, | ||||
/** | ||||
* 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 ) | ||||
.toggleClass('dtr-hidden', !showHide); | ||||
$( dt.column( col ).footer() ) | ||||
.css( 'display', display ) | ||||
.toggleClass('dtr-hidden', !showHide); | ||||
dt.column( col ).nodes().to$() | ||||
.css( 'display', display ) | ||||
.toggleClass('dtr-hidden', !showHide); | ||||
// 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 = $('<div class="dtr-modal"/>') | ||||
.append( $('<div class="dtr-modal-display"/>') | ||||
.append( $('<div class="dtr-modal-content"/>') | ||||
.append( render() ) | ||||
) | ||||
.append( $('<div class="dtr-modal-close">×</div>' ) | ||||
.click( function () { | ||||
close(); | ||||
} ) | ||||
) | ||||
) | ||||
.append( $('<div class="dtr-modal-background"/>') | ||||
.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( | ||||
'<h2>'+options.header( row )+'</h2>' | ||||
); | ||||
} | ||||
}; | ||||
} | ||||
}; | ||||
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<ien ; i++ ) { | ||||
nodes.push( children[i] ); | ||||
} | ||||
_childNodeStore[ name ] = nodes; | ||||
return nodes; | ||||
} | ||||
function _childNodesRestore( dt, row, col ) { | ||||
var name = row+'-'+col; | ||||
if ( ! _childNodeStore[ name ] ) { | ||||
return; | ||||
} | ||||
var node = dt.cell( row, col ).node(); | ||||
var store = _childNodeStore[ name ]; | ||||
var parent = store[0].parentNode; | ||||
var parentChildren = parent.childNodes; | ||||
var a = []; | ||||
for ( var i=0, ien=parentChildren.length ; i<ien ; i++ ) { | ||||
a.push( parentChildren[i] ); | ||||
} | ||||
for ( var j=0, jen=a.length ; j<jen ; j++ ) { | ||||
node.appendChild( a[j] ); | ||||
} | ||||
_childNodeStore[ name ] = undefined; | ||||
} | ||||
/** | ||||
* Display methods - functions which define how the hidden data should be shown | ||||
* in the table. | ||||
* | ||||
* @namespace | ||||
* @name Responsive.defaults | ||||
* @static | ||||
*/ | ||||
Responsive.renderer = { | ||||
listHiddenNodes: function () { | ||||
return function ( api, rowIdx, columns ) { | ||||
var ul = $('<ul data-dtr-index="'+rowIdx+'" class="dtr-details"/>'); | ||||
var found = false; | ||||
var data = $.each( columns, function ( i, col ) { | ||||
if ( col.hidden ) { | ||||
var klass = col.className ? | ||||
'class="'+ col.className +'"' : | ||||
''; | ||||
$( | ||||
'<li '+klass+' data-dtr-index="'+col.columnIndex+'" data-dt-row="'+col.rowIndex+'" data-dt-column="'+col.columnIndex+'">'+ | ||||
'<span class="dtr-title">'+ | ||||
col.title+ | ||||
'</span> '+ | ||||
'</li>' | ||||
) | ||||
.append( $('<span class="dtr-data"/>').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 ) { | ||||
var klass = col.className ? | ||||
'class="'+ col.className +'"' : | ||||
''; | ||||
return col.hidden ? | ||||
'<li '+klass+' data-dtr-index="'+col.columnIndex+'" data-dt-row="'+col.rowIndex+'" data-dt-column="'+col.columnIndex+'">'+ | ||||
'<span class="dtr-title">'+ | ||||
col.title+ | ||||
'</span> '+ | ||||
'<span class="dtr-data">'+ | ||||
col.data+ | ||||
'</span>'+ | ||||
'</li>' : | ||||
''; | ||||
} ).join(''); | ||||
return data ? | ||||
$('<ul data-dtr-index="'+rowIdx+'" class="dtr-details"/>').append( data ) : | ||||
false; | ||||
} | ||||
}, | ||||
tableAll: function ( options ) { | ||||
options = $.extend( { | ||||
tableClass: '' | ||||
}, options ); | ||||
return function ( api, rowIdx, columns ) { | ||||
var data = $.map( columns, function ( col ) { | ||||
var klass = col.className ? | ||||
'class="'+ col.className +'"' : | ||||
''; | ||||
return '<tr '+klass+' data-dt-row="'+col.rowIndex+'" data-dt-column="'+col.columnIndex+'">'+ | ||||
'<td>'+col.title+':'+'</td> '+ | ||||
'<td>'+col.data+'</td>'+ | ||||
'</tr>'; | ||||
} ).join(''); | ||||
return $('<table class="'+options.tableClass+' dtr-details" width="100%"/>').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._responsiveOnlyHidden() ) !== -1 : | ||||
false; | ||||
} ); | ||||
Api.registerPlural( 'columns().responsiveHidden()', 'column().responsiveHidden()', function () { | ||||
return this.iterator( 'column', function ( settings, column ) { | ||||
return settings._responsive ? | ||||
settings._responsive._responsiveOnlyHidden()[ column ] : | ||||
false; | ||||
}, 1 ); | ||||
} ); | ||||
/** | ||||
* Version information | ||||
* | ||||
* @name Responsive.version | ||||
* @static | ||||
*/ | ||||
Responsive.version = '2.3.0'; | ||||
$.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; | ||||
})); | ||||