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