jquery-datatables-rails 3.3.0 → 3.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (24) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/dataTables/bootstrap/3/jquery.dataTables.bootstrap.js +64 -29
  3. data/app/assets/javascripts/dataTables/extras/dataTables.autoFill.js +806 -648
  4. data/app/assets/javascripts/dataTables/extras/dataTables.buttons.js +1607 -0
  5. data/app/assets/javascripts/dataTables/extras/dataTables.colReorder.js +220 -267
  6. data/app/assets/javascripts/dataTables/extras/dataTables.fixedColumns.js +164 -69
  7. data/app/assets/javascripts/dataTables/extras/dataTables.fixedHeader.js +469 -870
  8. data/app/assets/javascripts/dataTables/extras/dataTables.keyTable.js +636 -972
  9. data/app/assets/javascripts/dataTables/extras/dataTables.responsive.js +472 -187
  10. data/app/assets/javascripts/dataTables/extras/dataTables.rowReorder.js +619 -0
  11. data/app/assets/javascripts/dataTables/extras/dataTables.scroller.js +146 -111
  12. data/app/assets/javascripts/dataTables/extras/dataTables.select.js +1038 -0
  13. data/app/assets/javascripts/dataTables/jquery.dataTables.api.fnGetColumnData.js +0 -0
  14. data/app/assets/javascripts/dataTables/jquery.dataTables.api.fnReloadAjax.js +0 -0
  15. data/app/assets/javascripts/dataTables/jquery.dataTables.foundation.js +37 -61
  16. data/app/assets/javascripts/dataTables/jquery.dataTables.js +720 -387
  17. data/app/assets/javascripts/dataTables/jquery.dataTables.sorting.ipAddress.js +44 -0
  18. data/app/assets/javascripts/dataTables/jquery.dataTables.sorting.numbersHtml.js +0 -0
  19. data/app/assets/javascripts/dataTables/jquery.dataTables.typeDetection.numbersHtml.js +0 -0
  20. data/app/assets/stylesheets/dataTables/jquery.dataTables.scss +34 -66
  21. data/app/assets/stylesheets/dataTables/src/demo_table.css +1 -1
  22. data/app/assets/stylesheets/dataTables/src/demo_table_jui.css.scss +4 -4
  23. data/lib/jquery/datatables/rails/version.rb +1 -1
  24. metadata +24 -19
@@ -1,11 +1,11 @@
1
- /*! Responsive 1.0.5
1
+ /*! Responsive 2.0.0
2
2
  * 2014-2015 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 1.0.5
8
+ * @version 2.0.0
9
9
  * @file dataTables.responsive.js
10
10
  * @author SpryMedia Ltd (www.sprymedia.co.uk)
11
11
  * @contact www.sprymedia.co.uk/contact
@@ -20,12 +20,35 @@
20
20
  *
21
21
  * For details please refer to: http://www.datatables.net
22
22
  */
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
+ }
23
36
 
24
- (function(window, document, undefined) {
37
+ if ( ! $ || ! $.fn.dataTable ) {
38
+ $ = require('datatables.net')(root, $).$;
39
+ }
25
40
 
41
+ return factory( $, root, root.document );
42
+ };
43
+ }
44
+ else {
45
+ // Browser
46
+ factory( jQuery, window, document );
47
+ }
48
+ }(function( $, window, document, undefined ) {
49
+ 'use strict';
50
+ var DataTable = $.fn.dataTable;
26
51
 
27
- var factory = function( $, DataTable ) {
28
- "use strict";
29
52
 
30
53
  /**
31
54
  * Responsive is a plug-in for the DataTables library that makes use of
@@ -64,7 +87,7 @@ var factory = function( $, DataTable ) {
64
87
  * @param {object} settings DataTables settings object for the host table
65
88
  * @param {object} [opts] Configuration options
66
89
  * @requires jQuery 1.7+
67
- * @requires DataTables 1.10.1+
90
+ * @requires DataTables 1.10.3+
68
91
  *
69
92
  * @example
70
93
  * $('#example').DataTable( {
@@ -74,13 +97,14 @@ var factory = function( $, DataTable ) {
74
97
  */
75
98
  var Responsive = function ( settings, opts ) {
76
99
  // Sanity check that we are using DataTables 1.10 or newer
77
- if ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.1' ) ) {
78
- throw 'DataTables Responsive requires DataTables 1.10.1 or newer';
100
+ if ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.3' ) ) {
101
+ throw 'DataTables Responsive requires DataTables 1.10.3 or newer';
79
102
  }
80
103
 
81
104
  this.s = {
82
105
  dt: new DataTable.Api( settings ),
83
- columns: []
106
+ columns: [],
107
+ current: []
84
108
  };
85
109
 
86
110
  // Check if responsive has already been initialised on this table
@@ -98,7 +122,7 @@ var Responsive = function ( settings, opts ) {
98
122
  this._constructor();
99
123
  };
100
124
 
101
- Responsive.prototype = {
125
+ $.extend( Responsive.prototype, {
102
126
  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
103
127
  * Constructor
104
128
  */
@@ -112,17 +136,43 @@ Responsive.prototype = {
112
136
  {
113
137
  var that = this;
114
138
  var dt = this.s.dt;
139
+ var dtPrivateSettings = dt.settings()[0];
115
140
 
116
141
  dt.settings()[0]._responsive = this;
117
142
 
118
- // Use DataTables' private throttle function to avoid processor thrashing
119
- $(window).on( 'resize.dtr orientationchange.dtr', dt.settings()[0].oApi._fnThrottle( function () {
143
+ // Use DataTables' throttle function to avoid processor thrashing on
144
+ // resize
145
+ $(window).on( 'resize.dtr orientationchange.dtr', DataTable.util.throttle( function () {
120
146
  that._resize();
121
147
  } ) );
122
148
 
149
+ // DataTables doesn't currently trigger an event when a row is added, so
150
+ // we need to hook into its private API to enforce the hidden rows when
151
+ // new data is added
152
+ dtPrivateSettings.oApi._fnCallbackReg( dtPrivateSettings, 'aoRowCreatedCallback', function (tr, data, idx) {
153
+ if ( $.inArray( false, that.s.current ) !== -1 ) {
154
+ $('td, th', tr).each( function ( i ) {
155
+ var idx = dt.column.index( 'toData', i );
156
+
157
+ if ( that.s.current[idx] === false ) {
158
+ $(this).css('display', 'none');
159
+ }
160
+ } );
161
+ }
162
+ } );
163
+
123
164
  // Destroy event handler
124
165
  dt.on( 'destroy.dtr', function () {
125
- $(window).off( 'resize.dtr orientationchange.dtr draw.dtr' );
166
+ dt.off( '.dtr' );
167
+ $( dt.table().body() ).off( '.dtr' );
168
+ $(window).off( 'resize.dtr orientationchange.dtr' );
169
+
170
+ // Restore the columns that we've hidden
171
+ $.each( that.s.current, function ( i, val ) {
172
+ if ( val === false ) {
173
+ that._setColumnVis( i, true );
174
+ }
175
+ } );
126
176
  } );
127
177
 
128
178
  // Reorder the breakpoints array here in case they have been added out
@@ -132,40 +182,41 @@ Responsive.prototype = {
132
182
  a.width > b.width ? -1 : 0;
133
183
  } );
134
184
 
135
- // Determine which columns are already hidden, and should therefore
136
- // remain hidden. todo - should this be done? See thread 22677
137
- //
138
- // this.s.alwaysHidden = dt.columns(':hidden').indexes();
139
-
140
185
  this._classLogic();
141
186
  this._resizeAuto();
142
187
 
143
188
  // Details handler
144
189
  var details = this.c.details;
145
- if ( details.type ) {
190
+ if ( details.type !== false ) {
146
191
  that._detailsInit();
147
- this._detailsVis();
148
192
 
149
- dt.on( 'column-visibility.dtr', function () {
150
- that._detailsVis();
193
+ // DataTables will trigger this event on every column it shows and
194
+ // hides individually
195
+ dt.on( 'column-visibility.dtr', function (e, ctx, col, vis) {
196
+ that._classLogic();
197
+ that._resizeAuto();
198
+ that._resize();
151
199
  } );
152
200
 
153
- // Redraw the details box on each draw. This is used until
154
- // DataTables implements a native `updated` event for rows
201
+ // Redraw the details box on each draw which will happen if the data
202
+ // has changed. This is used until DataTables implements a native
203
+ // `updated` event for rows
155
204
  dt.on( 'draw.dtr', function () {
156
- dt.rows( {page: 'current'} ).iterator( 'row', function ( settings, idx ) {
157
- var row = dt.row( idx );
158
-
159
- if ( row.child.isShown() ) {
160
- var info = that.c.details.renderer( dt, idx );
161
- row.child( info, 'child' ).show();
162
- }
163
- } );
205
+ that._redrawChildren();
164
206
  } );
165
207
 
166
208
  $(dt.table().node()).addClass( 'dtr-'+details.type );
167
209
  }
168
210
 
211
+ dt.on( 'column-reorder.dtr', function (e, settings, details) {
212
+ // This requires ColReorder 1.2.1 or newer
213
+ if ( details.drop ) {
214
+ that._classLogic();
215
+ that._resizeAuto();
216
+ that._resize();
217
+ }
218
+ } );
219
+
169
220
  // First pass - draw the table for the current viewport size
170
221
  this._resize();
171
222
  },
@@ -193,6 +244,24 @@ Responsive.prototype = {
193
244
  var columns = this.s.columns;
194
245
  var i, ien;
195
246
 
247
+ // Create an array that defines the column ordering based first on the
248
+ // column's priority, and secondly the column index. This allows the
249
+ // columns to be removed from the right if the priority matches
250
+ var order = columns
251
+ .map( function ( col, idx ) {
252
+ return {
253
+ columnIdx: idx,
254
+ priority: col.priority
255
+ };
256
+ } )
257
+ .sort( function ( a, b ) {
258
+ if ( a.priority !== b.priority ) {
259
+ return a.priority - b.priority;
260
+ }
261
+ return a.columnIdx - b.columnIdx;
262
+ } );
263
+
264
+
196
265
  // Class logic - determine which columns are in this breakpoint based
197
266
  // on the classes. If no class control (i.e. `auto`) then `-` is used
198
267
  // to indicate this to the rest of the function
@@ -234,23 +303,25 @@ Responsive.prototype = {
234
303
  }
235
304
  }
236
305
 
237
- // Allow columns to be shown (counting from the left) until we run out
238
- // of room
306
+ // Allow columns to be shown (counting by priority and then right to
307
+ // left) until we run out of room
239
308
  var empty = false;
240
- for ( i=0, ien=display.length ; i<ien ; i++ ) {
241
- if ( display[i] === '-' && ! columns[i].control ) {
309
+ for ( i=0, ien=order.length ; i<ien ; i++ ) {
310
+ var colIdx = order[i].columnIdx;
311
+
312
+ if ( display[colIdx] === '-' && ! columns[colIdx].control && columns[colIdx].minWidth ) {
242
313
  // Once we've found a column that won't fit we don't let any
243
314
  // others display either, or columns might disappear in the
244
315
  // middle of the table
245
- if ( empty || usedWidth - columns[i].minWidth < 0 ) {
316
+ if ( empty || usedWidth - columns[colIdx].minWidth < 0 ) {
246
317
  empty = true;
247
- display[i] = false;
318
+ display[colIdx] = false;
248
319
  }
249
320
  else {
250
- display[i] = true;
321
+ display[colIdx] = true;
251
322
  }
252
323
 
253
- usedWidth -= columns[i].minWidth;
324
+ usedWidth -= columns[colIdx].minWidth;
254
325
  }
255
326
  }
256
327
 
@@ -297,15 +368,25 @@ Responsive.prototype = {
297
368
  var that = this;
298
369
  var calc = {};
299
370
  var breakpoints = this.c.breakpoints;
300
- var columns = this.s.dt.columns().eq(0).map( function (i) {
301
- var className = this.column(i).header().className;
371
+ var dt = this.s.dt;
372
+ var columns = dt.columns().eq(0).map( function (i) {
373
+ var column = this.column(i);
374
+ var className = column.header().className;
375
+ var priority = dt.settings()[0].aoColumns[i].responsivePriority;
376
+
377
+ if ( priority === undefined ) {
378
+ priority = $(column.header).data('priority') !== undefined ?
379
+ $(column.header).data('priority') * 1 :
380
+ 10000;
381
+ }
302
382
 
303
383
  return {
304
384
  className: className,
305
385
  includeIn: [],
306
386
  auto: false,
307
387
  control: false,
308
- never: className.match(/\bnever\b/) ? true : false
388
+ never: className.match(/\bnever\b/) ? true : false,
389
+ priority: priority
309
390
  };
310
391
  } );
311
392
 
@@ -346,8 +427,7 @@ Responsive.prototype = {
346
427
  }
347
428
  }
348
429
  else if ( operator === 'not-' ) {
349
- // Add all but this breakpoint (xxx need extra information)
350
-
430
+ // Add all but this breakpoint
351
431
  for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) {
352
432
  if ( breakpoints[i].name.indexOf( matched ) === -1 ) {
353
433
  add( colIdx, breakpoints[i].name );
@@ -374,7 +454,7 @@ Responsive.prototype = {
374
454
  } );
375
455
  return;
376
456
  }
377
- else if ( className === 'none' || className === 'never' ) {
457
+ else if ( className === 'none' || col.never ) {
378
458
  // Include in none (default) and no auto
379
459
  hasClass = true;
380
460
  return;
@@ -418,6 +498,30 @@ Responsive.prototype = {
418
498
  },
419
499
 
420
500
 
501
+ /**
502
+ * Show the details for the child row
503
+ *
504
+ * @param {DataTables.Api} row API instance for the row
505
+ * @param {boolean} update Update flag
506
+ * @private
507
+ */
508
+ _detailsDisplay: function ( row, update )
509
+ {
510
+ var that = this;
511
+ var dt = this.s.dt;
512
+
513
+ var res = this.c.details.display( row, update, function () {
514
+ return that.c.details.renderer(
515
+ dt, row[0], that._detailsObj(row[0])
516
+ );
517
+ } );
518
+
519
+ if ( res === true || res === false ) {
520
+ $(dt.table().node()).triggerHandler( 'responsive-display.dt', [dt, row, res, update] );
521
+ }
522
+ },
523
+
524
+
421
525
  /**
422
526
  * Initialisation for the details handler
423
527
  *
@@ -434,109 +538,93 @@ Responsive.prototype = {
434
538
  details.target = 'td:first-child';
435
539
  }
436
540
 
541
+ // Keyboard accessibility
542
+ dt.on( 'draw.dtr', function () {
543
+ that._tabIndexes();
544
+ } );
545
+ that._tabIndexes(); // Initial draw has already happened
546
+
547
+ $( dt.table().body() ).on( 'keyup.dtr', 'td', function (e) {
548
+ if ( e.keyCode === 13 && $(this).data('dtr-keyboard') ) {
549
+ $(this).click();
550
+ }
551
+ } );
552
+
437
553
  // type.target can be a string jQuery selector or a column index
438
554
  var target = details.target;
439
555
  var selector = typeof target === 'string' ? target : 'td';
440
556
 
441
557
  // Click handler to show / hide the details rows when they are available
442
- $( dt.table().body() ).on( 'click', selector, function (e) {
443
- // If the table is not collapsed (i.e. there is no hidden columns)
444
- // then take no action
445
- if ( ! $(dt.table().node()).hasClass('collapsed' ) ) {
446
- return;
447
- }
558
+ $( dt.table().body() )
559
+ .on( 'mousedown.dtr', selector, function (e) {
560
+ // For mouse users, prevent the focus ring from showing
561
+ e.preventDefault();
562
+ } )
563
+ .on( 'click.dtr', selector, function () {
564
+ // If the table is not collapsed (i.e. there is no hidden columns)
565
+ // then take no action
566
+ if ( ! $(dt.table().node()).hasClass('collapsed' ) ) {
567
+ return;
568
+ }
448
569
 
449
- // Check that the row is actually a DataTable's controlled node
450
- if ( ! dt.row( $(this).closest('tr') ).length ) {
451
- return;
452
- }
570
+ // Check that the row is actually a DataTable's controlled node
571
+ if ( ! dt.row( $(this).closest('tr') ).length ) {
572
+ return;
573
+ }
453
574
 
454
- // For column index, we determine if we should act or not in the
455
- // handler - otherwise it is already okay
456
- if ( typeof target === 'number' ) {
457
- var targetIdx = target < 0 ?
458
- dt.columns().eq(0).length + target :
459
- target;
575
+ // For column index, we determine if we should act or not in the
576
+ // handler - otherwise it is already okay
577
+ if ( typeof target === 'number' ) {
578
+ var targetIdx = target < 0 ?
579
+ dt.columns().eq(0).length + target :
580
+ target;
460
581
 
461
- if ( dt.cell( this ).index().column !== targetIdx ) {
462
- return;
582
+ if ( dt.cell( this ).index().column !== targetIdx ) {
583
+ return;
584
+ }
463
585
  }
464
- }
465
586
 
466
- // $().closest() includes itself in its check
467
- var row = dt.row( $(this).closest('tr') );
587
+ // $().closest() includes itself in its check
588
+ var row = dt.row( $(this).closest('tr') );
468
589
 
469
- if ( row.child.isShown() ) {
470
- row.child( false );
471
- $( row.node() ).removeClass( 'parent' );
472
- }
473
- else {
474
- var info = that.c.details.renderer( dt, row[0] );
475
- row.child( info, 'child' ).show();
476
- $( row.node() ).addClass( 'parent' );
477
- }
478
- } );
590
+ // The renderer is given as a function so the caller can execute it
591
+ // only when they need (i.e. if hiding there is no point is running
592
+ // the renderer)
593
+ that._detailsDisplay( row, false );
594
+ } );
479
595
  },
480
596
 
481
597
 
482
598
  /**
483
- * Update the child rows in the table whenever the column visibility changes
484
- *
599
+ * Get the details to pass to a renderer for a row
600
+ * @param {int} rowIdx Row index
485
601
  * @private
486
602
  */
487
- _detailsVis: function ()
603
+ _detailsObj: function ( rowIdx )
488
604
  {
489
605
  var that = this;
490
606
  var dt = this.s.dt;
491
607
 
492
- // Find how many columns are hidden
493
- var hiddenColumns = dt.columns().indexes().filter( function ( idx ) {
494
- var col = dt.column( idx );
495
-
496
- if ( col.visible() ) {
497
- return null;
608
+ return $.map( this.s.columns, function( col, i ) {
609
+ if ( col.never ) {
610
+ return;
498
611
  }
499
612
 
500
- // Only counts as hidden if it doesn't have the `never` class
501
- return $( col.header() ).hasClass( 'never' ) ? null : idx;
613
+ return {
614
+ title: dt.settings()[0].aoColumns[ i ].sTitle,
615
+ data: dt.cell( rowIdx, i ).render( that.c.orthogonal ),
616
+ hidden: dt.column( i ).visible() && !that.s.current[ i ]
617
+ };
502
618
  } );
503
- var haveHidden = true;
504
-
505
- if ( hiddenColumns.length === 0 || ( hiddenColumns.length === 1 && this.s.columns[ hiddenColumns[0] ].control ) ) {
506
- haveHidden = false;
507
- }
508
-
509
- if ( haveHidden ) {
510
- // Show all existing child rows
511
- dt.rows( { page: 'current' } ).eq(0).each( function (idx) {
512
- var row = dt.row( idx );
513
-
514
- if ( row.child() ) {
515
- var info = that.c.details.renderer( dt, row[0] );
516
-
517
- // The renderer can return false to have no child row
518
- if ( info === false ) {
519
- row.child.hide();
520
- }
521
- else {
522
- row.child( info, 'child' ).show();
523
- }
524
- }
525
- } );
526
- }
527
- else {
528
- // Hide all existing child rows
529
- dt.rows( { page: 'current' } ).eq(0).each( function (idx) {
530
- dt.row( idx ).child.hide();
531
- } );
532
- }
533
619
  },
534
620
 
535
621
 
536
622
  /**
537
623
  * Find a breakpoint object from a name
624
+ *
538
625
  * @param {string} name Breakpoint name to find
539
626
  * @return {object} Breakpoint description object
627
+ * @private
540
628
  */
541
629
  _find: function ( name )
542
630
  {
@@ -550,6 +638,25 @@ Responsive.prototype = {
550
638
  },
551
639
 
552
640
 
641
+ /**
642
+ * Re-create the contents of the child rows as the display has changed in
643
+ * some way.
644
+ *
645
+ * @private
646
+ */
647
+ _redrawChildren: function ()
648
+ {
649
+ var that = this;
650
+ var dt = this.s.dt;
651
+
652
+ dt.rows( {page: 'current'} ).iterator( 'row', function ( settings, idx ) {
653
+ var row = dt.row( idx );
654
+
655
+ that._detailsDisplay( dt.row( idx ), true );
656
+ } );
657
+ },
658
+
659
+
553
660
  /**
554
661
  * Alter the table display for a resized viewport. This involves first
555
662
  * determining what breakpoint the window currently is in, getting the
@@ -559,12 +666,14 @@ Responsive.prototype = {
559
666
  */
560
667
  _resize: function ()
561
668
  {
669
+ var that = this;
562
670
  var dt = this.s.dt;
563
671
  var width = $(window).width();
564
672
  var breakpoints = this.c.breakpoints;
565
673
  var breakpoint = breakpoints[0].name;
566
674
  var columns = this.s.columns;
567
675
  var i, ien;
676
+ var oldVis = this.s.current.slice();
568
677
 
569
678
  // Determine what breakpoint we are currently at
570
679
  for ( i=breakpoints.length-1 ; i>=0 ; i-- ) {
@@ -576,6 +685,7 @@ Responsive.prototype = {
576
685
 
577
686
  // Show the columns for that break point
578
687
  var columnsVis = this._columnsVisiblity( breakpoint );
688
+ this.s.current = columnsVis;
579
689
 
580
690
  // Set the class before the column visibility is changed so event
581
691
  // listeners know what the state is. Need to determine if there are
@@ -588,11 +698,20 @@ Responsive.prototype = {
588
698
  }
589
699
  }
590
700
 
591
- $( dt.table().node() ).toggleClass('collapsed', collapsedClass );
701
+ $( dt.table().node() ).toggleClass( 'collapsed', collapsedClass );
702
+
703
+ var changed = false;
592
704
 
593
705
  dt.columns().eq(0).each( function ( colIdx, i ) {
594
- dt.column( colIdx ).visible( columnsVis[i] );
706
+ if ( columnsVis[i] !== oldVis[i] ) {
707
+ changed = true;
708
+ that._setColumnVis( colIdx, columnsVis[i] );
709
+ }
595
710
  } );
711
+
712
+ if ( changed ) {
713
+ this._redrawChildren();
714
+ }
596
715
  },
597
716
 
598
717
 
@@ -627,42 +746,120 @@ Responsive.prototype = {
627
746
  var clonedHeader = $( dt.table().header().cloneNode( false ) ).appendTo( clonedTable );
628
747
  var clonedBody = $( dt.table().body().cloneNode( false ) ).appendTo( clonedTable );
629
748
 
630
- $( dt.table().footer() ).clone( false ).appendTo( clonedTable );
631
-
632
- // This is a bit slow, but we need to get a clone of each row that
633
- // includes all columns. As such, try to do this as little as possible.
634
- dt.rows( { page: 'current' } ).indexes().flatten().each( function ( idx ) {
635
- var clone = dt.row( idx ).node().cloneNode( true );
636
-
637
- if ( dt.columns( ':hidden' ).flatten().length ) {
638
- $(clone).append( dt.cells( idx, ':hidden' ).nodes().to$().clone() );
639
- }
640
-
641
- $(clone).appendTo( clonedBody );
642
- } );
749
+ // Header
750
+ var headerCells = dt.columns()
751
+ .header()
752
+ .filter( function (idx) {
753
+ return dt.column(idx).visible();
754
+ } )
755
+ .to$()
756
+ .clone( false )
757
+ .css( 'display', 'table-cell' );
758
+
759
+ // Body rows - we don't need to take account of DataTables' column
760
+ // visibility since we implement our own here (hence the `display` set)
761
+ $(clonedBody)
762
+ .append( $(dt.rows( { page: 'current' } ).nodes()).clone( false ) )
763
+ .find( 'th, td' ).css( 'display', '' );
764
+
765
+ // Footer
766
+ var footer = dt.table().footer();
767
+ if ( footer ) {
768
+ var clonedFooter = $( footer.cloneNode( false ) ).appendTo( clonedTable );
769
+ var footerCells = dt.columns()
770
+ .header()
771
+ .filter( function (idx) {
772
+ return dt.column(idx).visible();
773
+ } )
774
+ .to$()
775
+ .clone( false )
776
+ .css( 'display', 'table-cell' );
777
+
778
+ $('<tr/>')
779
+ .append( footerCells )
780
+ .appendTo( clonedFooter );
781
+ }
643
782
 
644
- var cells = dt.columns().header().to$().clone( false );
645
783
  $('<tr/>')
646
- .append( cells )
784
+ .append( headerCells )
647
785
  .appendTo( clonedHeader );
648
786
 
787
+ // In the inline case extra padding is applied to the first column to
788
+ // give space for the show / hide icon. We need to use this in the
789
+ // calculation
790
+ if ( this.c.details.type === 'inline' ) {
791
+ $(clonedTable).addClass( 'dtr-inline collapsed' );
792
+ }
793
+
649
794
  var inserted = $('<div/>')
650
795
  .css( {
651
796
  width: 1,
652
797
  height: 1,
653
798
  overflow: 'hidden'
654
799
  } )
655
- .append( clonedTable )
656
- .insertBefore( dt.table().node() );
800
+ .append( clonedTable );
801
+
802
+ inserted.insertBefore( dt.table().node() );
657
803
 
658
804
  // The cloned header now contains the smallest that each column can be
659
- dt.columns().eq(0).each( function ( idx ) {
660
- columns[idx].minWidth = cells[ idx ].offsetWidth || 0;
805
+ headerCells.each( function (i) {
806
+ var idx = dt.column.index( 'fromVisible', i );
807
+ columns[ idx ].minWidth = this.offsetWidth || 0;
661
808
  } );
662
809
 
663
810
  inserted.remove();
811
+ },
812
+
813
+ /**
814
+ * Set a column's visibility.
815
+ *
816
+ * We don't use DataTables' column visibility controls in order to ensure
817
+ * that column visibility can Responsive can no-exist. Since only IE8+ is
818
+ * supported (and all evergreen browsers of course) the control of the
819
+ * display attribute works well.
820
+ *
821
+ * @param {integer} col Column index
822
+ * @param {boolean} showHide Show or hide (true or false)
823
+ * @private
824
+ */
825
+ _setColumnVis: function ( col, showHide )
826
+ {
827
+ var dt = this.s.dt;
828
+ var display = showHide ? '' : 'none'; // empty string will remove the attr
829
+
830
+ $( dt.column( col ).header() ).css( 'display', display );
831
+ $( dt.column( col ).footer() ).css( 'display', display );
832
+ dt.column( col ).nodes().to$().css( 'display', display );
833
+ },
834
+
835
+
836
+ /**
837
+ * Update the cell tab indexes for keyboard accessibility. This is called on
838
+ * every table draw - that is potentially inefficient, but also the least
839
+ * complex option given that column visibility can change on the fly. Its a
840
+ * shame user-focus was removed from CSS 3 UI, as it would have solved this
841
+ * issue with a single CSS statement.
842
+ *
843
+ * @private
844
+ */
845
+ _tabIndexes: function ()
846
+ {
847
+ var dt = this.s.dt;
848
+ var cells = dt.cells( { page: 'current' } ).nodes().to$();
849
+ var ctx = dt.settings()[0];
850
+ var target = this.c.details.target;
851
+
852
+ cells.filter( '[data-dtr-keyboard]' ).removeData( '[data-dtr-keyboard]' );
853
+
854
+ var selector = typeof target === 'number' ?
855
+ ':eq('+target+')' :
856
+ target;
857
+
858
+ $( selector, dt.rows( { page: 'current' } ).nodes() )
859
+ .attr( 'tabIndex', ctx.iTabIndex )
860
+ .data( 'dtr-keyboard', 1 );
664
861
  }
665
- };
862
+ } );
666
863
 
667
864
 
668
865
  /**
@@ -684,6 +881,110 @@ Responsive.breakpoints = [
684
881
  ];
685
882
 
686
883
 
884
+ /**
885
+ * Display methods - functions which define how the hidden data should be shown
886
+ * in the table.
887
+ *
888
+ * @namespace
889
+ * @name Responsive.defaults
890
+ * @static
891
+ */
892
+ Responsive.display = {
893
+ childRow: function ( row, update, render ) {
894
+ if ( update ) {
895
+ if ( $(row.node()).hasClass('parent') ) {
896
+ row.child( render(), 'child' ).show();
897
+
898
+ return true;
899
+ }
900
+ }
901
+ else {
902
+ if ( ! row.child.isShown() ) {
903
+ row.child( render(), 'child' ).show();
904
+ $( row.node() ).addClass( 'parent' );
905
+
906
+ return true;
907
+ }
908
+ else {
909
+ row.child( false );
910
+ $( row.node() ).removeClass( 'parent' );
911
+
912
+ return false;
913
+ }
914
+ }
915
+ },
916
+
917
+ childRowImmediate: function ( row, update, render ) {
918
+ if ( (! update && row.child.isShown()) || ! row.responsive.hasHidden() ) {
919
+ // User interaction and the row is show, or nothing to show
920
+ row.child( false );
921
+ $( row.node() ).removeClass( 'parent' );
922
+
923
+ return false;
924
+ }
925
+ else {
926
+ // Display
927
+ row.child( render(), 'child' ).show();
928
+ $( row.node() ).addClass( 'parent' );
929
+
930
+ return true;
931
+ }
932
+ },
933
+
934
+ // This is a wrapper so the modal options for Bootstrap and jQuery UI can
935
+ // have options passed into them. This specific one doesn't need to be a
936
+ // function but it is for consistency in the `modal` name
937
+ modal: function ( options ) {
938
+ return function ( row, update, render ) {
939
+ if ( ! update ) {
940
+ // Show a modal
941
+ var close = function () {
942
+ modal.remove(); // will tidy events for us
943
+ $(document).off( 'keypress.dtr' );
944
+ };
945
+
946
+ var modal = $('<div class="dtr-modal"/>')
947
+ .append( $('<div class="dtr-modal-display"/>')
948
+ .append( $('<div class="dtr-modal-content"/>')
949
+ .append( render() )
950
+ )
951
+ .append( $('<div class="dtr-modal-close">&times;</div>' )
952
+ .click( function () {
953
+ close();
954
+ } )
955
+ )
956
+ )
957
+ .append( $('<div class="dtr-modal-background"/>')
958
+ .click( function () {
959
+ close();
960
+ } )
961
+ )
962
+ .appendTo( 'body' );
963
+
964
+ if ( options && options.header ) {
965
+ modal.find( 'div.dtr-modal-content' ).prepend(
966
+ '<h2>'+options.header( row )+'</h2>'
967
+ );
968
+ }
969
+
970
+ $(document).on( 'keyup.dtr', function (e) {
971
+ if ( e.keyCode === 27 ) {
972
+ e.stopPropagation();
973
+
974
+ close();
975
+ }
976
+ } );
977
+ }
978
+ else {
979
+ $('div.dtr-modal-content')
980
+ .empty()
981
+ .append( render() );
982
+ }
983
+ };
984
+ }
985
+ };
986
+
987
+
687
988
  /**
688
989
  * Responsive default settings for initialisation
689
990
  *
@@ -719,6 +1020,7 @@ Responsive.defaults = {
719
1020
  *
720
1021
  * The object consists of the following properties:
721
1022
  *
1023
+ * * `display` - A function that is used to show and hide the hidden details
722
1024
  * * `renderer` - function that is called for display of the child row data.
723
1025
  * The default function will show the data from the hidden columns
724
1026
  * * `target` - Used as the selector for what objects to attach the child
@@ -729,36 +1031,21 @@ Responsive.defaults = {
729
1031
  * @type {Object|string}
730
1032
  */
731
1033
  details: {
732
- renderer: function ( api, rowIdx ) {
733
- var data = api.cells( rowIdx, ':hidden' ).eq(0).map( function ( cell ) {
734
- var header = $( api.column( cell.column ).header() );
735
- var idx = api.cell( cell ).index();
1034
+ display: Responsive.display.childRow,
736
1035
 
737
- if ( header.hasClass( 'control' ) || header.hasClass( 'never' ) ) {
738
- return '';
739
- }
740
-
741
- // Use a non-public DT API method to render the data for display
742
- // This needs to be updated when DT adds a suitable method for
743
- // this type of data retrieval
744
- var dtPrivate = api.settings()[0];
745
- var cellData = dtPrivate.oApi._fnGetCellData(
746
- dtPrivate, idx.row, idx.column, 'display'
747
- );
748
- var title = header.text();
749
- if ( title ) {
750
- title = title + ':';
751
- }
752
-
753
- return '<li data-dtr-index="'+idx.column+'">'+
1036
+ renderer: function ( api, rowIdx, columns ) {
1037
+ var data = $.map( columns, function ( col, i ) {
1038
+ return col.hidden ?
1039
+ '<li data-dtr-index="'+i+'">'+
754
1040
  '<span class="dtr-title">'+
755
- title+
1041
+ col.title+
756
1042
  '</span> '+
757
1043
  '<span class="dtr-data">'+
758
- cellData+
1044
+ col.data+
759
1045
  '</span>'+
760
- '</li>';
761
- } ).toArray().join('');
1046
+ '</li>' :
1047
+ '';
1048
+ } ).join('');
762
1049
 
763
1050
  return data ?
764
1051
  $('<ul data-dtr-index="'+rowIdx+'"/>').append( data ) :
@@ -768,7 +1055,15 @@ Responsive.defaults = {
768
1055
  target: 0,
769
1056
 
770
1057
  type: 'inline'
771
- }
1058
+ },
1059
+
1060
+ /**
1061
+ * Orthogonal data request option. This is used to define the data type
1062
+ * requested when Responsive gets the data to show in the child row.
1063
+ *
1064
+ * @type {String}
1065
+ */
1066
+ orthogonal: 'display'
772
1067
  };
773
1068
 
774
1069
 
@@ -808,6 +1103,14 @@ Api.register( 'responsive.recalc()', function () {
808
1103
  } );
809
1104
  } );
810
1105
 
1106
+ Api.register( 'responsive.hasHidden()', function () {
1107
+ var ctx = this.context[0];
1108
+
1109
+ return ctx._responsive ?
1110
+ $.inArray( false, ctx._responsive.s.current ) !== -1 :
1111
+ false;
1112
+ } );
1113
+
811
1114
 
812
1115
  /**
813
1116
  * Version information
@@ -815,7 +1118,7 @@ Api.register( 'responsive.recalc()', function () {
815
1118
  * @name Responsive.version
816
1119
  * @static
817
1120
  */
818
- Responsive.version = '1.0.5';
1121
+ Responsive.version = '2.0.0';
819
1122
 
820
1123
 
821
1124
  $.fn.dataTable.Responsive = Responsive;
@@ -833,8 +1136,6 @@ $(document).on( 'init.dt.dtr', function (e, settings, json) {
833
1136
  settings.oInit.responsive ||
834
1137
  DataTable.defaults.responsive
835
1138
  ) {
836
- console.log( e.namespace );
837
-
838
1139
  var init = settings.oInit.responsive;
839
1140
 
840
1141
  if ( init !== false ) {
@@ -843,22 +1144,6 @@ $(document).on( 'init.dt.dtr', function (e, settings, json) {
843
1144
  }
844
1145
  } );
845
1146
 
846
- return Responsive;
847
- }; // /factory
848
-
849
1147
 
850
- // Define as an AMD module if possible
851
- if ( typeof define === 'function' && define.amd ) {
852
- define( ['jquery', 'datatables'], factory );
853
- }
854
- else if ( typeof exports === 'object' ) {
855
- // Node/CommonJS
856
- factory( require('jquery'), require('datatables') );
857
- }
858
- else if ( jQuery && !jQuery.fn.dataTable.Responsive ) {
859
- // Otherwise simply initialise as normal, stopping multiple evaluation
860
- factory( jQuery, jQuery.fn.dataTable );
861
- }
862
-
863
-
864
- })(window, document);
1148
+ return Responsive;
1149
+ }));