effective_datatables 3.2.7 → 3.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,15 +1,15 @@
1
- /*! Responsive 2.1.0
2
- * 2014-2016 SpryMedia Ltd - datatables.net/license
1
+ /*! Responsive 2.2.0
2
+ * 2014-2017 SpryMedia Ltd - datatables.net/license
3
3
  */
4
4
 
5
5
  /**
6
6
  * @summary Responsive
7
7
  * @description Responsive tables plug-in for DataTables
8
- * @version 2.1.0
8
+ * @version 2.2.0
9
9
  * @file dataTables.responsive.js
10
10
  * @author SpryMedia Ltd (www.sprymedia.co.uk)
11
11
  * @contact www.sprymedia.co.uk/contact
12
- * @copyright Copyright 2014-2016 SpryMedia Ltd.
12
+ * @copyright Copyright 2014-2017 SpryMedia Ltd.
13
13
  *
14
14
  * This source file is free software, available under the following license:
15
15
  * MIT license - http://datatables.net/license/mit
@@ -21,30 +21,30 @@
21
21
  * For details please refer to: http://www.datatables.net
22
22
  */
23
23
  (function( factory ){
24
- if ( typeof define === 'function' && define.amd ) {
25
- // AMD
26
- define( ['jquery', 'datatables.net'], function ( $ ) {
27
- return factory( $, window, document );
28
- } );
29
- }
30
- else if ( typeof exports === 'object' ) {
31
- // CommonJS
32
- module.exports = function (root, $) {
33
- if ( ! root ) {
34
- root = window;
35
- }
36
-
37
- if ( ! $ || ! $.fn.dataTable ) {
38
- $ = require('datatables.net')(root, $).$;
39
- }
40
-
41
- return factory( $, root, root.document );
42
- };
43
- }
44
- else {
45
- // Browser
46
- factory( jQuery, window, document );
47
- }
24
+ if ( typeof define === 'function' && define.amd ) {
25
+ // AMD
26
+ define( ['jquery', 'datatables.net'], function ( $ ) {
27
+ return factory( $, window, document );
28
+ } );
29
+ }
30
+ else if ( typeof exports === 'object' ) {
31
+ // CommonJS
32
+ module.exports = function (root, $) {
33
+ if ( ! root ) {
34
+ root = window;
35
+ }
36
+
37
+ if ( ! $ || ! $.fn.dataTable ) {
38
+ $ = require('datatables.net')(root, $).$;
39
+ }
40
+
41
+ return factory( $, root, root.document );
42
+ };
43
+ }
44
+ else {
45
+ // Browser
46
+ factory( jQuery, window, document );
47
+ }
48
48
  }(function( $, window, document, undefined ) {
49
49
  'use strict';
50
50
  var DataTable = $.fn.dataTable;
@@ -96,821 +96,866 @@ var DataTable = $.fn.dataTable;
96
96
  * } );
97
97
  */
98
98
  var Responsive = function ( settings, opts ) {
99
- // Sanity check that we are using DataTables 1.10 or newer
100
- if ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.3' ) ) {
101
- throw 'DataTables Responsive requires DataTables 1.10.3 or newer';
102
- }
103
-
104
- this.s = {
105
- dt: new DataTable.Api( settings ),
106
- columns: [],
107
- current: []
108
- };
109
-
110
- // Check if responsive has already been initialised on this table
111
- if ( this.s.dt.settings()[0].responsive ) {
112
- return;
113
- }
114
-
115
- // details is an object, but for simplicity the user can give it as a string
116
- // or a boolean
117
- if ( opts && typeof opts.details === 'string' ) {
118
- opts.details = { type: opts.details };
119
- }
120
- else if ( opts && opts.details === false ) {
121
- opts.details = { type: false };
122
- }
123
- else if ( opts && opts.details === true ) {
124
- opts.details = { type: 'inline' };
125
- }
126
-
127
- this.c = $.extend( true, {}, Responsive.defaults, DataTable.defaults.responsive, opts );
128
- settings.responsive = this;
129
- this._constructor();
99
+ // Sanity check that we are using DataTables 1.10 or newer
100
+ if ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.3' ) ) {
101
+ throw 'DataTables Responsive requires DataTables 1.10.3 or newer';
102
+ }
103
+
104
+ this.s = {
105
+ dt: new DataTable.Api( settings ),
106
+ columns: [],
107
+ current: []
108
+ };
109
+
110
+ // Check if responsive has already been initialised on this table
111
+ if ( this.s.dt.settings()[0].responsive ) {
112
+ return;
113
+ }
114
+
115
+ // details is an object, but for simplicity the user can give it as a string
116
+ // or a boolean
117
+ if ( opts && typeof opts.details === 'string' ) {
118
+ opts.details = { type: opts.details };
119
+ }
120
+ else if ( opts && opts.details === false ) {
121
+ opts.details = { type: false };
122
+ }
123
+ else if ( opts && opts.details === true ) {
124
+ opts.details = { type: 'inline' };
125
+ }
126
+
127
+ this.c = $.extend( true, {}, Responsive.defaults, DataTable.defaults.responsive, opts );
128
+ settings.responsive = this;
129
+ this._constructor();
130
130
  };
131
131
 
132
132
  $.extend( Responsive.prototype, {
133
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
134
- * Constructor
135
- */
136
-
137
- /**
138
- * Initialise the Responsive instance
139
- *
140
- * @private
141
- */
142
- _constructor: function ()
143
- {
144
- var that = this;
145
- var dt = this.s.dt;
146
- var dtPrivateSettings = dt.settings()[0];
147
- var oldWindowWidth = $(window).width();
148
-
149
- dt.settings()[0]._responsive = this;
150
-
151
- // Use DataTables' throttle function to avoid processor thrashing on
152
- // resize
153
- $(window).on( 'resize.dtr orientationchange.dtr', DataTable.util.throttle( function () {
154
- // iOS has a bug whereby resize can fire when only scrolling
155
- // See: http://stackoverflow.com/questions/8898412
156
- var width = $(window).width();
157
-
158
- if ( width !== oldWindowWidth ) {
159
- that._resize();
160
- oldWindowWidth = width;
161
- }
162
- } ) );
163
-
164
- // DataTables doesn't currently trigger an event when a row is added, so
165
- // we need to hook into its private API to enforce the hidden rows when
166
- // new data is added
167
- dtPrivateSettings.oApi._fnCallbackReg( dtPrivateSettings, 'aoRowCreatedCallback', function (tr, data, idx) {
168
- if ( $.inArray( false, that.s.current ) !== -1 ) {
169
- $('td, th', tr).each( function ( i ) {
170
- var idx = dt.column.index( 'toData', i );
171
-
172
- if ( that.s.current[idx] === false ) {
173
- $(this).css('display', 'none');
174
- }
175
- } );
176
- }
177
- } );
178
-
179
- // Destroy event handler
180
- dt.on( 'destroy.dtr', function () {
181
- dt.off( '.dtr' );
182
- $( dt.table().body() ).off( '.dtr' );
183
- $(window).off( 'resize.dtr orientationchange.dtr' );
184
-
185
- // Restore the columns that we've hidden
186
- $.each( that.s.current, function ( i, val ) {
187
- if ( val === false ) {
188
- that._setColumnVis( i, true );
189
- }
190
- } );
191
- } );
192
-
193
- // Reorder the breakpoints array here in case they have been added out
194
- // of order
195
- this.c.breakpoints.sort( function (a, b) {
196
- return a.width < b.width ? 1 :
197
- a.width > b.width ? -1 : 0;
198
- } );
199
-
200
- this._classLogic();
201
- this._resizeAuto();
202
-
203
- // Details handler
204
- var details = this.c.details;
205
-
206
- if ( details.type !== false ) {
207
- that._detailsInit();
208
-
209
- // DataTables will trigger this event on every column it shows and
210
- // hides individually
211
- dt.on( 'column-visibility.dtr', function (e, ctx, col, vis) {
212
- that._classLogic();
213
- that._resizeAuto();
214
- that._resize();
215
- } );
216
-
217
- // Redraw the details box on each draw which will happen if the data
218
- // has changed. This is used until DataTables implements a native
219
- // `updated` event for rows
220
- dt.on( 'draw.dtr', function () {
221
- that._redrawChildren();
222
- } );
223
-
224
- $(dt.table().node()).addClass( 'dtr-'+details.type );
225
- }
226
-
227
- dt.on( 'column-reorder.dtr', function (e, settings, details) {
228
- that._classLogic();
229
- that._resizeAuto();
230
- that._resize();
231
- } );
232
-
233
- // Change in column sizes means we need to calc
234
- dt.on( 'column-sizing.dtr', function () {
235
- that._resizeAuto();
236
- that._resize();
237
- });
238
-
239
- dt.on( 'init.dtr', function (e, settings, details) {
240
- that._resizeAuto();
241
- that._resize();
242
-
243
- // If columns were hidden, then DataTables needs to adjust the
244
- // column sizing
245
- if ( $.inArray( false, that.s.current ) ) {
246
- dt.columns.adjust();
247
- }
248
- } );
249
-
250
- // First pass - draw the table for the current viewport size
251
- this._resize();
252
- },
253
-
254
-
255
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
256
- * Private methods
257
- */
258
-
259
- /**
260
- * Calculate the visibility for the columns in a table for a given
261
- * breakpoint. The result is pre-determined based on the class logic if
262
- * class names are used to control all columns, but the width of the table
263
- * is also used if there are columns which are to be automatically shown
264
- * and hidden.
265
- *
266
- * @param {string} breakpoint Breakpoint name to use for the calculation
267
- * @return {array} Array of boolean values initiating the visibility of each
268
- * column.
269
- * @private
270
- */
271
- _columnsVisiblity: function ( breakpoint )
272
- {
273
- var dt = this.s.dt;
274
- var columns = this.s.columns;
275
- var i, ien;
276
-
277
- // Create an array that defines the column ordering based first on the
278
- // column's priority, and secondly the column index. This allows the
279
- // columns to be removed from the right if the priority matches
280
- var order = columns
281
- .map( function ( col, idx ) {
282
- return {
283
- columnIdx: idx,
284
- priority: col.priority
285
- };
286
- } )
287
- .sort( function ( a, b ) {
288
- if ( a.priority !== b.priority ) {
289
- return a.priority - b.priority;
290
- }
291
- return a.columnIdx - b.columnIdx;
292
- } );
293
-
294
- // Class logic - determine which columns are in this breakpoint based
295
- // on the classes. If no class control (i.e. `auto`) then `-` is used
296
- // to indicate this to the rest of the function
297
- var display = $.map( columns, function ( col ) {
298
- return col.auto && col.minWidth === null ?
299
- false :
300
- col.auto === true ?
301
- '-' :
302
- $.inArray( breakpoint, col.includeIn ) !== -1;
303
- } );
304
-
305
- // Auto column control - first pass: how much width is taken by the
306
- // ones that must be included from the non-auto columns
307
- var requiredWidth = 0;
308
- for ( i=0, ien=display.length ; i<ien ; i++ ) {
309
- if ( display[i] === true ) {
310
- requiredWidth += columns[i].minWidth;
311
- }
312
- }
313
-
314
- // Second pass, use up any remaining width for other columns. For
315
- // scrolling tables we need to subtract the width of the scrollbar. It
316
- // may not be requires which makes this sub-optimal, but it would
317
- // require another full redraw to make complete use of those extra few
318
- // pixels
319
- var scrolling = dt.settings()[0].oScroll;
320
- var bar = scrolling.sY || scrolling.sX ? scrolling.iBarWidth : 0;
321
- var widthAvailable = dt.table().container().offsetWidth - bar;
322
- var usedWidth = widthAvailable - requiredWidth;
323
-
324
- // Control column needs to always be included. This makes it sub-
325
- // optimal in terms of using the available with, but to stop layout
326
- // thrashing or overflow. Also we need to account for the control column
327
- // width first so we know how much width is available for the other
328
- // columns, since the control column might not be the first one shown
329
- for ( i=0, ien=display.length ; i<ien ; i++ ) {
330
- if ( columns[i].control ) {
331
- usedWidth -= columns[i].minWidth;
332
- }
333
- }
334
-
335
- // Allow columns to be shown (counting by priority and then right to
336
- // left) until we run out of room
337
- var empty = false;
338
- for ( i=0, ien=order.length ; i<ien ; i++ ) {
339
- var colIdx = order[i].columnIdx;
340
-
341
- if ( display[colIdx] === '-' && ! columns[colIdx].control && columns[colIdx].minWidth ) {
342
- // Once we've found a column that won't fit we don't let any
343
- // others display either, or columns might disappear in the
344
- // middle of the table
345
- if ( empty || usedWidth - columns[colIdx].minWidth < 0 ) {
346
- empty = true;
347
- display[colIdx] = false;
348
- }
349
- else {
350
- display[colIdx] = true;
351
- }
352
-
353
- usedWidth -= columns[colIdx].minWidth;
354
- }
355
- }
356
-
357
- // Determine if the 'control' column should be shown (if there is one).
358
- // This is the case when there is a hidden column (that is not the
359
- // control column). The two loops look inefficient here, but they are
360
- // trivial and will fly through. We need to know the outcome from the
361
- // first , before the action in the second can be taken
362
- var showControl = false;
363
-
364
- for ( i=0, ien=columns.length ; i<ien ; i++ ) {
365
- if ( ! columns[i].control && ! columns[i].never && ! display[i] ) {
366
- showControl = true;
367
- break;
368
- }
369
- }
370
-
371
- for ( i=0, ien=columns.length ; i<ien ; i++ ) {
372
- if ( columns[i].control ) {
373
- display[i] = showControl;
374
- }
375
- }
376
-
377
- // Finally we need to make sure that there is at least one column that
378
- // is visible
379
- if ( $.inArray( true, display ) === -1 ) {
380
- display[0] = true;
381
- }
382
-
383
- return display;
384
- },
385
-
386
-
387
- /**
388
- * Create the internal `columns` array with information about the columns
389
- * for the table. This includes determining which breakpoints the column
390
- * will appear in, based upon class names in the column, which makes up the
391
- * vast majority of this method.
392
- *
393
- * @private
394
- */
395
- _classLogic: function ()
396
- {
397
- var that = this;
398
- var calc = {};
399
- var breakpoints = this.c.breakpoints;
400
- var dt = this.s.dt;
401
- var columns = dt.columns().eq(0).map( function (i) {
402
- var column = this.column(i);
403
- var className = column.header().className;
404
- var priority = dt.settings()[0].aoColumns[i].responsivePriority;
405
-
406
- if ( priority === undefined ) {
407
- var dataPriority = $(column.header()).data('priority');
408
-
409
- priority = dataPriority !== undefined ?
410
- dataPriority * 1 :
411
- 10000;
412
- }
413
-
414
- return {
415
- className: className,
416
- includeIn: [],
417
- auto: false,
418
- control: false,
419
- never: className.match(/\bnever\b/) ? true : false,
420
- priority: priority
421
- };
422
- } );
423
-
424
- // Simply add a breakpoint to `includeIn` array, ensuring that there are
425
- // no duplicates
426
- var add = function ( colIdx, name ) {
427
- var includeIn = columns[ colIdx ].includeIn;
428
-
429
- if ( $.inArray( name, includeIn ) === -1 ) {
430
- includeIn.push( name );
431
- }
432
- };
433
-
434
- var column = function ( colIdx, name, operator, matched ) {
435
- var size, i, ien;
436
-
437
- if ( ! operator ) {
438
- columns[ colIdx ].includeIn.push( name );
439
- }
440
- else if ( operator === 'max-' ) {
441
- // Add this breakpoint and all smaller
442
- size = that._find( name ).width;
443
-
444
- for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) {
445
- if ( breakpoints[i].width <= size ) {
446
- add( colIdx, breakpoints[i].name );
447
- }
448
- }
449
- }
450
- else if ( operator === 'min-' ) {
451
- // Add this breakpoint and all larger
452
- size = that._find( name ).width;
453
-
454
- for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) {
455
- if ( breakpoints[i].width >= size ) {
456
- add( colIdx, breakpoints[i].name );
457
- }
458
- }
459
- }
460
- else if ( operator === 'not-' ) {
461
- // Add all but this breakpoint
462
- for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) {
463
- if ( breakpoints[i].name.indexOf( matched ) === -1 ) {
464
- add( colIdx, breakpoints[i].name );
465
- }
466
- }
467
- }
468
- };
469
-
470
- // Loop over each column and determine if it has a responsive control
471
- // class
472
- columns.each( function ( col, i ) {
473
- var classNames = col.className.split(' ');
474
- var hasClass = false;
475
-
476
- // Split the class name up so multiple rules can be applied if needed
477
- for ( var k=0, ken=classNames.length ; k<ken ; k++ ) {
478
- var className = $.trim( classNames[k] );
479
-
480
- if ( className === 'all' ) {
481
- // Include in all
482
- hasClass = true;
483
- col.includeIn = $.map( breakpoints, function (a) {
484
- return a.name;
485
- } );
486
- return;
487
- }
488
- else if ( className === 'none' || col.never ) {
489
- // Include in none (default) and no auto
490
- hasClass = true;
491
- return;
492
- }
493
- else if ( className === 'control' ) {
494
- // Special column that is only visible, when one of the other
495
- // columns is hidden. This is used for the details control
496
- hasClass = true;
497
- col.control = true;
498
- return;
499
- }
500
-
501
- $.each( breakpoints, function ( j, breakpoint ) {
502
- // Does this column have a class that matches this breakpoint?
503
- var brokenPoint = breakpoint.name.split('-');
504
- var re = new RegExp( '(min\\-|max\\-|not\\-)?('+brokenPoint[0]+')(\\-[_a-zA-Z0-9])?' );
505
- var match = className.match( re );
506
-
507
- if ( match ) {
508
- hasClass = true;
509
-
510
- if ( match[2] === brokenPoint[0] && match[3] === '-'+brokenPoint[1] ) {
511
- // Class name matches breakpoint name fully
512
- column( i, breakpoint.name, match[1], match[2]+match[3] );
513
- }
514
- else if ( match[2] === brokenPoint[0] && ! match[3] ) {
515
- // Class name matched primary breakpoint name with no qualifier
516
- column( i, breakpoint.name, match[1], match[2] );
517
- }
518
- }
519
- } );
520
- }
521
-
522
- // If there was no control class, then automatic sizing is used
523
- if ( ! hasClass ) {
524
- col.auto = true;
525
- }
526
- } );
527
-
528
- this.s.columns = columns;
529
- },
530
-
531
-
532
- /**
533
- * Show the details for the child row
534
- *
535
- * @param {DataTables.Api} row API instance for the row
536
- * @param {boolean} update Update flag
537
- * @private
538
- */
539
- _detailsDisplay: function ( row, update )
540
- {
541
- var that = this;
542
- var dt = this.s.dt;
543
- var details = this.c.details;
544
-
545
- if ( details && details.type !== false ) {
546
- var res = details.display( row, update, function () {
547
- return details.renderer(
548
- dt, row[0], that._detailsObj(row[0])
549
- );
550
- } );
551
-
552
- if ( res === true || res === false ) {
553
- $(dt.table().node()).triggerHandler( 'responsive-display.dt', [dt, row, res, update] );
554
- }
555
- }
556
- },
557
-
558
-
559
- /**
560
- * Initialisation for the details handler
561
- *
562
- * @private
563
- */
564
- _detailsInit: function ()
565
- {
566
- var that = this;
567
- var dt = this.s.dt;
568
- var details = this.c.details;
569
-
570
- // The inline type always uses the first child as the target
571
- if ( details.type === 'inline' ) {
572
- details.target = 'td:first-child, th:first-child';
573
- }
574
-
575
- // Keyboard accessibility
576
- dt.on( 'draw.dtr', function () {
577
- that._tabIndexes();
578
- } );
579
- that._tabIndexes(); // Initial draw has already happened
580
-
581
- $( dt.table().body() ).on( 'keyup.dtr', 'td, th', function (e) {
582
- if ( e.keyCode === 13 && $(this).data('dtr-keyboard') ) {
583
- $(this).click();
584
- }
585
- } );
586
-
587
- // type.target can be a string jQuery selector or a column index
588
- var target = details.target;
589
- var selector = typeof target === 'string' ? target : 'td, th';
590
-
591
- // Click handler to show / hide the details rows when they are available
592
- $( dt.table().body() )
593
- .on( 'click.dtr mousedown.dtr mouseup.dtr', selector, function (e) {
594
- // If the table is not collapsed (i.e. there is no hidden columns)
595
- // then take no action
596
- if ( ! $(dt.table().node()).hasClass('collapsed' ) ) {
597
- return;
598
- }
599
-
600
- // Check that the row is actually a DataTable's controlled node
601
- if ( ! dt.row( $(this).closest('tr') ).length ) {
602
- return;
603
- }
604
-
605
- // For column index, we determine if we should act or not in the
606
- // handler - otherwise it is already okay
607
- if ( typeof target === 'number' ) {
608
- var targetIdx = target < 0 ?
609
- dt.columns().eq(0).length + target :
610
- target;
611
-
612
- if ( dt.cell( this ).index().column !== targetIdx ) {
613
- return;
614
- }
615
- }
616
-
617
- // $().closest() includes itself in its check
618
- var row = dt.row( $(this).closest('tr') );
619
-
620
- // Check event type to do an action
621
- if ( e.type === 'click' ) {
622
- // The renderer is given as a function so the caller can execute it
623
- // only when they need (i.e. if hiding there is no point is running
624
- // the renderer)
625
- that._detailsDisplay( row, false );
626
- }
627
- else if ( e.type === 'mousedown' ) {
628
- // For mouse users, prevent the focus ring from showing
629
- $(this).css('outline', 'none');
630
- }
631
- else if ( e.type === 'mouseup' ) {
632
- // And then re-allow at the end of the click
633
- $(this).blur().css('outline', '');
634
- }
635
- } );
636
- },
637
-
638
-
639
- /**
640
- * Get the details to pass to a renderer for a row
641
- * @param {int} rowIdx Row index
642
- * @private
643
- */
644
- _detailsObj: function ( rowIdx )
645
- {
646
- var that = this;
647
- var dt = this.s.dt;
648
-
649
- return $.map( this.s.columns, function( col, i ) {
650
- // Never and control columns should not be passed to the renderer
651
- if ( col.never || col.control ) {
652
- return;
653
- }
654
-
655
- return {
656
- title: dt.settings()[0].aoColumns[ i ].sTitle,
657
- data: dt.cell( rowIdx, i ).render( that.c.orthogonal ),
658
- hidden: dt.column( i ).visible() && !that.s.current[ i ],
659
- columnIndex: i,
660
- rowIndex: rowIdx
661
- };
662
- } );
663
- },
664
-
665
-
666
- /**
667
- * Find a breakpoint object from a name
668
- *
669
- * @param {string} name Breakpoint name to find
670
- * @return {object} Breakpoint description object
671
- * @private
672
- */
673
- _find: function ( name )
674
- {
675
- var breakpoints = this.c.breakpoints;
676
-
677
- for ( var i=0, ien=breakpoints.length ; i<ien ; i++ ) {
678
- if ( breakpoints[i].name === name ) {
679
- return breakpoints[i];
680
- }
681
- }
682
- },
683
-
684
-
685
- /**
686
- * Re-create the contents of the child rows as the display has changed in
687
- * some way.
688
- *
689
- * @private
690
- */
691
- _redrawChildren: function ()
692
- {
693
- var that = this;
694
- var dt = this.s.dt;
695
-
696
- dt.rows( {page: 'current'} ).iterator( 'row', function ( settings, idx ) {
697
- var row = dt.row( idx );
698
-
699
- that._detailsDisplay( dt.row( idx ), true );
700
- } );
701
- },
702
-
703
-
704
- /**
705
- * Alter the table display for a resized viewport. This involves first
706
- * determining what breakpoint the window currently is in, getting the
707
- * column visibilities to apply and then setting them.
708
- *
709
- * @private
710
- */
711
- _resize: function ()
712
- {
713
- var that = this;
714
- var dt = this.s.dt;
715
- var width = $(window).width();
716
- var breakpoints = this.c.breakpoints;
717
- var breakpoint = breakpoints[0].name;
718
- var columns = this.s.columns;
719
- var i, ien;
720
- var oldVis = this.s.current.slice();
721
-
722
- // Determine what breakpoint we are currently at
723
- for ( i=breakpoints.length-1 ; i>=0 ; i-- ) {
724
- if ( width <= breakpoints[i].width ) {
725
- breakpoint = breakpoints[i].name;
726
- break;
727
- }
728
- }
729
-
730
- // Show the columns for that break point
731
- var columnsVis = this._columnsVisiblity( breakpoint );
732
- this.s.current = columnsVis;
733
-
734
- // Set the class before the column visibility is changed so event
735
- // listeners know what the state is. Need to determine if there are
736
- // any columns that are not visible but can be shown
737
- var collapsedClass = false;
738
- for ( i=0, ien=columns.length ; i<ien ; i++ ) {
739
- if ( columnsVis[i] === false && ! columns[i].never && ! columns[i].control ) {
740
- collapsedClass = true;
741
- break;
742
- }
743
- }
744
-
745
- $( dt.table().node() ).toggleClass( 'collapsed', collapsedClass );
746
-
747
- var changed = false;
748
-
749
- dt.columns().eq(0).each( function ( colIdx, i ) {
750
- if ( columnsVis[i] !== oldVis[i] ) {
751
- changed = true;
752
- that._setColumnVis( colIdx, columnsVis[i] );
753
- }
754
- } );
755
-
756
- if ( changed ) {
757
- this._redrawChildren();
758
-
759
- // Inform listeners of the change
760
- $(dt.table().node()).trigger( 'responsive-resize.dt', [dt, this.s.current] );
761
- }
762
- },
763
-
764
-
765
- /**
766
- * Determine the width of each column in the table so the auto column hiding
767
- * has that information to work with. This method is never going to be 100%
768
- * perfect since column widths can change slightly per page, but without
769
- * seriously compromising performance this is quite effective.
770
- *
771
- * @private
772
- */
773
- _resizeAuto: function ()
774
- {
775
- var dt = this.s.dt;
776
- var columns = this.s.columns;
777
-
778
- // Are we allowed to do auto sizing?
779
- if ( ! this.c.auto ) {
780
- return;
781
- }
782
-
783
- // Are there any columns that actually need auto-sizing, or do they all
784
- // have classes defined
785
- if ( $.inArray( true, $.map( columns, function (c) { return c.auto; } ) ) === -1 ) {
786
- return;
787
- }
788
-
789
- // Clone the table with the current data in it
790
- var tableWidth = dt.table().node().offsetWidth;
791
- var columnWidths = dt.columns;
792
- var clonedTable = dt.table().node().cloneNode( false );
793
- var clonedHeader = $( dt.table().header().cloneNode( false ) ).appendTo( clonedTable );
794
- var clonedBody = $( dt.table().body() ).clone( false, false ).empty().appendTo( clonedTable ); // use jQuery because of IE8
795
-
796
- // Header
797
- var headerCells = dt.columns()
798
- .header()
799
- .filter( function (idx) {
800
- return dt.column(idx).visible();
801
- } )
802
- .to$()
803
- .clone( false )
804
- .css( 'display', 'table-cell' );
805
-
806
- // Body rows - we don't need to take account of DataTables' column
807
- // visibility since we implement our own here (hence the `display` set)
808
- $(clonedBody)
809
- .append( $(dt.rows( { page: 'current' } ).nodes()).clone( false ) )
810
- .find( 'th, td' ).css( 'display', '' );
811
-
812
- // Footer
813
- var footer = dt.table().footer();
814
- if ( footer ) {
815
- var clonedFooter = $( footer.cloneNode( false ) ).appendTo( clonedTable );
816
- var footerCells = dt.columns()
817
- .footer()
818
- .filter( function (idx) {
819
- return dt.column(idx).visible();
820
- } )
821
- .to$()
822
- .clone( false )
823
- .css( 'display', 'table-cell' );
824
-
825
- $('<tr/>')
826
- .append( footerCells )
827
- .appendTo( clonedFooter );
828
- }
829
-
830
- $('<tr/>')
831
- .append( headerCells )
832
- .appendTo( clonedHeader );
833
-
834
- // In the inline case extra padding is applied to the first column to
835
- // give space for the show / hide icon. We need to use this in the
836
- // calculation
837
- if ( this.c.details.type === 'inline' ) {
838
- $(clonedTable).addClass( 'dtr-inline collapsed' );
839
- }
840
-
841
- // It is unsafe to insert elements with the same name into the DOM
842
- // multiple times. For example, cloning and inserting a checked radio
843
- // clears the chcecked state of the original radio.
844
- $( clonedTable ).find( '[name]' ).removeAttr( 'name' );
845
-
846
- var inserted = $('<div/>')
847
- .css( {
848
- width: 1,
849
- height: 1,
850
- overflow: 'hidden'
851
- } )
852
- .append( clonedTable );
853
-
854
- inserted.insertBefore( dt.table().node() );
855
-
856
- // The cloned header now contains the smallest that each column can be
857
- headerCells.each( function (i) {
858
- var idx = dt.column.index( 'fromVisible', i );
859
- columns[ idx ].minWidth = this.offsetWidth || 0;
860
- } );
861
-
862
- inserted.remove();
863
- },
864
-
865
- /**
866
- * Set a column's visibility.
867
- *
868
- * We don't use DataTables' column visibility controls in order to ensure
869
- * that column visibility can Responsive can no-exist. Since only IE8+ is
870
- * supported (and all evergreen browsers of course) the control of the
871
- * display attribute works well.
872
- *
873
- * @param {integer} col Column index
874
- * @param {boolean} showHide Show or hide (true or false)
875
- * @private
876
- */
877
- _setColumnVis: function ( col, showHide )
878
- {
879
- var dt = this.s.dt;
880
- var display = showHide ? '' : 'none'; // empty string will remove the attr
881
-
882
- $( dt.column( col ).header() ).css( 'display', display );
883
- $( dt.column( col ).footer() ).css( 'display', display );
884
- dt.column( col ).nodes().to$().css( 'display', display );
885
- },
886
-
887
-
888
- /**
889
- * Update the cell tab indexes for keyboard accessibility. This is called on
890
- * every table draw - that is potentially inefficient, but also the least
891
- * complex option given that column visibility can change on the fly. Its a
892
- * shame user-focus was removed from CSS 3 UI, as it would have solved this
893
- * issue with a single CSS statement.
894
- *
895
- * @private
896
- */
897
- _tabIndexes: function ()
898
- {
899
- var dt = this.s.dt;
900
- var cells = dt.cells( { page: 'current' } ).nodes().to$();
901
- var ctx = dt.settings()[0];
902
- var target = this.c.details.target;
903
-
904
- cells.filter( '[data-dtr-keyboard]' ).removeData( '[data-dtr-keyboard]' );
905
-
906
- var selector = typeof target === 'number' ?
907
- ':eq('+target+')' :
908
- target;
909
-
910
- $( selector, dt.rows( { page: 'current' } ).nodes() )
911
- .attr( 'tabIndex', ctx.iTabIndex )
912
- .data( 'dtr-keyboard', 1 );
913
- }
133
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
134
+ * Constructor
135
+ */
136
+
137
+ /**
138
+ * Initialise the Responsive instance
139
+ *
140
+ * @private
141
+ */
142
+ _constructor: function ()
143
+ {
144
+ var that = this;
145
+ var dt = this.s.dt;
146
+ var dtPrivateSettings = dt.settings()[0];
147
+ var oldWindowWidth = $(window).width();
148
+
149
+ dt.settings()[0]._responsive = this;
150
+
151
+ // Use DataTables' throttle function to avoid processor thrashing on
152
+ // resize
153
+ $(window).on( 'resize.dtr orientationchange.dtr', DataTable.util.throttle( function () {
154
+ // iOS has a bug whereby resize can fire when only scrolling
155
+ // See: http://stackoverflow.com/questions/8898412
156
+ var width = $(window).width();
157
+
158
+ if ( width !== oldWindowWidth ) {
159
+ that._resize();
160
+ oldWindowWidth = width;
161
+ }
162
+ } ) );
163
+
164
+ // DataTables doesn't currently trigger an event when a row is added, so
165
+ // we need to hook into its private API to enforce the hidden rows when
166
+ // new data is added
167
+ dtPrivateSettings.oApi._fnCallbackReg( dtPrivateSettings, 'aoRowCreatedCallback', function (tr, data, idx) {
168
+ if ( $.inArray( false, that.s.current ) !== -1 ) {
169
+ $('>td, >th', tr).each( function ( i ) {
170
+ var idx = dt.column.index( 'toData', i );
171
+
172
+ if ( that.s.current[idx] === false ) {
173
+ $(this).css('display', 'none');
174
+ }
175
+ } );
176
+ }
177
+ } );
178
+
179
+ // Destroy event handler
180
+ dt.on( 'destroy.dtr', function () {
181
+ dt.off( '.dtr' );
182
+ $( dt.table().body() ).off( '.dtr' );
183
+ $(window).off( 'resize.dtr orientationchange.dtr' );
184
+
185
+ // Restore the columns that we've hidden
186
+ $.each( that.s.current, function ( i, val ) {
187
+ if ( val === false ) {
188
+ that._setColumnVis( i, true );
189
+ }
190
+ } );
191
+ } );
192
+
193
+ // Reorder the breakpoints array here in case they have been added out
194
+ // of order
195
+ this.c.breakpoints.sort( function (a, b) {
196
+ return a.width < b.width ? 1 :
197
+ a.width > b.width ? -1 : 0;
198
+ } );
199
+
200
+ this._classLogic();
201
+ this._resizeAuto();
202
+
203
+ // Details handler
204
+ var details = this.c.details;
205
+
206
+ if ( details.type !== false ) {
207
+ that._detailsInit();
208
+
209
+ // DataTables will trigger this event on every column it shows and
210
+ // hides individually
211
+ dt.on( 'column-visibility.dtr', function (e, ctx, col, vis) {
212
+ that._classLogic();
213
+ that._resizeAuto();
214
+ that._resize();
215
+ } );
216
+
217
+ // Redraw the details box on each draw which will happen if the data
218
+ // has changed. This is used until DataTables implements a native
219
+ // `updated` event for rows
220
+ dt.on( 'draw.dtr', function () {
221
+ that._redrawChildren();
222
+ } );
223
+
224
+ $(dt.table().node()).addClass( 'dtr-'+details.type );
225
+ }
226
+
227
+ dt.on( 'column-reorder.dtr', function (e, settings, details) {
228
+ that._classLogic();
229
+ that._resizeAuto();
230
+ that._resize();
231
+ } );
232
+
233
+ // Change in column sizes means we need to calc
234
+ dt.on( 'column-sizing.dtr', function () {
235
+ that._resizeAuto();
236
+ that._resize();
237
+ });
238
+
239
+ // On Ajax reload we want to reopen any child rows which are displayed
240
+ // by responsive
241
+ dt.on( 'preXhr.dtr', function () {
242
+ var rowIds = [];
243
+ dt.rows().every( function () {
244
+ if ( this.child.isShown() ) {
245
+ rowIds.push( this.id(true) );
246
+ }
247
+ } );
248
+
249
+ dt.one( 'draw.dtr', function () {
250
+ dt.rows( rowIds ).every( function () {
251
+ that._detailsDisplay( this, false );
252
+ } );
253
+ } );
254
+ });
255
+
256
+ dt.on( 'init.dtr', function (e, settings, details) {
257
+ that._resizeAuto();
258
+ that._resize();
259
+
260
+ // If columns were hidden, then DataTables needs to adjust the
261
+ // column sizing
262
+ if ( $.inArray( false, that.s.current ) ) {
263
+ dt.columns.adjust();
264
+ }
265
+ } );
266
+
267
+ // First pass - draw the table for the current viewport size
268
+ this._resize();
269
+ },
270
+
271
+
272
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
273
+ * Private methods
274
+ */
275
+
276
+ /**
277
+ * Calculate the visibility for the columns in a table for a given
278
+ * breakpoint. The result is pre-determined based on the class logic if
279
+ * class names are used to control all columns, but the width of the table
280
+ * is also used if there are columns which are to be automatically shown
281
+ * and hidden.
282
+ *
283
+ * @param {string} breakpoint Breakpoint name to use for the calculation
284
+ * @return {array} Array of boolean values initiating the visibility of each
285
+ * column.
286
+ * @private
287
+ */
288
+ _columnsVisiblity: function ( breakpoint )
289
+ {
290
+ var dt = this.s.dt;
291
+ var columns = this.s.columns;
292
+ var i, ien;
293
+
294
+ // Create an array that defines the column ordering based first on the
295
+ // column's priority, and secondly the column index. This allows the
296
+ // columns to be removed from the right if the priority matches
297
+ var order = columns
298
+ .map( function ( col, idx ) {
299
+ return {
300
+ columnIdx: idx,
301
+ priority: col.priority
302
+ };
303
+ } )
304
+ .sort( function ( a, b ) {
305
+ if ( a.priority !== b.priority ) {
306
+ return a.priority - b.priority;
307
+ }
308
+ return a.columnIdx - b.columnIdx;
309
+ } );
310
+
311
+ // Class logic - determine which columns are in this breakpoint based
312
+ // on the classes. If no class control (i.e. `auto`) then `-` is used
313
+ // to indicate this to the rest of the function
314
+ var display = $.map( columns, function ( col ) {
315
+ return col.auto && col.minWidth === null ?
316
+ false :
317
+ col.auto === true ?
318
+ '-' :
319
+ $.inArray( breakpoint, col.includeIn ) !== -1;
320
+ } );
321
+
322
+ // Auto column control - first pass: how much width is taken by the
323
+ // ones that must be included from the non-auto columns
324
+ var requiredWidth = 0;
325
+ for ( i=0, ien=display.length ; i<ien ; i++ ) {
326
+ if ( display[i] === true ) {
327
+ requiredWidth += columns[i].minWidth;
328
+ }
329
+ }
330
+
331
+ // Second pass, use up any remaining width for other columns. For
332
+ // scrolling tables we need to subtract the width of the scrollbar. It
333
+ // may not be requires which makes this sub-optimal, but it would
334
+ // require another full redraw to make complete use of those extra few
335
+ // pixels
336
+ var scrolling = dt.settings()[0].oScroll;
337
+ var bar = scrolling.sY || scrolling.sX ? scrolling.iBarWidth : 0;
338
+ var widthAvailable = dt.table().container().offsetWidth - bar;
339
+ var usedWidth = widthAvailable - requiredWidth;
340
+
341
+ // Control column needs to always be included. This makes it sub-
342
+ // optimal in terms of using the available with, but to stop layout
343
+ // thrashing or overflow. Also we need to account for the control column
344
+ // width first so we know how much width is available for the other
345
+ // columns, since the control column might not be the first one shown
346
+ for ( i=0, ien=display.length ; i<ien ; i++ ) {
347
+ if ( columns[i].control ) {
348
+ usedWidth -= columns[i].minWidth;
349
+ }
350
+ }
351
+
352
+ // Allow columns to be shown (counting by priority and then right to
353
+ // left) until we run out of room
354
+ var empty = false;
355
+ for ( i=0, ien=order.length ; i<ien ; i++ ) {
356
+ var colIdx = order[i].columnIdx;
357
+
358
+ if ( display[colIdx] === '-' && ! columns[colIdx].control && columns[colIdx].minWidth ) {
359
+ // Once we've found a column that won't fit we don't let any
360
+ // others display either, or columns might disappear in the
361
+ // middle of the table
362
+ if ( empty || usedWidth - columns[colIdx].minWidth < 0 ) {
363
+ empty = true;
364
+ display[colIdx] = false;
365
+ }
366
+ else {
367
+ display[colIdx] = true;
368
+ }
369
+
370
+ usedWidth -= columns[colIdx].minWidth;
371
+ }
372
+ }
373
+
374
+ // Determine if the 'control' column should be shown (if there is one).
375
+ // This is the case when there is a hidden column (that is not the
376
+ // control column). The two loops look inefficient here, but they are
377
+ // trivial and will fly through. We need to know the outcome from the
378
+ // first , before the action in the second can be taken
379
+ var showControl = false;
380
+
381
+ for ( i=0, ien=columns.length ; i<ien ; i++ ) {
382
+ if ( ! columns[i].control && ! columns[i].never && ! display[i] ) {
383
+ showControl = true;
384
+ break;
385
+ }
386
+ }
387
+
388
+ for ( i=0, ien=columns.length ; i<ien ; i++ ) {
389
+ if ( columns[i].control ) {
390
+ display[i] = showControl;
391
+ }
392
+ }
393
+
394
+ // Finally we need to make sure that there is at least one column that
395
+ // is visible
396
+ if ( $.inArray( true, display ) === -1 ) {
397
+ display[0] = true;
398
+ }
399
+
400
+ return display;
401
+ },
402
+
403
+
404
+ /**
405
+ * Create the internal `columns` array with information about the columns
406
+ * for the table. This includes determining which breakpoints the column
407
+ * will appear in, based upon class names in the column, which makes up the
408
+ * vast majority of this method.
409
+ *
410
+ * @private
411
+ */
412
+ _classLogic: function ()
413
+ {
414
+ var that = this;
415
+ var calc = {};
416
+ var breakpoints = this.c.breakpoints;
417
+ var dt = this.s.dt;
418
+ var columns = dt.columns().eq(0).map( function (i) {
419
+ var column = this.column(i);
420
+ var className = column.header().className;
421
+ var priority = dt.settings()[0].aoColumns[i].responsivePriority;
422
+
423
+ if ( priority === undefined ) {
424
+ var dataPriority = $(column.header()).data('priority');
425
+
426
+ priority = dataPriority !== undefined ?
427
+ dataPriority * 1 :
428
+ 10000;
429
+ }
430
+
431
+ return {
432
+ className: className,
433
+ includeIn: [],
434
+ auto: false,
435
+ control: false,
436
+ never: className.match(/\bnever\b/) ? true : false,
437
+ priority: priority
438
+ };
439
+ } );
440
+
441
+ // Simply add a breakpoint to `includeIn` array, ensuring that there are
442
+ // no duplicates
443
+ var add = function ( colIdx, name ) {
444
+ var includeIn = columns[ colIdx ].includeIn;
445
+
446
+ if ( $.inArray( name, includeIn ) === -1 ) {
447
+ includeIn.push( name );
448
+ }
449
+ };
450
+
451
+ var column = function ( colIdx, name, operator, matched ) {
452
+ var size, i, ien;
453
+
454
+ if ( ! operator ) {
455
+ columns[ colIdx ].includeIn.push( name );
456
+ }
457
+ else if ( operator === 'max-' ) {
458
+ // Add this breakpoint and all smaller
459
+ size = that._find( name ).width;
460
+
461
+ for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) {
462
+ if ( breakpoints[i].width <= size ) {
463
+ add( colIdx, breakpoints[i].name );
464
+ }
465
+ }
466
+ }
467
+ else if ( operator === 'min-' ) {
468
+ // Add this breakpoint and all larger
469
+ size = that._find( name ).width;
470
+
471
+ for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) {
472
+ if ( breakpoints[i].width >= size ) {
473
+ add( colIdx, breakpoints[i].name );
474
+ }
475
+ }
476
+ }
477
+ else if ( operator === 'not-' ) {
478
+ // Add all but this breakpoint
479
+ for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) {
480
+ if ( breakpoints[i].name.indexOf( matched ) === -1 ) {
481
+ add( colIdx, breakpoints[i].name );
482
+ }
483
+ }
484
+ }
485
+ };
486
+
487
+ // Loop over each column and determine if it has a responsive control
488
+ // class
489
+ columns.each( function ( col, i ) {
490
+ var classNames = col.className.split(' ');
491
+ var hasClass = false;
492
+
493
+ // Split the class name up so multiple rules can be applied if needed
494
+ for ( var k=0, ken=classNames.length ; k<ken ; k++ ) {
495
+ var className = $.trim( classNames[k] );
496
+
497
+ if ( className === 'all' ) {
498
+ // Include in all
499
+ hasClass = true;
500
+ col.includeIn = $.map( breakpoints, function (a) {
501
+ return a.name;
502
+ } );
503
+ return;
504
+ }
505
+ else if ( className === 'none' || col.never ) {
506
+ // Include in none (default) and no auto
507
+ hasClass = true;
508
+ return;
509
+ }
510
+ else if ( className === 'control' ) {
511
+ // Special column that is only visible, when one of the other
512
+ // columns is hidden. This is used for the details control
513
+ hasClass = true;
514
+ col.control = true;
515
+ return;
516
+ }
517
+
518
+ $.each( breakpoints, function ( j, breakpoint ) {
519
+ // Does this column have a class that matches this breakpoint?
520
+ var brokenPoint = breakpoint.name.split('-');
521
+ var re = new RegExp( '(min\\-|max\\-|not\\-)?('+brokenPoint[0]+')(\\-[_a-zA-Z0-9])?' );
522
+ var match = className.match( re );
523
+
524
+ if ( match ) {
525
+ hasClass = true;
526
+
527
+ if ( match[2] === brokenPoint[0] && match[3] === '-'+brokenPoint[1] ) {
528
+ // Class name matches breakpoint name fully
529
+ column( i, breakpoint.name, match[1], match[2]+match[3] );
530
+ }
531
+ else if ( match[2] === brokenPoint[0] && ! match[3] ) {
532
+ // Class name matched primary breakpoint name with no qualifier
533
+ column( i, breakpoint.name, match[1], match[2] );
534
+ }
535
+ }
536
+ } );
537
+ }
538
+
539
+ // If there was no control class, then automatic sizing is used
540
+ if ( ! hasClass ) {
541
+ col.auto = true;
542
+ }
543
+ } );
544
+
545
+ this.s.columns = columns;
546
+ },
547
+
548
+
549
+ /**
550
+ * Show the details for the child row
551
+ *
552
+ * @param {DataTables.Api} row API instance for the row
553
+ * @param {boolean} update Update flag
554
+ * @private
555
+ */
556
+ _detailsDisplay: function ( row, update )
557
+ {
558
+ var that = this;
559
+ var dt = this.s.dt;
560
+ var details = this.c.details;
561
+
562
+ if ( details && details.type !== false ) {
563
+ var res = details.display( row, update, function () {
564
+ return details.renderer(
565
+ dt, row[0], that._detailsObj(row[0])
566
+ );
567
+ } );
568
+
569
+ if ( res === true || res === false ) {
570
+ $(dt.table().node()).triggerHandler( 'responsive-display.dt', [dt, row, res, update] );
571
+ }
572
+ }
573
+ },
574
+
575
+
576
+ /**
577
+ * Initialisation for the details handler
578
+ *
579
+ * @private
580
+ */
581
+ _detailsInit: function ()
582
+ {
583
+ var that = this;
584
+ var dt = this.s.dt;
585
+ var details = this.c.details;
586
+
587
+ // The inline type always uses the first child as the target
588
+ if ( details.type === 'inline' ) {
589
+ details.target = 'td:first-child, th:first-child';
590
+ }
591
+
592
+ // Keyboard accessibility
593
+ dt.on( 'draw.dtr', function () {
594
+ that._tabIndexes();
595
+ } );
596
+ that._tabIndexes(); // Initial draw has already happened
597
+
598
+ $( dt.table().body() ).on( 'keyup.dtr', 'td, th', function (e) {
599
+ if ( e.keyCode === 13 && $(this).data('dtr-keyboard') ) {
600
+ $(this).click();
601
+ }
602
+ } );
603
+
604
+ // type.target can be a string jQuery selector or a column index
605
+ var target = details.target;
606
+ var selector = typeof target === 'string' ? target : 'td, th';
607
+
608
+ // Click handler to show / hide the details rows when they are available
609
+ $( dt.table().body() )
610
+ .on( 'click.dtr mousedown.dtr mouseup.dtr', selector, function (e) {
611
+ // If the table is not collapsed (i.e. there is no hidden columns)
612
+ // then take no action
613
+ if ( ! $(dt.table().node()).hasClass('collapsed' ) ) {
614
+ return;
615
+ }
616
+
617
+ // Check that the row is actually a DataTable's controlled node
618
+ if ( $.inArray( $(this).closest('tr').get(0), dt.rows().nodes().toArray() ) === -1 ) {
619
+ return;
620
+ }
621
+
622
+ // For column index, we determine if we should act or not in the
623
+ // handler - otherwise it is already okay
624
+ if ( typeof target === 'number' ) {
625
+ var targetIdx = target < 0 ?
626
+ dt.columns().eq(0).length + target :
627
+ target;
628
+
629
+ if ( dt.cell( this ).index().column !== targetIdx ) {
630
+ return;
631
+ }
632
+ }
633
+
634
+ // $().closest() includes itself in its check
635
+ var row = dt.row( $(this).closest('tr') );
636
+
637
+ // Check event type to do an action
638
+ if ( e.type === 'click' ) {
639
+ // The renderer is given as a function so the caller can execute it
640
+ // only when they need (i.e. if hiding there is no point is running
641
+ // the renderer)
642
+ that._detailsDisplay( row, false );
643
+ }
644
+ else if ( e.type === 'mousedown' ) {
645
+ // For mouse users, prevent the focus ring from showing
646
+ $(this).css('outline', 'none');
647
+ }
648
+ else if ( e.type === 'mouseup' ) {
649
+ // And then re-allow at the end of the click
650
+ $(this).blur().css('outline', '');
651
+ }
652
+ } );
653
+ },
654
+
655
+
656
+ /**
657
+ * Get the details to pass to a renderer for a row
658
+ * @param {int} rowIdx Row index
659
+ * @private
660
+ */
661
+ _detailsObj: function ( rowIdx )
662
+ {
663
+ var that = this;
664
+ var dt = this.s.dt;
665
+
666
+ return $.map( this.s.columns, function( col, i ) {
667
+ // Never and control columns should not be passed to the renderer
668
+ if ( col.never || col.control ) {
669
+ return;
670
+ }
671
+
672
+ return {
673
+ title: dt.settings()[0].aoColumns[ i ].sTitle,
674
+ data: dt.cell( rowIdx, i ).render( that.c.orthogonal ),
675
+ hidden: dt.column( i ).visible() && !that.s.current[ i ],
676
+ columnIndex: i,
677
+ rowIndex: rowIdx
678
+ };
679
+ } );
680
+ },
681
+
682
+
683
+ /**
684
+ * Find a breakpoint object from a name
685
+ *
686
+ * @param {string} name Breakpoint name to find
687
+ * @return {object} Breakpoint description object
688
+ * @private
689
+ */
690
+ _find: function ( name )
691
+ {
692
+ var breakpoints = this.c.breakpoints;
693
+
694
+ for ( var i=0, ien=breakpoints.length ; i<ien ; i++ ) {
695
+ if ( breakpoints[i].name === name ) {
696
+ return breakpoints[i];
697
+ }
698
+ }
699
+ },
700
+
701
+
702
+ /**
703
+ * Re-create the contents of the child rows as the display has changed in
704
+ * some way.
705
+ *
706
+ * @private
707
+ */
708
+ _redrawChildren: function ()
709
+ {
710
+ var that = this;
711
+ var dt = this.s.dt;
712
+
713
+ dt.rows( {page: 'current'} ).iterator( 'row', function ( settings, idx ) {
714
+ var row = dt.row( idx );
715
+
716
+ that._detailsDisplay( dt.row( idx ), true );
717
+ } );
718
+ },
719
+
720
+
721
+ /**
722
+ * Alter the table display for a resized viewport. This involves first
723
+ * determining what breakpoint the window currently is in, getting the
724
+ * column visibilities to apply and then setting them.
725
+ *
726
+ * @private
727
+ */
728
+ _resize: function ()
729
+ {
730
+ var that = this;
731
+ var dt = this.s.dt;
732
+ var width = $(window).width();
733
+ var breakpoints = this.c.breakpoints;
734
+ var breakpoint = breakpoints[0].name;
735
+ var columns = this.s.columns;
736
+ var i, ien;
737
+ var oldVis = this.s.current.slice();
738
+
739
+ // Determine what breakpoint we are currently at
740
+ for ( i=breakpoints.length-1 ; i>=0 ; i-- ) {
741
+ if ( width <= breakpoints[i].width ) {
742
+ breakpoint = breakpoints[i].name;
743
+ break;
744
+ }
745
+ }
746
+
747
+ // Show the columns for that break point
748
+ var columnsVis = this._columnsVisiblity( breakpoint );
749
+ this.s.current = columnsVis;
750
+
751
+ // Set the class before the column visibility is changed so event
752
+ // listeners know what the state is. Need to determine if there are
753
+ // any columns that are not visible but can be shown
754
+ var collapsedClass = false;
755
+ for ( i=0, ien=columns.length ; i<ien ; i++ ) {
756
+ if ( columnsVis[i] === false && ! columns[i].never && ! columns[i].control ) {
757
+ collapsedClass = true;
758
+ break;
759
+ }
760
+ }
761
+
762
+ $( dt.table().node() ).toggleClass( 'collapsed', collapsedClass );
763
+
764
+ var changed = false;
765
+
766
+ dt.columns().eq(0).each( function ( colIdx, i ) {
767
+ if ( columnsVis[i] !== oldVis[i] ) {
768
+ changed = true;
769
+ that._setColumnVis( colIdx, columnsVis[i] );
770
+ }
771
+ } );
772
+
773
+ if ( changed ) {
774
+ this._redrawChildren();
775
+
776
+ // Inform listeners of the change
777
+ $(dt.table().node()).trigger( 'responsive-resize.dt', [dt, this.s.current] );
778
+
779
+ // If no records, update the "No records" display element
780
+ if ( dt.page.info().recordsDisplay === 0 ) {
781
+ //dt.draw(); # effective_datatables - don't draw
782
+ }
783
+ }
784
+ },
785
+
786
+
787
+ /**
788
+ * Determine the width of each column in the table so the auto column hiding
789
+ * has that information to work with. This method is never going to be 100%
790
+ * perfect since column widths can change slightly per page, but without
791
+ * seriously compromising performance this is quite effective.
792
+ *
793
+ * @private
794
+ */
795
+ _resizeAuto: function ()
796
+ {
797
+ var dt = this.s.dt;
798
+ var columns = this.s.columns;
799
+
800
+ // Are we allowed to do auto sizing?
801
+ if ( ! this.c.auto ) {
802
+ return;
803
+ }
804
+
805
+ // Are there any columns that actually need auto-sizing, or do they all
806
+ // have classes defined
807
+ if ( $.inArray( true, $.map( columns, function (c) { return c.auto; } ) ) === -1 ) {
808
+ return;
809
+ }
810
+
811
+ // Need to restore all children. They will be reinstated by a re-render
812
+ if ( ! $.isEmptyObject( _childNodeStore ) ) {
813
+ $.each( _childNodeStore, function ( key ) {
814
+ var idx = key.split('-');
815
+
816
+ _childNodesRestore( dt, idx[0]*1, idx[1]*1 );
817
+ } );
818
+ }
819
+
820
+ // Clone the table with the current data in it
821
+ var tableWidth = dt.table().node().offsetWidth;
822
+ var columnWidths = dt.columns;
823
+ var clonedTable = dt.table().node().cloneNode( false );
824
+ var clonedHeader = $( dt.table().header().cloneNode( false ) ).appendTo( clonedTable );
825
+ var clonedBody = $( dt.table().body() ).clone( false, false ).empty().appendTo( clonedTable ); // use jQuery because of IE8
826
+
827
+ // Header
828
+ var headerCells = dt.columns()
829
+ .header()
830
+ .filter( function (idx) {
831
+ return dt.column(idx).visible();
832
+ } )
833
+ .to$()
834
+ .clone( false )
835
+ .css( 'display', 'table-cell' );
836
+
837
+ // Body rows - we don't need to take account of DataTables' column
838
+ // visibility since we implement our own here (hence the `display` set)
839
+ $(clonedBody)
840
+ .append( $(dt.rows( { page: 'current' } ).nodes()).clone( false ) )
841
+ .find( 'th, td' ).css( 'display', '' );
842
+
843
+ // Footer
844
+ var footer = dt.table().footer();
845
+ if ( footer ) {
846
+ var clonedFooter = $( footer.cloneNode( false ) ).appendTo( clonedTable );
847
+ var footerCells = dt.columns()
848
+ .footer()
849
+ .filter( function (idx) {
850
+ return dt.column(idx).visible();
851
+ } )
852
+ .to$()
853
+ .clone( false )
854
+ .css( 'display', 'table-cell' );
855
+
856
+ $('<tr/>')
857
+ .append( footerCells )
858
+ .appendTo( clonedFooter );
859
+ }
860
+
861
+ $('<tr/>')
862
+ .append( headerCells )
863
+ .appendTo( clonedHeader );
864
+
865
+ // In the inline case extra padding is applied to the first column to
866
+ // give space for the show / hide icon. We need to use this in the
867
+ // calculation
868
+ if ( this.c.details.type === 'inline' ) {
869
+ $(clonedTable).addClass( 'dtr-inline collapsed' );
870
+ }
871
+
872
+ // It is unsafe to insert elements with the same name into the DOM
873
+ // multiple times. For example, cloning and inserting a checked radio
874
+ // clears the chcecked state of the original radio.
875
+ $( clonedTable ).find( '[name]' ).removeAttr( 'name' );
876
+
877
+ var inserted = $('<div/>')
878
+ .css( {
879
+ width: 1,
880
+ height: 1,
881
+ overflow: 'hidden',
882
+ clear: 'both'
883
+ } )
884
+ .append( clonedTable );
885
+
886
+ inserted.insertBefore( dt.table().node() );
887
+
888
+ // The cloned header now contains the smallest that each column can be
889
+ headerCells.each( function (i) {
890
+ var idx = dt.column.index( 'fromVisible', i );
891
+ columns[ idx ].minWidth = this.offsetWidth || 0;
892
+ } );
893
+
894
+ inserted.remove();
895
+ },
896
+
897
+ /**
898
+ * Set a column's visibility.
899
+ *
900
+ * We don't use DataTables' column visibility controls in order to ensure
901
+ * that column visibility can Responsive can no-exist. Since only IE8+ is
902
+ * supported (and all evergreen browsers of course) the control of the
903
+ * display attribute works well.
904
+ *
905
+ * @param {integer} col Column index
906
+ * @param {boolean} showHide Show or hide (true or false)
907
+ * @private
908
+ */
909
+ _setColumnVis: function ( col, showHide )
910
+ {
911
+ var dt = this.s.dt;
912
+ var display = showHide ? '' : 'none'; // empty string will remove the attr
913
+
914
+ $( dt.column( col ).header() ).css( 'display', display );
915
+ $( dt.column( col ).footer() ).css( 'display', display );
916
+ dt.column( col ).nodes().to$().css( 'display', display );
917
+
918
+ // If the are child nodes stored, we might need to reinsert them
919
+ if ( ! $.isEmptyObject( _childNodeStore ) ) {
920
+ dt.cells( null, col ).indexes().each( function (idx) {
921
+ _childNodesRestore( dt, idx.row, idx.column );
922
+ } );
923
+ }
924
+ },
925
+
926
+
927
+ /**
928
+ * Update the cell tab indexes for keyboard accessibility. This is called on
929
+ * every table draw - that is potentially inefficient, but also the least
930
+ * complex option given that column visibility can change on the fly. Its a
931
+ * shame user-focus was removed from CSS 3 UI, as it would have solved this
932
+ * issue with a single CSS statement.
933
+ *
934
+ * @private
935
+ */
936
+ _tabIndexes: function ()
937
+ {
938
+ var dt = this.s.dt;
939
+ var cells = dt.cells( { page: 'current' } ).nodes().to$();
940
+ var ctx = dt.settings()[0];
941
+ var target = this.c.details.target;
942
+
943
+ cells.filter( '[data-dtr-keyboard]' ).removeData( '[data-dtr-keyboard]' );
944
+
945
+ var selector = typeof target === 'number' ?
946
+ ':eq('+target+')' :
947
+ target;
948
+
949
+ // This is a bit of a hack - we need to limit the selected nodes to just
950
+ // those of this table
951
+ if ( selector === 'td:first-child, th:first-child' ) {
952
+ selector = '>td:first-child, >th:first-child';
953
+ }
954
+
955
+ $( selector, dt.rows( { page: 'current' } ).nodes() )
956
+ .attr( 'tabIndex', ctx.iTabIndex )
957
+ .data( 'dtr-keyboard', 1 );
958
+ }
914
959
  } );
915
960
 
916
961
 
@@ -925,11 +970,11 @@ $.extend( Responsive.prototype, {
925
970
  * @static
926
971
  */
927
972
  Responsive.breakpoints = [
928
- { name: 'desktop', width: Infinity },
929
- { name: 'tablet-l', width: 1024 },
930
- { name: 'tablet-p', width: 768 },
931
- { name: 'mobile-l', width: 480 },
932
- { name: 'mobile-p', width: 320 }
973
+ { name: 'desktop', width: Infinity },
974
+ { name: 'tablet-l', width: 1024 },
975
+ { name: 'tablet-p', width: 768 },
976
+ { name: 'mobile-l', width: 480 },
977
+ { name: 'mobile-p', width: 320 }
933
978
  ];
934
979
 
935
980
 
@@ -942,101 +987,147 @@ Responsive.breakpoints = [
942
987
  * @static
943
988
  */
944
989
  Responsive.display = {
945
- childRow: function ( row, update, render ) {
946
- if ( update ) {
947
- if ( $(row.node()).hasClass('parent') ) {
948
- row.child( render(), 'child' ).show();
949
-
950
- return true;
951
- }
952
- }
953
- else {
954
- if ( ! row.child.isShown() ) {
955
- row.child( render(), 'child' ).show();
956
- $( row.node() ).addClass( 'parent' );
957
-
958
- return true;
959
- }
960
- else {
961
- row.child( false );
962
- $( row.node() ).removeClass( 'parent' );
963
-
964
- return false;
965
- }
966
- }
967
- },
968
-
969
- childRowImmediate: function ( row, update, render ) {
970
- if ( (! update && row.child.isShown()) || ! row.responsive.hasHidden() ) {
971
- // User interaction and the row is show, or nothing to show
972
- row.child( false );
973
- $( row.node() ).removeClass( 'parent' );
974
-
975
- return false;
976
- }
977
- else {
978
- // Display
979
- row.child( render(), 'child' ).show();
980
- $( row.node() ).addClass( 'parent' );
981
-
982
- return true;
983
- }
984
- },
985
-
986
- // This is a wrapper so the modal options for Bootstrap and jQuery UI can
987
- // have options passed into them. This specific one doesn't need to be a
988
- // function but it is for consistency in the `modal` name
989
- modal: function ( options ) {
990
- return function ( row, update, render ) {
991
- if ( ! update ) {
992
- // Show a modal
993
- var close = function () {
994
- modal.remove(); // will tidy events for us
995
- $(document).off( 'keypress.dtr' );
996
- };
997
-
998
- var modal = $('<div class="dtr-modal"/>')
999
- .append( $('<div class="dtr-modal-display"/>')
1000
- .append( $('<div class="dtr-modal-content"/>')
1001
- .append( render() )
1002
- )
1003
- .append( $('<div class="dtr-modal-close">&times;</div>' )
1004
- .click( function () {
1005
- close();
1006
- } )
1007
- )
1008
- )
1009
- .append( $('<div class="dtr-modal-background"/>')
1010
- .click( function () {
1011
- close();
1012
- } )
1013
- )
1014
- .appendTo( 'body' );
1015
-
1016
- $(document).on( 'keyup.dtr', function (e) {
1017
- if ( e.keyCode === 27 ) {
1018
- e.stopPropagation();
1019
-
1020
- close();
1021
- }
1022
- } );
1023
- }
1024
- else {
1025
- $('div.dtr-modal-content')
1026
- .empty()
1027
- .append( render() );
1028
- }
1029
-
1030
- if ( options && options.header ) {
1031
- $('div.dtr-modal-content').prepend(
1032
- '<h2>'+options.header( row )+'</h2>'
1033
- );
1034
- }
1035
- };
1036
- }
990
+ childRow: function ( row, update, render ) {
991
+ if ( update ) {
992
+ if ( $(row.node()).hasClass('parent') ) {
993
+ row.child( render(), 'child' ).show();
994
+
995
+ return true;
996
+ }
997
+ }
998
+ else {
999
+ if ( ! row.child.isShown() ) {
1000
+ row.child( render(), 'child' ).show();
1001
+ $( row.node() ).addClass( 'parent' );
1002
+
1003
+ return true;
1004
+ }
1005
+ else {
1006
+ row.child( false );
1007
+ $( row.node() ).removeClass( 'parent' );
1008
+
1009
+ return false;
1010
+ }
1011
+ }
1012
+ },
1013
+
1014
+ childRowImmediate: function ( row, update, render ) {
1015
+ if ( (! update && row.child.isShown()) || ! row.responsive.hasHidden() ) {
1016
+ // User interaction and the row is show, or nothing to show
1017
+ row.child( false );
1018
+ $( row.node() ).removeClass( 'parent' );
1019
+
1020
+ return false;
1021
+ }
1022
+ else {
1023
+ // Display
1024
+ row.child( render(), 'child' ).show();
1025
+ $( row.node() ).addClass( 'parent' );
1026
+
1027
+ return true;
1028
+ }
1029
+ },
1030
+
1031
+ // This is a wrapper so the modal options for Bootstrap and jQuery UI can
1032
+ // have options passed into them. This specific one doesn't need to be a
1033
+ // function but it is for consistency in the `modal` name
1034
+ modal: function ( options ) {
1035
+ return function ( row, update, render ) {
1036
+ if ( ! update ) {
1037
+ // Show a modal
1038
+ var close = function () {
1039
+ modal.remove(); // will tidy events for us
1040
+ $(document).off( 'keypress.dtr' );
1041
+ };
1042
+
1043
+ var modal = $('<div class="dtr-modal"/>')
1044
+ .append( $('<div class="dtr-modal-display"/>')
1045
+ .append( $('<div class="dtr-modal-content"/>')
1046
+ .append( render() )
1047
+ )
1048
+ .append( $('<div class="dtr-modal-close">&times;</div>' )
1049
+ .click( function () {
1050
+ close();
1051
+ } )
1052
+ )
1053
+ )
1054
+ .append( $('<div class="dtr-modal-background"/>')
1055
+ .click( function () {
1056
+ close();
1057
+ } )
1058
+ )
1059
+ .appendTo( 'body' );
1060
+
1061
+ $(document).on( 'keyup.dtr', function (e) {
1062
+ if ( e.keyCode === 27 ) {
1063
+ e.stopPropagation();
1064
+
1065
+ close();
1066
+ }
1067
+ } );
1068
+ }
1069
+ else {
1070
+ $('div.dtr-modal-content')
1071
+ .empty()
1072
+ .append( render() );
1073
+ }
1074
+
1075
+ if ( options && options.header ) {
1076
+ $('div.dtr-modal-content').prepend(
1077
+ '<h2>'+options.header( row )+'</h2>'
1078
+ );
1079
+ }
1080
+ };
1081
+ }
1037
1082
  };
1038
1083
 
1039
1084
 
1085
+ var _childNodeStore = {};
1086
+
1087
+ function _childNodes( dt, row, col ) {
1088
+ var name = row+'-'+col;
1089
+
1090
+ if ( _childNodeStore[ name ] ) {
1091
+ return _childNodeStore[ name ];
1092
+ }
1093
+
1094
+ // https://jsperf.com/childnodes-array-slice-vs-loop
1095
+ var nodes = [];
1096
+ var children = dt.cell( row, col ).node().childNodes;
1097
+ for ( var i=0, ien=children.length ; i<ien ; i++ ) {
1098
+ nodes.push( children[i] );
1099
+ }
1100
+
1101
+ _childNodeStore[ name ] = nodes;
1102
+
1103
+ return nodes;
1104
+ }
1105
+
1106
+ function _childNodesRestore( dt, row, col ) {
1107
+ var name = row+'-'+col;
1108
+
1109
+ if ( ! _childNodeStore[ name ] ) {
1110
+ return;
1111
+ }
1112
+
1113
+ var node = dt.cell( row, col ).node();
1114
+ var store = _childNodeStore[ name ];
1115
+ var parent = store[0].parentNode;
1116
+ var parentChildren = parent.childNodes;
1117
+ var a = [];
1118
+
1119
+ for ( var i=0, ien=parentChildren.length ; i<ien ; i++ ) {
1120
+ a.push( parentChildren[i] );
1121
+ }
1122
+
1123
+ for ( var j=0, jen=a.length ; j<jen ; j++ ) {
1124
+ node.appendChild( a[j] );
1125
+ }
1126
+
1127
+ _childNodeStore[ name ] = undefined;
1128
+ }
1129
+
1130
+
1040
1131
  /**
1041
1132
  * Display methods - functions which define how the hidden data should be shown
1042
1133
  * in the table.
@@ -1046,43 +1137,70 @@ Responsive.display = {
1046
1137
  * @static
1047
1138
  */
1048
1139
  Responsive.renderer = {
1049
- listHidden: function () {
1050
- return function ( api, rowIdx, columns ) {
1051
- var data = $.map( columns, function ( col ) {
1052
- return col.hidden ?
1053
- '<li data-dtr-index="'+col.columnIndex+'" data-dt-row="'+col.rowIndex+'" data-dt-column="'+col.columnIndex+'">'+
1054
- '<span class="dtr-title">'+
1055
- col.title+
1056
- '</span> '+
1057
- '<span class="dtr-data">'+
1058
- col.data+
1059
- '</span>'+
1060
- '</li>' :
1061
- '';
1062
- } ).join('');
1063
-
1064
- return data ?
1065
- $('<ul data-dtr-index="'+rowIdx+'"/>').append( data ) :
1066
- false;
1067
- }
1068
- },
1069
-
1070
- tableAll: function ( options ) {
1071
- options = $.extend( {
1072
- tableClass: ''
1073
- }, options );
1074
-
1075
- return function ( api, rowIdx, columns ) {
1076
- var data = $.map( columns, function ( col ) {
1077
- return '<tr data-dt-row="'+col.rowIndex+'" data-dt-column="'+col.columnIndex+'">'+
1078
- '<td>'+col.title+':'+'</td> '+
1079
- '<td>'+col.data+'</td>'+
1080
- '</tr>';
1081
- } ).join('');
1082
-
1083
- return $('<table class="'+options.tableClass+'" width="100%"/>').append( data );
1084
- }
1085
- }
1140
+ listHiddenNodes: function () {
1141
+ return function ( api, rowIdx, columns ) {
1142
+ var ul = $('<ul data-dtr-index="'+rowIdx+'" class="dtr-details"/>');
1143
+ var found = false;
1144
+
1145
+ var data = $.each( columns, function ( i, col ) {
1146
+ if ( col.hidden ) {
1147
+ $(
1148
+ '<li data-dtr-index="'+col.columnIndex+'" data-dt-row="'+col.rowIndex+'" data-dt-column="'+col.columnIndex+'">'+
1149
+ '<span class="dtr-title">'+
1150
+ col.title+
1151
+ '</span> '+
1152
+ '</li>'
1153
+ )
1154
+ .append( $('<span class="dtr-data"/>').append( _childNodes( api, col.rowIndex, col.columnIndex ) ) )// api.cell( col.rowIndex, col.columnIndex ).node().childNodes ) )
1155
+ .appendTo( ul );
1156
+
1157
+ found = true;
1158
+ }
1159
+ } );
1160
+
1161
+ return found ?
1162
+ ul :
1163
+ false;
1164
+ };
1165
+ },
1166
+
1167
+ listHidden: function () {
1168
+ return function ( api, rowIdx, columns ) {
1169
+ var data = $.map( columns, function ( col ) {
1170
+ return col.hidden ?
1171
+ '<li data-dtr-index="'+col.columnIndex+'" data-dt-row="'+col.rowIndex+'" data-dt-column="'+col.columnIndex+'">'+
1172
+ '<span class="dtr-title">'+
1173
+ col.title+
1174
+ '</span> '+
1175
+ '<span class="dtr-data">'+
1176
+ col.data+
1177
+ '</span>'+
1178
+ '</li>' :
1179
+ '';
1180
+ } ).join('');
1181
+
1182
+ return data ?
1183
+ $('<ul data-dtr-index="'+rowIdx+'" class="dtr-details"/>').append( data ) :
1184
+ false;
1185
+ }
1186
+ },
1187
+
1188
+ tableAll: function ( options ) {
1189
+ options = $.extend( {
1190
+ tableClass: ''
1191
+ }, options );
1192
+
1193
+ return function ( api, rowIdx, columns ) {
1194
+ var data = $.map( columns, function ( col ) {
1195
+ return '<tr data-dt-row="'+col.rowIndex+'" data-dt-column="'+col.columnIndex+'">'+
1196
+ '<td>'+col.title+':'+'</td> '+
1197
+ '<td>'+col.data+'</td>'+
1198
+ '</tr>';
1199
+ } ).join('');
1200
+
1201
+ return $('<table class="'+options.tableClass+' dtr-details" width="100%"/>').append( data );
1202
+ }
1203
+ }
1086
1204
  };
1087
1205
 
1088
1206
  /**
@@ -1093,60 +1211,60 @@ Responsive.renderer = {
1093
1211
  * @static
1094
1212
  */
1095
1213
  Responsive.defaults = {
1096
- /**
1097
- * List of breakpoints for the instance. Note that this means that each
1098
- * instance can have its own breakpoints. Additionally, the breakpoints
1099
- * cannot be changed once an instance has been creased.
1100
- *
1101
- * @type {Array}
1102
- * @default Takes the value of `Responsive.breakpoints`
1103
- */
1104
- breakpoints: Responsive.breakpoints,
1105
-
1106
- /**
1107
- * Enable / disable auto hiding calculations. It can help to increase
1108
- * performance slightly if you disable this option, but all columns would
1109
- * need to have breakpoint classes assigned to them
1110
- *
1111
- * @type {Boolean}
1112
- * @default `true`
1113
- */
1114
- auto: true,
1115
-
1116
- /**
1117
- * Details control. If given as a string value, the `type` property of the
1118
- * default object is set to that value, and the defaults used for the rest
1119
- * of the object - this is for ease of implementation.
1120
- *
1121
- * The object consists of the following properties:
1122
- *
1123
- * * `display` - A function that is used to show and hide the hidden details
1124
- * * `renderer` - function that is called for display of the child row data.
1125
- * The default function will show the data from the hidden columns
1126
- * * `target` - Used as the selector for what objects to attach the child
1127
- * open / close to
1128
- * * `type` - `false` to disable the details display, `inline` or `column`
1129
- * for the two control types
1130
- *
1131
- * @type {Object|string}
1132
- */
1133
- details: {
1134
- display: Responsive.display.childRow,
1135
-
1136
- renderer: Responsive.renderer.listHidden(),
1137
-
1138
- target: 0,
1139
-
1140
- type: 'inline'
1141
- },
1142
-
1143
- /**
1144
- * Orthogonal data request option. This is used to define the data type
1145
- * requested when Responsive gets the data to show in the child row.
1146
- *
1147
- * @type {String}
1148
- */
1149
- orthogonal: 'display'
1214
+ /**
1215
+ * List of breakpoints for the instance. Note that this means that each
1216
+ * instance can have its own breakpoints. Additionally, the breakpoints
1217
+ * cannot be changed once an instance has been creased.
1218
+ *
1219
+ * @type {Array}
1220
+ * @default Takes the value of `Responsive.breakpoints`
1221
+ */
1222
+ breakpoints: Responsive.breakpoints,
1223
+
1224
+ /**
1225
+ * Enable / disable auto hiding calculations. It can help to increase
1226
+ * performance slightly if you disable this option, but all columns would
1227
+ * need to have breakpoint classes assigned to them
1228
+ *
1229
+ * @type {Boolean}
1230
+ * @default `true`
1231
+ */
1232
+ auto: true,
1233
+
1234
+ /**
1235
+ * Details control. If given as a string value, the `type` property of the
1236
+ * default object is set to that value, and the defaults used for the rest
1237
+ * of the object - this is for ease of implementation.
1238
+ *
1239
+ * The object consists of the following properties:
1240
+ *
1241
+ * * `display` - A function that is used to show and hide the hidden details
1242
+ * * `renderer` - function that is called for display of the child row data.
1243
+ * The default function will show the data from the hidden columns
1244
+ * * `target` - Used as the selector for what objects to attach the child
1245
+ * open / close to
1246
+ * * `type` - `false` to disable the details display, `inline` or `column`
1247
+ * for the two control types
1248
+ *
1249
+ * @type {Object|string}
1250
+ */
1251
+ details: {
1252
+ display: Responsive.display.childRow,
1253
+
1254
+ renderer: Responsive.renderer.listHidden(),
1255
+
1256
+ target: 0,
1257
+
1258
+ type: 'inline'
1259
+ },
1260
+
1261
+ /**
1262
+ * Orthogonal data request option. This is used to define the data type
1263
+ * requested when Responsive gets the data to show in the child row.
1264
+ *
1265
+ * @type {String}
1266
+ */
1267
+ orthogonal: 'display'
1150
1268
  };
1151
1269
 
1152
1270
 
@@ -1157,41 +1275,41 @@ var Api = $.fn.dataTable.Api;
1157
1275
 
1158
1276
  // Doesn't do anything - work around for a bug in DT... Not documented
1159
1277
  Api.register( 'responsive()', function () {
1160
- return this;
1278
+ return this;
1161
1279
  } );
1162
1280
 
1163
1281
  Api.register( 'responsive.index()', function ( li ) {
1164
- li = $(li);
1282
+ li = $(li);
1165
1283
 
1166
- return {
1167
- column: li.data('dtr-index'),
1168
- row: li.parent().data('dtr-index')
1169
- };
1284
+ return {
1285
+ column: li.data('dtr-index'),
1286
+ row: li.parent().data('dtr-index')
1287
+ };
1170
1288
  } );
1171
1289
 
1172
1290
  Api.register( 'responsive.rebuild()', function () {
1173
- return this.iterator( 'table', function ( ctx ) {
1174
- if ( ctx._responsive ) {
1175
- ctx._responsive._classLogic();
1176
- }
1177
- } );
1291
+ return this.iterator( 'table', function ( ctx ) {
1292
+ if ( ctx._responsive ) {
1293
+ ctx._responsive._classLogic();
1294
+ }
1295
+ } );
1178
1296
  } );
1179
1297
 
1180
1298
  Api.register( 'responsive.recalc()', function () {
1181
- return this.iterator( 'table', function ( ctx ) {
1182
- if ( ctx._responsive ) {
1183
- ctx._responsive._resizeAuto();
1184
- ctx._responsive._resize();
1185
- }
1186
- } );
1299
+ return this.iterator( 'table', function ( ctx ) {
1300
+ if ( ctx._responsive ) {
1301
+ ctx._responsive._resizeAuto();
1302
+ ctx._responsive._resize();
1303
+ }
1304
+ } );
1187
1305
  } );
1188
1306
 
1189
1307
  Api.register( 'responsive.hasHidden()', function () {
1190
- var ctx = this.context[0];
1308
+ var ctx = this.context[0];
1191
1309
 
1192
- return ctx._responsive ?
1193
- $.inArray( false, ctx._responsive.s.current ) !== -1 :
1194
- false;
1310
+ return ctx._responsive ?
1311
+ $.inArray( false, ctx._responsive.s.current ) !== -1 :
1312
+ false;
1195
1313
  } );
1196
1314
 
1197
1315
 
@@ -1201,7 +1319,7 @@ Api.register( 'responsive.hasHidden()', function () {
1201
1319
  * @name Responsive.version
1202
1320
  * @static
1203
1321
  */
1204
- Responsive.version = '2.1.0';
1322
+ Responsive.version = '2.2.0';
1205
1323
 
1206
1324
 
1207
1325
  $.fn.dataTable.Responsive = Responsive;
@@ -1210,21 +1328,21 @@ $.fn.DataTable.Responsive = Responsive;
1210
1328
  // Attach a listener to the document which listens for DataTables initialisation
1211
1329
  // events so we can automatically initialise
1212
1330
  $(document).on( 'preInit.dt.dtr', function (e, settings, json) {
1213
- if ( e.namespace !== 'dt' ) {
1214
- return;
1215
- }
1216
-
1217
- if ( $(settings.nTable).hasClass( 'responsive' ) ||
1218
- $(settings.nTable).hasClass( 'dt-responsive' ) ||
1219
- settings.oInit.responsive ||
1220
- DataTable.defaults.responsive
1221
- ) {
1222
- var init = settings.oInit.responsive;
1223
-
1224
- if ( init !== false ) {
1225
- new Responsive( settings, $.isPlainObject( init ) ? init : {} );
1226
- }
1227
- }
1331
+ if ( e.namespace !== 'dt' ) {
1332
+ return;
1333
+ }
1334
+
1335
+ if ( $(settings.nTable).hasClass( 'responsive' ) ||
1336
+ $(settings.nTable).hasClass( 'dt-responsive' ) ||
1337
+ settings.oInit.responsive ||
1338
+ DataTable.defaults.responsive
1339
+ ) {
1340
+ var init = settings.oInit.responsive;
1341
+
1342
+ if ( init !== false ) {
1343
+ new Responsive( settings, $.isPlainObject( init ) ? init : {} );
1344
+ }
1345
+ }
1228
1346
  } );
1229
1347
 
1230
1348