datatables.net-autofill 2.7.1 → 3.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,1247 +1,951 @@
1
- /*! AutoFill 2.7.1
2
- * © SpryMedia Ltd - datatables.net/license
1
+ /*! AutoFill 3.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, { Dom, util, Api } from 'datatables.net';
7
6
 
8
- // Allow reassignment of the $ variable
9
- let $ = jQuery;
10
-
11
-
12
- /**
13
- * @summary AutoFill
14
- * @description Add Excel like click and drag auto-fill options to DataTables
15
- * @version 2.7.1
16
- * @author SpryMedia Ltd (www.sprymedia.co.uk)
17
- * @copyright SpryMedia Ltd.
18
- *
19
- * This source file is free software, available under the following license:
20
- * MIT license - http://datatables.net/license/mit
21
- *
22
- * This source file is distributed in the hope that it will be useful, but
23
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
24
- * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
25
- *
26
- * For details please refer to: http://www.datatables.net
27
- */
28
7
 
8
+ if (!DataTable || !DataTable.versionCheck || !DataTable.versionCheck('3')) {
9
+ throw 'Warning: AutoFill requires DataTables 3 or greater';
10
+ }
29
11
  var _instance = 0;
30
-
31
- /**
32
- * AutoFill provides Excel like auto-fill features for a DataTable
33
- *
34
- * @class AutoFill
35
- * @constructor
36
- * @param {object} oTD DataTables settings object
37
- * @param {object} oConfig Configuration object for AutoFill
12
+ class AutoFill {
13
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
14
+ * Public methods (exposed via the DataTables API below)
15
+ */
16
+ enabled() {
17
+ return this.s.enabled;
18
+ }
19
+ enable(flag = true) {
20
+ let that = this;
21
+ let namespace = this.s.namespace;
22
+ if (flag === false) {
23
+ return this.disable();
24
+ }
25
+ this.s.enabled = true;
26
+ this._focusListener();
27
+ this.dom.handle.on('mousedown touchstart', function (e) {
28
+ that._mousedown(e);
29
+ return false;
30
+ });
31
+ let orientationReset = function () {
32
+ that.s.handle = {
33
+ height: 0,
34
+ width: 0
35
+ };
36
+ that.dom.handle.css({
37
+ height: '',
38
+ width: ''
39
+ });
40
+ if (that.dom.attachedTo) {
41
+ that._attach(that.dom.attachedTo);
42
+ }
43
+ };
44
+ Dom.w.on('resize' + namespace, function () {
45
+ let handle = Dom.s('div.dtaf-handle');
46
+ if (handle.count() > 0 && that.dom.attachedTo) {
47
+ that._attach(that.dom.attachedTo);
48
+ }
49
+ });
50
+ Dom.w.on('orientationchange' + namespace, function () {
51
+ setTimeout(function () {
52
+ orientationReset();
53
+ setTimeout(orientationReset, 150);
54
+ }, 50);
55
+ });
56
+ return this;
57
+ }
58
+ disable() {
59
+ this.s.enabled = false;
60
+ this._focusListenerRemove();
61
+ return this;
62
+ }
63
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
64
+ * Constructor
65
+ */
66
+ constructor(dt, opts) {
67
+ this.c = util.object.assignDeep({}, AutoFill.defaults, opts);
68
+ this.s = {
69
+ dt: new DataTable.Api(dt),
70
+ enabled: false,
71
+ end: { column: 0, row: 0 },
72
+ handle: {
73
+ height: 0,
74
+ width: 0
75
+ },
76
+ namespace: '.autoFill' + _instance++,
77
+ scroll: {
78
+ windowHeight: 0,
79
+ windowWidth: 0,
80
+ dtTop: 0,
81
+ dtLeft: 0,
82
+ dtHeight: 0,
83
+ dtWidth: 0
84
+ },
85
+ scrollInterval: null,
86
+ start: { column: 0, row: 0 }
87
+ };
88
+ this.dom = {
89
+ attachedTo: null,
90
+ container: Dom.c('div').classAdd('dtaf-container'),
91
+ closeButton: Dom.c('button')
92
+ .classAdd(AutoFill.classes.close)
93
+ .html('×'),
94
+ dtScroll: null,
95
+ handle: Dom.c('div').classAdd('dtaf-handle'),
96
+ list: Dom.c('div')
97
+ .classAdd('dtaf-list')
98
+ .html(this.s.dt.i18n('autoFill.info', ''))
99
+ .attr('aria-modal', true)
100
+ .attr('role', 'dialog')
101
+ .append(Dom.c('div').classAdd('dtaf-list-items')),
102
+ offsetParent: null,
103
+ start: null,
104
+ select: {
105
+ top: Dom.c('div').classAdd('dtaf-select top'),
106
+ right: Dom.c('div').classAdd('dtaf-select right'),
107
+ bottom: Dom.c('div').classAdd('dtaf-select bottom'),
108
+ left: Dom.c('div').classAdd('dtaf-select left')
109
+ }
110
+ };
111
+ this.dom.list.appendTo(this.dom.container);
112
+ // Go!
113
+ this._init();
114
+ }
115
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
116
+ * Private methods
117
+ */
118
+ /**
119
+ * Initialise the RowReorder instance
120
+ */
121
+ _init() {
122
+ let dt = this.s.dt;
123
+ // Need to account for scrolling as it has a different DOM structure
124
+ let dtScroll = Dom.s(this.s.dt.table().container()).find('div.dt-scroll-body');
125
+ // Make the instance accessible to the API
126
+ dt.settings()[0].autoFill = this;
127
+ if (dtScroll.count()) {
128
+ this.dom.dtScroll = dtScroll;
129
+ // Need to scroll container to be the offset parent
130
+ if (dtScroll.css('position') === 'static') {
131
+ dtScroll.css('position', 'relative');
132
+ }
133
+ }
134
+ if (this.c.enable !== false) {
135
+ this.enable();
136
+ }
137
+ dt.on('destroy.autoFill', () => {
138
+ this._focusListenerRemove();
139
+ this.dom.handle.off();
140
+ });
141
+ }
142
+ /**
143
+ * Display the AutoFill drag handle by appending it to a table cell. This is
144
+ * the opposite of the _detach method.
145
+ *
146
+ * @param node Cell to insert the handle into
147
+ */
148
+ _attach(node) {
149
+ let dt = this.s.dt;
150
+ let idx = dt.cell(node).index();
151
+ let handle = this.dom.handle;
152
+ let handleDim = this.s.handle;
153
+ if (!idx ||
154
+ dt.columns(this.c.columns).indexes().indexOf(idx.column) === -1) {
155
+ this._detach();
156
+ return;
157
+ }
158
+ if (!this.dom.offsetParent) {
159
+ // We attach to the table's offset parent
160
+ this.dom.offsetParent = dt.table().node()
161
+ .offsetParent;
162
+ }
163
+ if (!handleDim.height || !handleDim.width) {
164
+ // Append to document so we can get its size. Not expecting it to
165
+ // change during the life time of the page
166
+ handle.appendTo('body');
167
+ handleDim.height = handle.height('outer');
168
+ handleDim.width = handle.width('outer');
169
+ }
170
+ // Might need to go through multiple offset parents
171
+ let offset = this._getPosition(node, this.dom.offsetParent);
172
+ this.dom.attachedTo = node;
173
+ handle
174
+ .css({
175
+ top: offset.top + node.offsetHeight - handleDim.height + 'px',
176
+ left: offset.left + node.offsetWidth - handleDim.width + 'px'
177
+ })
178
+ .appendTo(this.dom.offsetParent);
179
+ }
180
+ /**
181
+ * Determine can the fill type should be. This can be automatic, or ask the
182
+ * end user.
183
+ *
184
+ * @param cells Information about the selected cells from the key up
185
+ * function
186
+ */
187
+ _actionSelector(cells) {
188
+ let that = this;
189
+ let dt = this.s.dt;
190
+ let actions = AutoFill.actions;
191
+ let available = [];
192
+ // "Ask" each plug-in if it wants to handle this data
193
+ util.object.each(actions, function (key, action) {
194
+ if (action.available(dt, cells)) {
195
+ available.push(key);
196
+ }
197
+ });
198
+ if (available.length === 1 && this.c.alwaysAsk === false) {
199
+ // Only one action available - enact it immediately
200
+ let result = actions[available[0]].execute(dt, cells, null);
201
+ this._update(result, cells);
202
+ }
203
+ else if (available.length > 1 || this.c.alwaysAsk) {
204
+ // Multiple actions available - ask the end user what they want to
205
+ // do
206
+ let list = this.dom.list.children('div.dtaf-list-items').empty();
207
+ // Add a cancel option
208
+ available.push('cancel');
209
+ for (let i = 0; i < available.length; i++) {
210
+ let name = available[i];
211
+ list.append(Dom.c('button')
212
+ .classAdd(AutoFill.classes.btn)
213
+ .html(actions[name].option(dt, cells))
214
+ .append(Dom.c('span')
215
+ .classAdd('dtaf-button')
216
+ .html(dt.i18n('autoFill.button', '')))
217
+ .on('click', function (e) {
218
+ if (e.target.nodeName.toLowerCase() !== 'button') {
219
+ return;
220
+ }
221
+ let result = actions[name].execute(dt, cells, Dom.s(this).closest('button'));
222
+ that._update(result, cells);
223
+ that.dom.container.remove();
224
+ }));
225
+ }
226
+ this.dom.container.appendTo('body');
227
+ this.dom.container.on('click', function (e) {
228
+ // Ignore clicks that aren't on the background
229
+ if (e.target !== that.dom.container.get(0)) {
230
+ return;
231
+ }
232
+ that.dom.container.remove();
233
+ });
234
+ if (this.c.closeButton) {
235
+ this.dom.list
236
+ .prepend(this.dom.closeButton)
237
+ .classAdd(AutoFill.classes.closeable);
238
+ this.dom.closeButton.on('click', function () {
239
+ return that.dom.container.trigger('click');
240
+ });
241
+ }
242
+ }
243
+ }
244
+ /**
245
+ * Remove the AutoFill handle from the document
246
+ */
247
+ _detach() {
248
+ this.dom.attachedTo = null;
249
+ this.dom.handle.detach();
250
+ }
251
+ /**
252
+ * Draw the selection outline by calculating the range between the start
253
+ * and end cells, then placing the highlighting elements to draw a rectangle
254
+ *
255
+ * @param target End cell
256
+ * @param e Originating event
257
+ * @private
258
+ */
259
+ _drawSelection(target, e) {
260
+ // Calculate boundary for start cell to this one
261
+ var dt = this.s.dt;
262
+ var start = this.s.start;
263
+ var startCell = Dom.s(this.dom.start);
264
+ var end = {
265
+ row: this.c.vertical
266
+ ? dt
267
+ .rows({ page: 'current' })
268
+ .nodes()
269
+ .indexOf(target.parentNode)
270
+ : start.row,
271
+ column: this.c.horizontal ? Dom.s(target).index() : start.column
272
+ };
273
+ var colIndx = dt.column.index('toData', end.column);
274
+ var endRow = dt.row(':eq(' + end.row + ')', { page: 'current' }); // Workaround for M581
275
+ var endCell = Dom.s(dt.cell(endRow.index(), colIndx).node());
276
+ // Be sure that is a DataTables controlled cell
277
+ if (!dt.cell(endCell.get(0)).any()) {
278
+ return;
279
+ }
280
+ // if target is not in the columns available - do nothing
281
+ if (dt.columns(this.c.columns).indexes().indexOf(colIndx) === -1 ||
282
+ end.row === -1) {
283
+ return;
284
+ }
285
+ this.s.end = end;
286
+ var top, bottom, left, right, height, width;
287
+ top = start.row < end.row ? startCell : endCell;
288
+ bottom = start.row < end.row ? endCell : startCell;
289
+ left = start.column < end.column ? startCell : endCell;
290
+ right = start.column < end.column ? endCell : startCell;
291
+ top = this._getPosition(top.get(0)).top;
292
+ left = this._getPosition(left.get(0)).left;
293
+ height =
294
+ this._getPosition(bottom.get(0)).top + bottom.height('outer') - top;
295
+ width =
296
+ this._getPosition(right.get(0)).left + right.width('outer') - left;
297
+ var select = this.dom.select;
298
+ select.top.css({
299
+ top: top + 'px',
300
+ left: left + 'px',
301
+ width: width + 'px'
302
+ });
303
+ select.left.css({
304
+ top: top + 'px',
305
+ left: left + 'px',
306
+ height: height + 'px'
307
+ });
308
+ select.bottom.css({
309
+ top: top + height + 'px',
310
+ left: left + 'px',
311
+ width: width + 'px'
312
+ });
313
+ select.right.css({
314
+ top: top + 'px',
315
+ left: left + width + 'px',
316
+ height: height + 'px'
317
+ });
318
+ }
319
+ /**
320
+ * Use the Editor API to perform an update based on the new data for the
321
+ * cells
322
+ *
323
+ * @param cells Information about the selected cells from the key up
324
+ * function
325
+ */
326
+ _editor(cells) {
327
+ let dt = this.s.dt;
328
+ let editor = this.c.editor;
329
+ if (!editor) {
330
+ return;
331
+ }
332
+ // Build the object structure for Editor's multi-row editing
333
+ let idValues = {};
334
+ let nodes = [];
335
+ let fields = editor.fields();
336
+ for (let i = 0, ien = cells.length; i < ien; i++) {
337
+ for (let j = 0, jen = cells[i].length; j < jen; j++) {
338
+ let cell = cells[i][j];
339
+ // Determine the field name for the cell being edited
340
+ let col = dt.settings()[0].columns[cell.index.column];
341
+ let fieldName = col.editField;
342
+ if (fieldName === undefined) {
343
+ let dataSrc = col.data;
344
+ // dataSrc is the `field.data` property, but we need to set
345
+ // using the field name, so we need to translate from the
346
+ // data to the name
347
+ for (let k = 0, ken = fields.length; k < ken; k++) {
348
+ let field = editor.field(fields[k]);
349
+ if (field.dataSrc() === dataSrc) {
350
+ fieldName = field.name();
351
+ break;
352
+ }
353
+ }
354
+ }
355
+ if (!fieldName) {
356
+ throw ('Could not automatically determine field data. ' +
357
+ 'Please see https://datatables.net/tn/11');
358
+ }
359
+ if (typeof fieldName !== 'string') {
360
+ throw 'AutoFill with multiple edit fields is not supported';
361
+ }
362
+ if (!idValues[fieldName]) {
363
+ idValues[fieldName] = {};
364
+ }
365
+ let id = dt.row(cell.index.row).id();
366
+ idValues[fieldName][id] = cell.set;
367
+ // Keep a list of cells so we can activate the bubble editing
368
+ // with them
369
+ nodes.push(cell.index);
370
+ }
371
+ }
372
+ // Perform the edit using bubble editing as it allows us to specify
373
+ // the cells to be edited, rather than using full rows
374
+ editor
375
+ .bubble(nodes, false)
376
+ .multiSet(idValues)
377
+ .submit(null, function () {
378
+ // If an error happens, Editor will show an alert, and then we
379
+ // need to finish the edit since we can't do anything else.
380
+ editor.close();
381
+ });
382
+ }
383
+ /**
384
+ * Emit an event on the DataTable for listeners
385
+ *
386
+ * @param name Event name
387
+ * @param args Event arguments
388
+ */
389
+ _emitEvent(name, args) {
390
+ this.s.dt.trigger(name, args);
391
+ }
392
+ /**
393
+ * Attach suitable listeners (based on the configuration) that will attach
394
+ * and detach the AutoFill handle in the document.
395
+ */
396
+ _focusListener() {
397
+ var that = this;
398
+ var dt = this.s.dt;
399
+ var namespace = this.s.namespace;
400
+ var focus = this.c.focus !== null
401
+ ? this.c.focus
402
+ : dt.init().keys || dt.settings()[0].keytable
403
+ ? 'focus'
404
+ : 'hover';
405
+ // All event listeners attached here are removed in the `destroy`
406
+ // callback in the constructor
407
+ if (focus === 'focus') {
408
+ dt.on('key-focus.autoFill', function (e, dt, cell) {
409
+ that._attach(cell.node());
410
+ }).on('key-blur.autoFill', function (e, dt, cell) {
411
+ that._detach();
412
+ });
413
+ }
414
+ else if (focus === 'click') {
415
+ Dom.s(dt.table().body()).on('click' + namespace, 'td, th', function (e) {
416
+ that._attach(this);
417
+ });
418
+ Dom.s(document.body).on('click' + namespace, function (e) {
419
+ if (!Dom.s(e.target).closest(dt.table().body()).count()) {
420
+ that._detach();
421
+ }
422
+ });
423
+ }
424
+ else {
425
+ Dom.s(dt.table().body())
426
+ .on('mouseenter' + namespace + ' touchstart' + namespace, 'td, th', function (e) {
427
+ that._attach(this);
428
+ })
429
+ .on('mouseleave' + namespace + 'touchend' + namespace, function (e) {
430
+ if (Dom.s(e.relatedTarget).classHas('dtaf-handle')) {
431
+ return;
432
+ }
433
+ that._detach();
434
+ });
435
+ }
436
+ }
437
+ /**
438
+ * Clean up the event listeners
439
+ */
440
+ _focusListenerRemove() {
441
+ let namespace = this.s.namespace;
442
+ let dt = this.s.dt;
443
+ dt.off('.autoFill');
444
+ Dom.s(dt.table().body()).off(namespace);
445
+ Dom.s(document.body).off(namespace);
446
+ Dom.w.off(namespace);
447
+ }
448
+ /**
449
+ * Get the position of a node, relative to another, including any scrolling
450
+ * offsets.
451
+ *
452
+ * @param node Node to get the position of
453
+ * @param targetHost Node to use as the parent
454
+ * @return Offset calculation
455
+ */
456
+ _getPosition(node, targetHost) {
457
+ let targetParent = Dom.s(this.s.dt.table().node().offsetParent), currNode = node, currOffsetParent, top = 0, left = 0;
458
+ if (targetHost) {
459
+ targetParent = Dom.s(targetHost);
460
+ }
461
+ do {
462
+ let positionTop = currNode.offsetTop;
463
+ let positionLeft = currNode.offsetLeft;
464
+ currOffsetParent = Dom.s(currNode.offsetParent);
465
+ top +=
466
+ positionTop +
467
+ parseInt(currOffsetParent.css('border-top-width') || '0') * 1;
468
+ left +=
469
+ positionLeft +
470
+ parseInt(currOffsetParent.css('border-left-width') || '0') * 1;
471
+ // Emergency fall back. Shouldn't happen, but just in case!
472
+ if (currNode.nodeName.toLowerCase() === 'body') {
473
+ break;
474
+ }
475
+ currNode = currOffsetParent.get(0); // for next loop
476
+ } while (currOffsetParent.get(0) !== targetParent.get(0));
477
+ return {
478
+ top: top,
479
+ left: left
480
+ };
481
+ }
482
+ /**
483
+ * Start mouse drag - selects the start cell
484
+ *
485
+ * @param e Mouse down event
486
+ */
487
+ _mousedown(e) {
488
+ let that = this;
489
+ let dt = this.s.dt;
490
+ this.dom.start = this.dom.attachedTo;
491
+ this.s.start = {
492
+ row: dt
493
+ .rows({ page: 'current' })
494
+ .nodes()
495
+ .indexOf(Dom.s(this.dom.start).parent().get(0)),
496
+ column: Dom.s(this.dom.start).index()
497
+ };
498
+ Dom.s(document.body)
499
+ .on('mousemove.autoFill touchmove.autoFill', function (e) {
500
+ that._mousemove(e);
501
+ // If it is a touch event then when the touch ends we need to
502
+ // remove the handle
503
+ if (e.type === 'touchmove') {
504
+ Dom.s(document.body).one('touchend.autoFill', function () {
505
+ that._detach();
506
+ });
507
+ }
508
+ })
509
+ .on('mouseup.autoFill touchend.autoFill', function (e) {
510
+ that._mouseup(e);
511
+ });
512
+ let select = this.dom.select;
513
+ let offsetParent = dt.table().node().offsetParent;
514
+ select.top.appendTo(offsetParent);
515
+ select.left.appendTo(offsetParent);
516
+ select.right.appendTo(offsetParent);
517
+ select.bottom.appendTo(offsetParent);
518
+ this._drawSelection(this.dom.start, e);
519
+ this.dom.handle.css('display', 'none');
520
+ // Cache scrolling information so mouse move doesn't need to read.
521
+ // This assumes that the window and DT scroller will not change size
522
+ // during an AutoFill drag, which I think is a fair assumption
523
+ let scrollWrapper = this.dom.dtScroll;
524
+ this.s.scroll = {
525
+ windowHeight: window.innerHeight,
526
+ windowWidth: window.innerWidth,
527
+ dtTop: scrollWrapper ? scrollWrapper.offset().top : 0,
528
+ dtLeft: scrollWrapper ? scrollWrapper.offset().left : 0,
529
+ dtHeight: scrollWrapper ? scrollWrapper.height('outer') : 0,
530
+ dtWidth: scrollWrapper ? scrollWrapper.width('outer') : 0
531
+ };
532
+ }
533
+ /**
534
+ * Mouse drag - selects the end cell and update the selection display for
535
+ * the end user
536
+ *
537
+ * @param e Mouse move event
538
+ */
539
+ _mousemove(e) {
540
+ let target = e.touches && e.touches.length
541
+ ? document.elementFromPoint(e.touches[0].clientX, e.touches[0].clientY)
542
+ : e.target;
543
+ let name = target.nodeName.toLowerCase();
544
+ if (name !== 'td' && name !== 'th') {
545
+ return;
546
+ }
547
+ this._drawSelection(target, e);
548
+ this._shiftScroll(e);
549
+ }
550
+ /**
551
+ * End mouse drag - perform the update actions
552
+ *
553
+ * @param e Mouse up event
554
+ * @private
555
+ */
556
+ _mouseup(e) {
557
+ Dom.s(document.body).off('.autoFill');
558
+ let that = this;
559
+ let dt = this.s.dt;
560
+ let select = this.dom.select;
561
+ select.top.remove();
562
+ select.left.remove();
563
+ select.right.remove();
564
+ select.bottom.remove();
565
+ this.dom.handle.css('display', 'block');
566
+ // Display complete - now do something useful with the selection!
567
+ let start = this.s.start;
568
+ let end = this.s.end;
569
+ // Haven't selected multiple cells, so nothing to do
570
+ if (start.row === end.row && start.column === end.column) {
571
+ return;
572
+ }
573
+ let startDt = dt.cell(':eq(' + start.row + ')', start.column + ':visible', { page: 'current' });
574
+ // If Editor is active inside this cell (inline editing) we need to wait
575
+ // for Editor to submit and then we can loop back and trigger the fill.
576
+ if (Dom.s(startDt.node()).find('div.DTE').count()) {
577
+ let editor = dt.editor();
578
+ editor
579
+ .on('submitSuccess.dtaf close.dtaf', function () {
580
+ editor.off('.dtaf');
581
+ setTimeout(function () {
582
+ that._mouseup(e);
583
+ }, 100);
584
+ })
585
+ .on('submitComplete.dtaf preSubmitCancelled.dtaf close.dtaf', function () {
586
+ editor.off('.dtaf');
587
+ });
588
+ // Make the current input submit
589
+ editor.submit();
590
+ return;
591
+ }
592
+ // Build a matrix representation of the selected rows
593
+ let rows = this._range(start.row, end.row);
594
+ let columns = this._range(start.column, end.column);
595
+ let selected = [];
596
+ let dtSettings = dt.settings()[0];
597
+ let dtColumns = dtSettings.columns;
598
+ let enabledColumns = dt.columns(this.c.columns).indexes();
599
+ for (let rowIdx = 0; rowIdx < rows.length; rowIdx++) {
600
+ selected.push(columns
601
+ .map(function (column) {
602
+ let row = dt.row(':eq(' + rows[rowIdx] + ')', {
603
+ page: 'current'
604
+ });
605
+ let cell = dt.cell(row.index(), column + ':visible');
606
+ let data = cell.data();
607
+ let cellIndex = cell.index();
608
+ let editField = dtColumns[cellIndex.column].editField;
609
+ if (editField !== undefined) {
610
+ data = DataTable.util.get(editField)(dt.row(cellIndex.row).data());
611
+ }
612
+ if (enabledColumns.indexOf(cellIndex.column) === -1) {
613
+ return;
614
+ }
615
+ return {
616
+ cell: cell,
617
+ data: data,
618
+ label: cell.data(),
619
+ index: cellIndex
620
+ };
621
+ })
622
+ .filter(d => !!d));
623
+ }
624
+ this._actionSelector(selected);
625
+ // Stop shiftScroll
626
+ if (this.s.scrollInterval) {
627
+ clearInterval(this.s.scrollInterval);
628
+ this.s.scrollInterval = null;
629
+ }
630
+ }
631
+ /**
632
+ * Create an array with a range of numbers defined by the start and end
633
+ * parameters passed in (inclusive!).
634
+ *
635
+ * @param start Start
636
+ * @param end End
637
+ */
638
+ _range(start, end) {
639
+ var out = [];
640
+ var i;
641
+ if (start <= end) {
642
+ for (i = start; i <= end; i++) {
643
+ out.push(i);
644
+ }
645
+ }
646
+ else {
647
+ for (i = start; i >= end; i--) {
648
+ out.push(i);
649
+ }
650
+ }
651
+ return out;
652
+ }
653
+ /**
654
+ * Move the window and DataTables scrolling during a drag to scroll new
655
+ * content into view. This is done by proximity to the edge of the scrolling
656
+ * container of the mouse - for example near the top edge of the window
657
+ * should scroll up. This is a little complicated as there are two elements
658
+ * that can be scrolled - the window and the DataTables scrolling view port
659
+ * (if scrollX and / or scrollY is enabled).
660
+ *
661
+ * @param e Mouse move event object
662
+ */
663
+ _shiftScroll(e) {
664
+ var that = this;
665
+ var scroll = this.s.scroll;
666
+ var runInterval = false;
667
+ var scrollSpeed = 5;
668
+ var buffer = 65;
669
+ // Different values if using a touchscreen
670
+ var pageX = !e.type.includes('touch')
671
+ ? e.pageX - window.scrollX
672
+ : e.touches[0].clientX;
673
+ var pageY = !e.type.includes('touch')
674
+ ? e.pageY - window.scrollY
675
+ : e.touches[0].clientY;
676
+ var windowY = pageY, windowX = pageX, windowVert, windowHoriz, dtVert, dtHoriz;
677
+ // Window calculations - based on the mouse position in the window,
678
+ // regardless of scrolling
679
+ if (windowY < buffer) {
680
+ windowVert = scrollSpeed * -1;
681
+ }
682
+ else if (windowY > scroll.windowHeight - buffer) {
683
+ windowVert = scrollSpeed;
684
+ }
685
+ if (windowX < buffer) {
686
+ windowHoriz = scrollSpeed * -1;
687
+ }
688
+ else if (windowX > scroll.windowWidth - buffer) {
689
+ windowHoriz = scrollSpeed;
690
+ }
691
+ // DataTables scrolling calculations - based on the table's position in
692
+ // the document and the mouse position on the page
693
+ if (scroll.dtTop !== null && pageY < scroll.dtTop + buffer) {
694
+ dtVert = scrollSpeed * -1;
695
+ }
696
+ else if (scroll.dtTop !== null &&
697
+ pageY > scroll.dtTop + scroll.dtHeight - buffer) {
698
+ dtVert = scrollSpeed;
699
+ }
700
+ if (scroll.dtLeft !== null && pageX < scroll.dtLeft + buffer) {
701
+ dtHoriz = scrollSpeed * -1;
702
+ }
703
+ else if (scroll.dtLeft !== null &&
704
+ pageX > scroll.dtLeft + scroll.dtWidth - buffer) {
705
+ dtHoriz = scrollSpeed;
706
+ }
707
+ // This is where it gets interesting. We want to continue scrolling
708
+ // without requiring a mouse move, so we need an interval to be
709
+ // triggered. The interval should continue until it is no longer needed,
710
+ // but it must also use the latest scroll commands (for example consider
711
+ // that the mouse might move from scrolling up to scrolling left, all
712
+ // with the same interval running. We use the `scroll` object to "pass"
713
+ // this information to the interval. Can't use local variables as they
714
+ // wouldn't be the ones that are used by an already existing interval!
715
+ if (windowVert || windowHoriz || dtVert || dtHoriz) {
716
+ scroll.windowVert = windowVert;
717
+ scroll.windowHoriz = windowHoriz;
718
+ scroll.dtVert = dtVert;
719
+ scroll.dtHoriz = dtHoriz;
720
+ runInterval = true;
721
+ }
722
+ else if (this.s.scrollInterval) {
723
+ // Don't need to scroll - remove any existing timer
724
+ clearInterval(this.s.scrollInterval);
725
+ this.s.scrollInterval = null;
726
+ }
727
+ // If we need to run the interval to scroll and there is no existing
728
+ // interval (if there is an existing one, it will continue to run)
729
+ if (!this.s.scrollInterval && runInterval) {
730
+ this.s.scrollInterval = setInterval(function () {
731
+ var _a;
732
+ // Don't need to worry about setting scroll <0 or beyond the
733
+ // scroll bound as the browser will just reject that.
734
+ window.scrollTo(window.scrollX +
735
+ (scroll.windowHoriz ? scroll.windowHoriz : 0), window.scrollY + (scroll.windowVert ? scroll.windowVert : 0));
736
+ // DataTables scrolling
737
+ if (scroll.dtVert || scroll.dtHoriz) {
738
+ var scroller = (_a = that.dom.dtScroll) === null || _a === void 0 ? void 0 : _a.get(0);
739
+ if (scroller && scroll.dtVert) {
740
+ scroller.scrollTop += scroll.dtVert;
741
+ }
742
+ if (scroller && scroll.dtHoriz) {
743
+ scroller.scrollLeft += scroll.dtHoriz;
744
+ }
745
+ }
746
+ }, 20);
747
+ }
748
+ }
749
+ /**
750
+ * Update the DataTable after the user has selected what they want to do
751
+ *
752
+ * @param result Return from the `execute` method - can be false internally
753
+ * to do nothing. This is not documented for plug-ins and is used only by
754
+ * the cancel option.
755
+ * @param cells Information about the selected cells from the key up
756
+ * function, augmented with the set values
757
+ */
758
+ _update(result, cells) {
759
+ // Do nothing on `false` return from an execute function
760
+ if (result === false) {
761
+ return;
762
+ }
763
+ let dt = this.s.dt;
764
+ let cell;
765
+ let columns = dt.columns(this.c.columns).indexes();
766
+ // Potentially allow modifications to the cells matrix
767
+ this._emitEvent('preAutoFill', [dt, cells]);
768
+ this._editor(cells);
769
+ // Automatic updates are not performed if `update` is null and the
770
+ // `editor` parameter is passed in - the reason being that Editor will
771
+ // update the data once submitted
772
+ let update = this.c.update !== null
773
+ ? this.c.update
774
+ : this.c.editor
775
+ ? false
776
+ : true;
777
+ if (update) {
778
+ for (let i = 0, ien = cells.length; i < ien; i++) {
779
+ for (let j = 0, jen = cells[i].length; j < jen; j++) {
780
+ cell = cells[i][j];
781
+ if (columns.indexOf(cell.index.column) !== -1) {
782
+ cell.cell.data(cell.set);
783
+ }
784
+ }
785
+ }
786
+ dt.draw(false);
787
+ }
788
+ this._emitEvent('autoFill', [dt, cells]);
789
+ }
790
+ }
791
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
792
+ * Statics
38
793
  */
39
- var AutoFill = function( dt, opts )
40
- {
41
- if ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.11' ) ) {
42
- throw( "Warning: AutoFill requires DataTables 1.11 or greater");
43
- }
44
-
45
- // User and defaults configuration object
46
- this.c = $.extend( true, {},
47
- DataTable.defaults.autoFill,
48
- AutoFill.defaults,
49
- opts
50
- );
51
-
52
- /**
53
- * @namespace Settings object which contains customisable information for AutoFill instance
54
- */
55
- this.s = {
56
- /** @type {DataTable.Api} DataTables' API instance */
57
- dt: new DataTable.Api( dt ),
58
-
59
- /** @type {String} Unique namespace for events attached to the document */
60
- namespace: '.autoFill'+(_instance++),
61
-
62
- /** @type {Object} Cached dimension information for use in the mouse move event handler */
63
- scroll: {},
64
-
65
- /** @type {integer} Interval object used for smooth scrolling */
66
- scrollInterval: null,
67
-
68
- handle: {
69
- height: 0,
70
- width: 0
71
- },
72
-
73
- /**
74
- * Enabled setting
75
- * @type {Boolean}
76
- */
77
- enabled: false
78
- };
79
-
80
-
81
- /**
82
- * @namespace Common and useful DOM elements for the class instance
83
- */
84
- this.dom = {
85
- closeButton: $('<div class="dtaf-popover-close">&times;</div>'),
86
-
87
- /** @type {jQuery} AutoFill handle */
88
- handle: $('<div class="dt-autofill-handle"/>'),
89
-
90
- /**
91
- * @type {Object} Selected cells outline - Need to use 4 elements,
92
- * otherwise the mouse over if you back into the selected rectangle
93
- * will be over that element, rather than the cells!
94
- */
95
- select: {
96
- top: $('<div class="dt-autofill-select top"/>'),
97
- right: $('<div class="dt-autofill-select right"/>'),
98
- bottom: $('<div class="dt-autofill-select bottom"/>'),
99
- left: $('<div class="dt-autofill-select left"/>')
100
- },
101
-
102
- /** @type {jQuery} Fill type chooser background */
103
- background: $('<div class="dt-autofill-background"/>'),
104
-
105
- /** @type {jQuery} Fill type chooser */
106
- list: $('<div class="dt-autofill-list">'+this.s.dt.i18n('autoFill.info', '')+'</div>')
107
- .attr('aria-modal', true)
108
- .attr('role', 'dialog')
109
- .append('<div class="dt-autofill-list-items"></div>'),
110
-
111
- /** @type {jQuery} DataTables scrolling container */
112
- dtScroll: null,
113
-
114
- /** @type {jQuery} Offset parent element */
115
- offsetParent: null
116
- };
117
-
118
-
119
- /* Constructor logic */
120
- this._constructor();
121
- };
122
-
123
-
124
-
125
- $.extend( AutoFill.prototype, {
126
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
127
- * Public methods (exposed via the DataTables API below)
128
- */
129
- enabled: function ()
130
- {
131
- return this.s.enabled;
132
- },
133
-
134
-
135
- enable: function ( flag )
136
- {
137
- var that = this;
138
-
139
- if ( flag === false ) {
140
- return this.disable();
141
- }
142
-
143
- this.s.enabled = true;
144
-
145
- this._focusListener();
146
-
147
- this.dom.handle.on( 'mousedown touchstart', function (e) {
148
- that._mousedown( e );
149
- return false;
150
- } );
151
-
152
- $(window).on('resize', function() {
153
- var handle = $('div.dt-autofill-handle');
154
- if(handle.length > 0 && that.dom.attachedTo !== undefined) {
155
- that._attach(that.dom.attachedTo)
156
- }
157
- })
158
-
159
- let orientationReset = function() {
160
- that.s.handle = {
161
- height: false,
162
- width: false
163
- };
164
- $(that.dom.handle).css({
165
- 'height': '',
166
- 'width': ''
167
- })
168
- if(that.dom.attachedTo !== undefined) {
169
- that._attach(that.dom.attachedTo)
170
- }
171
- }
172
-
173
- $(window)
174
- .on('orientationchange', function() {
175
- setTimeout(function() {
176
- orientationReset();
177
- setTimeout(orientationReset, 150);
178
- }, 50);
179
- });
180
-
181
- return this;
182
- },
183
-
184
- disable: function ()
185
- {
186
- this.s.enabled = false;
187
-
188
- this._focusListenerRemove();
189
-
190
- return this;
191
- },
192
-
193
-
194
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
195
- * Constructor
196
- */
197
-
198
- /**
199
- * Initialise the RowReorder instance
200
- *
201
- * @private
202
- */
203
- _constructor: function ()
204
- {
205
- var that = this;
206
- var dt = this.s.dt;
207
-
208
- // Selectors for DataTables 1 and 2 - only one will be matched
209
- var dtScroll = $('div.dataTables_scrollBody, div.dt-scroll-body', this.s.dt.table().container());
210
-
211
- // Make the instance accessible to the API
212
- dt.settings()[0].autoFill = this;
213
-
214
- if ( dtScroll.length ) {
215
- this.dom.dtScroll = dtScroll;
216
-
217
- // Need to scroll container to be the offset parent
218
- if ( dtScroll.css('position') === 'static' ) {
219
- dtScroll.css( 'position', 'relative' );
220
- }
221
- }
222
-
223
- if ( this.c.enable !== false ) {
224
- this.enable();
225
- }
226
-
227
- dt.on( 'destroy.autoFill', function () {
228
- that._focusListenerRemove();
229
- } );
230
- },
231
-
232
-
233
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
234
- * Private methods
235
- */
236
-
237
- /**
238
- * Display the AutoFill drag handle by appending it to a table cell. This
239
- * is the opposite of the _detach method.
240
- *
241
- * @param {node} node TD/TH cell to insert the handle into
242
- * @private
243
- */
244
- _attach: function ( node )
245
- {
246
- var dt = this.s.dt;
247
- var idx = dt.cell( node ).index();
248
- var handle = this.dom.handle;
249
- var handleDim = this.s.handle;
250
-
251
- if ( ! idx || dt.columns( this.c.columns ).indexes().indexOf( idx.column ) === -1 ) {
252
- this._detach();
253
- return;
254
- }
255
-
256
- if ( ! this.dom.offsetParent ) {
257
- // We attach to the table's offset parent
258
- this.dom.offsetParent = $( dt.table().node() ).offsetParent();
259
- }
260
-
261
- if ( ! handleDim.height || ! handleDim.width ) {
262
- // Append to document so we can get its size. Not expecting it to
263
- // change during the life time of the page
264
- handle.appendTo( 'body' );
265
- handleDim.height = handle.outerHeight();
266
- handleDim.width = handle.outerWidth();
267
- }
268
-
269
- // Might need to go through multiple offset parents
270
- var offset = this._getPosition( node, this.dom.offsetParent );
271
-
272
- this.dom.attachedTo = node;
273
- handle
274
- .css( {
275
- top: offset.top + node.offsetHeight - handleDim.height,
276
- left: offset.left + node.offsetWidth - handleDim.width
277
- } )
278
- .appendTo( this.dom.offsetParent );
279
- },
280
-
281
-
282
- /**
283
- * Determine can the fill type should be. This can be automatic, or ask the
284
- * end user.
285
- *
286
- * @param {array} cells Information about the selected cells from the key
287
- * up function
288
- * @private
289
- */
290
- _actionSelector: function ( cells )
291
- {
292
- var that = this;
293
- var dt = this.s.dt;
294
- var actions = AutoFill.actions;
295
- var available = [];
296
-
297
- // "Ask" each plug-in if it wants to handle this data
298
- $.each( actions, function ( key, action ) {
299
- if ( action.available( dt, cells ) ) {
300
- available.push( key );
301
- }
302
- } );
303
-
304
- if ( available.length === 1 && this.c.alwaysAsk === false ) {
305
- // Only one action available - enact it immediately
306
- var result = actions[ available[0] ].execute( dt, cells );
307
- this._update( result, cells );
308
- }
309
- else if ( available.length > 1 || this.c.alwaysAsk ) {
310
- // Multiple actions available - ask the end user what they want to do
311
- var list = this.dom.list.children('div.dt-autofill-list-items').empty();
312
-
313
- // Add a cancel option
314
- available.push( 'cancel' );
315
-
316
- $.each( available, function ( i, name ) {
317
- list.append( $('<button/>')
318
- .html(actions[ name ].option( dt, cells ))
319
- .append( $('<span class="dt-autofill-button"/>').html(dt.i18n('autoFill.button', '&gt;')))
320
- .on( 'click', function (e) {
321
- if (e.target.nodeName.toLowerCase() !== 'button') {
322
- return;
323
- }
324
-
325
- var result = actions[ name ].execute(
326
- dt, cells, $(this).closest('button')
327
- );
328
- that._update( result, cells );
329
-
330
- that.dom.background.remove();
331
- that.dom.list.remove();
332
- } )
333
- );
334
- } );
335
-
336
- this.dom.background.appendTo( 'body' );
337
- this.dom.background.one('click', function() {
338
- that.dom.background.remove();
339
- that.dom.list.remove();
340
- })
341
- this.dom.list.appendTo( 'body' );
342
-
343
- if (this.c.closeButton) {
344
- this.dom.list.prepend(this.dom.closeButton).addClass(AutoFill.classes.closeable)
345
- this.dom.closeButton.on('click', function() {
346
- return that.dom.background.click()
347
- });
348
- }
349
-
350
- this.dom.list.css( 'margin-top', this.dom.list.outerHeight()/2 * -1 );
351
- }
352
- },
353
-
354
-
355
- /**
356
- * Remove the AutoFill handle from the document
357
- *
358
- * @private
359
- */
360
- _detach: function ()
361
- {
362
- this.dom.attachedTo = null;
363
- this.dom.handle.detach();
364
- },
365
-
366
-
367
- /**
368
- * Draw the selection outline by calculating the range between the start
369
- * and end cells, then placing the highlighting elements to draw a rectangle
370
- *
371
- * @param {node} target End cell
372
- * @param {object} e Originating event
373
- * @private
374
- */
375
- _drawSelection: function ( target, e )
376
- {
377
- // Calculate boundary for start cell to this one
378
- var dt = this.s.dt;
379
- var start = this.s.start;
380
- var startCell = $(this.dom.start);
381
- var end = {
382
- row: this.c.vertical ?
383
- dt.rows( { page: 'current' } ).nodes().indexOf( target.parentNode ) :
384
- start.row,
385
- column: this.c.horizontal ?
386
- $(target).index() :
387
- start.column
388
- };
389
- var colIndx = dt.column.index( 'toData', end.column );
390
- var endRow = dt.row( ':eq('+end.row+')', { page: 'current' } ); // Workaround for M581
391
- var endCell = $( dt.cell( endRow.index(), colIndx ).node() );
392
-
393
- // Be sure that is a DataTables controlled cell
394
- if ( ! dt.cell( endCell ).any() ) {
395
- return;
396
- }
397
-
398
- // if target is not in the columns available - do nothing
399
- if ( dt.columns( this.c.columns ).indexes().indexOf( colIndx ) === -1 || end.row === -1) {
400
- return;
401
- }
402
-
403
- this.s.end = end;
404
-
405
- var top, bottom, left, right, height, width;
406
-
407
- top = start.row < end.row ? startCell : endCell;
408
- bottom = start.row < end.row ? endCell : startCell;
409
- left = start.column < end.column ? startCell : endCell;
410
- right = start.column < end.column ? endCell : startCell;
411
-
412
- top = this._getPosition( top.get(0) ).top;
413
- left = this._getPosition( left.get(0) ).left;
414
- height = this._getPosition( bottom.get(0) ).top + bottom.outerHeight() - top;
415
- width = this._getPosition( right.get(0) ).left + right.outerWidth() - left;
416
-
417
- var select = this.dom.select;
418
- select.top.css( {
419
- top: top,
420
- left: left,
421
- width: width
422
- } );
423
-
424
- select.left.css( {
425
- top: top,
426
- left: left,
427
- height: height
428
- } );
429
-
430
- select.bottom.css( {
431
- top: top + height,
432
- left: left,
433
- width: width
434
- } );
435
-
436
- select.right.css( {
437
- top: top,
438
- left: left + width,
439
- height: height
440
- } );
441
- },
442
-
443
-
444
- /**
445
- * Use the Editor API to perform an update based on the new data for the
446
- * cells
447
- *
448
- * @param {array} cells Information about the selected cells from the key
449
- * up function
450
- * @private
451
- */
452
- _editor: function ( cells )
453
- {
454
- var dt = this.s.dt;
455
- var editor = this.c.editor;
456
-
457
- if ( ! editor ) {
458
- return;
459
- }
460
-
461
- // Build the object structure for Editor's multi-row editing
462
- var idValues = {};
463
- var nodes = [];
464
- var fields = editor.fields();
465
-
466
- for ( var i=0, ien=cells.length ; i<ien ; i++ ) {
467
- for ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {
468
- var cell = cells[i][j];
469
-
470
- // Determine the field name for the cell being edited
471
- var col = dt.settings()[0].aoColumns[ cell.index.column ];
472
- var fieldName = col.editField;
473
-
474
- if ( fieldName === undefined ) {
475
- var dataSrc = col.mData;
476
-
477
- // dataSrc is the `field.data` property, but we need to set
478
- // using the field name, so we need to translate from the
479
- // data to the name
480
- for ( var k=0, ken=fields.length ; k<ken ; k++ ) {
481
- var field = editor.field( fields[k] );
482
-
483
- if ( field.dataSrc() === dataSrc ) {
484
- fieldName = field.name();
485
- break;
486
- }
487
- }
488
- }
489
-
490
- if ( ! fieldName ) {
491
- throw 'Could not automatically determine field data. '+
492
- 'Please see https://datatables.net/tn/11';
493
- }
494
-
495
- if ( ! idValues[ fieldName ] ) {
496
- idValues[ fieldName ] = {};
497
- }
498
-
499
- var id = dt.row( cell.index.row ).id();
500
- idValues[ fieldName ][ id ] = cell.set;
501
-
502
- // Keep a list of cells so we can activate the bubble editing
503
- // with them
504
- nodes.push( cell.index );
505
- }
506
- }
507
-
508
- // Perform the edit using bubble editing as it allows us to specify
509
- // the cells to be edited, rather than using full rows
510
- editor
511
- .bubble( nodes, false )
512
- .multiSet( idValues )
513
- .submit(null, function () {
514
- // If an error happens, Editor will show an alert, and then we need
515
- // to finish the edit since we can't do anything else.
516
- editor.close();
517
- });
518
- },
519
-
520
-
521
- /**
522
- * Emit an event on the DataTable for listeners
523
- *
524
- * @param {string} name Event name
525
- * @param {array} args Event arguments
526
- * @private
527
- */
528
- _emitEvent: function ( name, args )
529
- {
530
- this.s.dt.iterator( 'table', function ( ctx, i ) {
531
- $(ctx.nTable).triggerHandler( name+'.dt', args );
532
- } );
533
- },
534
-
535
-
536
- /**
537
- * Attach suitable listeners (based on the configuration) that will attach
538
- * and detach the AutoFill handle in the document.
539
- *
540
- * @private
541
- */
542
- _focusListener: function ()
543
- {
544
- var that = this;
545
- var dt = this.s.dt;
546
- var namespace = this.s.namespace;
547
- var focus = this.c.focus !== null ?
548
- this.c.focus :
549
- dt.init().keys || dt.settings()[0].keytable ?
550
- 'focus' :
551
- 'hover';
552
-
553
- // All event listeners attached here are removed in the `destroy`
554
- // callback in the constructor
555
- if ( focus === 'focus' ) {
556
- dt
557
- .on( 'key-focus.autoFill', function ( e, dt, cell ) {
558
- that._attach( cell.node() );
559
- } )
560
- .on( 'key-blur.autoFill', function ( e, dt, cell ) {
561
- that._detach();
562
- } );
563
- }
564
- else if ( focus === 'click' ) {
565
- $(dt.table().body()).on( 'click'+namespace, 'td, th', function (e) {
566
- that._attach( this );
567
- } );
568
-
569
- $(document.body).on( 'click'+namespace, function (e) {
570
- if ( ! $(e.target).parents().filter( dt.table().body() ).length ) {
571
- that._detach();
572
- }
573
- } );
574
- }
575
- else {
576
- $(dt.table().body())
577
- .on( 'mouseenter'+namespace+' touchstart'+namespace, 'td, th', function (e) {
578
- that._attach( this );
579
- } )
580
- .on( 'mouseleave'+namespace+'touchend'+namespace, function (e) {
581
- if ( $(e.relatedTarget).hasClass('dt-autofill-handle') ) {
582
- return;
583
- }
584
-
585
- that._detach();
586
- } );
587
-
588
-
589
- }
590
- },
591
-
592
-
593
- _focusListenerRemove: function ()
594
- {
595
- var dt = this.s.dt;
596
-
597
- dt.off( '.autoFill' );
598
- $(dt.table().body()).off( this.s.namespace );
599
- $(document.body).off( this.s.namespace );
600
- },
601
-
602
-
603
- /**
604
- * Get the position of a node, relative to another, including any scrolling
605
- * offsets.
606
- * @param {Node} node Node to get the position of
607
- * @param {jQuery} targetParent Node to use as the parent
608
- * @return {object} Offset calculation
609
- * @private
610
- */
611
- _getPosition: function ( node, targetParent )
612
- {
613
- var
614
- currNode = node,
615
- currOffsetParent,
616
- top = 0,
617
- left = 0;
618
-
619
- if ( ! targetParent ) {
620
- targetParent = $( $( this.s.dt.table().node() )[0].offsetParent );
621
- }
622
-
623
- do {
624
- // Don't use jQuery().position() the behaviour changes between 1.x and 3.x for
625
- // tables
626
- var positionTop = currNode.offsetTop;
627
- var positionLeft = currNode.offsetLeft;
628
-
629
- // jQuery doesn't give a `table` as the offset parent oddly, so use DOM directly
630
- currOffsetParent = $( currNode.offsetParent );
631
-
632
- top += positionTop + parseInt( currOffsetParent.css('border-top-width') || 0 ) * 1;
633
- left += positionLeft + parseInt( currOffsetParent.css('border-left-width') || 0 ) * 1;
634
-
635
- // Emergency fall back. Shouldn't happen, but just in case!
636
- if ( currNode.nodeName.toLowerCase() === 'body' ) {
637
- break;
638
- }
639
-
640
- currNode = currOffsetParent.get(0); // for next loop
641
- }
642
- while ( currOffsetParent.get(0) !== targetParent.get(0) )
643
-
644
- return {
645
- top: top,
646
- left: left
647
- };
648
- },
649
-
650
-
651
- /**
652
- * Start mouse drag - selects the start cell
653
- *
654
- * @param {object} e Mouse down event
655
- * @private
656
- */
657
- _mousedown: function ( e )
658
- {
659
- var that = this;
660
- var dt = this.s.dt;
661
-
662
- this.dom.start = this.dom.attachedTo;
663
- this.s.start = {
664
- row: dt.rows( { page: 'current' } ).nodes().indexOf( $(this.dom.start).parent()[0] ),
665
- column: $(this.dom.start).index()
666
- };
667
-
668
- $(document.body)
669
- .on( 'mousemove.autoFill touchmove.autoFill', function (e) {
670
- that._mousemove( e );
671
- // If it is a touch event then when the touch ends we need to remove the handle
672
- if(e.type === 'touchmove') {
673
- $(document.body).one('touchend.autoFill', function() {
674
- that._detach();
675
- })
676
- }
677
- } )
678
- .on( 'mouseup.autoFill touchend.autoFill', function (e) {
679
- that._mouseup( e );
680
- } );
681
-
682
- var select = this.dom.select;
683
- var offsetParent = $( dt.table().node() ).offsetParent();
684
- select.top.appendTo( offsetParent );
685
- select.left.appendTo( offsetParent );
686
- select.right.appendTo( offsetParent );
687
- select.bottom.appendTo( offsetParent );
688
-
689
- this._drawSelection( this.dom.start, e );
690
-
691
- this.dom.handle.css( 'display', 'none' );
692
-
693
- // Cache scrolling information so mouse move doesn't need to read.
694
- // This assumes that the window and DT scroller will not change size
695
- // during an AutoFill drag, which I think is a fair assumption
696
- var scrollWrapper = this.dom.dtScroll;
697
- this.s.scroll = {
698
- windowHeight: $(window).height(),
699
- windowWidth: $(window).width(),
700
- dtTop: scrollWrapper ? scrollWrapper.offset().top : null,
701
- dtLeft: scrollWrapper ? scrollWrapper.offset().left : null,
702
- dtHeight: scrollWrapper ? scrollWrapper.outerHeight() : null,
703
- dtWidth: scrollWrapper ? scrollWrapper.outerWidth() : null
704
- };
705
- },
706
-
707
-
708
- /**
709
- * Mouse drag - selects the end cell and update the selection display for
710
- * the end user
711
- *
712
- * @param {object} e Mouse move event
713
- * @private
714
- */
715
- _mousemove: function ( e )
716
- {
717
- var target = e.touches && e.touches.length
718
- ? document.elementFromPoint(e.touches[0].clientX, e.touches[0].clientY)
719
- : e.target;
720
- var name = target.nodeName.toLowerCase();
721
-
722
- if ( name !== 'td' && name !== 'th' ) {
723
- return;
724
- }
725
-
726
- this._drawSelection( target, e );
727
- this._shiftScroll( e );
728
- },
729
-
730
-
731
- /**
732
- * End mouse drag - perform the update actions
733
- *
734
- * @param {object} e Mouse up event
735
- * @private
736
- */
737
- _mouseup: function ( e )
738
- {
739
- $(document.body).off( '.autoFill' );
740
-
741
- var that = this;
742
- var dt = this.s.dt;
743
- var select = this.dom.select;
744
- select.top.remove();
745
- select.left.remove();
746
- select.right.remove();
747
- select.bottom.remove();
748
-
749
- this.dom.handle.css( 'display', 'block' );
750
-
751
- // Display complete - now do something useful with the selection!
752
- var start = this.s.start;
753
- var end = this.s.end;
754
-
755
- // Haven't selected multiple cells, so nothing to do
756
- if ( start.row === end.row && start.column === end.column ) {
757
- return;
758
- }
759
-
760
- var startDt = dt.cell( ':eq('+start.row+')', start.column+':visible', {page:'current'} );
761
-
762
- // If Editor is active inside this cell (inline editing) we need to wait for Editor to
763
- // submit and then we can loop back and trigger the fill.
764
- if ( $('div.DTE', startDt.node()).length ) {
765
- var editor = dt.editor();
766
-
767
- editor
768
- .on( 'submitSuccess.dtaf close.dtaf', function () {
769
- editor.off( '.dtaf');
770
-
771
- setTimeout( function () {
772
- that._mouseup( e );
773
- }, 100 );
774
- } )
775
- .on( 'submitComplete.dtaf preSubmitCancelled.dtaf close.dtaf', function () {
776
- editor.off( '.dtaf');
777
- } );
778
-
779
- // Make the current input submit
780
- editor.submit();
781
-
782
- return;
783
- }
784
-
785
- // Build a matrix representation of the selected rows
786
- var rows = this._range( start.row, end.row );
787
- var columns = this._range( start.column, end.column );
788
- var selected = [];
789
- var dtSettings = dt.settings()[0];
790
- var dtColumns = dtSettings.aoColumns;
791
- var enabledColumns = dt.columns( this.c.columns ).indexes();
792
-
793
- // Can't use Array.prototype.map as IE8 doesn't support it
794
- // Can't use $.map as jQuery flattens 2D arrays
795
- // Need to use a good old fashioned for loop
796
- for ( var rowIdx=0 ; rowIdx<rows.length ; rowIdx++ ) {
797
- selected.push(
798
- $.map( columns, function (column) {
799
- var row = dt.row( ':eq('+rows[rowIdx]+')', {page:'current'} ); // Workaround for M581
800
- var cell = dt.cell( row.index(), column+':visible' );
801
- var data = cell.data();
802
- var cellIndex = cell.index();
803
- var editField = dtColumns[ cellIndex.column ].editField;
804
-
805
- if ( editField !== undefined ) {
806
- data = DataTable.util.get( editField )( dt.row( cellIndex.row ).data() );
807
- }
808
-
809
- if ( enabledColumns.indexOf(cellIndex.column) === -1 ) {
810
- return;
811
- }
812
-
813
- return {
814
- cell: cell,
815
- data: data,
816
- label: cell.data(),
817
- index: cellIndex
818
- };
819
- } )
820
- );
821
- }
822
-
823
- this._actionSelector( selected );
824
-
825
- // Stop shiftScroll
826
- clearInterval( this.s.scrollInterval );
827
- this.s.scrollInterval = null;
828
- },
829
-
830
-
831
- /**
832
- * Create an array with a range of numbers defined by the start and end
833
- * parameters passed in (inclusive!).
834
- *
835
- * @param {integer} start Start
836
- * @param {integer} end End
837
- * @private
838
- */
839
- _range: function ( start, end )
840
- {
841
- var out = [];
842
- var i;
843
-
844
- if ( start <= end ) {
845
- for ( i=start ; i<=end ; i++ ) {
846
- out.push( i );
847
- }
848
- }
849
- else {
850
- for ( i=start ; i>=end ; i-- ) {
851
- out.push( i );
852
- }
853
- }
854
-
855
- return out;
856
- },
857
-
858
-
859
- /**
860
- * Move the window and DataTables scrolling during a drag to scroll new
861
- * content into view. This is done by proximity to the edge of the scrolling
862
- * container of the mouse - for example near the top edge of the window
863
- * should scroll up. This is a little complicated as there are two elements
864
- * that can be scrolled - the window and the DataTables scrolling view port
865
- * (if scrollX and / or scrollY is enabled).
866
- *
867
- * @param {object} e Mouse move event object
868
- * @private
869
- */
870
- _shiftScroll: function ( e )
871
- {
872
- var that = this;
873
- var scroll = this.s.scroll;
874
- var runInterval = false;
875
- var scrollSpeed = 5;
876
- var buffer = 65;
877
-
878
- // Different values if using a touchscreen
879
- var pageX = !e.type.includes('touch') ? e.pageX - window.scrollX :e.touches[0].clientX;
880
- var pageY = !e.type.includes('touch') ? e.pageY - window.scrollY :e.touches[0].clientY;
881
- var
882
- windowY = pageY,
883
- windowX = pageX,
884
- windowVert, windowHoriz,
885
- dtVert, dtHoriz;
886
-
887
- // Window calculations - based on the mouse position in the window,
888
- // regardless of scrolling
889
- if ( windowY < buffer ) {
890
- windowVert = scrollSpeed * -1;
891
- }
892
- else if ( windowY > scroll.windowHeight - buffer ) {
893
- windowVert = scrollSpeed;
894
- }
895
-
896
- if ( windowX < buffer ) {
897
- windowHoriz = scrollSpeed * -1;
898
- }
899
- else if ( windowX > scroll.windowWidth - buffer ) {
900
- windowHoriz = scrollSpeed;
901
- }
902
-
903
- // DataTables scrolling calculations - based on the table's position in
904
- // the document and the mouse position on the page
905
- if ( scroll.dtTop !== null && pageY < scroll.dtTop + buffer ) {
906
- dtVert = scrollSpeed * -1;
907
- }
908
- else if ( scroll.dtTop !== null && pageY > scroll.dtTop + scroll.dtHeight - buffer ) {
909
- dtVert = scrollSpeed;
910
- }
911
-
912
- if ( scroll.dtLeft !== null && pageX < scroll.dtLeft + buffer ) {
913
- dtHoriz = scrollSpeed * -1;
914
- }
915
- else if ( scroll.dtLeft !== null && pageX > scroll.dtLeft + scroll.dtWidth - buffer ) {
916
- dtHoriz = scrollSpeed;
917
- }
918
-
919
- // This is where it gets interesting. We want to continue scrolling
920
- // without requiring a mouse move, so we need an interval to be
921
- // triggered. The interval should continue until it is no longer needed,
922
- // but it must also use the latest scroll commands (for example consider
923
- // that the mouse might move from scrolling up to scrolling left, all
924
- // with the same interval running. We use the `scroll` object to "pass"
925
- // this information to the interval. Can't use local variables as they
926
- // wouldn't be the ones that are used by an already existing interval!
927
- if ( windowVert || windowHoriz || dtVert || dtHoriz ) {
928
- scroll.windowVert = windowVert;
929
- scroll.windowHoriz = windowHoriz;
930
- scroll.dtVert = dtVert;
931
- scroll.dtHoriz = dtHoriz;
932
- runInterval = true;
933
- }
934
- else if ( this.s.scrollInterval ) {
935
- // Don't need to scroll - remove any existing timer
936
- clearInterval( this.s.scrollInterval );
937
- this.s.scrollInterval = null;
938
- }
939
-
940
- // If we need to run the interval to scroll and there is no existing
941
- // interval (if there is an existing one, it will continue to run)
942
- if ( ! this.s.scrollInterval && runInterval ) {
943
- this.s.scrollInterval = setInterval( function () {
944
- // Don't need to worry about setting scroll <0 or beyond the
945
- // scroll bound as the browser will just reject that.
946
- window.scrollTo(window.scrollX + (scroll.windowHoriz ? scroll.windowHoriz : 0), window.scrollY + (scroll.windowVert ? scroll.windowVert : 0))
947
-
948
- // DataTables scrolling
949
- if ( scroll.dtVert || scroll.dtHoriz ) {
950
- var scroller = that.dom.dtScroll[0];
951
-
952
- if ( scroll.dtVert ) {
953
- scroller.scrollTop += scroll.dtVert;
954
- }
955
- if ( scroll.dtHoriz ) {
956
- scroller.scrollLeft += scroll.dtHoriz;
957
- }
958
- }
959
- }, 20 );
960
- }
961
- },
962
-
963
-
964
- /**
965
- * Update the DataTable after the user has selected what they want to do
966
- *
967
- * @param {false|undefined} result Return from the `execute` method - can
968
- * be false internally to do nothing. This is not documented for plug-ins
969
- * and is used only by the cancel option.
970
- * @param {array} cells Information about the selected cells from the key
971
- * up function, argumented with the set values
972
- * @private
973
- */
974
- _update: function ( result, cells )
975
- {
976
- // Do nothing on `false` return from an execute function
977
- if ( result === false ) {
978
- return;
979
- }
980
-
981
- var dt = this.s.dt;
982
- var cell;
983
- var columns = dt.columns( this.c.columns ).indexes();
984
-
985
- // Potentially allow modifications to the cells matrix
986
- this._emitEvent( 'preAutoFill', [ dt, cells ] );
987
-
988
- this._editor( cells );
989
-
990
- // Automatic updates are not performed if `update` is null and the
991
- // `editor` parameter is passed in - the reason being that Editor will
992
- // update the data once submitted
993
- var update = this.c.update !== null ?
994
- this.c.update :
995
- this.c.editor ?
996
- false :
997
- true;
998
-
999
- if ( update ) {
1000
- for ( var i=0, ien=cells.length ; i<ien ; i++ ) {
1001
- for ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {
1002
- cell = cells[i][j];
1003
-
1004
- if ( columns.indexOf(cell.index.column) !== -1 ) {
1005
- cell.cell.data( cell.set );
1006
- }
1007
- }
1008
- }
1009
-
1010
- dt.draw(false);
1011
- }
1012
-
1013
- this._emitEvent( 'autoFill', [ dt, cells ] );
1014
- }
1015
- } );
1016
-
1017
-
1018
794
  /**
1019
- * AutoFill actions. The options here determine how AutoFill will fill the data
1020
- * in the table when the user has selected a range of cells. Please see the
1021
- * documentation on the DataTables site for full details on how to create plug-
1022
- * ins.
1023
- *
1024
- * @type {Object}
795
+ * AutoFill actions. The options here determine how AutoFill will fill the
796
+ * data in the table when the user has selected a range of cells. Please see
797
+ * the documentation on the DataTables site for full details on how to
798
+ * create plug- ins.
1025
799
  */
1026
800
  AutoFill.actions = {
1027
- increment: {
1028
- available: function ( dt, cells ) {
1029
- var d = cells[0][0].label;
1030
-
1031
- // is numeric test based on jQuery's old `isNumeric` function
1032
- return !isNaN( d - parseFloat( d ) );
1033
- },
1034
-
1035
- option: function ( dt, cells ) {
1036
- return dt.i18n(
1037
- 'autoFill.increment',
1038
- 'Increment / decrement each cell by: <input type="number" value="1">'
1039
- );
1040
- },
1041
-
1042
- execute: function ( dt, cells, node ) {
1043
- var value = cells[0][0].data * 1;
1044
- var increment = $('input', node).val() * 1;
1045
-
1046
- for ( var i=0, ien=cells.length ; i<ien ; i++ ) {
1047
- for ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {
1048
- cells[i][j].set = value;
1049
-
1050
- value += increment;
1051
- }
1052
- }
1053
- }
1054
- },
1055
-
1056
- fill: {
1057
- available: function ( dt, cells ) {
1058
- return true;
1059
- },
1060
-
1061
- option: function ( dt, cells ) {
1062
- return dt.i18n('autoFill.fill', 'Fill all cells with <i>%d</i>', cells[0][0].label );
1063
- },
1064
-
1065
- execute: function ( dt, cells, node ) {
1066
- var value = cells[0][0].data;
1067
-
1068
- for ( var i=0, ien=cells.length ; i<ien ; i++ ) {
1069
- for ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {
1070
- cells[i][j].set = value;
1071
- }
1072
- }
1073
- }
1074
- },
1075
-
1076
- fillHorizontal: {
1077
- available: function ( dt, cells ) {
1078
- return cells.length > 1 && cells[0].length > 1;
1079
- },
1080
-
1081
- option: function ( dt, cells ) {
1082
- return dt.i18n('autoFill.fillHorizontal', 'Fill cells horizontally' );
1083
- },
1084
-
1085
- execute: function ( dt, cells, node ) {
1086
- for ( var i=0, ien=cells.length ; i<ien ; i++ ) {
1087
- for ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {
1088
- cells[i][j].set = cells[i][0].data;
1089
- }
1090
- }
1091
- }
1092
- },
1093
-
1094
- fillVertical: {
1095
- available: function ( dt, cells ) {
1096
- return cells.length > 1 && cells[0].length > 1;
1097
- },
1098
-
1099
- option: function ( dt, cells ) {
1100
- return dt.i18n('autoFill.fillVertical', 'Fill cells vertically' );
1101
- },
1102
-
1103
- execute: function ( dt, cells, node ) {
1104
- for ( var i=0, ien=cells.length ; i<ien ; i++ ) {
1105
- for ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {
1106
- cells[i][j].set = cells[0][j].data;
1107
- }
1108
- }
1109
- }
1110
- },
1111
-
1112
- // Special type that does not make itself available, but is added
1113
- // automatically by AutoFill if a multi-choice list is shown. This allows
1114
- // sensible code reuse
1115
- cancel: {
1116
- available: function () {
1117
- return false;
1118
- },
1119
-
1120
- option: function ( dt ) {
1121
- return dt.i18n('autoFill.cancel', 'Cancel' );
1122
- },
1123
-
1124
- execute: function () {
1125
- return false;
1126
- }
1127
- }
801
+ increment: {
802
+ available: function (dt, cells) {
803
+ let d = cells[0][0].label;
804
+ // is numeric test based on jQuery's old `isNumeric` function
805
+ return !isNaN(d - parseFloat(d));
806
+ },
807
+ option: function (dt, cells) {
808
+ return dt.i18n('autoFill.increment', 'Increment / decrement each cell by: <input type="number" value="1">');
809
+ },
810
+ execute: function (dt, cells, node) {
811
+ let value = cells[0][0].data * 1;
812
+ let increment = node ? parseFloat(node.find('input').val()) : 1;
813
+ for (let i = 0, ien = cells.length; i < ien; i++) {
814
+ for (let j = 0, jen = cells[i].length; j < jen; j++) {
815
+ cells[i][j].set = value;
816
+ value += increment;
817
+ }
818
+ }
819
+ }
820
+ },
821
+ fill: {
822
+ available: function (dt, cells) {
823
+ return true;
824
+ },
825
+ option: function (dt, cells) {
826
+ return dt.i18n('autoFill.fill', 'Fill all cells with <i>%d</i>', cells[0][0].label);
827
+ },
828
+ execute: function (dt, cells, node) {
829
+ let value = cells[0][0].data;
830
+ for (let i = 0, ien = cells.length; i < ien; i++) {
831
+ for (let j = 0, jen = cells[i].length; j < jen; j++) {
832
+ cells[i][j].set = value;
833
+ }
834
+ }
835
+ }
836
+ },
837
+ fillHorizontal: {
838
+ available: function (dt, cells) {
839
+ return cells.length > 1 && cells[0].length > 1;
840
+ },
841
+ option: function (dt, cells) {
842
+ return dt.i18n('autoFill.fillHorizontal', 'Fill cells horizontally');
843
+ },
844
+ execute: function (dt, cells, node) {
845
+ for (let i = 0, ien = cells.length; i < ien; i++) {
846
+ for (let j = 0, jen = cells[i].length; j < jen; j++) {
847
+ cells[i][j].set = cells[i][0].data;
848
+ }
849
+ }
850
+ }
851
+ },
852
+ fillVertical: {
853
+ available: function (dt, cells) {
854
+ return cells.length > 1 && cells[0].length > 1;
855
+ },
856
+ option: function (dt, cells) {
857
+ return dt.i18n('autoFill.fillVertical', 'Fill cells vertically');
858
+ },
859
+ execute: function (dt, cells, node) {
860
+ for (let i = 0, ien = cells.length; i < ien; i++) {
861
+ for (let j = 0, jen = cells[i].length; j < jen; j++) {
862
+ cells[i][j].set = cells[0][j].data;
863
+ }
864
+ }
865
+ }
866
+ },
867
+ // Special type that does not make itself available, but is added
868
+ // automatically by AutoFill if a multi-choice list is shown. This
869
+ // allows sensible code reuse
870
+ cancel: {
871
+ available: function () {
872
+ return false;
873
+ },
874
+ option: function (dt) {
875
+ return dt.i18n('autoFill.cancel', 'Cancel');
876
+ },
877
+ execute: function () {
878
+ return false;
879
+ }
880
+ }
1128
881
  };
1129
-
1130
-
1131
- /**
1132
- * AutoFill version
1133
- *
1134
- * @static
1135
- * @type String
1136
- */
1137
- AutoFill.version = '2.7.1';
1138
-
1139
-
1140
- /**
1141
- * AutoFill defaults
1142
- *
1143
- * @namespace
1144
- */
1145
- AutoFill.defaults = {
1146
- /** @type {Boolean} Ask user what they want to do, even for a single option */
1147
- alwaysAsk: false,
1148
-
1149
- closeButton: true,
1150
-
1151
- /** @type {string|null} What will trigger a focus */
1152
- focus: null, // focus, click, hover
1153
-
1154
- /** @type {column-selector} Columns to provide auto fill for */
1155
- columns: '', // all
1156
-
1157
- /** @type {Boolean} Enable AutoFill on load */
1158
- enable: true,
1159
-
1160
- /** @type {boolean|null} Update the cells after a drag */
1161
- update: null, // false is editor given, true otherwise
1162
-
1163
- /** @type {DataTable.Editor} Editor instance for automatic submission */
1164
- editor: null,
1165
-
1166
- /** @type {boolean} Enable vertical fill */
1167
- vertical: true,
1168
-
1169
- /** @type {boolean} Enable horizontal fill */
1170
- horizontal: true
1171
- };
1172
-
1173
-
1174
- /**
1175
- * Classes used by AutoFill that are configurable
1176
- *
1177
- * @namespace
1178
- */
882
+ /** Class names used by AutoFill for customisation */
1179
883
  AutoFill.classes = {
1180
- /** @type {String} Class used by the selection button */
1181
- btn: 'btn',
1182
-
1183
- closeable: 'dtaf-popover-closeable'
884
+ btn: 'btn',
885
+ close: 'dtaf-list-close',
886
+ closeable: 'dtaf-list-closeable'
1184
887
  };
1185
-
1186
-
1187
- /*
1188
- * API
1189
- */
1190
- var Api = $.fn.dataTable.Api;
888
+ /** Defaults */
889
+ AutoFill.defaults = {
890
+ alwaysAsk: false,
891
+ closeButton: true,
892
+ focus: null,
893
+ columns: '',
894
+ enable: true,
895
+ update: true,
896
+ editor: null,
897
+ vertical: true,
898
+ horizontal: true
899
+ };
900
+ /** AutoFill version */
901
+ AutoFill.version = '3.0.0';
1191
902
 
1192
903
  // Doesn't do anything - Not documented
1193
- Api.register( 'autoFill()', function () {
1194
- return this;
1195
- } );
1196
-
1197
- Api.register( 'autoFill().enabled()', function () {
1198
- var ctx = this.context[0];
1199
-
1200
- return ctx.autoFill ?
1201
- ctx.autoFill.enabled() :
1202
- false;
1203
- } );
1204
-
1205
- Api.register( 'autoFill().enable()', function ( flag ) {
1206
- return this.iterator( 'table', function ( ctx ) {
1207
- if ( ctx.autoFill ) {
1208
- ctx.autoFill.enable( flag );
1209
- }
1210
- } );
1211
- } );
1212
-
1213
- Api.register( 'autoFill().disable()', function () {
1214
- return this.iterator( 'table', function ( ctx ) {
1215
- if ( ctx.autoFill ) {
1216
- ctx.autoFill.disable();
1217
- }
1218
- } );
1219
- } );
1220
-
1221
-
904
+ Api.register('autoFill()', function () {
905
+ return this.inst(this.context);
906
+ });
907
+ Api.register('autoFill().enabled()', function () {
908
+ var ctx = this.context[0];
909
+ return ctx.autoFill ? ctx.autoFill.enabled() : false;
910
+ });
911
+ Api.register('autoFill().enable()', function (flag) {
912
+ return this.iterator('table', function (ctx) {
913
+ if (ctx.autoFill) {
914
+ ctx.autoFill.enable(flag);
915
+ }
916
+ });
917
+ });
918
+ Api.register('autoFill().disable()', function () {
919
+ return this.iterator('table', function (ctx) {
920
+ if (ctx.autoFill) {
921
+ ctx.autoFill.disable();
922
+ }
923
+ });
924
+ });
1222
925
  // Attach a listener to the document which listens for DataTables initialisation
1223
926
  // events so we can automatically initialise
1224
- $(document).on( 'preInit.dt.autofill', function (e, settings, json) {
1225
- if ( e.namespace !== 'dt' ) {
1226
- return;
1227
- }
1228
-
1229
- var init = settings.oInit.autoFill;
1230
- var defaults = DataTable.defaults.autoFill;
1231
-
1232
- if ( init || defaults ) {
1233
- var opts = $.extend( {}, init, defaults );
1234
-
1235
- if ( init !== false ) {
1236
- new AutoFill( settings, opts );
1237
- }
1238
- }
1239
- } );
1240
-
1241
-
927
+ Dom.s(document).on('preInit.dt.autofill', function (e, settings) {
928
+ if (e.namespace !== 'dt') {
929
+ return;
930
+ }
931
+ let init = settings.init.autoFill;
932
+ let defaults = DataTable.defaults.autoFill;
933
+ if (init || defaults) {
934
+ let opts = {};
935
+ if (util.is.plainObject(defaults)) {
936
+ util.object.assign(opts, defaults);
937
+ }
938
+ if (util.is.plainObject(init)) {
939
+ util.object.assign(opts, init);
940
+ }
941
+ if (init !== false) {
942
+ new AutoFill(settings, opts);
943
+ }
944
+ }
945
+ });
1242
946
  // Alias for access
1243
947
  DataTable.AutoFill = AutoFill;
1244
- $.fn.DataTable.AutoFill = AutoFill;
1245
948
 
1246
949
 
1247
950
  export default DataTable;
951
+