PageSourceSearch

https://cota-cundinamarca.gov.co/Style%20Library/Datatables/assets/js/dataTables.responsive.js

js cota-cundinamarca.gov.co collected 2026-10-09 03:32:37 UTC 48,881 bytes, 1,861 lines download raw bytes

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">&times;</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.