datatables.net-select 3.1.3 → 4.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,229 +1,199 @@
1
- /*! Select for DataTables 3.1.3
2
- * © SpryMedia Ltd - datatables.net/license/mit
1
+ /*! Select 4.0.0 for DataTables
2
+ * Copyright (c) SpryMedia Ltd - datatables.net/license
3
3
  */
4
4
 
5
- (function( factory ){
6
- if ( typeof define === 'function' && define.amd ) {
5
+ (function(factory){
6
+ if (typeof define === 'function' && define.amd) {
7
7
  // AMD
8
- define( ['jquery', 'datatables.net'], function ( $ ) {
9
- return factory( $, window, document );
10
- } );
8
+ define(['datatables.net'], function (dt) {
9
+ return factory(window, document, dt);
10
+ });
11
11
  }
12
- else if ( typeof exports === 'object' ) {
12
+ else if (typeof exports === 'object') {
13
13
  // CommonJS
14
- var jq = require('jquery');
15
- var cjsRequires = function (root, $) {
16
- if ( ! $.fn.dataTable ) {
17
- require('datatables.net')(root, $);
14
+ var cjsRequires = function (root) {
15
+ if (! root.DataTable) {
16
+ require('datatables.net')(root);
18
17
  }
19
18
  };
20
19
 
21
20
  if (typeof window === 'undefined') {
22
- module.exports = function (root, $) {
23
- if ( ! root ) {
21
+ module.exports = function (root) {
22
+ if (! root) {
24
23
  // CommonJS environments without a window global must pass a
25
24
  // root. This will give an error otherwise
26
25
  root = window;
27
26
  }
28
27
 
29
- if ( ! $ ) {
30
- $ = jq( root );
31
- }
32
-
33
- cjsRequires( root, $ );
34
- return factory( $, root, root.document );
28
+ cjsRequires(root);
29
+ return factory(root, root.document, root.DataTable);
35
30
  };
36
31
  }
37
32
  else {
38
- cjsRequires( window, jq );
39
- module.exports = factory( jq, window, window.document );
33
+ cjsRequires(window);
34
+ module.exports = factory(window, window.document, window.DataTable);
40
35
  }
41
36
  }
42
37
  else {
43
38
  // Browser
44
- factory( jQuery, window, document );
39
+ factory(window, document, window.DataTable);
45
40
  }
46
- }(function( $, window, document ) {
41
+ }(function(window, document, DataTable) {
47
42
  'use strict';
48
- var DataTable = $.fn.dataTable;
49
-
50
-
51
-
52
- // Version information for debugger
53
- DataTable.select = {};
54
-
55
- DataTable.select.classes = {
56
- checkbox: 'dt-select-checkbox'
57
- };
58
-
59
- DataTable.select.version = '3.1.3';
60
-
61
- DataTable.select.init = function (dt) {
62
- var ctx = dt.settings()[0];
63
-
64
- if (!DataTable.versionCheck('2')) {
65
- throw 'Warning: Select requires DataTables 2 or newer';
66
- }
67
-
68
- if (ctx._select) {
69
- return;
70
- }
71
-
72
- var savedSelected = dt.state.loaded();
73
-
74
- var selectAndSave = function (e, settings, data) {
75
- if (data === null || data.select === undefined) {
76
- return;
77
- }
78
-
79
- // Clear any currently selected rows, before restoring state
80
- // None will be selected on first initialisation
81
- if (dt.rows({ selected: true }).any()) {
82
- dt.rows().deselect();
83
- }
84
- if (data.select.rows !== undefined) {
85
- dt.rows(data.select.rows).select();
86
- }
87
-
88
- if (dt.columns({ selected: true }).any()) {
89
- dt.columns().deselect();
90
- }
91
- if (data.select.columns !== undefined) {
92
- dt.columns(data.select.columns).select();
93
- }
94
-
95
- if (dt.cells({ selected: true }).any()) {
96
- dt.cells().deselect();
97
- }
98
- if (data.select.cells !== undefined) {
99
- for (var i = 0; i < data.select.cells.length; i++) {
100
- dt.cell(data.select.cells[i].row, data.select.cells[i].column).select();
101
- }
102
- }
103
-
104
- dt.state.save();
105
- };
106
-
107
- dt.on('stateSaveParams', function (e, settings, data) {
108
- data.select = {};
109
- data.select.rows = dt.rows({ selected: true }).ids(true).toArray();
110
- data.select.columns = dt.columns({ selected: true })[0];
111
- data.select.cells = dt.cells({ selected: true })[0].map(function (coords) {
112
- return { row: dt.row(coords.row).id(true), column: coords.column };
113
- });
114
- })
115
- .on('stateLoadParams', selectAndSave)
116
- .one('init', function () {
117
- selectAndSave(undefined, undefined, savedSelected);
118
- });
119
-
120
- var init = ctx.oInit.select;
121
- var defaults = DataTable.defaults.select;
122
- var opts = init === undefined ? defaults : init;
123
43
 
124
- // Set defaults
125
- var items = 'row';
126
- var style = 'api';
127
- var blurable = false;
128
- var toggleable = true;
129
- var selectable = null;
130
- var info = true;
131
- var selector = 'td, th';
132
- var className = 'selected';
133
- var headerCheckbox = true;
134
- var setStyle = false;
135
- var keys = false;
136
- var keysWrap = false;
44
+ var Dom = DataTable.Dom;
45
+ var util = DataTable.util;
137
46
 
138
- ctx._select = {
139
- infoEls: []
140
- };
141
47
 
142
- // Initialisation customisations
143
- if (opts === true) {
144
- style = 'os';
145
- setStyle = true;
146
- }
147
- else if (typeof opts === 'string') {
148
- style = opts;
149
- setStyle = true;
150
- }
151
- else if ($.isPlainObject(opts)) {
152
- if (opts.blurable !== undefined) {
153
- blurable = opts.blurable;
154
- }
155
-
156
- if (opts.toggleable !== undefined) {
157
- toggleable = opts.toggleable;
158
- }
159
-
160
- if (opts.info !== undefined) {
161
- info = opts.info;
162
- }
163
-
164
- if (opts.items !== undefined) {
165
- items = opts.items;
166
- }
167
-
168
- if (opts.style !== undefined) {
169
- style = opts.style;
170
- setStyle = true;
171
- }
172
- else {
173
- style = 'os';
174
- setStyle = true;
175
- }
176
-
177
- if (opts.selector !== undefined) {
178
- selector = opts.selector;
179
- }
180
-
181
- if (opts.className !== undefined) {
182
- className = opts.className;
183
- }
184
-
185
- if (opts.headerCheckbox !== undefined) {
186
- headerCheckbox = opts.headerCheckbox;
187
- }
188
-
189
- if (opts.selectable !== undefined) {
190
- selectable = opts.selectable;
191
- }
192
-
193
- if (opts.keys !== undefined) {
194
- keys = opts.keys;
195
- }
196
-
197
- if (opts.keysWrap !== undefined) {
198
- keysWrap = opts.keysWrap;
199
- }
200
- }
201
-
202
- dt.select.selector(selector);
203
- dt.select.items(items);
204
- dt.select.style(style);
205
- dt.select.blurable(blurable);
206
- dt.select.toggleable(toggleable);
207
- dt.select.info(info);
208
- dt.select.keys(keys, keysWrap);
209
- dt.select.selectable(selectable);
210
- ctx._select.className = className;
211
-
212
- // If the init options haven't enabled select, but there is a selectable
213
- // class name, then enable
214
- if (!setStyle && $(dt.table().node()).hasClass('selectable')) {
215
- dt.select.style('os');
216
- }
217
-
218
- // Insert a checkbox into the header if needed - might need to wait
219
- // for init complete
220
- if (headerCheckbox || headerCheckbox === 'select-page' || headerCheckbox === 'select-all') {
221
- dt.ready(function () {
222
- initCheckboxHeader(dt, headerCheckbox);
223
- });
224
- }
48
+ if (!DataTable || !DataTable.versionCheck('3')) {
49
+ throw 'Error: Select requires DataTables 3 or newer';
50
+ }
51
+ DataTable.select = {
52
+ classes: {
53
+ checkbox: 'dt-select-checkbox'
54
+ },
55
+ init: function (dt) {
56
+ var ctx = dt.settings()[0];
57
+ if (ctx._select) {
58
+ return;
59
+ }
60
+ var selectAndSave = function (e, settings, data) {
61
+ if (data === null || data.select === undefined) {
62
+ return;
63
+ }
64
+ // Clear any currently selected rows, before restoring state
65
+ // None will be selected on first initialisation
66
+ if (dt.rows({ selected: true }).any()) {
67
+ dt.rows().deselect();
68
+ }
69
+ if (data.select.rows !== undefined) {
70
+ dt.rows(data.select.rows).select();
71
+ }
72
+ if (dt.columns({ selected: true }).any()) {
73
+ dt.columns().deselect();
74
+ }
75
+ if (data.select.columns !== undefined) {
76
+ dt.columns(data.select.columns).select();
77
+ }
78
+ if (dt.cells({ selected: true }).any()) {
79
+ dt.cells().deselect();
80
+ }
81
+ if (data.select.cells !== undefined) {
82
+ for (var i = 0; i < data.select.cells.length; i++) {
83
+ dt.cell(data.select.cells[i].row, data.select.cells[i].column).select();
84
+ }
85
+ }
86
+ dt.state.save();
87
+ };
88
+ dt.on('stateSaveParams', function (e, settings, data) {
89
+ data.select = {};
90
+ data.select.rows = dt.rows({ selected: true }).ids(true).toArray();
91
+ data.select.columns = dt.columns({ selected: true })[0];
92
+ data.select.cells = dt
93
+ .cells({ selected: true })[0]
94
+ .map(function (coords) {
95
+ return {
96
+ row: dt.row(coords.row).id(true),
97
+ column: coords.column
98
+ };
99
+ });
100
+ })
101
+ .on('stateLoadParams', selectAndSave)
102
+ .one('init', function () {
103
+ selectAndSave(undefined, undefined, dt.state.loaded());
104
+ });
105
+ var init = dt.init() ? dt.init().select : null;
106
+ var defaults = DataTable.defaults.select;
107
+ var opts = init === undefined ? defaults : init;
108
+ // Set defaults
109
+ var items = 'row';
110
+ var style = 'api';
111
+ var blurable = false;
112
+ var toggleable = true;
113
+ var selectable = null;
114
+ var info = true;
115
+ var selector = 'td, th';
116
+ var className = 'selected';
117
+ var headerCheckbox = true;
118
+ var setStyle = false;
119
+ var keys = false;
120
+ var keysWrap = false;
121
+ ctx._select = {
122
+ infoEls: []
123
+ };
124
+ // Initialisation customisations
125
+ if (opts === true) {
126
+ style = 'os';
127
+ setStyle = true;
128
+ }
129
+ else if (typeof opts === 'string') {
130
+ style = opts;
131
+ setStyle = true;
132
+ }
133
+ else if (util.is.plainObject(opts)) {
134
+ if (opts.blurable !== undefined) {
135
+ blurable = opts.blurable;
136
+ }
137
+ if (opts.toggleable !== undefined) {
138
+ toggleable = opts.toggleable;
139
+ }
140
+ if (opts.info !== undefined) {
141
+ info = opts.info;
142
+ }
143
+ if (opts.items !== undefined) {
144
+ items = opts.items;
145
+ }
146
+ if (opts.style !== undefined) {
147
+ style = opts.style;
148
+ setStyle = true;
149
+ }
150
+ else {
151
+ style = 'os';
152
+ setStyle = true;
153
+ }
154
+ if (opts.selector !== undefined) {
155
+ selector = opts.selector;
156
+ }
157
+ if (opts.className !== undefined) {
158
+ className = opts.className;
159
+ }
160
+ if (opts.headerCheckbox !== undefined) {
161
+ headerCheckbox = opts.headerCheckbox;
162
+ }
163
+ if (opts.selectable !== undefined) {
164
+ selectable = opts.selectable;
165
+ }
166
+ if (opts.keys !== undefined) {
167
+ keys = opts.keys;
168
+ }
169
+ if (opts.keysWrap !== undefined) {
170
+ keysWrap = opts.keysWrap;
171
+ }
172
+ }
173
+ dt.select.selector(selector);
174
+ dt.select.items(items);
175
+ dt.select.style(style);
176
+ dt.select.blurable(blurable);
177
+ dt.select.toggleable(toggleable);
178
+ dt.select.info(info);
179
+ dt.select.keys(keys, keysWrap);
180
+ dt.select.selectable(selectable);
181
+ ctx._select.className = className;
182
+ // If the init options haven't enabled select, but there is a selectable
183
+ // class name, then enable
184
+ if (!setStyle && Dom.s(dt.table().node()).classHas('selectable')) {
185
+ dt.select.style('os');
186
+ }
187
+ // Insert a checkbox into the header if needed - might need to wait
188
+ // for init complete
189
+ if (headerCheckbox) {
190
+ dt.ready(function () {
191
+ initCheckboxHeader(dt, headerCheckbox);
192
+ });
193
+ }
194
+ },
195
+ version: '4.0.0'
225
196
  };
226
-
227
197
  /*
228
198
 
229
199
  Select is a collection of API methods, event handlers, event emitters and
@@ -234,12 +204,12 @@ features, with an overview of how they are implemented:
234
204
  stored in:
235
205
 
236
206
  * rows: a `_select_selected` property which contains a boolean value of the
237
- DataTables' `aoData` object for each row
207
+ DataTables' `data` object for each row
238
208
  * columns: a `_select_selected` property which contains a boolean value of the
239
- DataTables' `aoColumns` object for each column
209
+ DataTables' `columns` object for each column
240
210
  * cells: a `_selected_cells` property which contains an array of boolean values
241
- of the `aoData` object for each row. The array is the same length as the
242
- columns array, with each element of it representing a cell.
211
+ of the `data` object for each row. The array is the same length as the columns
212
+ array, with each element of it representing a cell.
243
213
 
244
214
  This method of using boolean flags allows Select to operate when nodes have not
245
215
  been created for rows / cells (DataTables' defer rendering feature).
@@ -262,18 +232,18 @@ The `_select` object contains the following properties:
262
232
 
263
233
  ```
264
234
  {
265
- items:string - Can be `rows`, `columns` or `cells`. Defines what item
266
- will be selected if the user is allowed to activate row
267
- selection using the mouse.
268
- style:string - Can be `none`, `single`, `multi` or `os`. Defines the
269
- interaction style when selecting items
270
- blurable:boolean - If row selection can be cleared by clicking outside of
271
- the table
272
- toggleable:boolean - If row selection can be cancelled by repeated clicking
273
- on the row
274
- info:boolean - If the selection summary should be shown in the table
275
- information elements
276
- infoEls:element[] - List of HTML elements with info elements for a table
235
+ items:string - Can be `rows`, `columns` or `cells`. Defines what item
236
+ will be selected if the user is allowed to activate row
237
+ selection using the mouse.
238
+ style:string - Can be `none`, `single`, `multi` or `os`. Defines the
239
+ interaction style when selecting items
240
+ blurable:boolean - If row selection can be cleared by clicking outside of
241
+ the table
242
+ toggleable:boolean - If row selection can be cancelled by repeated clicking
243
+ on the row
244
+ info:boolean - If the selection summary should be shown in the table
245
+ information elements
246
+ infoEls:element[] - List of HTML elements with info elements for a table
277
247
  }
278
248
  ```
279
249
 
@@ -288,11 +258,9 @@ Clicking on items can be used to select items. This is done by a simple event
288
258
  handler that will select the items using the API methods.
289
259
 
290
260
  */
291
-
292
261
  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
293
262
  * Local functions
294
263
  */
295
-
296
264
  /**
297
265
  * Add one or more cells to the selection when shift clicking in OS selection
298
266
  * style cell selection.
@@ -302,598 +270,525 @@ handler that will select the items using the API methods.
302
270
  * click first in cell 1-1 and then shift click in 2-2 - cells 1-2 and 2-1
303
271
  * should also be selected (and not 1-3, 1-4. etc)
304
272
  *
305
- * @param {DataTable.Api} dt DataTable
306
- * @param {object} idx Cell index to select to
307
- * @param {object} last Cell index to select from
308
- * @private
273
+ * @param dt DataTable
274
+ * @param idx Cell index to select to
275
+ * @param last Cell index to select from
309
276
  */
310
277
  function cellRange(dt, idx, last) {
311
- var indexes;
312
- var columnIndexes;
313
- var rowIndexes;
314
- var selectColumns = function (start, end) {
315
- if (start > end) {
316
- var tmp = end;
317
- end = start;
318
- start = tmp;
319
- }
320
-
321
- var record = false;
322
- return dt
323
- .columns(':visible')
324
- .indexes()
325
- .filter(function (i) {
326
- if (i === start) {
327
- record = true;
328
- }
329
-
330
- if (i === end) {
331
- // not else if, as start might === end
332
- record = false;
333
- return true;
334
- }
335
-
336
- return record;
337
- });
338
- };
339
-
340
- var selectRows = function (start, end) {
341
- var indexes = dt.rows({ search: 'applied' }).indexes();
342
-
343
- // Which comes first - might need to swap
344
- if (indexes.indexOf(start) > indexes.indexOf(end)) {
345
- var tmp = end;
346
- end = start;
347
- start = tmp;
348
- }
349
-
350
- var record = false;
351
- return indexes.filter(function (i) {
352
- if (i === start) {
353
- record = true;
354
- }
355
-
356
- if (i === end) {
357
- record = false;
358
- return true;
359
- }
360
-
361
- return record;
362
- });
363
- };
364
-
365
- if (!dt.cells({ selected: true }).any() && !last) {
366
- // select from the top left cell to this one
367
- columnIndexes = selectColumns(0, idx.column);
368
- rowIndexes = selectRows(0, idx.row);
369
- }
370
- else {
371
- // Get column indexes between old and new
372
- columnIndexes = selectColumns(last.column, idx.column);
373
- rowIndexes = selectRows(last.row, idx.row);
374
- }
375
-
376
- indexes = dt.cells(rowIndexes, columnIndexes).flatten();
377
-
378
- if (!dt.cells(idx, { selected: true }).any()) {
379
- // Select range
380
- dt.cells(indexes).select();
381
- }
382
- else {
383
- // Deselect range
384
- dt.cells(indexes).deselect();
385
- }
278
+ var indexes;
279
+ var columnIndexes;
280
+ var rowIndexes;
281
+ var selectColumns = function (start, end) {
282
+ if (start > end) {
283
+ var tmp = end;
284
+ end = start;
285
+ start = tmp;
286
+ }
287
+ var record = false;
288
+ return dt
289
+ .columns(':visible')
290
+ .indexes()
291
+ .filter(function (i) {
292
+ if (i === start) {
293
+ record = true;
294
+ }
295
+ if (i === end) {
296
+ // not else if, as start might === end
297
+ record = false;
298
+ return true;
299
+ }
300
+ return record;
301
+ });
302
+ };
303
+ var selectRows = function (start, end) {
304
+ var indexes = dt.rows({ search: 'applied' }).indexes();
305
+ // Which comes first - might need to swap
306
+ if (indexes.indexOf(start) > indexes.indexOf(end)) {
307
+ var tmp = end;
308
+ end = start;
309
+ start = tmp;
310
+ }
311
+ var record = false;
312
+ return indexes.filter(function (i) {
313
+ if (i === start) {
314
+ record = true;
315
+ }
316
+ if (i === end) {
317
+ record = false;
318
+ return true;
319
+ }
320
+ return record;
321
+ });
322
+ };
323
+ if (!dt.cells({ selected: true }).any() && !last) {
324
+ // select from the top left cell to this one
325
+ columnIndexes = selectColumns(0, idx.column);
326
+ rowIndexes = selectRows(0, idx.row);
327
+ }
328
+ else {
329
+ // Get column indexes between old and new
330
+ columnIndexes = selectColumns(last.column, idx.column);
331
+ rowIndexes = selectRows(last.row, idx.row);
332
+ }
333
+ indexes = dt.cells(rowIndexes, columnIndexes).flatten();
334
+ if (!dt.cells(idx, { selected: true }).any()) {
335
+ // Select range
336
+ dt.cells(indexes).select();
337
+ }
338
+ else {
339
+ // Deselect range
340
+ dt.cells(indexes).deselect();
341
+ }
386
342
  }
387
-
388
343
  /**
389
- * Get the class
390
- * @returns
344
+ * Get a selector for the checkbox used
345
+ *
346
+ * @param asSelector Indicate if we want it as a selector, or as class names
347
+ * @returns Checkbox selector or class list
391
348
  */
392
- function checkboxClass(selector) {
393
- var name = DataTable.select.classes.checkbox;
394
-
395
- return selector
396
- ? name.replace(/ /g, '.')
397
- : name;
349
+ function checkboxClass(asSelector) {
350
+ var name = DataTable.select.classes.checkbox;
351
+ return asSelector ? name.replace(/ /g, '.') : name;
398
352
  }
399
-
400
353
  /**
401
354
  * Disable mouse selection by removing the selectors
402
355
  *
403
- * @param {DataTable.Api} dt DataTable to remove events from
404
- * @private
356
+ * @param dt DataTable to remove events from
405
357
  */
406
358
  function disableMouseSelection(dt) {
407
- var ctx = dt.settings()[0];
408
- var selector = ctx._select.selector;
409
-
410
- $(dt.table().container())
411
- .off('mousedown.dtSelect', selector)
412
- .off('mouseup.dtSelect', selector)
413
- .off('click.dtSelect', selector);
414
-
415
- $('body').off('click.dtSelect' + _safeId(dt.table().node()));
359
+ var ctx = dt.settings()[0];
360
+ var selector = ctx._select.selector;
361
+ Dom.s(dt.table().container())
362
+ .off('mousedown.dtSelect', selector)
363
+ .off('mouseup.dtSelect', selector)
364
+ .off('click.dtSelect', selector);
365
+ Dom.s('body').off('click.dtSelect' + _safeId(dt.table().node()));
416
366
  }
417
-
418
367
  /**
419
368
  * Attach mouse listeners to the table to allow mouse selection of items
420
369
  *
421
- * @param {DataTable.Api} dt DataTable to remove events from
422
- * @private
370
+ * @param dt DataTable to remove events from
423
371
  */
424
372
  function enableMouseSelection(dt) {
425
- var container = $(dt.table().container());
426
- var ctx = dt.settings()[0];
427
- var selector = ctx._select.selector;
428
- var matchSelection;
429
-
430
- container
431
- .on('mousedown.dtSelect', selector, function (e) {
432
- // Disallow text selection for shift clicking on the table so multi
433
- // element selection doesn't look terrible!
434
- if (e.shiftKey || e.metaKey || e.ctrlKey) {
435
- container
436
- .css('-moz-user-select', 'none')
437
- .one('selectstart.dtSelect', selector, function () {
438
- return false;
439
- });
440
- }
441
-
442
- if (window.getSelection) {
443
- matchSelection = window.getSelection();
444
- }
445
- })
446
- .on('mouseup.dtSelect', selector, function () {
447
- // Allow text selection to occur again, Mozilla style (tested in FF
448
- // 35.0.1 - still required)
449
- container.css('-moz-user-select', '');
450
- })
451
- .on('click.dtSelect', selector, function (e) {
452
- var items = dt.select.items();
453
- var idx;
454
-
455
- // If text was selected (click and drag), then we shouldn't change
456
- // the row's selected state
457
- if (matchSelection) {
458
- var selection = window.getSelection();
459
-
460
- // If the element that contains the selection is not in the table, we can ignore it
461
- // This can happen if the developer selects text from the click event
462
- if (
463
- !selection.anchorNode ||
464
- $(selection.anchorNode).closest('table')[0] === dt.table().node()
465
- ) {
466
- if (selection !== matchSelection) {
467
- return;
468
- }
469
- }
470
- }
471
-
472
- var ctx = dt.settings()[0];
473
- var container = dt.table().container();
474
-
475
- // Ignore clicks inside a sub-table
476
- if ($(e.target).closest('div.dt-container')[0] != container) {
477
- return;
478
- }
479
-
480
- var cell = dt.cell($(e.target).closest('td, th'));
481
-
482
- // Check the cell actually belongs to the host DataTable (so child
483
- // rows, etc, are ignored)
484
- if (!cell.any()) {
485
- return;
486
- }
487
-
488
- var event = $.Event('user-select.dt');
489
- eventTrigger(dt, event, [items, cell, e]);
490
-
491
- if (event.isDefaultPrevented()) {
492
- return;
493
- }
494
-
495
- var cellIndex = cell.index();
496
- if (items === 'row') {
497
- idx = cellIndex.row;
498
- typeSelect(e, dt, ctx, 'row', idx);
499
- }
500
- else if (items === 'column') {
501
- idx = cell.index().column;
502
- typeSelect(e, dt, ctx, 'column', idx);
503
- }
504
- else if (items === 'cell') {
505
- idx = cell.index();
506
- typeSelect(e, dt, ctx, 'cell', idx);
507
- }
508
-
509
- ctx._select_lastCell = cellIndex;
510
- });
511
-
512
- // Blurable
513
- $('body').on('click.dtSelect' + _safeId(dt.table().node()), function (e) {
514
- if (ctx._select.blurable) {
515
- // If the click was inside the DataTables container, don't blur
516
- if ($(e.target).parents().filter(dt.table().container()).length) {
517
- return;
518
- }
519
-
520
- // Ignore elements which have been removed from the DOM (i.e. paging
521
- // buttons)
522
- if ($(e.target).parents('html').length === 0) {
523
- return;
524
- }
525
-
526
- // Don't blur in Editor form
527
- if ($(e.target).parents('div.DTE').length) {
528
- return;
529
- }
530
-
531
- var event = $.Event('select-blur.dt');
532
- eventTrigger(dt, event, [e.target, e]);
533
-
534
- if (event.isDefaultPrevented()) {
535
- return;
536
- }
537
-
538
- clear(ctx, true);
539
- }
540
- });
373
+ var container = Dom.s(dt.table().container());
374
+ var ctx = dt.settings()[0];
375
+ var selector = ctx._select.selector;
376
+ var matchSelection;
377
+ container
378
+ .on('mousedown.dtSelect', selector, function (e) {
379
+ // Disallow text selection for shift clicking on the table so multi
380
+ // element selection doesn't look terrible!
381
+ if (e.shiftKey || e.metaKey || e.ctrlKey) {
382
+ container
383
+ .css('-moz-user-select', 'none')
384
+ .one('selectstart.dtSelect', selector, function () {
385
+ return false;
386
+ });
387
+ }
388
+ if (window.getSelection) {
389
+ matchSelection = window.getSelection();
390
+ }
391
+ })
392
+ .on('mouseup.dtSelect', selector, function () {
393
+ // Allow text selection to occur again, Mozilla style (tested in FF
394
+ // 35.0.1 - still required)
395
+ container.css('-moz-user-select', '');
396
+ })
397
+ .on('click.dtSelect', selector, function (e) {
398
+ var items = dt.select.items();
399
+ var idx;
400
+ // If text was selected (click and drag), then we shouldn't change
401
+ // the row's selected state
402
+ if (matchSelection) {
403
+ var selection = window.getSelection();
404
+ // If the element that contains the selection is not in the
405
+ // table, we can ignore it This can happen if the developer
406
+ // selects text from the click event
407
+ if (!selection.anchorNode ||
408
+ Dom.s(selection.anchorNode.parentNode)
409
+ .closest('table')
410
+ .get(0) === dt.table().node()) {
411
+ if (selection !== matchSelection) {
412
+ return;
413
+ }
414
+ }
415
+ }
416
+ var ctx = dt.settings()[0];
417
+ var container = dt.table().container();
418
+ // Ignore clicks inside a sub-table
419
+ if (Dom.s(e.target).closest('div.dt-container').get(0) != container) {
420
+ return;
421
+ }
422
+ var cell = dt.cell(Dom.s(e.target).closest('td, th').get(0));
423
+ // Check the cell actually belongs to the host DataTable (so child
424
+ // rows, etc, are ignored)
425
+ if (!cell.any()) {
426
+ return;
427
+ }
428
+ let res = eventTrigger(dt, 'user-select', [items, cell, e]);
429
+ if (res) {
430
+ return;
431
+ }
432
+ var cellIndex = cell.index();
433
+ if (items === 'row') {
434
+ idx = cellIndex.row;
435
+ typeSelect(e, dt, ctx, 'row', idx);
436
+ }
437
+ else if (items === 'column') {
438
+ idx = cell.index().column;
439
+ typeSelect(e, dt, ctx, 'column', idx);
440
+ }
441
+ else if (items === 'cell') {
442
+ idx = cell.index();
443
+ typeSelect(e, dt, ctx, 'cell', idx);
444
+ }
445
+ ctx._select_lastCell = cellIndex;
446
+ });
447
+ // Blurable
448
+ Dom.s('body').on('click.dtSelect' + _safeId(dt.table().node()), function (e) {
449
+ if (ctx._select.blurable) {
450
+ // If the click was inside the DataTables container, don't blur
451
+ if (Dom.s(e.target).closest(dt.table().container()).count()) {
452
+ return;
453
+ }
454
+ // Ignore elements which have been removed from the DOM (i.e.
455
+ // paging buttons)
456
+ if (Dom.s(e.target).closest('html').count() === 0) {
457
+ return;
458
+ }
459
+ // Don't blur in Editor form
460
+ if (Dom.s(e.target).closest('div.DTE').count()) {
461
+ return;
462
+ }
463
+ let res = eventTrigger(dt, 'select-blur', [e.target, e]);
464
+ if (res) {
465
+ return;
466
+ }
467
+ clear(ctx, true);
468
+ }
469
+ });
541
470
  }
542
-
543
471
  /**
544
472
  * Trigger an event on a DataTable
545
473
  *
546
- * @param {DataTable.Api} api DataTable to trigger events on
547
- * @param {boolean} selected true if selected, false if deselected
548
- * @param {string} type Item type acting on
549
- * @param {boolean} any Require that there are values before
550
- * triggering
551
- * @private
474
+ * @param api DataTable to trigger events on
475
+ * @param selected true if selected, false if deselected
476
+ * @param type Item type acting on
477
+ * @param any Require that there are values before triggering
478
+ * @returns `true` if the default action was prevented (i.e. execution should
479
+ * stop there)
552
480
  */
553
481
  function eventTrigger(api, type, args, any) {
554
- if (any && !api.flatten().length) {
555
- return;
556
- }
557
-
558
- if (typeof type === 'string') {
559
- type = type + '.dt';
560
- }
561
-
562
- args.unshift(api);
563
-
564
- $(api.table().node()).trigger(type, args);
482
+ if (any && !api.flatten().length) {
483
+ return;
484
+ }
485
+ if (typeof type === 'string') {
486
+ type = type + '.dt';
487
+ }
488
+ args.unshift(api);
489
+ let ev = Dom.s(api.table().node()).trigger(type, true, args);
490
+ return ev.includes(false);
565
491
  }
566
-
567
492
  /**
568
493
  * Determine if a column is a checkbox column
569
- * @param {*} col DataTables column object
570
- * @returns
494
+ *
495
+ * @param col DataTables column object
496
+ * @returns Boolean indicating if it is a checkbox column
571
497
  */
572
498
  function isCheckboxColumn(col) {
573
- return col.mRender && col.mRender._name === 'selectCheckbox';
499
+ return col.render && col.render._name === 'selectCheckbox';
574
500
  }
575
-
576
501
  /**
577
502
  * Update the information element of the DataTable showing information about the
578
503
  * items selected. This is done by adding tags to the existing text
579
504
  *
580
- * @param {DataTable.Api} api DataTable to update
581
- * @private
505
+ * @param api DataTable to update
582
506
  */
583
507
  function info(api, node) {
584
- if (api.select.style() === 'api' || api.select.info() === false) {
585
- return;
586
- }
587
-
588
- var ctx = api.settings()[0];
589
- var rowSet = ctx._select_set;
590
-
591
- // Check that the ids are still in ctx.aIds - row might have been deleted before it was
592
- // unselected
593
- if (! api.page.info().serverSide) {
594
- for (var i=rowSet.length-1 ; i>=0 ; i--) {
595
- if (! ctx.aIds[rowSet[i]]) {
596
- rowSet.splice(i, 1);
597
- }
598
- }
599
- }
600
-
601
- var rows = rowSet.length ? rowSet.length : api.rows({ selected: true }).count();
602
- var columns = api.columns({ selected: true }).count();
603
- var cells = api.cells({ selected: true }).count();
604
-
605
- // If subtractive selection, then we need to take the number of rows and
606
- // subtract those that have been deselected
607
- if (ctx._select_mode === 'subtractive') {
608
- rows = api.page.info().recordsDisplay - rowSet.length;
609
- }
610
-
611
- var add = function (el, name, num) {
612
- el.append(
613
- $('<span class="select-item"/>').append(
614
- api.i18n(
615
- 'select.' + name + 's',
616
- { _: '%d ' + name + 's selected', 0: '', 1: '1 ' + name + ' selected' },
617
- num
618
- )
619
- )
620
- );
621
- };
622
-
623
- var el = $(node);
624
- var output = $('<span class="select-info"/>');
625
-
626
- add(output, 'row', rows);
627
- add(output, 'column', columns);
628
- add(output, 'cell', cells);
629
-
630
- var existing = el.children('span.select-info');
631
-
632
- if (existing.length) {
633
- existing.remove();
634
- }
635
-
636
- if (output.text() !== '') {
637
- el.append(output);
638
- }
508
+ if (api.select.style() === 'api' || api.select.info() === false) {
509
+ return;
510
+ }
511
+ var ctx = api.settings()[0];
512
+ var rowSet = ctx._select_set;
513
+ // Check that the ids are still in ctx.ids - row might have been deleted
514
+ // before it was unselected
515
+ if (!api.page.info().serverSide) {
516
+ for (var i = rowSet.length - 1; i >= 0; i--) {
517
+ if (!ctx.ids[rowSet[i]]) {
518
+ rowSet.splice(i, 1);
519
+ }
520
+ }
521
+ }
522
+ var rows = rowSet.length
523
+ ? rowSet.length
524
+ : api.rows({ selected: true }).count();
525
+ var columns = api.columns({ selected: true }).count();
526
+ var cells = api.cells({ selected: true }).count();
527
+ // If subtractive selection, then we need to take the number of rows and
528
+ // subtract those that have been deselected
529
+ if (ctx._select_mode === 'subtractive') {
530
+ rows = api.page.info().recordsDisplay - rowSet.length;
531
+ }
532
+ var add = function (el, name, num) {
533
+ el.append(Dom.c('span')
534
+ .classAdd('select-item')
535
+ .text(api.i18n('select.' + name + 's', {
536
+ _: '%d ' + name + 's selected',
537
+ 0: '',
538
+ 1: '1 ' + name + ' selected'
539
+ }, num)));
540
+ };
541
+ var el = Dom.s(node);
542
+ var output = Dom.c('span').classAdd('select-info');
543
+ add(output, 'row', rows);
544
+ add(output, 'column', columns);
545
+ add(output, 'cell', cells);
546
+ var existing = el.children('span.select-info');
547
+ if (existing.count()) {
548
+ existing.remove();
549
+ }
550
+ if (output.text() !== '') {
551
+ el.append(output);
552
+ }
639
553
  }
640
-
641
554
  /**
642
555
  * Add a checkbox to the header for checkbox columns, allowing all rows to
643
556
  * be selected, deselected or just to show the state.
644
557
  *
645
- * @param {*} dt API
646
- * @param {*} headerCheckbox the header checkbox option
558
+ * @param dt API
559
+ * @param headerCheckbox the header checkbox option
647
560
  */
648
- function initCheckboxHeader( dt, headerCheckbox ) {
649
- var dtSettings = dt.settings()[0];
650
- var dtInternalColumns = dtSettings.aoColumns;
651
-
652
- // Find any checkbox column(s)
653
- dt.columns().iterator('column', function (s, idx) {
654
- var col = dtInternalColumns[idx];
655
-
656
- // Checkbox columns have a rendering function with a given name
657
- if (! isCheckboxColumn(col)) {
658
- return;
659
- }
660
-
661
- var header = dt.column(idx).header();
662
- var liner = $('div.dt-column-header', header);
663
-
664
- // DataTables 2.3 as an extra wrapper element
665
- if (liner.length) {
666
- header = liner;
667
- }
668
-
669
- if (! $('input', header).length) {
670
- // If no checkbox yet, insert one
671
- var input = $('<input>')
672
- .attr({
673
- class: checkboxClass(false),
674
- type: 'checkbox',
675
- 'aria-label': dt.i18n('select.aria.headerCheckbox') || 'Select all rows'
676
- })
677
- .appendTo(header)
678
- .on('change', function () {
679
- if (this.checked) {
680
- if (headerCheckbox == 'select-page') {
681
- dt.rows({page: 'current'}).select();
682
- }
683
- else {
684
- dt.rows({search: 'applied'}).select();
685
- }
686
- }
687
- else {
688
- if (headerCheckbox == 'select-page') {
689
- dt.rows({page: 'current', selected: true}).deselect();
690
- }
691
- else {
692
- dt.rows({selected: true}).deselect();
693
- }
694
- }
695
- })
696
- .on('click', function (e) {
697
- e.stopPropagation();
698
- });
699
-
700
- // Update the header checkbox's state when the selection in the
701
- // table changes
702
- dt.on('draw select deselect', function (e, pass, type) {
703
- if (type === 'row' || ! type) {
704
- var nums = headerCheckboxState(dt, headerCheckbox);
705
-
706
- if (nums.search && nums.search <= nums.count && nums.search === nums.available) {
707
- input
708
- .prop('checked', true)
709
- .prop('indeterminate', false);
710
- }
711
- else if (nums.search === 0 && nums.count === 0) {
712
- input
713
- .prop('checked', false)
714
- .prop('indeterminate', false);
715
- }
716
- else {
717
- input
718
- .prop('checked', false)
719
- .prop('indeterminate', true);
720
- }
721
- }
722
- });
723
- }
724
- });
561
+ function initCheckboxHeader(dt, headerCheckbox) {
562
+ var dtSettings = dt.settings()[0];
563
+ var dtInternalColumns = dtSettings.columns;
564
+ // Find any checkbox column(s)
565
+ dt.columns().iterator('column', function (s, idx) {
566
+ var col = dtInternalColumns[idx];
567
+ // Checkbox columns have a rendering function with a given name
568
+ if (!isCheckboxColumn(col)) {
569
+ return;
570
+ }
571
+ var header = Dom.s(dt.column(idx).header());
572
+ var liner = header.find('div.dt-column-header');
573
+ if (liner.count()) {
574
+ header = liner;
575
+ }
576
+ if (!header.find('input').count()) {
577
+ // If no checkbox yet, insert one
578
+ var input = Dom.c('input')
579
+ .attr({
580
+ class: checkboxClass(false),
581
+ type: 'checkbox',
582
+ 'aria-label': dt.i18n('select.aria.headerCheckbox', 'Select all rows')
583
+ })
584
+ .appendTo(header)
585
+ .on('change', function () {
586
+ if (input.prop('checked')) {
587
+ if (headerCheckbox == 'select-page') {
588
+ dt.rows({ page: 'current' }).select();
589
+ }
590
+ else {
591
+ dt.rows({ search: 'applied' }).select();
592
+ }
593
+ }
594
+ else {
595
+ if (headerCheckbox == 'select-page') {
596
+ dt.rows({
597
+ page: 'current',
598
+ selected: true
599
+ }).deselect();
600
+ }
601
+ else {
602
+ dt.rows({ selected: true }).deselect();
603
+ }
604
+ }
605
+ })
606
+ .on('click', function (e) {
607
+ e.stopPropagation();
608
+ });
609
+ // Update the header checkbox's state when the selection in the
610
+ // table changes
611
+ dt.on('draw select deselect', function (e, pass, type) {
612
+ if (type === 'row' || !type) {
613
+ var nums = headerCheckboxState(dt, headerCheckbox);
614
+ if (nums.search &&
615
+ nums.search <= nums.count &&
616
+ nums.search === nums.available) {
617
+ input
618
+ .prop('checked', true)
619
+ .prop('indeterminate', false);
620
+ }
621
+ else if (nums.search === 0 && nums.count === 0) {
622
+ input
623
+ .prop('checked', false)
624
+ .prop('indeterminate', false);
625
+ }
626
+ else {
627
+ input
628
+ .prop('checked', false)
629
+ .prop('indeterminate', true);
630
+ }
631
+ }
632
+ });
633
+ }
634
+ });
725
635
  }
726
-
727
636
  function keysSet(dt) {
728
- var ctx = dt.settings()[0];
729
- var flag = ctx._select.keys;
730
- var wrap = ctx._select.keysWrap;
731
- var namespace = 'dts-keys-' + ctx.sTableId;
732
-
733
- if (flag) {
734
- // Need a tabindex of the `tr` elements to make them focusable by the browser
735
- $(dt.rows({page: 'current'}).nodes()).attr('tabindex', 0);
736
-
737
- dt.on('draw.' + namespace, function () {
738
- $(dt.rows({page: 'current'}).nodes()).attr('tabindex', 0);
739
- });
740
-
741
- // Listen on document for tab, up and down
742
- $(document).on('keydown.' + namespace, function (e) {
743
- var key = e.keyCode;
744
- var active = document.activeElement;
745
-
746
- // Can't use e.key as it wasn't widely supported until 2017
747
- // 9 Tab
748
- // 13 Return
749
- // 32 Space
750
- // 38 ArrowUp
751
- // 40 ArrowDown
752
- if (! [9, 13, 32, 38, 40].includes(key)) {
753
- return;
754
- }
755
-
756
- var nodes = dt.rows({page: 'current'}).nodes().toArray();
757
- var idx = nodes.indexOf(active);
758
- var preventDefault = true;
759
- var pageInfo = dt.page.info();
760
-
761
- // Only take an action if a row has focus
762
- if (idx === -1) {
763
- return;
764
- }
765
-
766
- if (key === 9) {
767
- // Tab focus change
768
- if (e.shift === false && idx === nodes.length - 1) {
769
- keysPageChange(dt, 'next', ':first-child');
770
- }
771
- else if (e.shift === true && idx === 0) {
772
- keysPageChange(dt, 'previous', ':last-child');
773
- }
774
- else {
775
- // Browser will do it for us
776
- preventDefault = false;
777
- }
778
- }
779
- else if (key === 13 || key === 32) {
780
- // Row selection / deselection
781
- var row = dt.row(active);
782
-
783
- if (row.selected()) {
784
- row.deselect();
785
- }
786
- else {
787
- row.select();
788
- }
789
- }
790
- else if (key === 38) {
791
- // Move up
792
- if (idx > 0) {
793
- nodes[idx-1].focus();
794
- }
795
- else if (pageInfo.start > 0) {
796
- // Shift back to the previous page
797
- keysPageChange(dt, 'previous', ':last-child');
798
- }
799
- else if (wrap) {
800
- // Wrap
801
- keysPageChange(dt, 'last', ':last-child');
802
- }
803
- }
804
- else {
805
- // Move down
806
- if (idx < nodes.length -1) {
807
- nodes[idx+1].focus();
808
- }
809
- else if (pageInfo.page < pageInfo.pages-1) {
810
- // Move on to the next page
811
- keysPageChange(dt, 'next', ':first-child');
812
- }
813
- else if (wrap) {
814
- // Wrap
815
- keysPageChange(dt, 'first', ':first-child');
816
- }
817
- }
818
-
819
- if (preventDefault) {
820
- e.stopPropagation();
821
- e.preventDefault();
822
- }
823
- });
824
- }
825
- else {
826
- // Stop the rows from being able to gain focus
827
- $(dt.rows().nodes()).removeAttr('tabindex');
828
-
829
- // Nuke events
830
- dt.off('draw.' + namespace);
831
- $(document).off('keydown.' + namespace);
832
- }
637
+ var ctx = dt.settings()[0];
638
+ var flag = ctx._select.keys;
639
+ var wrap = ctx._select.keysWrap;
640
+ var namespace = 'dts-keys-' + ctx.tableId;
641
+ if (flag) {
642
+ // Need a tabindex of the `tr` elements to make them focusable by the
643
+ // browser
644
+ Dom.s(dt.rows({ page: 'current' }).nodes().toArray()).attr('tabindex', 0);
645
+ dt.on('draw.' + namespace, function () {
646
+ Dom.s(dt.rows({ page: 'current' }).nodes().toArray()).attr('tabindex', 0);
647
+ });
648
+ // Listen on document for tab, up and down
649
+ Dom.s(document).on('keydown.' + namespace, function (e) {
650
+ var key = e.keyCode;
651
+ var active = document.activeElement;
652
+ // Can't use e.key as it wasn't widely supported until 2017
653
+ // 9 Tab
654
+ // 13 Return
655
+ // 32 Space
656
+ // 38 ArrowUp
657
+ // 40 ArrowDown
658
+ if (![9, 13, 32, 38, 40].includes(key)) {
659
+ return;
660
+ }
661
+ var nodes = dt.rows({ page: 'current' }).nodes().toArray();
662
+ var idx = nodes.indexOf(active);
663
+ var preventDefault = true;
664
+ var pageInfo = dt.page.info();
665
+ // Only take an action if a row has focus
666
+ if (idx === -1) {
667
+ return;
668
+ }
669
+ if (key === 9) {
670
+ // Tab focus change
671
+ if (e.shift === false && idx === nodes.length - 1) {
672
+ keysPageChange(dt, 'next', ':first-child');
673
+ }
674
+ else if (e.shift === true && idx === 0) {
675
+ keysPageChange(dt, 'previous', ':last-child');
676
+ }
677
+ else {
678
+ // Browser will do it for us
679
+ preventDefault = false;
680
+ }
681
+ }
682
+ else if (key === 13 || key === 32) {
683
+ // Row selection / deselection
684
+ var row = dt.row(active);
685
+ if (row.selected()) {
686
+ row.deselect();
687
+ }
688
+ else {
689
+ row.select();
690
+ }
691
+ }
692
+ else if (key === 38) {
693
+ // Move up
694
+ if (idx > 0) {
695
+ nodes[idx - 1].focus();
696
+ }
697
+ else if (pageInfo.start > 0) {
698
+ // Shift back to the previous page
699
+ keysPageChange(dt, 'previous', ':last-child');
700
+ }
701
+ else if (wrap) {
702
+ // Wrap
703
+ keysPageChange(dt, 'last', ':last-child');
704
+ }
705
+ }
706
+ else {
707
+ // Move down
708
+ if (idx < nodes.length - 1) {
709
+ nodes[idx + 1].focus();
710
+ }
711
+ else if (pageInfo.page < pageInfo.pages - 1) {
712
+ // Move on to the next page
713
+ keysPageChange(dt, 'next', ':first-child');
714
+ }
715
+ else if (wrap) {
716
+ // Wrap
717
+ keysPageChange(dt, 'first', ':first-child');
718
+ }
719
+ }
720
+ if (preventDefault) {
721
+ e.stopPropagation();
722
+ e.preventDefault();
723
+ }
724
+ });
725
+ }
726
+ else {
727
+ // Stop the rows from being able to gain focus
728
+ Dom.s(dt.rows().nodes().toArray()).attrRemove('tabindex');
729
+ // Nuke events
730
+ dt.off('draw.' + namespace);
731
+ Dom.s(document).off('keydown.' + namespace);
732
+ }
833
733
  }
834
-
835
734
  /**
836
735
  * Change change to a new page and focus
837
736
  *
838
- * @param {DataTable.Api} dt DataTable instance
737
+ * @param dt DataTable instance
738
+ * @param page Which page to change to
739
+ * @param focus Which row to focus on
839
740
  */
840
741
  function keysPageChange(dt, page, focus) {
841
- dt
842
- .one('draw', function () {
843
- dt.row(focus).node().focus();
844
- })
845
- .page(page)
846
- .draw(false);
742
+ dt.one('draw', function () {
743
+ dt.row(focus).node().focus();
744
+ })
745
+ .page(page)
746
+ .draw(false);
847
747
  }
848
-
849
748
  /**
850
749
  * Determine the counts used to define the header checkbox's state
851
750
  *
852
- * @param {*} dt DT API
853
- * @param {*} headerCheckbox Configuration for what the header checkbox does
751
+ * @param dt DT API
752
+ * @param headerCheckbox Configuration for what the header checkbox does
854
753
  * @returns Counts object
855
754
  */
856
755
  function headerCheckboxState(dt, headerCheckbox) {
857
- var ctx = dt.settings()[0];
858
- var selectable = ctx._select.selectable;
859
- var available = 0;
860
- var count = headerCheckbox == 'select-page'
861
- ? dt.rows({page: 'current', selected: true}).count()
862
- : dt.rows({selected: true}).count();
863
- var search = headerCheckbox == 'select-page'
864
- ? dt.rows({page: 'current', selected: true}).count()
865
- : dt.rows({search: 'applied', selected: true}).count();
866
-
867
- if (! selectable) {
868
- available = headerCheckbox == 'select-page'
869
- ? dt.rows({page: 'current'}).count()
870
- : dt.rows({search: 'applied'}).count();
871
- }
872
- else {
873
- // Need to count how many rows are actually selectable to know if all selectable
874
- // rows are selected or not
875
- var indexes = headerCheckbox == 'select-page'
876
- ? dt.rows({page: 'current'}).indexes()
877
- : dt.rows({search: 'applied'}).indexes();
878
-
879
- for (var i=0 ; i<indexes.length ; i++) {
880
- // For speed I use the internal DataTables object.
881
- var rowInternal = ctx.aoData[indexes[i]];
882
- var result = selectable(rowInternal._aData, rowInternal.nTr, indexes[i]);
883
-
884
- if (result) {
885
- available++;
886
- }
887
- }
888
- }
889
-
890
- return {
891
- available: available,
892
- count: count,
893
- search: search
894
- }
756
+ var ctx = dt.settings()[0];
757
+ var selectable = ctx._select.selectable;
758
+ var available = 0;
759
+ var count = headerCheckbox == 'select-page'
760
+ ? dt.rows({ page: 'current', selected: true }).count()
761
+ : dt.rows({ selected: true }).count();
762
+ var search = headerCheckbox == 'select-page'
763
+ ? dt.rows({ page: 'current', selected: true }).count()
764
+ : dt.rows({ search: 'applied', selected: true }).count();
765
+ if (!selectable) {
766
+ available =
767
+ headerCheckbox == 'select-page'
768
+ ? dt.rows({ page: 'current' }).count()
769
+ : dt.rows({ search: 'applied' }).count();
770
+ }
771
+ else {
772
+ // Need to count how many rows are actually selectable to know if all
773
+ // selectable rows are selected or not
774
+ var indexes = headerCheckbox == 'select-page'
775
+ ? dt.rows({ page: 'current' }).indexes().toArray()
776
+ : dt.rows({ search: 'applied' }).indexes().toArray();
777
+ for (var i = 0; i < indexes.length; i++) {
778
+ // For speed I use the internal DataTables object.
779
+ var rowInternal = ctx.data[indexes[i]];
780
+ var result = selectable(rowInternal.data, rowInternal.tr, indexes[i]);
781
+ if (result) {
782
+ available++;
783
+ }
784
+ }
785
+ }
786
+ return {
787
+ available: available,
788
+ count: count,
789
+ search: search
790
+ };
895
791
  }
896
-
897
792
  /**
898
793
  * Initialisation of a new table. Attach event handlers and callbacks to allow
899
794
  * Select to operate correctly.
@@ -901,1130 +796,934 @@ function headerCheckboxState(dt, headerCheckbox) {
901
796
  * This will occur _after_ the initial DataTables initialisation, although
902
797
  * before Ajax data is rendered, if there is ajax data
903
798
  *
904
- * @param {DataTable.settings} ctx Settings object to operate on
905
- * @private
799
+ * @param ctx Settings object to operate on
906
800
  */
907
801
  function init(ctx) {
908
- var api = new DataTable.Api(ctx);
909
- ctx._select_init = true;
910
-
911
- // When `additive` then `_select_set` contains a list of the row ids that
912
- // are selected. If `subtractive` then all rows are selected, except those
913
- // in `_select_set`, which is a list of ids.
914
- ctx._select_mode = 'additive';
915
- ctx._select_set = [];
916
-
917
- // Row callback so that classes can be added to rows and cells if the item
918
- // was selected before the element was created. This will happen with the
919
- // `deferRender` option enabled.
920
- //
921
- // This method of attaching to `aoRowCreatedCallback` is a hack until
922
- // DataTables has proper events for row manipulation If you are reviewing
923
- // this code to create your own plug-ins, please do not do this!
924
- ctx.aoRowCreatedCallback.push(function (row, data, index) {
925
- var i, ien;
926
- var d = ctx.aoData[index];
927
- var id = api.row(index).id();
928
-
929
- // Row
930
- if (
931
- d._select_selected ||
932
- (ctx._select_mode === 'additive' && ctx._select_set.includes(id)) ||
933
- (ctx._select_mode === 'subtractive' && ! ctx._select_set.includes(id))
934
- ) {
935
- d._select_selected = true;
936
-
937
- $(row)
938
- .addClass(ctx._select.className)
939
- .find('input.' + checkboxClass(true)).prop('checked', true);
940
- }
941
-
942
- // Cells and columns - if separated out, we would need to do two
943
- // loops, so it makes sense to combine them into a single one
944
- for (i = 0, ien = ctx.aoColumns.length; i < ien; i++) {
945
- if (
946
- ctx.aoColumns[i]._select_selected ||
947
- (d._selected_cells && d._selected_cells[i])
948
- ) {
949
- $(d.anCells[i]).addClass(ctx._select.className)
950
- }
951
- }
952
- }
953
- );
954
-
955
- _cumulativeEvents(api);
956
-
957
- // Update the table information element with selected item summary
958
- api.on('info.dt', function (e, ctx, node) {
959
- // Store the info node for updating on select / deselect
960
- if (!ctx._select.infoEls.includes(node)) {
961
- ctx._select.infoEls.push(node);
962
- }
963
-
964
- info(api, node);
965
- });
966
-
967
- api.on('select.dtSelect.dt deselect.dtSelect.dt', function () {
968
- ctx._select.infoEls.forEach(function (el) {
969
- info(api, el);
970
- });
971
-
972
- api.state.save();
973
- });
974
-
975
- // Clean up and release
976
- api.on('destroy.dtSelect', function () {
977
- // Remove class directly rather than calling deselect - which would trigger events
978
- $(api.rows({ selected: true }).nodes()).removeClass(api.settings()[0]._select.className);
979
-
980
- $('input.' + checkboxClass(true), api.table().header()).remove();
981
-
982
- disableMouseSelection(api);
983
- api.off('.dtSelect');
984
- $('body').off('.dtSelect' + _safeId(api.table().node()));
985
- });
802
+ var api = new DataTable.Api(ctx);
803
+ ctx._select_init = true;
804
+ // When `additive` then `_select_set` contains a list of the row ids that
805
+ // are selected. If `subtractive` then all rows are selected, except those
806
+ // in `_select_set`, which is a list of ids.
807
+ ctx._select_mode = 'additive';
808
+ ctx._select_set = [];
809
+ // Row callback so that classes can be added to rows and cells if the item
810
+ // was selected before the element was created. This will happen with the
811
+ // `deferRender` option enabled.
812
+ //
813
+ // This method of attaching to `aoRowCreatedCallback` is a hack until
814
+ // DataTables has proper events for row manipulation If you are reviewing
815
+ // this code to create your own plug-ins, please do not do this!
816
+ ctx.callbacks.rowCreated.push(function (row, data, index) {
817
+ var i, ien;
818
+ var d = ctx.data[index];
819
+ var id = api.row(index).id();
820
+ // Row
821
+ if (d._select_selected ||
822
+ (ctx._select_mode === 'additive' && ctx._select_set.includes(id)) ||
823
+ (ctx._select_mode === 'subtractive' &&
824
+ !ctx._select_set.includes(id))) {
825
+ d._select_selected = true;
826
+ Dom.s(row)
827
+ .classAdd(ctx._select.className)
828
+ .find('input.' + checkboxClass(true))
829
+ .prop('checked', true);
830
+ }
831
+ // Cells and columns - if separated out, we would need to do two
832
+ // loops, so it makes sense to combine them into a single one
833
+ for (i = 0, ien = ctx.columns.length; i < ien; i++) {
834
+ if (ctx.columns[i]._select_selected ||
835
+ (d._selected_cells && d._selected_cells[i])) {
836
+ Dom.s(d.cells[i]).classAdd(ctx._select.className);
837
+ }
838
+ }
839
+ });
840
+ _cumulativeEvents(api);
841
+ // Update the table information element with selected item summary
842
+ api.on('info.dt', function (e, ctx, node) {
843
+ // Store the info node for updating on select / deselect
844
+ if (!ctx._select.infoEls.includes(node)) {
845
+ ctx._select.infoEls.push(node);
846
+ }
847
+ info(api, node);
848
+ });
849
+ api.on('select.dtSelect.dt deselect.dtSelect.dt', function () {
850
+ ctx._select.infoEls.forEach(function (el) {
851
+ info(api, el);
852
+ });
853
+ api.state.save();
854
+ });
855
+ // Clean up and release
856
+ api.on('destroy.dtSelect', function () {
857
+ // Remove class directly rather than calling deselect - which would
858
+ // trigger events
859
+ Dom.s(api.rows({ selected: true }).nodes().toArray()).classRemove(api.settings()[0]._select.className);
860
+ Dom.s(api.table().header())
861
+ .find('input.' + checkboxClass(true))
862
+ .remove();
863
+ disableMouseSelection(api);
864
+ api.off('.dtSelect');
865
+ Dom.s('body').off('.dtSelect' + _safeId(api.table().node()));
866
+ });
986
867
  }
987
-
988
868
  /**
989
869
  * Add one or more items (rows or columns) to the selection when shift clicking
990
870
  * in OS selection style
991
871
  *
992
- * @param {DataTable.Api} dt DataTable
993
- * @param {string} type Row or column range selector
994
- * @param {object} idx Item index to select to
995
- * @param {object} last Item index to select from
996
- * @private
872
+ * @param dt DataTable
873
+ * @param type Row or column range selector
874
+ * @param idx Item index to select to
875
+ * @param last Item index to select from
997
876
  */
998
877
  function rowColumnRange(dt, type, idx, last) {
999
- // Add a range of rows from the last selected row to this one
1000
- var indexes = dt[type + 's']({ search: 'applied' }).indexes();
1001
- var idx1 = indexes.indexOf(last);
1002
- var idx2 = indexes.indexOf(idx);
1003
-
1004
- if (!dt[type + 's']({ selected: true }).any() && idx1 === -1) {
1005
- // select from top to here - slightly odd, but both Windows and Mac OS
1006
- // do this
1007
- indexes.splice(indexes.indexOf(idx) + 1, indexes.length);
1008
- }
1009
- else {
1010
- // reverse so we can shift click 'up' as well as down
1011
- if (idx1 > idx2) {
1012
- var tmp = idx2;
1013
- idx2 = idx1;
1014
- idx1 = tmp;
1015
- }
1016
-
1017
- indexes.splice(idx2 + 1, indexes.length);
1018
- indexes.splice(0, idx1);
1019
- }
1020
-
1021
- if (!dt[type](idx, { selected: true }).any()) {
1022
- // Select range
1023
- dt[type + 's'](indexes).select();
1024
- }
1025
- else {
1026
- // Deselect range - need to keep the clicked on row selected
1027
- indexes.splice(indexes.indexOf(idx), 1);
1028
- dt[type + 's'](indexes).deselect();
1029
- }
878
+ // Add a range of rows from the last selected row to this one
879
+ var indexes = dt[type + 's']({ search: 'applied' }).indexes();
880
+ var idx1 = indexes.indexOf(last);
881
+ var idx2 = indexes.indexOf(idx);
882
+ if (!dt[type + 's']({ selected: true }).any() && idx1 === -1) {
883
+ // select from top to here - slightly odd, but both Windows and Mac OS
884
+ // do this
885
+ indexes.splice(indexes.indexOf(idx) + 1, indexes.length);
886
+ }
887
+ else {
888
+ // reverse so we can shift click 'up' as well as down
889
+ if (idx1 > idx2) {
890
+ var tmp = idx2;
891
+ idx2 = idx1;
892
+ idx1 = tmp;
893
+ }
894
+ indexes.splice(idx2 + 1, indexes.length);
895
+ indexes.splice(0, idx1);
896
+ }
897
+ if (!dt[type](idx, { selected: true }).any()) {
898
+ // Select range
899
+ dt[type + 's'](indexes).select();
900
+ }
901
+ else {
902
+ // Deselect range - need to keep the clicked on row selected
903
+ indexes.splice(indexes.indexOf(idx), 1);
904
+ dt[type + 's'](indexes).deselect();
905
+ }
1030
906
  }
1031
-
1032
907
  /**
1033
908
  * Clear all selected items
1034
909
  *
1035
- * @param {DataTable.settings} ctx Settings object of the host DataTable
1036
- * @param {boolean} [force=false] Force the de-selection to happen, regardless
1037
- * of selection style
1038
- * @private
910
+ * @param ctx Settings object of the host DataTable
911
+ * @param force Force the de-selection to happen, regardless of selection style
1039
912
  */
1040
- function clear(ctx, force) {
1041
- if (force || ctx._select.style === 'single') {
1042
- var api = new DataTable.Api(ctx);
1043
-
1044
- api.rows({ selected: true }).deselect();
1045
- api.columns({ selected: true }).deselect();
1046
- api.cells({ selected: true }).deselect();
1047
- }
913
+ function clear(ctx, force = false) {
914
+ if (force || ctx._select.style === 'single') {
915
+ var api = new DataTable.Api(ctx);
916
+ api.rows({ selected: true }).deselect();
917
+ api.columns({ selected: true }).deselect();
918
+ api.cells({ selected: true }).deselect();
919
+ }
1048
920
  }
1049
-
1050
921
  /**
1051
922
  * Select items based on the current configuration for style and items.
1052
923
  *
1053
- * @param {object} e Mouse event object
1054
- * @param {DataTables.Api} dt DataTable
1055
- * @param {DataTable.settings} ctx Settings object of the host DataTable
1056
- * @param {string} type Items to select
1057
- * @param {int|object} idx Index of the item to select
1058
- * @private
924
+ * @param e Mouse event object
925
+ * @param dt DataTable
926
+ * @param ctx Settings object of the host DataTable
927
+ * @param type Items to select
928
+ * @param idx Index of the item to select
1059
929
  */
1060
930
  function typeSelect(e, dt, ctx, type, idx) {
1061
- var style = dt.select.style();
1062
- var toggleable = dt.select.toggleable();
1063
- var isSelected = dt[type](idx, { selected: true }).any();
1064
-
1065
- if (isSelected && !toggleable) {
1066
- return;
1067
- }
1068
-
1069
- if (style === 'os') {
1070
- if (e.ctrlKey || e.metaKey) {
1071
- // Add or remove from the selection
1072
- dt[type](idx).select(!isSelected);
1073
- }
1074
- else if (e.shiftKey) {
1075
- if (type === 'cell') {
1076
- cellRange(dt, idx, ctx._select_lastCell || null);
1077
- }
1078
- else {
1079
- rowColumnRange(
1080
- dt,
1081
- type,
1082
- idx,
1083
- ctx._select_lastCell ? ctx._select_lastCell[type] : null
1084
- );
1085
- }
1086
- }
1087
- else {
1088
- // No cmd or shift click - deselect if selected, or select
1089
- // this row only
1090
- var selected = dt[type + 's']({ selected: true });
1091
-
1092
- if (isSelected && selected.flatten().length === 1) {
1093
- dt[type](idx).deselect();
1094
- }
1095
- else {
1096
- selected.deselect();
1097
- dt[type](idx).select();
1098
- }
1099
- }
1100
- }
1101
- else if (style == 'multi+shift') {
1102
- if (e.shiftKey) {
1103
- if (type === 'cell') {
1104
- cellRange(dt, idx, ctx._select_lastCell || null);
1105
- }
1106
- else {
1107
- rowColumnRange(
1108
- dt,
1109
- type,
1110
- idx,
1111
- ctx._select_lastCell ? ctx._select_lastCell[type] : null
1112
- );
1113
- }
1114
- }
1115
- else {
1116
- dt[type](idx).select(!isSelected);
1117
- }
1118
- }
1119
- else {
1120
- dt[type](idx).select(!isSelected);
1121
- }
931
+ var style = dt.select.style();
932
+ var toggleable = dt.select.toggleable();
933
+ var isSelected = dt[type](idx, { selected: true }).any();
934
+ if (isSelected && !toggleable) {
935
+ return;
936
+ }
937
+ if (style === 'os') {
938
+ if (e.ctrlKey || e.metaKey) {
939
+ // Add or remove from the selection
940
+ dt[type](idx).select(!isSelected);
941
+ }
942
+ else if (e.shiftKey) {
943
+ if (type === 'cell') {
944
+ cellRange(dt, idx, ctx._select_lastCell || null);
945
+ }
946
+ else {
947
+ rowColumnRange(dt, type, idx, ctx._select_lastCell ? ctx._select_lastCell[type] : null);
948
+ }
949
+ }
950
+ else {
951
+ // No cmd or shift click - deselect if selected, or select
952
+ // this row only
953
+ var selected = dt[type + 's']({ selected: true });
954
+ if (isSelected && selected.flatten().length === 1) {
955
+ dt[type](idx).deselect();
956
+ }
957
+ else {
958
+ selected.deselect();
959
+ dt[type](idx).select();
960
+ }
961
+ }
962
+ }
963
+ else if (style == 'multi+shift') {
964
+ if (e.shiftKey) {
965
+ if (type === 'cell') {
966
+ cellRange(dt, idx, ctx._select_lastCell || null);
967
+ }
968
+ else {
969
+ rowColumnRange(dt, type, idx, ctx._select_lastCell ? ctx._select_lastCell[type] : null);
970
+ }
971
+ }
972
+ else {
973
+ dt[type](idx).select(!isSelected);
974
+ }
975
+ }
976
+ else {
977
+ dt[type](idx).select(!isSelected);
978
+ }
1122
979
  }
1123
-
980
+ /**
981
+ * Get an id from an element
982
+ *
983
+ * @param node
984
+ * @returns The id
985
+ */
1124
986
  function _safeId(node) {
1125
- return node.id.replace(/[^a-zA-Z0-9\-\_]/g, '-');
987
+ return node.id.replace(/[^a-zA-Z0-9\-\_]/g, '-');
1126
988
  }
1127
-
1128
989
  /**
1129
990
  * Set up event handlers for cumulative selection
1130
991
  *
1131
- * @param {*} api DT API instance
992
+ * @param api DT API instance
1132
993
  */
1133
994
  function _cumulativeEvents(api) {
1134
- // Add event listeners to add / remove from the _select_set
1135
- api.on('select', function (e, dt, type, indexes) {
1136
- // Only support for rows at the moment
1137
- if (type !== 'row') {
1138
- return;
1139
- }
1140
-
1141
- var ctx = api.settings()[0];
1142
-
1143
- if (ctx._select_mode === 'additive') {
1144
- // Add row to the selection list if it isn't already there
1145
- _add(api, ctx._select_set, indexes);
1146
- }
1147
- else {
1148
- // Subtractive - if a row is selected it should not in the list
1149
- // as in subtractive mode the list gives the rows which are not
1150
- // selected
1151
- _remove(api, ctx._select_set, indexes);
1152
- }
1153
- });
1154
-
1155
- api.on('deselect', function (e, dt, type, indexes) {
1156
- // Only support for rows at the moment
1157
- if (type !== 'row') {
1158
- return;
1159
- }
1160
-
1161
- var ctx = api.settings()[0];
1162
-
1163
- if (ctx._select_mode === 'additive') {
1164
- // List is of those rows selected, so remove it
1165
- _remove(api, ctx._select_set, indexes);
1166
- }
1167
- else {
1168
- // List is of rows which are deselected, so add it!
1169
- _add(api, ctx._select_set, indexes);
1170
- }
1171
- });
995
+ // Add event listeners to add / remove from the _select_set
996
+ api.on('select', function (e, dt, type, indexes) {
997
+ // Only support for rows at the moment
998
+ if (type !== 'row') {
999
+ return;
1000
+ }
1001
+ var ctx = api.settings()[0];
1002
+ if (ctx._select_mode === 'additive') {
1003
+ // Add row to the selection list if it isn't already there
1004
+ _add(api, ctx._select_set, indexes);
1005
+ }
1006
+ else {
1007
+ // Subtractive - if a row is selected it should not in the list
1008
+ // as in subtractive mode the list gives the rows which are not
1009
+ // selected
1010
+ _remove(api, ctx._select_set, indexes);
1011
+ }
1012
+ });
1013
+ api.on('deselect', function (e, dt, type, indexes) {
1014
+ // Only support for rows at the moment
1015
+ if (type !== 'row') {
1016
+ return;
1017
+ }
1018
+ var ctx = api.settings()[0];
1019
+ if (ctx._select_mode === 'additive') {
1020
+ // List is of those rows selected, so remove it
1021
+ _remove(api, ctx._select_set, indexes);
1022
+ }
1023
+ else {
1024
+ // List is of rows which are deselected, so add it!
1025
+ _add(api, ctx._select_set, indexes);
1026
+ }
1027
+ });
1172
1028
  }
1173
-
1174
1029
  function _add(api, arr, indexes) {
1175
- for (var i=0 ; i<indexes.length ; i++) {
1176
- var id = api.row(indexes[i]).id();
1177
-
1178
- if (id && id !== 'undefined' && ! arr.includes(id)) {
1179
- arr.push(id);
1180
- }
1181
- }
1030
+ for (var i = 0; i < indexes.length; i++) {
1031
+ var id = api.row(indexes[i]).id();
1032
+ if (id && id !== 'undefined' && !arr.includes(id)) {
1033
+ arr.push(id);
1034
+ }
1035
+ }
1182
1036
  }
1183
-
1184
1037
  function _remove(api, arr, indexes) {
1185
- for (var i=0 ; i<indexes.length ; i++) {
1186
- var id = api.row(indexes[i]).id();
1187
- var idx = arr.indexOf(id);
1188
-
1189
- if (idx !== -1) {
1190
- arr.splice(idx, 1);
1191
- }
1192
- }
1038
+ for (var i = 0; i < indexes.length; i++) {
1039
+ var id = api.row(indexes[i]).id();
1040
+ var idx = arr.indexOf(id);
1041
+ if (idx !== -1) {
1042
+ arr.splice(idx, 1);
1043
+ }
1044
+ }
1193
1045
  }
1194
-
1195
1046
  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1196
1047
  * DataTables selectors
1197
1048
  */
1198
-
1199
1049
  // row and column are basically identical just assigned to different properties
1200
1050
  // and checking a different array, so we can dynamically create the functions to
1201
1051
  // reduce the code size
1202
- $.each(
1203
- [
1204
- { type: 'row', prop: 'aoData' },
1205
- { type: 'column', prop: 'aoColumns' }
1206
- ],
1207
- function (i, o) {
1208
- DataTable.ext.selector[o.type].push(function (settings, opts, indexes) {
1209
- var selected = opts.selected;
1210
- var data;
1211
- var out = [];
1212
-
1213
- if (selected !== true && selected !== false) {
1214
- return indexes;
1215
- }
1216
-
1217
- for (var i = 0, ien = indexes.length; i < ien; i++) {
1218
- data = settings[o.prop][indexes[i]];
1219
-
1220
- if (
1221
- data && (
1222
- (selected === true && data._select_selected === true) ||
1223
- (selected === false && !data._select_selected)
1224
- )
1225
- ) {
1226
- out.push(indexes[i]);
1227
- }
1228
- }
1229
-
1230
- return out;
1231
- });
1232
- }
1233
- );
1234
-
1052
+ [
1053
+ { type: 'row', prop: 'data' },
1054
+ { type: 'column', prop: 'columns' }
1055
+ ].forEach(function (o) {
1056
+ DataTable.ext.selector[o.type].push(function (settings, opts, indexes) {
1057
+ var selected = opts.selected;
1058
+ var data;
1059
+ var out = [];
1060
+ if (selected !== true && selected !== false) {
1061
+ return indexes;
1062
+ }
1063
+ for (var i = 0, ien = indexes.length; i < ien; i++) {
1064
+ data = settings[o.prop][indexes[i]];
1065
+ if (data &&
1066
+ ((selected === true && data._select_selected === true) ||
1067
+ (selected === false && !data._select_selected))) {
1068
+ out.push(indexes[i]);
1069
+ }
1070
+ }
1071
+ return out;
1072
+ });
1073
+ });
1235
1074
  DataTable.ext.selector.cell.push(function (settings, opts, cells) {
1236
- var selected = opts.selected;
1237
- var rowData;
1238
- var out = [];
1239
-
1240
- if (selected === undefined) {
1241
- return cells;
1242
- }
1243
-
1244
- for (var i = 0, ien = cells.length; i < ien; i++) {
1245
- rowData = settings.aoData[cells[i].row];
1246
-
1247
- if (
1248
- rowData && (
1249
- (selected === true &&
1250
- rowData._selected_cells &&
1251
- rowData._selected_cells[cells[i].column] === true) ||
1252
- (selected === false &&
1253
- (!rowData._selected_cells || !rowData._selected_cells[cells[i].column]))
1254
- )
1255
- ) {
1256
- out.push(cells[i]);
1257
- }
1258
- }
1259
-
1260
- return out;
1075
+ var selected = opts.selected;
1076
+ var rowData;
1077
+ var out = [];
1078
+ if (selected === undefined) {
1079
+ return cells;
1080
+ }
1081
+ for (var i = 0, ien = cells.length; i < ien; i++) {
1082
+ rowData = settings.data[cells[i].row];
1083
+ if (rowData &&
1084
+ ((selected === true &&
1085
+ rowData._selected_cells &&
1086
+ rowData._selected_cells[cells[i].column] === true) ||
1087
+ (selected === false &&
1088
+ (!rowData._selected_cells ||
1089
+ !rowData._selected_cells[cells[i].column])))) {
1090
+ out.push(cells[i]);
1091
+ }
1092
+ }
1093
+ return out;
1261
1094
  });
1262
-
1263
1095
  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1264
1096
  * DataTables API
1265
1097
  *
1266
1098
  * For complete documentation, please refer to the docs/api directory or the
1267
1099
  * DataTables site
1268
1100
  */
1269
-
1270
1101
  // Local variables to improve compression
1271
1102
  var apiRegister = DataTable.Api.register;
1272
1103
  var apiRegisterPlural = DataTable.Api.registerPlural;
1273
-
1274
1104
  apiRegister('select()', function () {
1275
- return this.iterator('table', function (ctx) {
1276
- DataTable.select.init(new DataTable.Api(ctx));
1277
- });
1105
+ return this.iterator('table', function (ctx) {
1106
+ DataTable.select.init(new DataTable.Api(ctx));
1107
+ });
1278
1108
  });
1279
-
1280
1109
  apiRegister('select.blurable()', function (flag) {
1281
- if (flag === undefined) {
1282
- return this.context[0]._select.blurable;
1283
- }
1284
-
1285
- return this.iterator('table', function (ctx) {
1286
- ctx._select.blurable = flag;
1287
- });
1110
+ if (flag === undefined) {
1111
+ return this.context[0]._select.blurable;
1112
+ }
1113
+ return this.iterator('table', function (ctx) {
1114
+ ctx._select.blurable = flag;
1115
+ });
1288
1116
  });
1289
-
1290
1117
  apiRegister('select.toggleable()', function (flag) {
1291
- if (flag === undefined) {
1292
- return this.context[0]._select.toggleable;
1293
- }
1294
-
1295
- return this.iterator('table', function (ctx) {
1296
- ctx._select.toggleable = flag;
1297
- });
1118
+ if (flag === undefined) {
1119
+ return this.context[0]._select.toggleable;
1120
+ }
1121
+ return this.iterator('table', function (ctx) {
1122
+ ctx._select.toggleable = flag;
1123
+ });
1298
1124
  });
1299
-
1300
1125
  apiRegister('select.info()', function (flag) {
1301
- if (flag === undefined) {
1302
- return this.context[0]._select.info;
1303
- }
1304
-
1305
- return this.iterator('table', function (ctx) {
1306
- ctx._select.info = flag;
1307
- });
1126
+ if (flag === undefined) {
1127
+ return this.context[0]._select.info;
1128
+ }
1129
+ return this.iterator('table', function (ctx) {
1130
+ ctx._select.info = flag;
1131
+ });
1308
1132
  });
1309
-
1310
1133
  apiRegister('select.items()', function (items) {
1311
- if (items === undefined) {
1312
- return this.context[0]._select.items;
1313
- }
1314
-
1315
- return this.iterator('table', function (ctx) {
1316
- ctx._select.items = items;
1317
-
1318
- eventTrigger(new DataTable.Api(ctx), 'selectItems', [items]);
1319
- });
1134
+ if (items === undefined) {
1135
+ return this.context[0]._select.items;
1136
+ }
1137
+ return this.iterator('table', function (ctx) {
1138
+ ctx._select.items = items;
1139
+ eventTrigger(new DataTable.Api(ctx), 'selectItems', [items]);
1140
+ });
1320
1141
  });
1321
-
1322
1142
  apiRegister('select.keys()', function (flag, wrap) {
1323
- if (flag === undefined) {
1324
- return this.context[0]._select.keys;
1325
- }
1326
-
1327
- return this.iterator('table', function (ctx) {
1328
- if (!ctx._select) {
1329
- DataTable.select.init(new DataTable.Api(ctx));
1330
- }
1331
-
1332
- ctx._select.keys = flag;
1333
- ctx._select.keysWrap = wrap;
1334
-
1335
- keysSet(new DataTable.Api(ctx));
1336
- });
1143
+ if (flag === undefined) {
1144
+ return this.context[0]._select.keys;
1145
+ }
1146
+ return this.iterator('table', function (ctx) {
1147
+ if (!ctx._select) {
1148
+ DataTable.select.init(new DataTable.Api(ctx));
1149
+ }
1150
+ ctx._select.keys = flag;
1151
+ ctx._select.keysWrap = wrap;
1152
+ keysSet(new DataTable.Api(ctx));
1153
+ });
1337
1154
  });
1338
-
1339
1155
  // Takes effect from the _next_ selection. None disables future selection, but
1340
1156
  // does not clear the current selection. Use the `deselect` methods for that
1341
1157
  apiRegister('select.style()', function (style) {
1342
- if (style === undefined) {
1343
- return this.context[0]._select.style;
1344
- }
1345
-
1346
- return this.iterator('table', function (ctx) {
1347
- if (!ctx._select) {
1348
- DataTable.select.init(new DataTable.Api(ctx));
1349
- }
1350
-
1351
- if (!ctx._select_init) {
1352
- init(ctx);
1353
- }
1354
-
1355
- ctx._select.style = style;
1356
-
1357
- // Add / remove mouse event handlers. They aren't required when only
1358
- // API selection is available
1359
- var dt = new DataTable.Api(ctx);
1360
-
1361
- if (style !== 'api') {
1362
- dt.ready(function () {
1363
- disableMouseSelection(dt);
1364
- enableMouseSelection(dt);
1365
- });
1366
- }
1367
- else {
1368
- disableMouseSelection(dt);
1369
- }
1370
-
1371
- eventTrigger(new DataTable.Api(ctx), 'selectStyle', [style]);
1372
- });
1158
+ if (style === undefined) {
1159
+ return this.context[0]._select.style;
1160
+ }
1161
+ return this.iterator('table', function (ctx) {
1162
+ if (!ctx._select) {
1163
+ DataTable.select.init(new DataTable.Api(ctx));
1164
+ }
1165
+ if (!ctx._select_init) {
1166
+ init(ctx);
1167
+ }
1168
+ ctx._select.style = style;
1169
+ // Add / remove mouse event handlers. They aren't required when only
1170
+ // API selection is available
1171
+ var dt = new DataTable.Api(ctx);
1172
+ if (style !== 'api') {
1173
+ dt.ready(function () {
1174
+ disableMouseSelection(dt);
1175
+ enableMouseSelection(dt);
1176
+ });
1177
+ }
1178
+ else {
1179
+ disableMouseSelection(dt);
1180
+ }
1181
+ eventTrigger(new DataTable.Api(ctx), 'selectStyle', [style]);
1182
+ });
1373
1183
  });
1374
-
1375
1184
  apiRegister('select.selector()', function (selector) {
1376
- if (selector === undefined) {
1377
- return this.context[0]._select.selector;
1378
- }
1379
-
1380
- return this.iterator('table', function (ctx) {
1381
- var dt = new DataTable.Api(ctx);
1382
- var style = ctx._select.style;
1383
-
1384
- disableMouseSelection(dt);
1385
-
1386
- ctx._select.selector = selector;
1387
-
1388
- if (style && style !== 'api') {
1389
- dt.ready(function () {
1390
- disableMouseSelection(dt);
1391
- enableMouseSelection(dt);
1392
- });
1393
- }
1394
- else {
1395
- disableMouseSelection(dt);
1396
- }
1397
- });
1185
+ if (selector === undefined) {
1186
+ return this.context[0]._select.selector;
1187
+ }
1188
+ return this.iterator('table', function (ctx) {
1189
+ var dt = new DataTable.Api(ctx);
1190
+ var style = ctx._select.style;
1191
+ disableMouseSelection(dt);
1192
+ ctx._select.selector = selector;
1193
+ if (style && style !== 'api') {
1194
+ dt.ready(function () {
1195
+ disableMouseSelection(dt);
1196
+ enableMouseSelection(dt);
1197
+ });
1198
+ }
1199
+ else {
1200
+ disableMouseSelection(dt);
1201
+ }
1202
+ });
1398
1203
  });
1399
-
1400
1204
  apiRegister('select.selectable()', function (set) {
1401
- let ctx = this.context[0];
1402
-
1403
- if (set) {
1404
- ctx._select.selectable = set;
1405
- return this;
1406
- }
1407
-
1408
- return ctx._select.selectable;
1205
+ let ctx = this.context[0];
1206
+ if (set) {
1207
+ ctx._select.selectable = set;
1208
+ return this;
1209
+ }
1210
+ return ctx._select.selectable;
1409
1211
  });
1410
-
1411
1212
  apiRegister('select.last()', function (set) {
1412
- let ctx = this.context[0];
1413
-
1414
- if (set) {
1415
- ctx._select_lastCell = set;
1416
- return this;
1417
- }
1418
-
1419
- return ctx._select_lastCell;
1213
+ let ctx = this.context[0];
1214
+ if (set) {
1215
+ ctx._select_lastCell = set;
1216
+ return this;
1217
+ }
1218
+ return ctx._select_lastCell;
1420
1219
  });
1421
-
1422
1220
  apiRegister('select.cumulative()', function (mode) {
1423
- if (mode) {
1424
- return this.iterator('table', function (ctx) {
1425
- if (ctx._select_mode === mode) {
1426
- return;
1427
- }
1428
-
1429
- var dt = new DataTable.Api(ctx);
1430
-
1431
- // Convert from the current mode, to the new
1432
- if (mode === 'subtractive') {
1433
- // For subtractive mode we track the row ids which are not selected
1434
- var unselected = dt.rows({selected: false}).ids().toArray();
1435
-
1436
- ctx._select_mode = mode;
1437
- ctx._select_set.length = 0;
1438
- ctx._select_set.push.apply(ctx._select_set, unselected);
1439
- }
1440
- else {
1441
- // Switching to additive, so selected rows are to be used
1442
- var selected = dt.rows({selected: true}).ids().toArray();
1443
-
1444
- ctx._select_mode = mode;
1445
- ctx._select_set.length = 0;
1446
- ctx._select_set.push.apply(ctx._select_set, selected);
1447
- }
1448
- }).draw(false);
1449
- }
1450
-
1451
- let ctx = this.context[0];
1452
-
1453
- if (ctx && ctx._select_set) {
1454
- return {
1455
- mode: ctx._select_mode,
1456
- rows: ctx._select_set
1457
- };
1458
- }
1459
-
1460
- return null;
1221
+ if (mode) {
1222
+ return this.iterator('table', function (ctx) {
1223
+ if (ctx._select_mode === mode) {
1224
+ return;
1225
+ }
1226
+ var dt = new DataTable.Api(ctx);
1227
+ // Convert from the current mode, to the new
1228
+ if (mode === 'subtractive') {
1229
+ // For subtractive mode we track the row ids which are not
1230
+ // selected
1231
+ var unselected = dt.rows({ selected: false }).ids().toArray();
1232
+ ctx._select_mode = mode;
1233
+ ctx._select_set.length = 0;
1234
+ ctx._select_set.push.apply(ctx._select_set, unselected);
1235
+ }
1236
+ else {
1237
+ // Switching to additive, so selected rows are to be used
1238
+ var selected = dt.rows({ selected: true }).ids().toArray();
1239
+ ctx._select_mode = mode;
1240
+ ctx._select_set.length = 0;
1241
+ ctx._select_set.push.apply(ctx._select_set, selected);
1242
+ }
1243
+ }).draw(false);
1244
+ }
1245
+ let ctx = this.context[0];
1246
+ if (ctx && ctx._select_set) {
1247
+ return {
1248
+ mode: ctx._select_mode,
1249
+ rows: ctx._select_set
1250
+ };
1251
+ }
1252
+ return null;
1461
1253
  });
1462
-
1463
- apiRegisterPlural('rows().select()', 'row().select()', function (select) {
1464
- var api = this;
1465
- var selectedIndexes = [];
1466
-
1467
- if (select === false) {
1468
- return this.deselect();
1469
- }
1470
-
1471
- this.iterator('row', function (ctx, idx) {
1472
- clear(ctx);
1473
-
1474
- // There is a good amount of knowledge of DataTables internals in
1475
- // this function. It _could_ be done without that, but it would hurt
1476
- // performance (or DT would need new APIs for this work)
1477
- var dtData = ctx.aoData[idx];
1478
- var dtColumns = ctx.aoColumns;
1479
-
1480
- if (ctx._select.selectable) {
1481
- var result = ctx._select.selectable(dtData._aData, dtData.nTr, idx);
1482
-
1483
- if (result === false) {
1484
- // Not selectable - do nothing
1485
- return;
1486
- }
1487
- }
1488
-
1489
- $(dtData.nTr).addClass(ctx._select.className);
1490
- dtData._select_selected = true;
1491
-
1492
- selectedIndexes.push(idx);
1493
-
1494
- for (var i=0 ; i<dtColumns.length ; i++) {
1495
- var col = dtColumns[i];
1496
-
1497
- // Regenerate the column type if not present
1498
- if (col.sType === null) {
1499
- api.columns().types()
1500
- }
1501
-
1502
- if (isCheckboxColumn(col)) {
1503
- var cells = dtData.anCells;
1504
-
1505
- // Make sure the checkbox shows the right state
1506
- if (cells && cells[i]) {
1507
- $('input.' + checkboxClass(true), cells[i]).prop('checked', true);
1508
- }
1509
-
1510
- // Invalidate the sort data for this column, if not already done
1511
- if (dtData._aSortData !== null) {
1512
- dtData._aSortData[i] = null;
1513
- }
1514
- }
1515
- }
1516
- });
1517
-
1518
- this.iterator('table', function (ct) {
1519
- eventTrigger(api, 'select', ['row', selectedIndexes], true);
1520
- });
1521
-
1522
- return this;
1254
+ DataTable.Api.registerPlural('rows().select()', 'row().select()', function (select = true) {
1255
+ var api = this;
1256
+ var selectedIndexes = [];
1257
+ if (select === false) {
1258
+ return this.deselect();
1259
+ }
1260
+ this.iterator('row', function (ctx, idx) {
1261
+ clear(ctx);
1262
+ // There is a good amount of knowledge of DataTables internals in
1263
+ // this function. It _could_ be done without that, but it would hurt
1264
+ // performance (or DT would need new APIs for this work)
1265
+ var dtData = ctx.data[idx];
1266
+ var dtColumns = ctx.columns;
1267
+ if (ctx._select.selectable) {
1268
+ var result = ctx._select.selectable(dtData.data, dtData.tr, idx);
1269
+ if (result === false) {
1270
+ // Not selectable - do nothing
1271
+ return;
1272
+ }
1273
+ }
1274
+ Dom.s(dtData.tr).classAdd(ctx._select.className);
1275
+ dtData._select_selected = true;
1276
+ selectedIndexes.push(idx);
1277
+ for (var i = 0; i < dtColumns.length; i++) {
1278
+ var col = dtColumns[i];
1279
+ // Regenerate the column type if not present
1280
+ if (col.type === null) {
1281
+ api.columns().types();
1282
+ }
1283
+ if (isCheckboxColumn(col)) {
1284
+ var cells = dtData.cells;
1285
+ // Make sure the checkbox shows the right state
1286
+ if (cells && cells[i]) {
1287
+ Dom.s(cells[i])
1288
+ .find('input.' + checkboxClass(true))
1289
+ .prop('checked', true);
1290
+ }
1291
+ // Invalidate the sort data for this column, if not already
1292
+ // done
1293
+ if (dtData.orderCache !== null) {
1294
+ dtData.orderCache[i] = null;
1295
+ }
1296
+ }
1297
+ }
1298
+ });
1299
+ this.iterator('table', function (innerCtx) {
1300
+ eventTrigger(api, 'select', ['row', selectedIndexes], true);
1301
+ });
1302
+ return this;
1523
1303
  });
1524
-
1525
1304
  apiRegister('row().selected()', function () {
1526
- var ctx = this.context[0];
1527
-
1528
- if (ctx && this.length && ctx.aoData[this[0]] && ctx.aoData[this[0]]._select_selected) {
1529
- return true;
1530
- }
1531
-
1532
- return false;
1305
+ var ctx = this.context[0];
1306
+ if (ctx &&
1307
+ this.length &&
1308
+ ctx.data[this[0]] &&
1309
+ ctx.data[this[0]]._select_selected) {
1310
+ return true;
1311
+ }
1312
+ return false;
1533
1313
  });
1534
-
1535
1314
  apiRegister('row().focus()', function () {
1536
- var ctx = this.context[0];
1537
-
1538
- if (ctx && this.length && ctx.aoData[this[0]] && ctx.aoData[this[0]].nTr) {
1539
- ctx.aoData[this[0]].nTr.focus();
1540
- }
1315
+ var ctx = this.context[0];
1316
+ if (ctx && this.length && ctx.data[this[0]] && ctx.data[this[0]].tr) {
1317
+ ctx.data[this[0]].tr.focus();
1318
+ }
1541
1319
  });
1542
-
1543
1320
  apiRegister('row().blur()', function () {
1544
- var ctx = this.context[0];
1545
-
1546
- if (ctx && this.length && ctx.aoData[this[0]] && ctx.aoData[this[0]].nTr) {
1547
- ctx.aoData[this[0]].nTr.blur();
1548
- }
1321
+ var ctx = this.context[0];
1322
+ if (ctx && this.length && ctx.data[this[0]] && ctx.data[this[0]].tr) {
1323
+ ctx.data[this[0]].tr.blur();
1324
+ }
1549
1325
  });
1550
-
1551
1326
  apiRegisterPlural('columns().select()', 'column().select()', function (select) {
1552
- var api = this;
1553
-
1554
- if (select === false) {
1555
- return this.deselect();
1556
- }
1557
-
1558
- this.iterator('column', function (ctx, idx) {
1559
- clear(ctx);
1560
-
1561
- ctx.aoColumns[idx]._select_selected = true;
1562
-
1563
- var column = new DataTable.Api(ctx).column(idx);
1564
-
1565
- $(column.header()).addClass(ctx._select.className);
1566
- $(column.footer()).addClass(ctx._select.className);
1567
-
1568
- column.nodes().to$().addClass(ctx._select.className);
1569
- });
1570
-
1571
- this.iterator('table', function (ctx, i) {
1572
- eventTrigger(api, 'select', ['column', api[i]], true);
1573
- });
1574
-
1575
- return this;
1327
+ var api = this;
1328
+ if (select === false) {
1329
+ return this.deselect();
1330
+ }
1331
+ this.iterator('column', function (ctx, idx) {
1332
+ clear(ctx);
1333
+ ctx.columns[idx]._select_selected = true;
1334
+ var column = new DataTable.Api(ctx).column(idx);
1335
+ Dom.s(column.header()).classAdd(ctx._select.className);
1336
+ Dom.s(column.footer()).classAdd(ctx._select.className);
1337
+ Dom.s(column.nodes().toArray()).classAdd(ctx._select.className);
1338
+ });
1339
+ this.iterator('table', function (innerCtx, i) {
1340
+ eventTrigger(api, 'select', ['column', api[i]], true);
1341
+ });
1342
+ return this;
1576
1343
  });
1577
-
1578
1344
  apiRegister('column().selected()', function () {
1579
- var ctx = this.context[0];
1580
-
1581
- if (ctx && this.length && ctx.aoColumns[this[0]] && ctx.aoColumns[this[0]]._select_selected) {
1582
- return true;
1583
- }
1584
-
1585
- return false;
1345
+ var ctx = this.context[0];
1346
+ if (ctx &&
1347
+ this.length &&
1348
+ ctx.columns[this[0]] &&
1349
+ ctx.columns[this[0]]._select_selected) {
1350
+ return true;
1351
+ }
1352
+ return false;
1586
1353
  });
1587
-
1588
1354
  apiRegisterPlural('cells().select()', 'cell().select()', function (select) {
1589
- var api = this;
1590
-
1591
- if (select === false) {
1592
- return this.deselect();
1593
- }
1594
-
1595
- this.iterator('cell', function (ctx, rowIdx, colIdx) {
1596
- clear(ctx);
1597
-
1598
- var data = ctx.aoData[rowIdx];
1599
-
1600
- if (data._selected_cells === undefined) {
1601
- data._selected_cells = [];
1602
- }
1603
-
1604
- data._selected_cells[colIdx] = true;
1605
-
1606
- if (data.anCells) {
1607
- $(data.anCells[colIdx]).addClass(ctx._select.className);
1608
- }
1609
- });
1610
-
1611
- this.iterator('table', function (ctx, i) {
1612
- eventTrigger(api, 'select', ['cell', api.cells(api[i]).indexes().toArray()], true);
1613
- });
1614
-
1615
- return this;
1355
+ var api = this;
1356
+ if (select === false) {
1357
+ return this.deselect();
1358
+ }
1359
+ this.iterator('cell', function (ctx, rowIdx, colIdx) {
1360
+ clear(ctx);
1361
+ var data = ctx.data[rowIdx];
1362
+ if (data._selected_cells === undefined) {
1363
+ data._selected_cells = [];
1364
+ }
1365
+ data._selected_cells[colIdx] = true;
1366
+ if (data.cells) {
1367
+ Dom.s(data.cells[colIdx]).classAdd(ctx._select.className);
1368
+ }
1369
+ });
1370
+ this.iterator('table', function (innerCtx, i) {
1371
+ eventTrigger(api, 'select', ['cell', api.cells(api[i]).indexes().toArray()], true);
1372
+ });
1373
+ return this;
1616
1374
  });
1617
-
1618
1375
  apiRegister('cell().selected()', function () {
1619
- var ctx = this.context[0];
1620
-
1621
- if (ctx && this.length) {
1622
- var row = ctx.aoData[this[0][0].row];
1623
-
1624
- if (row && row._selected_cells && row._selected_cells[this[0][0].column]) {
1625
- return true;
1626
- }
1627
- }
1628
-
1629
- return false;
1376
+ var ctx = this.context[0];
1377
+ if (ctx && this.length) {
1378
+ var row = ctx.data[this[0][0].row];
1379
+ if (row &&
1380
+ row._selected_cells &&
1381
+ row._selected_cells[this[0][0].column]) {
1382
+ return true;
1383
+ }
1384
+ }
1385
+ return false;
1630
1386
  });
1631
-
1632
1387
  apiRegisterPlural('rows().deselect()', 'row().deselect()', function () {
1633
- var api = this;
1634
-
1635
- this.iterator('row', function (ctx, idx) {
1636
- // Like the select action, this has a lot of knowledge about DT internally
1637
- var dtData = ctx.aoData[idx];
1638
- var dtColumns = ctx.aoColumns;
1639
-
1640
- $(dtData.nTr).removeClass(ctx._select.className);
1641
- dtData._select_selected = false;
1642
- ctx._select_lastCell = null;
1643
-
1644
- for (var i=0 ; i<dtColumns.length ; i++) {
1645
- var col = dtColumns[i];
1646
-
1647
- // Regenerate the column type if not present
1648
- if (col.sType === null) {
1649
- api.columns().types()
1650
- }
1651
-
1652
- if (isCheckboxColumn(col)) {
1653
- var cells = dtData.anCells;
1654
-
1655
- // Make sure the checkbox shows the right state
1656
- if (cells && cells[i]) {
1657
- $('input.' + checkboxClass(true), dtData.anCells[i]).prop('checked', false);
1658
- }
1659
-
1660
- // Invalidate the sort data for this column, if not already done
1661
- if (dtData._aSortData !== null) {
1662
- dtData._aSortData[i] = null;
1663
- }
1664
- }
1665
- }
1666
- });
1667
-
1668
- this.iterator('table', function (ctx, i) {
1669
- eventTrigger(api, 'deselect', ['row', api[i]], true);
1670
- });
1671
-
1672
- return this;
1388
+ var api = this;
1389
+ this.iterator('row', function (ctx, idx) {
1390
+ // Like the select action, this has a lot of knowledge about DT
1391
+ // internally
1392
+ var dtData = ctx.data[idx];
1393
+ var dtColumns = ctx.columns;
1394
+ Dom.s(dtData.tr).classRemove(ctx._select.className);
1395
+ dtData._select_selected = false;
1396
+ ctx._select_lastCell = null;
1397
+ for (var i = 0; i < dtColumns.length; i++) {
1398
+ var col = dtColumns[i];
1399
+ // Regenerate the column type if not present
1400
+ if (col.type === null) {
1401
+ api.columns().types();
1402
+ }
1403
+ if (isCheckboxColumn(col)) {
1404
+ var cells = dtData.cells;
1405
+ // Make sure the checkbox shows the right state
1406
+ if (cells && cells[i]) {
1407
+ Dom.s(dtData.cells[i])
1408
+ .find('input.' + checkboxClass(true))
1409
+ .prop('checked', false);
1410
+ }
1411
+ // Invalidate the sort data for this column, if not already done
1412
+ if (dtData.orderCache !== null) {
1413
+ dtData.orderCache[i] = null;
1414
+ }
1415
+ }
1416
+ }
1417
+ });
1418
+ this.iterator('table', function (ctx, i) {
1419
+ eventTrigger(api, 'deselect', ['row', api[i]], true);
1420
+ });
1421
+ return this;
1673
1422
  });
1674
-
1675
1423
  apiRegisterPlural('columns().deselect()', 'column().deselect()', function () {
1676
- var api = this;
1677
-
1678
- this.iterator('column', function (ctx, idx) {
1679
- ctx.aoColumns[idx]._select_selected = false;
1680
-
1681
- var api = new DataTable.Api(ctx);
1682
- var column = api.column(idx);
1683
-
1684
- $(column.header()).removeClass(ctx._select.className);
1685
- $(column.footer()).removeClass(ctx._select.className);
1686
-
1687
- // Need to loop over each cell, rather than just using
1688
- // `column().nodes()` as cells which are individually selected should
1689
- // not have the `selected` class removed from them
1690
- api.cells(null, idx)
1691
- .indexes()
1692
- .each(function (cellIdx) {
1693
- var data = ctx.aoData[cellIdx.row];
1694
- var cellSelected = data._selected_cells;
1695
-
1696
- if (data.anCells && (!cellSelected || !cellSelected[cellIdx.column])) {
1697
- $(data.anCells[cellIdx.column]).removeClass(ctx._select.className);
1698
- }
1699
- });
1700
- });
1701
-
1702
- this.iterator('table', function (ctx, i) {
1703
- eventTrigger(api, 'deselect', ['column', api[i]], true);
1704
- });
1705
-
1706
- return this;
1424
+ var api = this;
1425
+ this.iterator('column', function (ctx, idx) {
1426
+ ctx.columns[idx]._select_selected = false;
1427
+ var api = new DataTable.Api(ctx);
1428
+ var column = api.column(idx);
1429
+ Dom.s(column.header()).classRemove(ctx._select.className);
1430
+ Dom.s(column.footer()).classRemove(ctx._select.className);
1431
+ // Need to loop over each cell, rather than just using
1432
+ // `column().nodes()` as cells which are individually selected should
1433
+ // not have the `selected` class removed from them
1434
+ api.cells(null, idx)
1435
+ .indexes()
1436
+ .each(function (cellIdx) {
1437
+ var data = ctx.data[cellIdx.row];
1438
+ var cellSelected = data._selected_cells;
1439
+ if (data.cells &&
1440
+ (!cellSelected || !cellSelected[cellIdx.column])) {
1441
+ Dom.s(data.cells[cellIdx.column]).classRemove(ctx._select.className);
1442
+ }
1443
+ });
1444
+ });
1445
+ this.iterator('table', function (ctx, i) {
1446
+ eventTrigger(api, 'deselect', ['column', api[i]], true);
1447
+ });
1448
+ return this;
1707
1449
  });
1708
-
1709
1450
  apiRegisterPlural('cells().deselect()', 'cell().deselect()', function () {
1710
- var api = this;
1711
-
1712
- this.iterator('cell', function (ctx, rowIdx, colIdx) {
1713
- var data = ctx.aoData[rowIdx];
1714
-
1715
- if (data._selected_cells !== undefined) {
1716
- data._selected_cells[colIdx] = false;
1717
- }
1718
-
1719
- // Remove class only if the cells exist, and the cell is not column
1720
- // selected, in which case the class should remain (since it is selected
1721
- // in the column)
1722
- if (data.anCells && !ctx.aoColumns[colIdx]._select_selected) {
1723
- $(data.anCells[colIdx]).removeClass(ctx._select.className);
1724
- }
1725
- });
1726
-
1727
- this.iterator('table', function (ctx, i) {
1728
- eventTrigger(api, 'deselect', ['cell', api[i]], true);
1729
- });
1730
-
1731
- return this;
1451
+ var api = this;
1452
+ this.iterator('cell', function (ctx, rowIdx, colIdx) {
1453
+ var data = ctx.data[rowIdx];
1454
+ if (data._selected_cells !== undefined) {
1455
+ data._selected_cells[colIdx] = false;
1456
+ }
1457
+ // Remove class only if the cells exist, and the cell is not column
1458
+ // selected, in which case the class should remain (since it is selected
1459
+ // in the column)
1460
+ if (data.cells && !ctx.columns[colIdx]._select_selected) {
1461
+ Dom.s(data.cells[colIdx]).classRemove(ctx._select.className);
1462
+ }
1463
+ });
1464
+ this.iterator('table', function (ctx, i) {
1465
+ eventTrigger(api, 'deselect', ['cell', api[i]], true);
1466
+ });
1467
+ return this;
1732
1468
  });
1733
-
1734
1469
  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1735
1470
  * Buttons
1736
1471
  */
1737
1472
  function i18n(label, def) {
1738
- return function (dt) {
1739
- return dt.i18n('buttons.' + label, def);
1740
- };
1473
+ return function (dt) {
1474
+ return dt.i18n('buttons.' + label, def);
1475
+ };
1741
1476
  }
1742
-
1743
1477
  // Common events with suitable namespaces
1744
1478
  function namespacedEvents(config) {
1745
- var unique = config._eventNamespace;
1746
-
1747
- return 'draw.dt.DT' + unique + ' select.dt.DT' + unique + ' deselect.dt.DT' + unique;
1479
+ var unique = config._eventNamespace;
1480
+ return ('draw.dt.DT' +
1481
+ unique +
1482
+ ' select.dt.DT' +
1483
+ unique +
1484
+ ' deselect.dt.DT' +
1485
+ unique);
1748
1486
  }
1749
-
1750
1487
  function enabled(dt, config) {
1751
- if (config.limitTo.indexOf('rows') !== -1 && dt.rows({ selected: true }).any()) {
1752
- return true;
1753
- }
1754
-
1755
- if (config.limitTo.indexOf('columns') !== -1 && dt.columns({ selected: true }).any()) {
1756
- return true;
1757
- }
1758
-
1759
- if (config.limitTo.indexOf('cells') !== -1 && dt.cells({ selected: true }).any()) {
1760
- return true;
1761
- }
1762
-
1763
- return false;
1488
+ if (config.limitTo.indexOf('rows') !== -1 &&
1489
+ dt.rows({ selected: true }).any()) {
1490
+ return true;
1491
+ }
1492
+ if (config.limitTo.indexOf('columns') !== -1 &&
1493
+ dt.columns({ selected: true }).any()) {
1494
+ return true;
1495
+ }
1496
+ if (config.limitTo.indexOf('cells') !== -1 &&
1497
+ dt.cells({ selected: true }).any()) {
1498
+ return true;
1499
+ }
1500
+ return false;
1764
1501
  }
1765
-
1766
1502
  var _buttonNamespace = 0;
1767
-
1768
- $.extend(DataTable.ext.buttons, {
1769
- selected: {
1770
- text: i18n('selected', 'Selected'),
1771
- className: 'buttons-selected',
1772
- limitTo: ['rows', 'columns', 'cells'],
1773
- init: function (dt, node, config) {
1774
- var that = this;
1775
- config._eventNamespace = '.select' + _buttonNamespace++;
1776
-
1777
- // .DT namespace listeners are removed by DataTables automatically
1778
- // on table destroy
1779
- dt.on(namespacedEvents(config), function () {
1780
- that.enable(enabled(dt, config));
1781
- });
1782
-
1783
- this.disable();
1784
- },
1785
- destroy: function (dt, node, config) {
1786
- dt.off(config._eventNamespace);
1787
- }
1788
- },
1789
- selectedSingle: {
1790
- text: i18n('selectedSingle', 'Selected single'),
1791
- className: 'buttons-selected-single',
1792
- init: function (dt, node, config) {
1793
- var that = this;
1794
- config._eventNamespace = '.select' + _buttonNamespace++;
1795
-
1796
- dt.on(namespacedEvents(config), function () {
1797
- var count =
1798
- dt.rows({ selected: true }).flatten().length +
1799
- dt.columns({ selected: true }).flatten().length +
1800
- dt.cells({ selected: true }).flatten().length;
1801
-
1802
- that.enable(count === 1);
1803
- });
1804
-
1805
- this.disable();
1806
- },
1807
- destroy: function (dt, node, config) {
1808
- dt.off(config._eventNamespace);
1809
- }
1810
- },
1811
- selectAll: {
1812
- text: i18n('selectAll', 'Select all'),
1813
- className: 'buttons-select-all',
1814
- action: function (e, dt, node, config) {
1815
- var items = this.select.items();
1816
- var mod = config.selectorModifier;
1817
-
1818
- if (mod) {
1819
- if (typeof mod === 'function') {
1820
- mod = mod.call(dt, e, dt, node, config);
1821
- }
1822
-
1823
- this[items + 's'](mod).select();
1824
- }
1825
- else {
1826
- this[items + 's']().select();
1827
- }
1828
- }
1829
- // selectorModifier can be specified
1830
- },
1831
- selectNone: {
1832
- text: i18n('selectNone', 'Deselect all'),
1833
- className: 'buttons-select-none',
1834
- action: function () {
1835
- clear(this.settings()[0], true);
1836
- },
1837
- init: function (dt, node, config) {
1838
- var that = this;
1839
- config._eventNamespace = '.select' + _buttonNamespace++;
1840
-
1841
- dt.on(namespacedEvents(config), function () {
1842
- var count =
1843
- dt.rows({ selected: true }).flatten().length +
1844
- dt.columns({ selected: true }).flatten().length +
1845
- dt.cells({ selected: true }).flatten().length;
1846
-
1847
- that.enable(count > 0);
1848
- });
1849
-
1850
- this.disable();
1851
- },
1852
- destroy: function (dt, node, config) {
1853
- dt.off(config._eventNamespace);
1854
- }
1855
- },
1856
- showSelected: {
1857
- text: i18n('showSelected', 'Show only selected'),
1858
- className: 'buttons-show-selected',
1859
- action: function (e, dt) {
1860
- if (dt.search.fixed('dt-select')) {
1861
- // Remove existing function
1862
- dt.search.fixed('dt-select', null);
1863
-
1864
- this.active(false);
1865
- }
1866
- else {
1867
- // Use a fixed filtering function to match on selected rows
1868
- // This needs to reference the internal aoData since that is
1869
- // where Select stores its reference for the selected state
1870
- var dataSrc = dt.settings()[0].aoData;
1871
-
1872
- dt.search.fixed('dt-select', function (text, data, idx) {
1873
- // _select_selected is set by Select on the data object for the row
1874
- return dataSrc[idx]._select_selected;
1875
- });
1876
-
1877
- this.active(true);
1878
- }
1879
-
1880
- dt.draw();
1881
- }
1882
- }
1503
+ util.object.assign(DataTable.ext.buttons, {
1504
+ selected: {
1505
+ text: i18n('selected', 'Selected'),
1506
+ className: 'buttons-selected',
1507
+ limitTo: ['rows', 'columns', 'cells'],
1508
+ init: function (dt, node, config) {
1509
+ var that = this;
1510
+ config._eventNamespace = '.select' + _buttonNamespace++;
1511
+ // .DT namespace listeners are removed by DataTables automatically
1512
+ // on table destroy
1513
+ dt.on(namespacedEvents(config), function () {
1514
+ that.enable(enabled(dt, config));
1515
+ });
1516
+ this.disable();
1517
+ },
1518
+ destroy: function (dt, node, config) {
1519
+ dt.off(config._eventNamespace);
1520
+ }
1521
+ },
1522
+ selectedSingle: {
1523
+ text: i18n('selectedSingle', 'Selected single'),
1524
+ className: 'buttons-selected-single',
1525
+ init: function (dt, node, config) {
1526
+ var that = this;
1527
+ config._eventNamespace = '.select' + _buttonNamespace++;
1528
+ dt.on(namespacedEvents(config), function () {
1529
+ var count = dt.rows({ selected: true }).flatten().length +
1530
+ dt.columns({ selected: true }).flatten().length +
1531
+ dt.cells({ selected: true }).flatten().length;
1532
+ that.enable(count === 1);
1533
+ });
1534
+ this.disable();
1535
+ },
1536
+ destroy: function (dt, node, config) {
1537
+ dt.off(config._eventNamespace);
1538
+ }
1539
+ },
1540
+ selectAll: {
1541
+ text: i18n('selectAll', 'Select all'),
1542
+ className: 'buttons-select-all',
1543
+ action: function (e, dt, node, config) {
1544
+ var items = this.select.items();
1545
+ var mod = config.selectorModifier;
1546
+ if (mod) {
1547
+ if (typeof mod === 'function') {
1548
+ mod = mod.call(dt, e, dt, node, config);
1549
+ }
1550
+ this[items + 's'](mod).select();
1551
+ }
1552
+ else {
1553
+ this[items + 's']().select();
1554
+ }
1555
+ }
1556
+ // selectorModifier can be specified
1557
+ },
1558
+ selectNone: {
1559
+ text: i18n('selectNone', 'Deselect all'),
1560
+ className: 'buttons-select-none',
1561
+ action: function () {
1562
+ clear(this.settings()[0], true);
1563
+ },
1564
+ init: function (dt, node, config) {
1565
+ var that = this;
1566
+ config._eventNamespace = '.select' + _buttonNamespace++;
1567
+ dt.on(namespacedEvents(config), function () {
1568
+ var count = dt.rows({ selected: true }).flatten().length +
1569
+ dt.columns({ selected: true }).flatten().length +
1570
+ dt.cells({ selected: true }).flatten().length;
1571
+ that.enable(count > 0);
1572
+ });
1573
+ this.disable();
1574
+ },
1575
+ destroy: function (dt, node, config) {
1576
+ dt.off(config._eventNamespace);
1577
+ }
1578
+ },
1579
+ showSelected: {
1580
+ text: i18n('showSelected', 'Show only selected'),
1581
+ className: 'buttons-show-selected',
1582
+ action: function (e, dt) {
1583
+ if (dt.search.fixed('dt-select')) {
1584
+ // Remove existing function
1585
+ dt.search.fixed('dt-select', null);
1586
+ this.active(false);
1587
+ }
1588
+ else {
1589
+ // Use a fixed filtering function to match on selected rows
1590
+ // This needs to reference the internal data since that is
1591
+ // where Select stores its reference for the selected state
1592
+ var dataSrc = dt.settings()[0].data;
1593
+ dt.search.fixed('dt-select', function (text, data, idx) {
1594
+ // _select_selected is set by Select on the data object for
1595
+ // the row
1596
+ return dataSrc[idx]._select_selected;
1597
+ });
1598
+ this.active(true);
1599
+ }
1600
+ dt.draw();
1601
+ }
1602
+ }
1883
1603
  });
1884
-
1885
- $.each(['Row', 'Column', 'Cell'], function (i, item) {
1886
- var lc = item.toLowerCase();
1887
-
1888
- DataTable.ext.buttons['select' + item + 's'] = {
1889
- text: i18n('select' + item + 's', 'Select ' + lc + 's'),
1890
- className: 'buttons-select-' + lc + 's',
1891
- action: function () {
1892
- this.select.items(lc);
1893
- },
1894
- init: function (dt) {
1895
- var that = this;
1896
-
1897
- this.active(dt.select.items() === lc);
1898
-
1899
- dt.on('selectItems.dt.DT', function (e, ctx, items) {
1900
- that.active(items === lc);
1901
- });
1902
- }
1903
- };
1604
+ ['Row', 'Column', 'Cell'].forEach(function (item) {
1605
+ var lc = item.toLowerCase();
1606
+ DataTable.ext.buttons['select' + item + 's'] = {
1607
+ text: i18n('select' + item + 's', 'Select ' + lc + 's'),
1608
+ className: 'buttons-select-' + lc + 's',
1609
+ action: function () {
1610
+ this.select.items(lc);
1611
+ },
1612
+ init: function (dt) {
1613
+ var that = this;
1614
+ this.active(dt.select.items() === lc);
1615
+ dt.on('selectItems.dt.DT', function (e, ctx, items) {
1616
+ that.active(items === lc);
1617
+ });
1618
+ }
1619
+ };
1904
1620
  });
1905
-
1906
- // Note that DataTables 2.1 has more robust type detection, but we retain
1907
- // backwards compatibility with 2.0 for the moment.
1908
1621
  DataTable.type('select-checkbox', {
1909
- className: 'dt-select',
1910
- detect: DataTable.versionCheck('2.1')
1911
- ? {
1912
- oneOf: function () {
1913
- return false; // no op
1914
- },
1915
- allOf: function () {
1916
- return false; // no op
1917
- },
1918
- init: function (settings, col, idx) {
1919
- return isCheckboxColumn(col);
1920
- }
1921
- }
1922
- : function (data) {
1923
- // Rendering function will tell us if it is a checkbox type
1924
- return data === 'select-checkbox' ? data : false;
1925
- },
1926
- order: {
1927
- pre: function (d) {
1928
- return d === 'X' ? -1 : 0;
1929
- }
1930
- }
1622
+ className: 'dt-select',
1623
+ detect: {
1624
+ oneOf: function () {
1625
+ return false; // no op
1626
+ },
1627
+ allOf: function () {
1628
+ return false; // no op
1629
+ },
1630
+ init: function (settings, col, idx) {
1631
+ return isCheckboxColumn(col);
1632
+ }
1633
+ },
1634
+ order: {
1635
+ pre: function (d) {
1636
+ return d === 'X' ? -1 : 0;
1637
+ }
1638
+ }
1931
1639
  });
1932
-
1933
- $.extend(true, DataTable.defaults.oLanguage, {
1934
- select: {
1935
- aria: {
1936
- rowCheckbox: 'Select row'
1937
- }
1938
- }
1640
+ util.object.assignDeep(DataTable.defaults.language, {
1641
+ select: {
1642
+ aria: {
1643
+ rowCheckbox: 'Select row'
1644
+ }
1645
+ }
1939
1646
  });
1940
-
1941
1647
  DataTable.render.select = function (valueProp, nameProp) {
1942
- var valueFn = valueProp ? DataTable.util.get(valueProp) : null;
1943
- var nameFn = nameProp ? DataTable.util.get(nameProp) : null;
1944
-
1945
- var fn = function (data, type, row, meta) {
1946
- var dtRow = meta.settings.aoData[meta.row];
1947
- var selected = dtRow._select_selected;
1948
- var ariaLabel = meta.settings.oLanguage.select.aria.rowCheckbox;
1949
- var selectable = meta.settings._select.selectable;
1950
-
1951
- if (type === 'display') {
1952
- // Check if the row is selectable before showing the checkbox
1953
- if (selectable) {
1954
- var result = selectable(row, dtRow.nTr, meta.row);
1955
-
1956
- if (result === false) {
1957
- return '';
1958
- }
1959
- }
1960
-
1961
- return $('<input>')
1962
- .attr({
1963
- 'aria-label': ariaLabel,
1964
- class: checkboxClass(),
1965
- name: nameFn ? nameFn(row) : null,
1966
- type: 'checkbox',
1967
- value: valueFn ? valueFn(row) : null,
1968
- checked: selected
1969
- })
1970
- .on('input', function (e) {
1971
- // Let Select 100% control the state of the checkbox
1972
- e.preventDefault();
1973
-
1974
- // And make sure this checkbox matches it's row as it is possible
1975
- // to check out of sync if this was clicked on to deselect a range
1976
- // but remains selected itself
1977
- this.checked = $(this).closest('tr').hasClass('selected');
1978
- })[0];
1979
- }
1980
- else if (type === 'type') {
1981
- return 'select-checkbox';
1982
- }
1983
- else if (type === 'filter') {
1984
- return '';
1985
- }
1986
-
1987
- return selected ? 'X' : '';
1988
- }
1989
-
1990
- // Workaround so uglify doesn't strip the function name. It is used
1991
- // for the column type detection.
1992
- fn._name = 'selectCheckbox';
1993
-
1994
- return fn;
1995
- }
1996
-
1648
+ var valueFn = valueProp ? DataTable.util.get(valueProp) : null;
1649
+ var nameFn = nameProp ? DataTable.util.get(nameProp) : null;
1650
+ var fn = function (data, type, row, meta) {
1651
+ var dtRow = meta.settings.data[meta.row];
1652
+ var selected = dtRow._select_selected;
1653
+ var ariaLabel = meta.settings.language.select.aria.rowCheckbox;
1654
+ var selectable = meta.settings._select.selectable;
1655
+ var selectedClass = meta.settings._select.className;
1656
+ if (type === 'display') {
1657
+ // Check if the row is selectable before showing the checkbox
1658
+ if (selectable) {
1659
+ var result = selectable(row, dtRow.tr, meta.row);
1660
+ if (result === false) {
1661
+ return '';
1662
+ }
1663
+ }
1664
+ return Dom.c('input')
1665
+ .attr({
1666
+ 'aria-label': ariaLabel,
1667
+ class: checkboxClass(false),
1668
+ name: nameFn ? nameFn(row) : null,
1669
+ type: 'checkbox',
1670
+ value: valueFn ? valueFn(row) : null,
1671
+ checked: selected
1672
+ })
1673
+ .on('input', function (e) {
1674
+ // Let Select 100% cotrol the state of the checkbox
1675
+ e.preventDefault();
1676
+ // And make sure this checkbox matches it's row as it is
1677
+ // possible to check out of sync if this was clicked on to
1678
+ // deselect a range but remains selected itself
1679
+ Dom.s(this).prop('checked', Dom.s(this).closest('tr').classHas(selectedClass));
1680
+ })
1681
+ .get(0);
1682
+ }
1683
+ else if (type === 'type') {
1684
+ return 'select-checkbox';
1685
+ }
1686
+ else if (type === 'filter') {
1687
+ return '';
1688
+ }
1689
+ return selected ? 'X' : '';
1690
+ };
1691
+ // Workaround so uglify doesn't strip the function name. It is used
1692
+ // for the column type detection.
1693
+ fn._name = 'selectCheckbox';
1694
+ return fn;
1695
+ };
1997
1696
  // Legacy checkbox ordering
1998
1697
  DataTable.ext.order['select-checkbox'] = function (settings, col) {
1999
- return this.api()
2000
- .column(col, { order: 'index' })
2001
- .nodes()
2002
- .map(function (td) {
2003
- if (settings._select.items === 'row') {
2004
- return $(td).parent().hasClass(settings._select.className).toString();
2005
- }
2006
- else if (settings._select.items === 'cell') {
2007
- return $(td).hasClass(settings._select.className).toString();
2008
- }
2009
- return false;
2010
- });
1698
+ return this.api()
1699
+ .column(col, { order: 'index' })
1700
+ .nodes()
1701
+ .map(function (td) {
1702
+ if (settings._select.items === 'row') {
1703
+ return Dom.s(td)
1704
+ .parent()
1705
+ .classHas(settings._select.className)
1706
+ .toString();
1707
+ }
1708
+ else if (settings._select.items === 'cell') {
1709
+ return Dom.s(td)
1710
+ .classHas(settings._select.className)
1711
+ .toString();
1712
+ }
1713
+ return false;
1714
+ });
2011
1715
  };
2012
-
2013
- $.fn.DataTable.select = DataTable.select;
2014
-
2015
1716
  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2016
1717
  * Initialisation
2017
1718
  */
2018
-
2019
1719
  // DataTables creation - we need this to run _before_ data is read in, but
2020
1720
  // for backwards compat. we also run again on preInit. If it happens twice
2021
1721
  // it will simply do nothing the second time around.
2022
- $(document).on('i18n.dt.dtSelect preInit.dt.dtSelect', function (e, ctx) {
2023
- if (e.namespace !== 'dt') {
2024
- return;
2025
- }
2026
-
2027
- DataTable.select.init(new DataTable.Api(ctx));
1722
+ Dom.s(document).on('i18n.dt.dtSelect preInit.dt.dtSelect', function (e, ctx) {
1723
+ if (e.namespace !== 'dt') {
1724
+ return;
1725
+ }
1726
+ DataTable.select.init(new DataTable.Api(ctx));
2028
1727
  });
2029
1728
 
2030
1729