datatables.net-select 1.6.2 → 2.0.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.
@@ -1,4 +1,4 @@
1
- /*! Select for DataTables 1.6.2
1
+ /*! Select for DataTables 2.0.0
2
2
  * © SpryMedia Ltd - datatables.net/license/mit
3
3
  */
4
4
 
@@ -18,7 +18,7 @@
18
18
  }
19
19
  };
20
20
 
21
- if (typeof window !== 'undefined') {
21
+ if (typeof window === 'undefined') {
22
22
  module.exports = function (root, $) {
23
23
  if ( ! root ) {
24
24
  // CommonJS environments without a window global must pass a
@@ -43,7 +43,7 @@
43
43
  // Browser
44
44
  factory( jQuery, window, document );
45
45
  }
46
- }(function( $, window, document, undefined ) {
46
+ }(function( $, window, document ) {
47
47
  'use strict';
48
48
  var DataTable = $.fn.dataTable;
49
49
 
@@ -52,69 +52,70 @@ var DataTable = $.fn.dataTable;
52
52
  // Version information for debugger
53
53
  DataTable.select = {};
54
54
 
55
- DataTable.select.version = '1.6.2';
55
+ DataTable.select.version = '2.0.0';
56
56
 
57
- DataTable.select.init = function ( dt ) {
57
+ DataTable.select.init = function (dt) {
58
58
  var ctx = dt.settings()[0];
59
59
 
60
+ if (!DataTable.versionCheck('2')) {
61
+ throw 'Warning: Select requires DataTables 2 or newer';
62
+ }
63
+
60
64
  if (ctx._select) {
61
65
  return;
62
66
  }
63
67
 
64
68
  var savedSelected = dt.state.loaded();
65
69
 
66
- var selectAndSave = function(e, settings, data) {
67
- if(data === null || data.select === undefined) {
70
+ var selectAndSave = function (e, settings, data) {
71
+ if (data === null || data.select === undefined) {
68
72
  return;
69
73
  }
70
74
 
71
75
  // Clear any currently selected rows, before restoring state
72
76
  // None will be selected on first initialisation
73
- if (dt.rows({selected: true}).any()) {
77
+ if (dt.rows({ selected: true }).any()) {
74
78
  dt.rows().deselect();
75
79
  }
76
80
  if (data.select.rows !== undefined) {
77
81
  dt.rows(data.select.rows).select();
78
82
  }
79
83
 
80
- if (dt.columns({selected: true}).any()) {
84
+ if (dt.columns({ selected: true }).any()) {
81
85
  dt.columns().deselect();
82
86
  }
83
87
  if (data.select.columns !== undefined) {
84
88
  dt.columns(data.select.columns).select();
85
89
  }
86
90
 
87
- if (dt.cells({selected: true}).any()) {
91
+ if (dt.cells({ selected: true }).any()) {
88
92
  dt.cells().deselect();
89
93
  }
90
94
  if (data.select.cells !== undefined) {
91
- for(var i = 0; i < data.select.cells.length; i++) {
95
+ for (var i = 0; i < data.select.cells.length; i++) {
92
96
  dt.cell(data.select.cells[i].row, data.select.cells[i].column).select();
93
97
  }
94
98
  }
95
99
 
96
100
  dt.state.save();
97
- }
98
-
99
- dt
100
- .on('stateSaveParams', function(e, settings, data) {
101
- data.select = {};
102
- data.select.rows = dt.rows({selected:true}).ids(true).toArray();
103
- data.select.columns = dt.columns({selected:true})[0];
104
- data.select.cells = dt.cells({selected:true})[0].map(function(coords) {
105
- return {row: dt.row(coords.row).id(true), column: coords.column}
106
- });
107
- })
101
+ };
102
+
103
+ dt.on('stateSaveParams', function (e, settings, data) {
104
+ data.select = {};
105
+ data.select.rows = dt.rows({ selected: true }).ids(true).toArray();
106
+ data.select.columns = dt.columns({ selected: true })[0];
107
+ data.select.cells = dt.cells({ selected: true })[0].map(function (coords) {
108
+ return { row: dt.row(coords.row).id(true), column: coords.column };
109
+ });
110
+ })
108
111
  .on('stateLoadParams', selectAndSave)
109
- .one('init', function() {
112
+ .one('init', function () {
110
113
  selectAndSave(undefined, undefined, savedSelected);
111
114
  });
112
115
 
113
116
  var init = ctx.oInit.select;
114
117
  var defaults = DataTable.defaults.select;
115
- var opts = init === undefined ?
116
- defaults :
117
- init;
118
+ var opts = init === undefined ? defaults : init;
118
119
 
119
120
  // Set defaults
120
121
  var items = 'row';
@@ -124,37 +125,40 @@ DataTable.select.init = function ( dt ) {
124
125
  var info = true;
125
126
  var selector = 'td, th';
126
127
  var className = 'selected';
128
+ var headerCheckbox = true;
127
129
  var setStyle = false;
128
130
 
129
- ctx._select = {};
131
+ ctx._select = {
132
+ infoEls: []
133
+ };
130
134
 
131
135
  // Initialisation customisations
132
- if ( opts === true ) {
136
+ if (opts === true) {
133
137
  style = 'os';
134
138
  setStyle = true;
135
139
  }
136
- else if ( typeof opts === 'string' ) {
140
+ else if (typeof opts === 'string') {
137
141
  style = opts;
138
142
  setStyle = true;
139
143
  }
140
- else if ( $.isPlainObject( opts ) ) {
141
- if ( opts.blurable !== undefined ) {
144
+ else if ($.isPlainObject(opts)) {
145
+ if (opts.blurable !== undefined) {
142
146
  blurable = opts.blurable;
143
147
  }
144
-
145
- if ( opts.toggleable !== undefined ) {
148
+
149
+ if (opts.toggleable !== undefined) {
146
150
  toggleable = opts.toggleable;
147
151
  }
148
152
 
149
- if ( opts.info !== undefined ) {
153
+ if (opts.info !== undefined) {
150
154
  info = opts.info;
151
155
  }
152
156
 
153
- if ( opts.items !== undefined ) {
157
+ if (opts.items !== undefined) {
154
158
  items = opts.items;
155
159
  }
156
160
 
157
- if ( opts.style !== undefined ) {
161
+ if (opts.style !== undefined) {
158
162
  style = opts.style;
159
163
  setStyle = true;
160
164
  }
@@ -163,40 +167,41 @@ DataTable.select.init = function ( dt ) {
163
167
  setStyle = true;
164
168
  }
165
169
 
166
- if ( opts.selector !== undefined ) {
170
+ if (opts.selector !== undefined) {
167
171
  selector = opts.selector;
168
172
  }
169
173
 
170
- if ( opts.className !== undefined ) {
174
+ if (opts.className !== undefined) {
171
175
  className = opts.className;
172
176
  }
177
+
178
+ if (opts.headerCheckbox !== undefined) {
179
+ headerCheckbox = opts.headerCheckbox;
180
+ }
173
181
  }
174
182
 
175
- dt.select.selector( selector );
176
- dt.select.items( items );
177
- dt.select.style( style );
178
- dt.select.blurable( blurable );
179
- dt.select.toggleable( toggleable );
180
- dt.select.info( info );
183
+ dt.select.selector(selector);
184
+ dt.select.items(items);
185
+ dt.select.style(style);
186
+ dt.select.blurable(blurable);
187
+ dt.select.toggleable(toggleable);
188
+ dt.select.info(info);
181
189
  ctx._select.className = className;
182
190
 
183
-
184
- // Sort table based on selected rows. Requires Select Datatables extension
185
- $.fn.dataTable.ext.order['select-checkbox'] = function ( settings, col ) {
186
- return this.api().column( col, {order: 'index'} ).nodes().map( function ( td ) {
187
- if ( settings._select.items === 'row' ) {
188
- return $( td ).parent().hasClass( settings._select.className );
189
- } else if ( settings._select.items === 'cell' ) {
190
- return $( td ).hasClass( settings._select.className );
191
- }
192
- return false;
193
- });
194
- };
195
-
196
191
  // If the init options haven't enabled select, but there is a selectable
197
192
  // class name, then enable
198
- if ( ! setStyle && $( dt.table().node() ).hasClass( 'selectable' ) ) {
199
- dt.select.style( 'os' );
193
+ if (!setStyle && $(dt.table().node()).hasClass('selectable')) {
194
+ dt.select.style('os');
195
+ }
196
+
197
+ // Insert a checkbox into the header if needed - might need to wait
198
+ // for init complete, or it might already be done
199
+ if (headerCheckbox) {
200
+ initCheckboxHeader(dt);
201
+
202
+ dt.on('init', function () {
203
+ initCheckboxHeader(dt);
204
+ });
200
205
  }
201
206
  };
202
207
 
@@ -249,6 +254,7 @@ The `_select` object contains the following properties:
249
254
  on the row
250
255
  info:boolean - If the selection summary should be shown in the table
251
256
  information elements
257
+ infoEls:element[] - List of HTML elements with info elements for a table
252
258
  }
253
259
  ```
254
260
 
@@ -264,7 +270,6 @@ handler that will select the items using the API methods.
264
270
 
265
271
  */
266
272
 
267
-
268
273
  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
269
274
  * Local functions
270
275
  */
@@ -277,84 +282,87 @@ handler that will select the items using the API methods.
277
282
  * in the visible grid rather than by index in sequence. For example, if you
278
283
  * click first in cell 1-1 and then shift click in 2-2 - cells 1-2 and 2-1
279
284
  * should also be selected (and not 1-3, 1-4. etc)
280
- *
285
+ *
281
286
  * @param {DataTable.Api} dt DataTable
282
287
  * @param {object} idx Cell index to select to
283
288
  * @param {object} last Cell index to select from
284
289
  * @private
285
290
  */
286
- function cellRange( dt, idx, last )
287
- {
291
+ function cellRange(dt, idx, last) {
288
292
  var indexes;
289
293
  var columnIndexes;
290
294
  var rowIndexes;
291
- var selectColumns = function ( start, end ) {
292
- if ( start > end ) {
295
+ var selectColumns = function (start, end) {
296
+ if (start > end) {
293
297
  var tmp = end;
294
298
  end = start;
295
299
  start = tmp;
296
300
  }
297
-
301
+
298
302
  var record = false;
299
- return dt.columns( ':visible' ).indexes().filter( function (i) {
300
- if ( i === start ) {
301
- record = true;
302
- }
303
-
304
- if ( i === end ) { // not else if, as start might === end
305
- record = false;
306
- return true;
307
- }
303
+ return dt
304
+ .columns(':visible')
305
+ .indexes()
306
+ .filter(function (i) {
307
+ if (i === start) {
308
+ record = true;
309
+ }
308
310
 
309
- return record;
310
- } );
311
+ if (i === end) {
312
+ // not else if, as start might === end
313
+ record = false;
314
+ return true;
315
+ }
316
+
317
+ return record;
318
+ });
311
319
  };
312
320
 
313
- var selectRows = function ( start, end ) {
314
- var indexes = dt.rows( { search: 'applied' } ).indexes();
321
+ var selectRows = function (start, end) {
322
+ var indexes = dt.rows({ search: 'applied' }).indexes();
315
323
 
316
324
  // Which comes first - might need to swap
317
- if ( indexes.indexOf( start ) > indexes.indexOf( end ) ) {
325
+ if (indexes.indexOf(start) > indexes.indexOf(end)) {
318
326
  var tmp = end;
319
327
  end = start;
320
328
  start = tmp;
321
329
  }
322
330
 
323
331
  var record = false;
324
- return indexes.filter( function (i) {
325
- if ( i === start ) {
332
+ return indexes.filter(function (i) {
333
+ if (i === start) {
326
334
  record = true;
327
335
  }
328
-
329
- if ( i === end ) {
336
+
337
+ if (i === end) {
330
338
  record = false;
331
339
  return true;
332
340
  }
333
341
 
334
342
  return record;
335
- } );
343
+ });
336
344
  };
337
345
 
338
- if ( ! dt.cells( { selected: true } ).any() && ! last ) {
346
+ if (!dt.cells({ selected: true }).any() && !last) {
339
347
  // select from the top left cell to this one
340
- columnIndexes = selectColumns( 0, idx.column );
341
- rowIndexes = selectRows( 0 , idx.row );
348
+ columnIndexes = selectColumns(0, idx.column);
349
+ rowIndexes = selectRows(0, idx.row);
342
350
  }
343
351
  else {
344
352
  // Get column indexes between old and new
345
- columnIndexes = selectColumns( last.column, idx.column );
346
- rowIndexes = selectRows( last.row , idx.row );
353
+ columnIndexes = selectColumns(last.column, idx.column);
354
+ rowIndexes = selectRows(last.row, idx.row);
347
355
  }
348
356
 
349
- indexes = dt.cells( rowIndexes, columnIndexes ).flatten();
357
+ indexes = dt.cells(rowIndexes, columnIndexes).flatten();
350
358
 
351
- if ( ! dt.cells( idx, { selected: true } ).any() ) {
359
+ if (!dt.cells(idx, { selected: true }).any()) {
352
360
  // Select range
353
- dt.cells( indexes ).select();
361
+ dt.cells(indexes).select();
354
362
  }
355
363
  else {
356
364
  // Deselect range
357
- dt.cells( indexes ).deselect();
365
+ dt.cells(indexes).deselect();
358
366
  }
359
367
  }
360
368
 
@@ -364,17 +372,16 @@ function cellRange( dt, idx, last )
364
372
  * @param {DataTable.Api} dt DataTable to remove events from
365
373
  * @private
366
374
  */
367
- function disableMouseSelection( dt )
368
- {
375
+ function disableMouseSelection(dt) {
369
376
  var ctx = dt.settings()[0];
370
377
  var selector = ctx._select.selector;
371
378
 
372
- $( dt.table().container() )
373
- .off( 'mousedown.dtSelect', selector )
374
- .off( 'mouseup.dtSelect', selector )
375
- .off( 'click.dtSelect', selector );
379
+ $(dt.table().container())
380
+ .off('mousedown.dtSelect', selector)
381
+ .off('mouseup.dtSelect', selector)
382
+ .off('click.dtSelect', selector);
376
383
 
377
- $('body').off( 'click.dtSelect' + _safeId(dt.table().node()) );
384
+ $('body').off('click.dtSelect' + _safeId(dt.table().node()));
378
385
  }
379
386
 
380
387
  /**
@@ -383,121 +390,123 @@ function disableMouseSelection( dt )
383
390
  * @param {DataTable.Api} dt DataTable to remove events from
384
391
  * @private
385
392
  */
386
- function enableMouseSelection ( dt )
387
- {
388
- var container = $( dt.table().container() );
393
+ function enableMouseSelection(dt) {
394
+ var container = $(dt.table().container());
389
395
  var ctx = dt.settings()[0];
390
396
  var selector = ctx._select.selector;
391
397
  var matchSelection;
392
398
 
393
399
  container
394
- .on( 'mousedown.dtSelect', selector, function(e) {
400
+ .on('mousedown.dtSelect', selector, function (e) {
395
401
  // Disallow text selection for shift clicking on the table so multi
396
402
  // element selection doesn't look terrible!
397
- if ( e.shiftKey || e.metaKey || e.ctrlKey ) {
403
+ if (e.shiftKey || e.metaKey || e.ctrlKey) {
398
404
  container
399
- .css( '-moz-user-select', 'none' )
405
+ .css('-moz-user-select', 'none')
400
406
  .one('selectstart.dtSelect', selector, function () {
401
407
  return false;
402
- } );
408
+ });
403
409
  }
404
410
 
405
- if ( window.getSelection ) {
411
+ if (window.getSelection) {
406
412
  matchSelection = window.getSelection();
407
413
  }
408
- } )
409
- .on( 'mouseup.dtSelect', selector, function() {
414
+ })
415
+ .on('mouseup.dtSelect', selector, function () {
410
416
  // Allow text selection to occur again, Mozilla style (tested in FF
411
417
  // 35.0.1 - still required)
412
- container.css( '-moz-user-select', '' );
413
- } )
414
- .on( 'click.dtSelect', selector, function ( e ) {
418
+ container.css('-moz-user-select', '');
419
+ })
420
+ .on('click.dtSelect', selector, function (e) {
415
421
  var items = dt.select.items();
416
422
  var idx;
417
423
 
418
424
  // If text was selected (click and drag), then we shouldn't change
419
425
  // the row's selected state
420
- if ( matchSelection ) {
426
+ if (matchSelection) {
421
427
  var selection = window.getSelection();
422
428
 
423
429
  // If the element that contains the selection is not in the table, we can ignore it
424
430
  // This can happen if the developer selects text from the click event
425
- if ( ! selection.anchorNode || $(selection.anchorNode).closest('table')[0] === dt.table().node() ) {
426
- if ( selection !== matchSelection ) {
431
+ if (
432
+ !selection.anchorNode ||
433
+ $(selection.anchorNode).closest('table')[0] === dt.table().node()
434
+ ) {
435
+ if (selection !== matchSelection) {
427
436
  return;
428
437
  }
429
438
  }
430
439
  }
431
440
 
432
441
  var ctx = dt.settings()[0];
433
- var wrapperClass = dt.settings()[0].oClasses.sWrapper.trim().replace(/ +/g, '.');
442
+ var container = dt.table().container();
434
443
 
435
444
  // Ignore clicks inside a sub-table
436
- if ( $(e.target).closest('div.'+wrapperClass)[0] != dt.table().container() ) {
445
+ if ($(e.target).closest('div.dt-container')[0] != container) {
437
446
  return;
438
447
  }
439
448
 
440
- var cell = dt.cell( $(e.target).closest('td, th') );
449
+ var cell = dt.cell($(e.target).closest('td, th'));
441
450
 
442
451
  // Check the cell actually belongs to the host DataTable (so child
443
452
  // rows, etc, are ignored)
444
- if ( ! cell.any() ) {
453
+ if (!cell.any()) {
445
454
  return;
446
455
  }
447
456
 
448
457
  var event = $.Event('user-select.dt');
449
- eventTrigger( dt, event, [ items, cell, e ] );
458
+ eventTrigger(dt, event, [items, cell, e]);
450
459
 
451
- if ( event.isDefaultPrevented() ) {
460
+ if (event.isDefaultPrevented()) {
452
461
  return;
453
462
  }
454
463
 
455
464
  var cellIndex = cell.index();
456
- if ( items === 'row' ) {
465
+ if (items === 'row') {
457
466
  idx = cellIndex.row;
458
- typeSelect( e, dt, ctx, 'row', idx );
467
+ typeSelect(e, dt, ctx, 'row', idx);
459
468
  }
460
- else if ( items === 'column' ) {
469
+ else if (items === 'column') {
461
470
  idx = cell.index().column;
462
- typeSelect( e, dt, ctx, 'column', idx );
471
+ typeSelect(e, dt, ctx, 'column', idx);
463
472
  }
464
- else if ( items === 'cell' ) {
473
+ else if (items === 'cell') {
465
474
  idx = cell.index();
466
- typeSelect( e, dt, ctx, 'cell', idx );
475
+ typeSelect(e, dt, ctx, 'cell', idx);
467
476
  }
468
477
 
469
478
  ctx._select_lastCell = cellIndex;
470
- } );
479
+ });
471
480
 
472
481
  // Blurable
473
- $('body').on( 'click.dtSelect' + _safeId(dt.table().node()), function ( e ) {
474
- if ( ctx._select.blurable ) {
482
+ $('body').on('click.dtSelect' + _safeId(dt.table().node()), function (e) {
483
+ if (ctx._select.blurable) {
475
484
  // If the click was inside the DataTables container, don't blur
476
- if ( $(e.target).parents().filter( dt.table().container() ).length ) {
485
+ if ($(e.target).parents().filter(dt.table().container()).length) {
477
486
  return;
478
487
  }
479
488
 
480
489
  // Ignore elements which have been removed from the DOM (i.e. paging
481
490
  // buttons)
482
- if ( $(e.target).parents('html').length === 0 ) {
483
- return;
491
+ if ($(e.target).parents('html').length === 0) {
492
+ return;
484
493
  }
485
494
 
486
495
  // Don't blur in Editor form
487
- if ( $(e.target).parents('div.DTE').length ) {
496
+ if ($(e.target).parents('div.DTE').length) {
488
497
  return;
489
498
  }
490
499
 
491
500
  var event = $.Event('select-blur.dt');
492
- eventTrigger( dt, event, [ e.target, e ] );
501
+ eventTrigger(dt, event, [e.target, e]);
493
502
 
494
- if ( event.isDefaultPrevented() ) {
503
+ if (event.isDefaultPrevented()) {
495
504
  return;
496
505
  }
497
506
 
498
- clear( ctx, true );
507
+ clear(ctx, true);
499
508
  }
500
- } );
509
+ });
501
510
  }
502
511
 
503
512
  /**
@@ -510,70 +519,125 @@ function enableMouseSelection ( dt )
510
519
  * triggering
511
520
  * @private
512
521
  */
513
- function eventTrigger ( api, type, args, any )
514
- {
515
- if ( any && ! api.flatten().length ) {
522
+ function eventTrigger(api, type, args, any) {
523
+ if (any && !api.flatten().length) {
516
524
  return;
517
525
  }
518
526
 
519
- if ( typeof type === 'string' ) {
520
- type = type +'.dt';
527
+ if (typeof type === 'string') {
528
+ type = type + '.dt';
521
529
  }
522
530
 
523
- args.unshift( api );
531
+ args.unshift(api);
524
532
 
525
- $(api.table().node()).trigger( type, args );
533
+ $(api.table().node()).trigger(type, args);
526
534
  }
527
535
 
528
536
  /**
529
537
  * Update the information element of the DataTable showing information about the
530
538
  * items selected. This is done by adding tags to the existing text
531
- *
539
+ *
532
540
  * @param {DataTable.Api} api DataTable to update
533
541
  * @private
534
542
  */
535
- function info ( api )
536
- {
537
- var ctx = api.settings()[0];
538
-
539
- if ( ! ctx._select.info || ! ctx.aanFeatures.i ) {
543
+ function info(api, node) {
544
+ if (api.select.style() === 'api' || api.select.info() === false) {
540
545
  return;
541
546
  }
542
547
 
543
- if ( api.select.style() === 'api' ) {
544
- return;
545
- }
548
+ var rows = api.rows({ selected: true }).flatten().length;
549
+ var columns = api.columns({ selected: true }).flatten().length;
550
+ var cells = api.cells({ selected: true }).flatten().length;
551
+
552
+ var add = function (el, name, num) {
553
+ el.append(
554
+ $('<span class="select-item"/>').append(
555
+ api.i18n(
556
+ 'select.' + name + 's',
557
+ { _: '%d ' + name + 's selected', 0: '', 1: '1 ' + name + ' selected' },
558
+ num
559
+ )
560
+ )
561
+ );
562
+ };
546
563
 
547
- var rows = api.rows( { selected: true } ).flatten().length;
548
- var columns = api.columns( { selected: true } ).flatten().length;
549
- var cells = api.cells( { selected: true } ).flatten().length;
564
+ var el = $(node);
565
+ var output = $('<span class="select-info"/>');
550
566
 
551
- var add = function ( el, name, num ) {
552
- el.append( $('<span class="select-item"/>').append( api.i18n(
553
- 'select.'+name+'s',
554
- { _: '%d '+name+'s selected', 0: '', 1: '1 '+name+' selected' },
555
- num
556
- ) ) );
557
- };
567
+ add(output, 'row', rows);
568
+ add(output, 'column', columns);
569
+ add(output, 'cell', cells);
558
570
 
559
- // Internal knowledge of DataTables to loop over all information elements
560
- $.each( ctx.aanFeatures.i, function ( i, el ) {
561
- el = $(el);
571
+ var existing = el.children('span.select-info');
562
572
 
563
- var output = $('<span class="select-info"/>');
564
- add( output, 'row', rows );
565
- add( output, 'column', columns );
566
- add( output, 'cell', cells );
573
+ if (existing.length) {
574
+ existing.remove();
575
+ }
567
576
 
568
- var exisiting = el.children('span.select-info');
569
- if ( exisiting.length ) {
570
- exisiting.remove();
571
- }
577
+ if (output.text() !== '') {
578
+ el.append(output);
579
+ }
580
+ }
572
581
 
573
- if ( output.text() !== '' ) {
574
- el.append( output );
582
+ /**
583
+ * Add a checkbox to the header for checkbox columns, allowing all rows to
584
+ * be selected, deselected or just to show the state.
585
+ *
586
+ * @param {*} dt API
587
+ */
588
+ function initCheckboxHeader( dt ) {
589
+ // Find any checkbox column(s)
590
+ dt.columns('.dt-select').every(function () {
591
+ var header = this.header();
592
+
593
+ if (! $('input', header).length) {
594
+ // If no checkbox yet, insert one
595
+ var input = $('<input>')
596
+ .attr({
597
+ class: 'dt-select-checkbox',
598
+ type: 'checkbox',
599
+ 'aria-label': dt.i18n('select.aria.headerCheckbox') || 'Select all rows'
600
+ })
601
+ .appendTo(header)
602
+ .on('change', function () {
603
+ if (this.checked) {
604
+ dt.rows({search: 'applied'}).select();
605
+ }
606
+ else {
607
+ dt.rows({selected: true}).deselect();
608
+ }
609
+ })
610
+ .on('click', function (e) {
611
+ e.stopPropagation();
612
+ });
613
+
614
+ // Update the header checkbox's state when the selection in the
615
+ // table changes
616
+ dt.on('draw select deselect', function (e, pass, type) {
617
+ if (type === 'row' || ! type) {
618
+ var count = dt.rows({selected: true}).count();
619
+ var search = dt.rows({search: 'applied', selected: true}).count();
620
+ var available = dt.rows({search: 'applied'}).count();
621
+
622
+ if (search && search <= count && search === available) {
623
+ input
624
+ .prop('checked', true)
625
+ .prop('indeterminate', false);
626
+ }
627
+ else if (search === 0 && count === 0) {
628
+ input
629
+ .prop('checked', false)
630
+ .prop('indeterminate', false);
631
+ }
632
+ else {
633
+ input
634
+ .prop('checked', false)
635
+ .prop('indeterminate', true);
636
+ }
637
+ }
638
+ });
575
639
  }
576
- } );
640
+ });
577
641
  }
578
642
 
579
643
  /**
@@ -586,41 +650,42 @@ function info ( api )
586
650
  * @param {DataTable.settings} ctx Settings object to operate on
587
651
  * @private
588
652
  */
589
- function init ( ctx ) {
590
- var api = new DataTable.Api( ctx );
653
+ function init(ctx) {
654
+ var api = new DataTable.Api(ctx);
591
655
  ctx._select_init = true;
592
656
 
593
657
  // Row callback so that classes can be added to rows and cells if the item
594
658
  // was selected before the element was created. This will happen with the
595
659
  // `deferRender` option enabled.
596
- //
660
+ //
597
661
  // This method of attaching to `aoRowCreatedCallback` is a hack until
598
662
  // DataTables has proper events for row manipulation If you are reviewing
599
663
  // this code to create your own plug-ins, please do not do this!
600
- ctx.aoRowCreatedCallback.push( {
601
- fn: function ( row, data, index ) {
664
+ ctx.aoRowCreatedCallback.push(function (row, data, index) {
602
665
  var i, ien;
603
- var d = ctx.aoData[ index ];
666
+ var d = ctx.aoData[index];
604
667
 
605
668
  // Row
606
- if ( d._select_selected ) {
607
- $( row ).addClass( ctx._select.className );
669
+ if (d._select_selected) {
670
+ $(row).addClass(ctx._select.className);
608
671
  }
609
672
 
610
673
  // Cells and columns - if separated out, we would need to do two
611
674
  // loops, so it makes sense to combine them into a single one
612
- for ( i=0, ien=ctx.aoColumns.length ; i<ien ; i++ ) {
613
- if ( ctx.aoColumns[i]._select_selected || (d._selected_cells && d._selected_cells[i]) ) {
614
- $(d.anCells[i]).addClass( ctx._select.className );
675
+ for (i = 0, ien = ctx.aoColumns.length; i < ien; i++) {
676
+ if (
677
+ ctx.aoColumns[i]._select_selected ||
678
+ (d._selected_cells && d._selected_cells[i])
679
+ ) {
680
+ $(d.anCells[i]).addClass(ctx._select.className);
615
681
  }
616
682
  }
617
- },
618
- sName: 'select-deferRender'
619
- } );
683
+ }
684
+ );
620
685
 
621
686
  // On Ajax reload we want to reselect all rows which are currently selected,
622
687
  // if there is an rowId (i.e. a unique value to identify each row with)
623
- api.on( 'preXhr.dt.dtSelect', function (e, settings) {
688
+ api.on('preXhr.dt.dtSelect', function (e, settings) {
624
689
  if (settings !== api.settings()[0]) {
625
690
  // Not triggered by our DataTable!
626
691
  return;
@@ -628,47 +693,64 @@ function init ( ctx ) {
628
693
 
629
694
  // note that column selection doesn't need to be cached and then
630
695
  // reselected, as they are already selected
631
- var rows = api.rows( { selected: true } ).ids( true ).filter( function ( d ) {
632
- return d !== undefined;
633
- } );
696
+ var rows = api
697
+ .rows({ selected: true })
698
+ .ids(true)
699
+ .filter(function (d) {
700
+ return d !== undefined;
701
+ });
634
702
 
635
- var cells = api.cells( { selected: true } ).eq(0).map( function ( cellIdx ) {
636
- var id = api.row( cellIdx.row ).id( true );
637
- return id ?
638
- { row: id, column: cellIdx.column } :
639
- undefined;
640
- } ).filter( function ( d ) {
641
- return d !== undefined;
642
- } );
703
+ var cells = api
704
+ .cells({ selected: true })
705
+ .eq(0)
706
+ .map(function (cellIdx) {
707
+ var id = api.row(cellIdx.row).id(true);
708
+ return id ? { row: id, column: cellIdx.column } : undefined;
709
+ })
710
+ .filter(function (d) {
711
+ return d !== undefined;
712
+ });
643
713
 
644
714
  // On the next draw, reselect the currently selected items
645
- api.one( 'draw.dt.dtSelect', function () {
646
- api.rows( rows ).select();
715
+ api.one('draw.dt.dtSelect', function () {
716
+ api.rows(rows).select();
647
717
 
648
718
  // `cells` is not a cell index selector, so it needs a loop
649
- if ( cells.any() ) {
650
- cells.each( function ( id ) {
651
- api.cells( id.row, id.column ).select();
652
- } );
719
+ if (cells.any()) {
720
+ cells.each(function (id) {
721
+ api.cells(id.row, id.column).select();
722
+ });
653
723
  }
654
- } );
655
- } );
724
+ });
725
+ });
656
726
 
657
727
  // Update the table information element with selected item summary
658
- api.on( 'draw.dtSelect.dt select.dtSelect.dt deselect.dtSelect.dt info.dt', function () {
659
- info( api );
728
+ api.on('info.dt', function (e, ctx, node) {
729
+ // Store the info node for updating on select / deselect
730
+ if (!ctx._select.infoEls.includes(node)) {
731
+ ctx._select.infoEls.push(node);
732
+ }
733
+
734
+ info(api, node);
735
+ });
736
+
737
+ api.on('select.dtSelect.dt deselect.dtSelect.dt', function () {
738
+ ctx._select.infoEls.forEach(function (el) {
739
+ info(api, el);
740
+ });
741
+
660
742
  api.state.save();
661
- } );
743
+ });
662
744
 
663
745
  // Clean up and release
664
- api.on( 'destroy.dtSelect', function () {
746
+ api.on('destroy.dtSelect', function () {
665
747
  // Remove class directly rather than calling deselect - which would trigger events
666
- $(api.rows({selected: true}).nodes()).removeClass(api.settings()[0]._select.className);
748
+ $(api.rows({ selected: true }).nodes()).removeClass(api.settings()[0]._select.className);
667
749
 
668
- disableMouseSelection( api );
669
- api.off( '.dtSelect' );
750
+ disableMouseSelection(api);
751
+ api.off('.dtSelect');
670
752
  $('body').off('.dtSelect' + _safeId(api.table().node()));
671
- } );
753
+ });
672
754
  }
673
755
 
674
756
  /**
@@ -681,38 +763,37 @@ function init ( ctx ) {
681
763
  * @param {object} last Item index to select from
682
764
  * @private
683
765
  */
684
- function rowColumnRange( dt, type, idx, last )
685
- {
766
+ function rowColumnRange(dt, type, idx, last) {
686
767
  // Add a range of rows from the last selected row to this one
687
- var indexes = dt[type+'s']( { search: 'applied' } ).indexes();
688
- var idx1 = $.inArray( last, indexes );
689
- var idx2 = $.inArray( idx, indexes );
768
+ var indexes = dt[type + 's']({ search: 'applied' }).indexes();
769
+ var idx1 = indexes.indexOf(last);
770
+ var idx2 = indexes.indexOf(idx);
690
771
 
691
- if ( ! dt[type+'s']( { selected: true } ).any() && idx1 === -1 ) {
772
+ if (!dt[type + 's']({ selected: true }).any() && idx1 === -1) {
692
773
  // select from top to here - slightly odd, but both Windows and Mac OS
693
774
  // do this
694
- indexes.splice( $.inArray( idx, indexes )+1, indexes.length );
775
+ indexes.splice(indexes.indexOf(idx) + 1, indexes.length);
695
776
  }
696
777
  else {
697
778
  // reverse so we can shift click 'up' as well as down
698
- if ( idx1 > idx2 ) {
779
+ if (idx1 > idx2) {
699
780
  var tmp = idx2;
700
781
  idx2 = idx1;
701
782
  idx1 = tmp;
702
783
  }
703
784
 
704
- indexes.splice( idx2+1, indexes.length );
705
- indexes.splice( 0, idx1 );
785
+ indexes.splice(idx2 + 1, indexes.length);
786
+ indexes.splice(0, idx1);
706
787
  }
707
788
 
708
- if ( ! dt[type]( idx, { selected: true } ).any() ) {
789
+ if (!dt[type](idx, { selected: true }).any()) {
709
790
  // Select range
710
- dt[type+'s']( indexes ).select();
791
+ dt[type + 's'](indexes).select();
711
792
  }
712
793
  else {
713
794
  // Deselect range - need to keep the clicked on row selected
714
- indexes.splice( $.inArray( idx, indexes ), 1 );
715
- dt[type+'s']( indexes ).deselect();
795
+ indexes.splice(indexes.indexOf(idx), 1);
796
+ dt[type + 's'](indexes).deselect();
716
797
  }
717
798
  }
718
799
 
@@ -724,14 +805,13 @@ function rowColumnRange( dt, type, idx, last )
724
805
  * of selection style
725
806
  * @private
726
807
  */
727
- function clear( ctx, force )
728
- {
729
- if ( force || ctx._select.style === 'single' ) {
730
- var api = new DataTable.Api( ctx );
731
-
732
- api.rows( { selected: true } ).deselect();
733
- api.columns( { selected: true } ).deselect();
734
- api.cells( { selected: true } ).deselect();
808
+ function clear(ctx, force) {
809
+ if (force || ctx._select.style === 'single') {
810
+ var api = new DataTable.Api(ctx);
811
+
812
+ api.rows({ selected: true }).deselect();
813
+ api.columns({ selected: true }).deselect();
814
+ api.cells({ selected: true }).deselect();
735
815
  }
736
816
  }
737
817
 
@@ -745,72 +825,74 @@ function clear( ctx, force )
745
825
  * @param {int|object} idx Index of the item to select
746
826
  * @private
747
827
  */
748
- function typeSelect ( e, dt, ctx, type, idx )
749
- {
828
+ function typeSelect(e, dt, ctx, type, idx) {
750
829
  var style = dt.select.style();
751
830
  var toggleable = dt.select.toggleable();
752
- var isSelected = dt[type]( idx, { selected: true } ).any();
753
-
754
- if ( isSelected && ! toggleable ) {
831
+ var isSelected = dt[type](idx, { selected: true }).any();
832
+
833
+ if (isSelected && !toggleable) {
755
834
  return;
756
835
  }
757
836
 
758
- if ( style === 'os' ) {
759
- if ( e.ctrlKey || e.metaKey ) {
837
+ if (style === 'os') {
838
+ if (e.ctrlKey || e.metaKey) {
760
839
  // Add or remove from the selection
761
- dt[type]( idx ).select( ! isSelected );
840
+ dt[type](idx).select(!isSelected);
762
841
  }
763
- else if ( e.shiftKey ) {
764
- if ( type === 'cell' ) {
765
- cellRange( dt, idx, ctx._select_lastCell || null );
842
+ else if (e.shiftKey) {
843
+ if (type === 'cell') {
844
+ cellRange(dt, idx, ctx._select_lastCell || null);
766
845
  }
767
846
  else {
768
- rowColumnRange( dt, type, idx, ctx._select_lastCell ?
769
- ctx._select_lastCell[type] :
770
- null
847
+ rowColumnRange(
848
+ dt,
849
+ type,
850
+ idx,
851
+ ctx._select_lastCell ? ctx._select_lastCell[type] : null
771
852
  );
772
853
  }
773
854
  }
774
855
  else {
775
856
  // No cmd or shift click - deselect if selected, or select
776
857
  // this row only
777
- var selected = dt[type+'s']( { selected: true } );
858
+ var selected = dt[type + 's']({ selected: true });
778
859
 
779
- if ( isSelected && selected.flatten().length === 1 ) {
780
- dt[type]( idx ).deselect();
860
+ if (isSelected && selected.flatten().length === 1) {
861
+ dt[type](idx).deselect();
781
862
  }
782
863
  else {
783
864
  selected.deselect();
784
- dt[type]( idx ).select();
865
+ dt[type](idx).select();
785
866
  }
786
867
  }
787
- } else if ( style == 'multi+shift' ) {
788
- if ( e.shiftKey ) {
789
- if ( type === 'cell' ) {
790
- cellRange( dt, idx, ctx._select_lastCell || null );
868
+ }
869
+ else if (style == 'multi+shift') {
870
+ if (e.shiftKey) {
871
+ if (type === 'cell') {
872
+ cellRange(dt, idx, ctx._select_lastCell || null);
791
873
  }
792
874
  else {
793
- rowColumnRange( dt, type, idx, ctx._select_lastCell ?
794
- ctx._select_lastCell[type] :
795
- null
875
+ rowColumnRange(
876
+ dt,
877
+ type,
878
+ idx,
879
+ ctx._select_lastCell ? ctx._select_lastCell[type] : null
796
880
  );
797
881
  }
798
882
  }
799
883
  else {
800
- dt[ type ]( idx ).select( ! isSelected );
884
+ dt[type](idx).select(!isSelected);
801
885
  }
802
886
  }
803
887
  else {
804
- dt[ type ]( idx ).select( ! isSelected );
888
+ dt[type](idx).select(!isSelected);
805
889
  }
806
890
  }
807
891
 
808
- function _safeId( node ) {
892
+ function _safeId(node) {
809
893
  return node.id.replace(/[^a-zA-Z0-9\-\_]/g, '-');
810
894
  }
811
895
 
812
-
813
-
814
896
  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
815
897
  * DataTables selectors
816
898
  */
@@ -818,56 +900,66 @@ function _safeId( node ) {
818
900
  // row and column are basically identical just assigned to different properties
819
901
  // and checking a different array, so we can dynamically create the functions to
820
902
  // reduce the code size
821
- $.each( [
822
- { type: 'row', prop: 'aoData' },
823
- { type: 'column', prop: 'aoColumns' }
824
- ], function ( i, o ) {
825
- DataTable.ext.selector[ o.type ].push( function ( settings, opts, indexes ) {
826
- var selected = opts.selected;
827
- var data;
828
- var out = [];
829
-
830
- if ( selected !== true && selected !== false ) {
831
- return indexes;
832
- }
903
+ $.each(
904
+ [
905
+ { type: 'row', prop: 'aoData' },
906
+ { type: 'column', prop: 'aoColumns' }
907
+ ],
908
+ function (i, o) {
909
+ DataTable.ext.selector[o.type].push(function (settings, opts, indexes) {
910
+ var selected = opts.selected;
911
+ var data;
912
+ var out = [];
913
+
914
+ if (selected !== true && selected !== false) {
915
+ return indexes;
916
+ }
833
917
 
834
- for ( var i=0, ien=indexes.length ; i<ien ; i++ ) {
835
- data = settings[ o.prop ][ indexes[i] ];
918
+ for (var i = 0, ien = indexes.length; i < ien; i++) {
919
+ data = settings[o.prop][indexes[i]];
836
920
 
837
- if ( (selected === true && data._select_selected === true) ||
838
- (selected === false && ! data._select_selected )
839
- ) {
840
- out.push( indexes[i] );
921
+ if (
922
+ data && (
923
+ (selected === true && data._select_selected === true) ||
924
+ (selected === false && !data._select_selected)
925
+ )
926
+ ) {
927
+ out.push(indexes[i]);
928
+ }
841
929
  }
842
- }
843
930
 
844
- return out;
845
- } );
846
- } );
931
+ return out;
932
+ });
933
+ }
934
+ );
847
935
 
848
- DataTable.ext.selector.cell.push( function ( settings, opts, cells ) {
936
+ DataTable.ext.selector.cell.push(function (settings, opts, cells) {
849
937
  var selected = opts.selected;
850
938
  var rowData;
851
939
  var out = [];
852
940
 
853
- if ( selected === undefined ) {
941
+ if (selected === undefined) {
854
942
  return cells;
855
943
  }
856
944
 
857
- for ( var i=0, ien=cells.length ; i<ien ; i++ ) {
858
- rowData = settings.aoData[ cells[i].row ];
859
-
860
- if ( (selected === true && rowData._selected_cells && rowData._selected_cells[ cells[i].column ] === true) ||
861
- (selected === false && ( ! rowData._selected_cells || ! rowData._selected_cells[ cells[i].column ] ) )
945
+ for (var i = 0, ien = cells.length; i < ien; i++) {
946
+ rowData = settings.aoData[cells[i].row];
947
+
948
+ if (
949
+ rowData && (
950
+ (selected === true &&
951
+ rowData._selected_cells &&
952
+ rowData._selected_cells[cells[i].column] === true) ||
953
+ (selected === false &&
954
+ (!rowData._selected_cells || !rowData._selected_cells[cells[i].column]))
955
+ )
862
956
  ) {
863
- out.push( cells[i] );
957
+ out.push(cells[i]);
864
958
  }
865
959
  }
866
960
 
867
961
  return out;
868
- } );
869
-
870
-
962
+ });
871
963
 
872
964
  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
873
965
  * DataTables API
@@ -880,67 +972,67 @@ DataTable.ext.selector.cell.push( function ( settings, opts, cells ) {
880
972
  var apiRegister = DataTable.Api.register;
881
973
  var apiRegisterPlural = DataTable.Api.registerPlural;
882
974
 
883
- apiRegister( 'select()', function () {
884
- return this.iterator( 'table', function ( ctx ) {
885
- DataTable.select.init( new DataTable.Api( ctx ) );
886
- } );
887
- } );
975
+ apiRegister('select()', function () {
976
+ return this.iterator('table', function (ctx) {
977
+ DataTable.select.init(new DataTable.Api(ctx));
978
+ });
979
+ });
888
980
 
889
- apiRegister( 'select.blurable()', function ( flag ) {
890
- if ( flag === undefined ) {
981
+ apiRegister('select.blurable()', function (flag) {
982
+ if (flag === undefined) {
891
983
  return this.context[0]._select.blurable;
892
984
  }
893
985
 
894
- return this.iterator( 'table', function ( ctx ) {
986
+ return this.iterator('table', function (ctx) {
895
987
  ctx._select.blurable = flag;
896
- } );
897
- } );
988
+ });
989
+ });
898
990
 
899
- apiRegister( 'select.toggleable()', function ( flag ) {
900
- if ( flag === undefined ) {
991
+ apiRegister('select.toggleable()', function (flag) {
992
+ if (flag === undefined) {
901
993
  return this.context[0]._select.toggleable;
902
994
  }
903
995
 
904
- return this.iterator( 'table', function ( ctx ) {
996
+ return this.iterator('table', function (ctx) {
905
997
  ctx._select.toggleable = flag;
906
- } );
907
- } );
998
+ });
999
+ });
908
1000
 
909
- apiRegister( 'select.info()', function ( flag ) {
910
- if ( flag === undefined ) {
1001
+ apiRegister('select.info()', function (flag) {
1002
+ if (flag === undefined) {
911
1003
  return this.context[0]._select.info;
912
1004
  }
913
1005
 
914
- return this.iterator( 'table', function ( ctx ) {
1006
+ return this.iterator('table', function (ctx) {
915
1007
  ctx._select.info = flag;
916
- } );
917
- } );
1008
+ });
1009
+ });
918
1010
 
919
- apiRegister( 'select.items()', function ( items ) {
920
- if ( items === undefined ) {
1011
+ apiRegister('select.items()', function (items) {
1012
+ if (items === undefined) {
921
1013
  return this.context[0]._select.items;
922
1014
  }
923
1015
 
924
- return this.iterator( 'table', function ( ctx ) {
1016
+ return this.iterator('table', function (ctx) {
925
1017
  ctx._select.items = items;
926
1018
 
927
- eventTrigger( new DataTable.Api( ctx ), 'selectItems', [ items ] );
928
- } );
929
- } );
1019
+ eventTrigger(new DataTable.Api(ctx), 'selectItems', [items]);
1020
+ });
1021
+ });
930
1022
 
931
1023
  // Takes effect from the _next_ selection. None disables future selection, but
932
1024
  // does not clear the current selection. Use the `deselect` methods for that
933
- apiRegister( 'select.style()', function ( style ) {
934
- if ( style === undefined ) {
1025
+ apiRegister('select.style()', function (style) {
1026
+ if (style === undefined) {
935
1027
  return this.context[0]._select.style;
936
1028
  }
937
1029
 
938
- return this.iterator( 'table', function ( ctx ) {
939
- if ( ! ctx._select ) {
940
- DataTable.select.init( new DataTable.Api(ctx) );
1030
+ return this.iterator('table', function (ctx) {
1031
+ if (!ctx._select) {
1032
+ DataTable.select.init(new DataTable.Api(ctx));
941
1033
  }
942
1034
 
943
- if ( ! ctx._select_init ) {
1035
+ if (!ctx._select_init) {
944
1036
  init(ctx);
945
1037
  }
946
1038
 
@@ -948,144 +1040,161 @@ apiRegister( 'select.style()', function ( style ) {
948
1040
 
949
1041
  // Add / remove mouse event handlers. They aren't required when only
950
1042
  // API selection is available
951
- var dt = new DataTable.Api( ctx );
952
- disableMouseSelection( dt );
953
-
954
- if ( style !== 'api' ) {
955
- enableMouseSelection( dt );
1043
+ var dt = new DataTable.Api(ctx);
1044
+ disableMouseSelection(dt);
1045
+
1046
+ if (style !== 'api') {
1047
+ enableMouseSelection(dt);
956
1048
  }
957
1049
 
958
- eventTrigger( new DataTable.Api( ctx ), 'selectStyle', [ style ] );
959
- } );
960
- } );
1050
+ eventTrigger(new DataTable.Api(ctx), 'selectStyle', [style]);
1051
+ });
1052
+ });
961
1053
 
962
- apiRegister( 'select.selector()', function ( selector ) {
963
- if ( selector === undefined ) {
1054
+ apiRegister('select.selector()', function (selector) {
1055
+ if (selector === undefined) {
964
1056
  return this.context[0]._select.selector;
965
1057
  }
966
1058
 
967
- return this.iterator( 'table', function ( ctx ) {
968
- disableMouseSelection( new DataTable.Api( ctx ) );
1059
+ return this.iterator('table', function (ctx) {
1060
+ disableMouseSelection(new DataTable.Api(ctx));
969
1061
 
970
1062
  ctx._select.selector = selector;
971
1063
 
972
- if ( ctx._select.style !== 'api' ) {
973
- enableMouseSelection( new DataTable.Api( ctx ) );
1064
+ if (ctx._select.style !== 'api') {
1065
+ enableMouseSelection(new DataTable.Api(ctx));
974
1066
  }
975
- } );
976
- } );
1067
+ });
1068
+ });
1069
+
1070
+ apiRegister('select.last()', function (set) {
1071
+ let ctx = this.context[0];
977
1072
 
1073
+ if (set) {
1074
+ ctx._select_lastCell = set;
1075
+ return this;
1076
+ }
978
1077
 
1078
+ return ctx._select_lastCell;
1079
+ });
979
1080
 
980
- apiRegisterPlural( 'rows().select()', 'row().select()', function ( select ) {
1081
+ apiRegisterPlural('rows().select()', 'row().select()', function (select) {
981
1082
  var api = this;
982
1083
 
983
- if ( select === false ) {
1084
+ if (select === false) {
984
1085
  return this.deselect();
985
1086
  }
986
1087
 
987
- this.iterator( 'row', function ( ctx, idx ) {
988
- clear( ctx );
1088
+ this.iterator('row', function (ctx, idx) {
1089
+ clear(ctx);
1090
+
1091
+ // There is a good amount of knowledge of DataTables internals in
1092
+ // this function. It _could_ be done without that, but it would hurt
1093
+ // performance (or DT would need new APIs for this work)
1094
+ var dtData = ctx.aoData[idx];
1095
+ var dtColumns = ctx.aoColumns;
1096
+
1097
+ $(dtData.nTr).addClass(ctx._select.className);
1098
+ dtData._select_selected = true;
1099
+
1100
+ for (var i=0 ; i<dtColumns.length ; i++) {
1101
+ var col = dtColumns[i];
1102
+
1103
+ if (col.sType === 'select-checkbox') {
1104
+ // Make sure the checkbox shows the right state
1105
+ $('input.dt-select-checkbox', dtData.anCells[i]).prop('checked', true);
989
1106
 
990
- ctx.aoData[ idx ]._select_selected = true;
991
- $( ctx.aoData[ idx ].nTr ).addClass( ctx._select.className );
992
- } );
1107
+ // Invalidate the sort data for this column
1108
+ dtData._aSortData[i] = null;
1109
+ }
1110
+ }
1111
+ });
993
1112
 
994
- this.iterator( 'table', function ( ctx, i ) {
995
- eventTrigger( api, 'select', [ 'row', api[i] ], true );
996
- } );
1113
+ this.iterator('table', function (ctx, i) {
1114
+ eventTrigger(api, 'select', ['row', api[i]], true);
1115
+ });
997
1116
 
998
1117
  return this;
999
- } );
1118
+ });
1000
1119
 
1001
- apiRegister( 'row().selected()', function () {
1120
+ apiRegister('row().selected()', function () {
1002
1121
  var ctx = this.context[0];
1003
1122
 
1004
- if (
1005
- ctx &&
1006
- this.length &&
1007
- ctx.aoData[this[0]] &&
1008
- ctx.aoData[this[0]]._select_selected
1009
- ) {
1123
+ if (ctx && this.length && ctx.aoData[this[0]] && ctx.aoData[this[0]]._select_selected) {
1010
1124
  return true;
1011
1125
  }
1012
1126
 
1013
1127
  return false;
1014
- } );
1128
+ });
1015
1129
 
1016
- apiRegisterPlural( 'columns().select()', 'column().select()', function ( select ) {
1130
+ apiRegisterPlural('columns().select()', 'column().select()', function (select) {
1017
1131
  var api = this;
1018
1132
 
1019
- if ( select === false ) {
1133
+ if (select === false) {
1020
1134
  return this.deselect();
1021
1135
  }
1022
1136
 
1023
- this.iterator( 'column', function ( ctx, idx ) {
1024
- clear( ctx );
1137
+ this.iterator('column', function (ctx, idx) {
1138
+ clear(ctx);
1025
1139
 
1026
- ctx.aoColumns[ idx ]._select_selected = true;
1140
+ ctx.aoColumns[idx]._select_selected = true;
1027
1141
 
1028
- var column = new DataTable.Api( ctx ).column( idx );
1142
+ var column = new DataTable.Api(ctx).column(idx);
1029
1143
 
1030
- $( column.header() ).addClass( ctx._select.className );
1031
- $( column.footer() ).addClass( ctx._select.className );
1144
+ $(column.header()).addClass(ctx._select.className);
1145
+ $(column.footer()).addClass(ctx._select.className);
1032
1146
 
1033
- column.nodes().to$().addClass( ctx._select.className );
1034
- } );
1147
+ column.nodes().to$().addClass(ctx._select.className);
1148
+ });
1035
1149
 
1036
- this.iterator( 'table', function ( ctx, i ) {
1037
- eventTrigger( api, 'select', [ 'column', api[i] ], true );
1038
- } );
1150
+ this.iterator('table', function (ctx, i) {
1151
+ eventTrigger(api, 'select', ['column', api[i]], true);
1152
+ });
1039
1153
 
1040
1154
  return this;
1041
- } );
1155
+ });
1042
1156
 
1043
- apiRegister( 'column().selected()', function () {
1157
+ apiRegister('column().selected()', function () {
1044
1158
  var ctx = this.context[0];
1045
1159
 
1046
- if (
1047
- ctx &&
1048
- this.length &&
1049
- ctx.aoColumns[this[0]] &&
1050
- ctx.aoColumns[this[0]]._select_selected
1051
- ) {
1160
+ if (ctx && this.length && ctx.aoColumns[this[0]] && ctx.aoColumns[this[0]]._select_selected) {
1052
1161
  return true;
1053
1162
  }
1054
1163
 
1055
1164
  return false;
1056
- } );
1165
+ });
1057
1166
 
1058
- apiRegisterPlural( 'cells().select()', 'cell().select()', function ( select ) {
1167
+ apiRegisterPlural('cells().select()', 'cell().select()', function (select) {
1059
1168
  var api = this;
1060
1169
 
1061
- if ( select === false ) {
1170
+ if (select === false) {
1062
1171
  return this.deselect();
1063
1172
  }
1064
1173
 
1065
- this.iterator( 'cell', function ( ctx, rowIdx, colIdx ) {
1066
- clear( ctx );
1174
+ this.iterator('cell', function (ctx, rowIdx, colIdx) {
1175
+ clear(ctx);
1067
1176
 
1068
- var data = ctx.aoData[ rowIdx ];
1177
+ var data = ctx.aoData[rowIdx];
1069
1178
 
1070
- if ( data._selected_cells === undefined ) {
1179
+ if (data._selected_cells === undefined) {
1071
1180
  data._selected_cells = [];
1072
1181
  }
1073
1182
 
1074
- data._selected_cells[ colIdx ] = true;
1183
+ data._selected_cells[colIdx] = true;
1075
1184
 
1076
- if ( data.anCells ) {
1077
- $( data.anCells[ colIdx ] ).addClass( ctx._select.className );
1185
+ if (data.anCells) {
1186
+ $(data.anCells[colIdx]).addClass(ctx._select.className);
1078
1187
  }
1079
- } );
1188
+ });
1080
1189
 
1081
- this.iterator( 'table', function ( ctx, i ) {
1082
- eventTrigger( api, 'select', [ 'cell', api.cells(api[i]).indexes().toArray() ], true );
1083
- } );
1190
+ this.iterator('table', function (ctx, i) {
1191
+ eventTrigger(api, 'select', ['cell', api.cells(api[i]).indexes().toArray()], true);
1192
+ });
1084
1193
 
1085
1194
  return this;
1086
- } );
1195
+ });
1087
1196
 
1088
- apiRegister( 'cell().selected()', function () {
1197
+ apiRegister('cell().selected()', function () {
1089
1198
  var ctx = this.context[0];
1090
1199
 
1091
1200
  if (ctx && this.length) {
@@ -1097,110 +1206,125 @@ apiRegister( 'cell().selected()', function () {
1097
1206
  }
1098
1207
 
1099
1208
  return false;
1100
- } );
1101
-
1209
+ });
1102
1210
 
1103
- apiRegisterPlural( 'rows().deselect()', 'row().deselect()', function () {
1211
+ apiRegisterPlural('rows().deselect()', 'row().deselect()', function () {
1104
1212
  var api = this;
1105
1213
 
1106
- this.iterator( 'row', function ( ctx, idx ) {
1107
- ctx.aoData[ idx ]._select_selected = false;
1214
+ this.iterator('row', function (ctx, idx) {
1215
+ // Like the select action, this has a lot of knowledge about DT internally
1216
+ var dtData = ctx.aoData[idx];
1217
+ var dtColumns = ctx.aoColumns;
1218
+
1219
+ $(dtData.nTr).removeClass(ctx._select.className);
1220
+ dtData._select_selected = false;
1108
1221
  ctx._select_lastCell = null;
1109
- $( ctx.aoData[ idx ].nTr ).removeClass( ctx._select.className );
1110
- } );
1111
1222
 
1112
- this.iterator( 'table', function ( ctx, i ) {
1113
- eventTrigger( api, 'deselect', [ 'row', api[i] ], true );
1114
- } );
1223
+ for (var i=0 ; i<dtColumns.length ; i++) {
1224
+ var col = dtColumns[i];
1225
+
1226
+ if (col.sType === 'select-checkbox') {
1227
+ // Make sure the checkbox shows the right state
1228
+ $('input.dt-select-checkbox', dtData.anCells[i]).prop('checked', false);
1229
+
1230
+ // Invalidate the sort data for this column
1231
+ dtData._aSortData[i] = null;
1232
+ }
1233
+ }
1234
+ });
1235
+
1236
+ this.iterator('table', function (ctx, i) {
1237
+ eventTrigger(api, 'deselect', ['row', api[i]], true);
1238
+ });
1115
1239
 
1116
1240
  return this;
1117
- } );
1241
+ });
1118
1242
 
1119
- apiRegisterPlural( 'columns().deselect()', 'column().deselect()', function () {
1243
+ apiRegisterPlural('columns().deselect()', 'column().deselect()', function () {
1120
1244
  var api = this;
1121
1245
 
1122
- this.iterator( 'column', function ( ctx, idx ) {
1123
- ctx.aoColumns[ idx ]._select_selected = false;
1246
+ this.iterator('column', function (ctx, idx) {
1247
+ ctx.aoColumns[idx]._select_selected = false;
1124
1248
 
1125
- var api = new DataTable.Api( ctx );
1126
- var column = api.column( idx );
1249
+ var api = new DataTable.Api(ctx);
1250
+ var column = api.column(idx);
1127
1251
 
1128
- $( column.header() ).removeClass( ctx._select.className );
1129
- $( column.footer() ).removeClass( ctx._select.className );
1252
+ $(column.header()).removeClass(ctx._select.className);
1253
+ $(column.footer()).removeClass(ctx._select.className);
1130
1254
 
1131
1255
  // Need to loop over each cell, rather than just using
1132
1256
  // `column().nodes()` as cells which are individually selected should
1133
1257
  // not have the `selected` class removed from them
1134
- api.cells( null, idx ).indexes().each( function (cellIdx) {
1135
- var data = ctx.aoData[ cellIdx.row ];
1136
- var cellSelected = data._selected_cells;
1137
-
1138
- if ( data.anCells && (! cellSelected || ! cellSelected[ cellIdx.column ]) ) {
1139
- $( data.anCells[ cellIdx.column ] ).removeClass( ctx._select.className );
1140
- }
1141
- } );
1142
- } );
1258
+ api.cells(null, idx)
1259
+ .indexes()
1260
+ .each(function (cellIdx) {
1261
+ var data = ctx.aoData[cellIdx.row];
1262
+ var cellSelected = data._selected_cells;
1263
+
1264
+ if (data.anCells && (!cellSelected || !cellSelected[cellIdx.column])) {
1265
+ $(data.anCells[cellIdx.column]).removeClass(ctx._select.className);
1266
+ }
1267
+ });
1268
+ });
1143
1269
 
1144
- this.iterator( 'table', function ( ctx, i ) {
1145
- eventTrigger( api, 'deselect', [ 'column', api[i] ], true );
1146
- } );
1270
+ this.iterator('table', function (ctx, i) {
1271
+ eventTrigger(api, 'deselect', ['column', api[i]], true);
1272
+ });
1147
1273
 
1148
1274
  return this;
1149
- } );
1275
+ });
1150
1276
 
1151
- apiRegisterPlural( 'cells().deselect()', 'cell().deselect()', function () {
1277
+ apiRegisterPlural('cells().deselect()', 'cell().deselect()', function () {
1152
1278
  var api = this;
1153
1279
 
1154
- this.iterator( 'cell', function ( ctx, rowIdx, colIdx ) {
1155
- var data = ctx.aoData[ rowIdx ];
1280
+ this.iterator('cell', function (ctx, rowIdx, colIdx) {
1281
+ var data = ctx.aoData[rowIdx];
1156
1282
 
1157
- if(data._selected_cells !== undefined) {
1158
- data._selected_cells[ colIdx ] = false;
1283
+ if (data._selected_cells !== undefined) {
1284
+ data._selected_cells[colIdx] = false;
1159
1285
  }
1160
1286
 
1161
1287
  // Remove class only if the cells exist, and the cell is not column
1162
1288
  // selected, in which case the class should remain (since it is selected
1163
1289
  // in the column)
1164
- if ( data.anCells && ! ctx.aoColumns[ colIdx ]._select_selected ) {
1165
- $( data.anCells[ colIdx ] ).removeClass( ctx._select.className );
1290
+ if (data.anCells && !ctx.aoColumns[colIdx]._select_selected) {
1291
+ $(data.anCells[colIdx]).removeClass(ctx._select.className);
1166
1292
  }
1167
- } );
1293
+ });
1168
1294
 
1169
- this.iterator( 'table', function ( ctx, i ) {
1170
- eventTrigger( api, 'deselect', [ 'cell', api[i] ], true );
1171
- } );
1295
+ this.iterator('table', function (ctx, i) {
1296
+ eventTrigger(api, 'deselect', ['cell', api[i]], true);
1297
+ });
1172
1298
 
1173
1299
  return this;
1174
- } );
1175
-
1176
-
1300
+ });
1177
1301
 
1178
1302
  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1179
1303
  * Buttons
1180
1304
  */
1181
- function i18n( label, def ) {
1305
+ function i18n(label, def) {
1182
1306
  return function (dt) {
1183
- return dt.i18n( 'buttons.'+label, def );
1307
+ return dt.i18n('buttons.' + label, def);
1184
1308
  };
1185
1309
  }
1186
1310
 
1187
1311
  // Common events with suitable namespaces
1188
- function namespacedEvents ( config ) {
1312
+ function namespacedEvents(config) {
1189
1313
  var unique = config._eventNamespace;
1190
1314
 
1191
- return 'draw.dt.DT'+unique+' select.dt.DT'+unique+' deselect.dt.DT'+unique;
1315
+ return 'draw.dt.DT' + unique + ' select.dt.DT' + unique + ' deselect.dt.DT' + unique;
1192
1316
  }
1193
1317
 
1194
- function enabled ( dt, config ) {
1195
- if ( $.inArray( 'rows', config.limitTo ) !== -1 && dt.rows( { selected: true } ).any() ) {
1318
+ function enabled(dt, config) {
1319
+ if (config.limitTo.indexOf('rows') !== -1 && dt.rows({ selected: true }).any()) {
1196
1320
  return true;
1197
1321
  }
1198
1322
 
1199
- if ( $.inArray( 'columns', config.limitTo ) !== -1 && dt.columns( { selected: true } ).any() ) {
1323
+ if (config.limitTo.indexOf('columns') !== -1 && dt.columns({ selected: true }).any()) {
1200
1324
  return true;
1201
1325
  }
1202
1326
 
1203
- if ( $.inArray( 'cells', config.limitTo ) !== -1 && dt.cells( { selected: true } ).any() ) {
1327
+ if (config.limitTo.indexOf('cells') !== -1 && dt.cells({ selected: true }).any()) {
1204
1328
  return true;
1205
1329
  }
1206
1330
 
@@ -1209,111 +1333,114 @@ function enabled ( dt, config ) {
1209
1333
 
1210
1334
  var _buttonNamespace = 0;
1211
1335
 
1212
- $.extend( DataTable.ext.buttons, {
1336
+ $.extend(DataTable.ext.buttons, {
1213
1337
  selected: {
1214
- text: i18n( 'selected', 'Selected' ),
1338
+ text: i18n('selected', 'Selected'),
1215
1339
  className: 'buttons-selected',
1216
- limitTo: [ 'rows', 'columns', 'cells' ],
1217
- init: function ( dt, node, config ) {
1340
+ limitTo: ['rows', 'columns', 'cells'],
1341
+ init: function (dt, node, config) {
1218
1342
  var that = this;
1219
- config._eventNamespace = '.select'+(_buttonNamespace++);
1343
+ config._eventNamespace = '.select' + _buttonNamespace++;
1220
1344
 
1221
1345
  // .DT namespace listeners are removed by DataTables automatically
1222
1346
  // on table destroy
1223
- dt.on( namespacedEvents(config), function () {
1224
- that.enable( enabled(dt, config) );
1225
- } );
1347
+ dt.on(namespacedEvents(config), function () {
1348
+ that.enable(enabled(dt, config));
1349
+ });
1226
1350
 
1227
1351
  this.disable();
1228
1352
  },
1229
- destroy: function ( dt, node, config ) {
1230
- dt.off( config._eventNamespace );
1353
+ destroy: function (dt, node, config) {
1354
+ dt.off(config._eventNamespace);
1231
1355
  }
1232
1356
  },
1233
1357
  selectedSingle: {
1234
- text: i18n( 'selectedSingle', 'Selected single' ),
1358
+ text: i18n('selectedSingle', 'Selected single'),
1235
1359
  className: 'buttons-selected-single',
1236
- init: function ( dt, node, config ) {
1360
+ init: function (dt, node, config) {
1237
1361
  var that = this;
1238
- config._eventNamespace = '.select'+(_buttonNamespace++);
1362
+ config._eventNamespace = '.select' + _buttonNamespace++;
1239
1363
 
1240
- dt.on( namespacedEvents(config), function () {
1241
- var count = dt.rows( { selected: true } ).flatten().length +
1242
- dt.columns( { selected: true } ).flatten().length +
1243
- dt.cells( { selected: true } ).flatten().length;
1364
+ dt.on(namespacedEvents(config), function () {
1365
+ var count =
1366
+ dt.rows({ selected: true }).flatten().length +
1367
+ dt.columns({ selected: true }).flatten().length +
1368
+ dt.cells({ selected: true }).flatten().length;
1244
1369
 
1245
- that.enable( count === 1 );
1246
- } );
1370
+ that.enable(count === 1);
1371
+ });
1247
1372
 
1248
1373
  this.disable();
1249
1374
  },
1250
- destroy: function ( dt, node, config ) {
1251
- dt.off( config._eventNamespace );
1375
+ destroy: function (dt, node, config) {
1376
+ dt.off(config._eventNamespace);
1252
1377
  }
1253
1378
  },
1254
1379
  selectAll: {
1255
- text: i18n( 'selectAll', 'Select all' ),
1380
+ text: i18n('selectAll', 'Select all'),
1256
1381
  className: 'buttons-select-all',
1257
- action: function () {
1382
+ action: function (e, dt, node, config) {
1258
1383
  var items = this.select.items();
1259
- this[ items+'s' ]().select();
1384
+ var mod = config.selectorModifier;
1385
+
1386
+ if (mod) {
1387
+ if (typeof mod === 'function') {
1388
+ mod = mod.call(dt, e, dt, node, config);
1389
+ }
1390
+
1391
+ this[items + 's'](mod).select();
1392
+ }
1393
+ else {
1394
+ this[items + 's']().select();
1395
+ }
1260
1396
  }
1397
+ // selectorModifier can be specified
1261
1398
  },
1262
1399
  selectNone: {
1263
- text: i18n( 'selectNone', 'Deselect all' ),
1400
+ text: i18n('selectNone', 'Deselect all'),
1264
1401
  className: 'buttons-select-none',
1265
1402
  action: function () {
1266
- clear( this.settings()[0], true );
1403
+ clear(this.settings()[0], true);
1267
1404
  },
1268
- init: function ( dt, node, config ) {
1405
+ init: function (dt, node, config) {
1269
1406
  var that = this;
1270
- config._eventNamespace = '.select'+(_buttonNamespace++);
1407
+ config._eventNamespace = '.select' + _buttonNamespace++;
1271
1408
 
1272
- dt.on( namespacedEvents(config), function () {
1273
- var count = dt.rows( { selected: true } ).flatten().length +
1274
- dt.columns( { selected: true } ).flatten().length +
1275
- dt.cells( { selected: true } ).flatten().length;
1409
+ dt.on(namespacedEvents(config), function () {
1410
+ var count =
1411
+ dt.rows({ selected: true }).flatten().length +
1412
+ dt.columns({ selected: true }).flatten().length +
1413
+ dt.cells({ selected: true }).flatten().length;
1276
1414
 
1277
- that.enable( count > 0 );
1278
- } );
1415
+ that.enable(count > 0);
1416
+ });
1279
1417
 
1280
1418
  this.disable();
1281
1419
  },
1282
- destroy: function ( dt, node, config ) {
1283
- dt.off( config._eventNamespace );
1420
+ destroy: function (dt, node, config) {
1421
+ dt.off(config._eventNamespace);
1284
1422
  }
1285
1423
  },
1286
1424
  showSelected: {
1287
- text: i18n( 'showSelected', 'Show only selected' ),
1425
+ text: i18n('showSelected', 'Show only selected'),
1288
1426
  className: 'buttons-show-selected',
1289
- action: function (e, dt, node, conf) {
1290
- // Works by having a filtering function which will reduce to the selected
1291
- // items only. So we can re-reference the function it gets stored in the
1292
- // `conf` object
1293
- if (conf._filter) {
1294
- var idx = DataTable.ext.search.indexOf(conf._filter);
1295
-
1296
- if (idx !== -1) {
1297
- DataTable.ext.search.splice(idx, 1);
1298
- conf._filter = null;
1299
- }
1427
+ action: function (e, dt) {
1428
+ if (dt.search.fixed('dt-select')) {
1429
+ // Remove existing function
1430
+ dt.search.fixed('dt-select', null);
1300
1431
 
1301
1432
  this.active(false);
1302
1433
  }
1303
1434
  else {
1304
- var fn = function (s, data, idx) {
1305
- // Need to be sure we are operating on our table!
1306
- if (s !== dt.settings()[0]) {
1307
- return true;
1308
- }
1309
-
1310
- let row = s.aoData[idx];
1311
-
1312
- return row._select_selected;
1313
- }
1435
+ // Use a fixed filtering function to match on selected rows
1436
+ // This needs to reference the internal aoData since that is
1437
+ // where Select stores its reference for the selected state
1438
+ var dataSrc = dt.settings()[0].aoData;
1314
1439
 
1315
- conf._filter = fn;
1316
- DataTable.ext.search.push(fn);
1440
+ dt.search.fixed('dt-select', function (text, data, idx) {
1441
+ // _select_selected is set by Select on the data object for the row
1442
+ return dataSrc[idx]._select_selected;
1443
+ });
1317
1444
 
1318
1445
  this.active(true);
1319
1446
  }
@@ -1321,27 +1448,94 @@ $.extend( DataTable.ext.buttons, {
1321
1448
  dt.draw();
1322
1449
  }
1323
1450
  }
1324
- } );
1451
+ });
1325
1452
 
1326
- $.each( [ 'Row', 'Column', 'Cell' ], function ( i, item ) {
1453
+ $.each(['Row', 'Column', 'Cell'], function (i, item) {
1327
1454
  var lc = item.toLowerCase();
1328
1455
 
1329
- DataTable.ext.buttons[ 'select'+item+'s' ] = {
1330
- text: i18n( 'select'+item+'s', 'Select '+lc+'s' ),
1331
- className: 'buttons-select-'+lc+'s',
1456
+ DataTable.ext.buttons['select' + item + 's'] = {
1457
+ text: i18n('select' + item + 's', 'Select ' + lc + 's'),
1458
+ className: 'buttons-select-' + lc + 's',
1332
1459
  action: function () {
1333
- this.select.items( lc );
1460
+ this.select.items(lc);
1334
1461
  },
1335
- init: function ( dt ) {
1462
+ init: function (dt) {
1336
1463
  var that = this;
1337
1464
 
1338
- dt.on( 'selectItems.dt.DT', function ( e, ctx, items ) {
1339
- that.active( items === lc );
1340
- } );
1465
+ dt.on('selectItems.dt.DT', function (e, ctx, items) {
1466
+ that.active(items === lc);
1467
+ });
1341
1468
  }
1342
1469
  };
1343
- } );
1470
+ });
1471
+
1472
+ DataTable.type('select-checkbox', {
1473
+ className: 'dt-select',
1474
+ detect: function (data) {
1475
+ // Rendering function will tell us if it is a checkbox type
1476
+ return data === 'select-checkbox' ? data : false;
1477
+ },
1478
+ order: {
1479
+ pre: function (d) {
1480
+ return d === 'X' ? -1 : 0;
1481
+ }
1482
+ }
1483
+ });
1484
+
1485
+ $.extend(true, DataTable.defaults.oLanguage, {
1486
+ select: {
1487
+ aria: {
1488
+ rowCheckbox: 'Select row'
1489
+ }
1490
+ }
1491
+ });
1492
+
1493
+ DataTable.render.select = function (valueProp, nameProp) {
1494
+ var valueFn = valueProp ? DataTable.util.get(valueProp) : null;
1495
+ var nameFn = nameProp ? DataTable.util.get(nameProp) : null;
1496
+
1497
+ return function (data, type, row, meta) {
1498
+ var dtRow = meta.settings.aoData[meta.row];
1499
+ var selected = dtRow._select_selected;
1500
+ var ariaLabel = meta.settings.oLanguage.select.aria.rowCheckbox;
1501
+
1502
+ if (type === 'display') {
1503
+ return $('<input>')
1504
+ .attr({
1505
+ 'aria-label': ariaLabel,
1506
+ class: 'dt-select-checkbox',
1507
+ name: nameFn ? nameFn(row) : null,
1508
+ type: 'checkbox',
1509
+ value: valueFn ? valueFn(row) : null,
1510
+ checked: selected
1511
+ })[0];
1512
+ }
1513
+ else if (type === 'type') {
1514
+ return 'select-checkbox';
1515
+ }
1516
+ else if (type === 'filter') {
1517
+ return '';
1518
+ }
1519
+
1520
+ return selected ? 'X' : '';
1521
+ }
1522
+ }
1344
1523
 
1524
+ // Legacy checkbox ordering
1525
+ DataTable.ext.order['select-checkbox'] = function (settings, col) {
1526
+ return this.api()
1527
+ .column(col, { order: 'index' })
1528
+ .nodes()
1529
+ .map(function (td) {
1530
+ if (settings._select.items === 'row') {
1531
+ return $(td).parent().hasClass(settings._select.className);
1532
+ }
1533
+ else if (settings._select.items === 'cell') {
1534
+ return $(td).hasClass(settings._select.className);
1535
+ }
1536
+ return false;
1537
+ });
1538
+ };
1345
1539
 
1346
1540
  $.fn.DataTable.select = DataTable.select;
1347
1541
 
@@ -1353,13 +1547,13 @@ $.fn.DataTable.select = DataTable.select;
1353
1547
  // this required that the table be in the document! If it isn't then something
1354
1548
  // needs to trigger this method unfortunately. The next major release of
1355
1549
  // DataTables will rework the events and address this.
1356
- $(document).on( 'preInit.dt.dtSelect', function (e, ctx) {
1357
- if ( e.namespace !== 'dt' ) {
1550
+ $(document).on('preInit.dt.dtSelect', function (e, ctx) {
1551
+ if (e.namespace !== 'dt') {
1358
1552
  return;
1359
1553
  }
1360
1554
 
1361
- DataTable.select.init( new DataTable.Api( ctx ) );
1362
- } );
1555
+ DataTable.select.init(new DataTable.Api(ctx));
1556
+ });
1363
1557
 
1364
1558
 
1365
1559
  return DataTable;