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