jquery-datatables-rails 3.3.0 → 3.4.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.
- checksums.yaml +4 -4
- data/app/assets/javascripts/dataTables/bootstrap/3/jquery.dataTables.bootstrap.js +64 -29
- data/app/assets/javascripts/dataTables/extras/dataTables.autoFill.js +806 -648
- data/app/assets/javascripts/dataTables/extras/dataTables.buttons.js +1607 -0
- data/app/assets/javascripts/dataTables/extras/dataTables.colReorder.js +220 -267
- data/app/assets/javascripts/dataTables/extras/dataTables.fixedColumns.js +164 -69
- data/app/assets/javascripts/dataTables/extras/dataTables.fixedHeader.js +469 -870
- data/app/assets/javascripts/dataTables/extras/dataTables.keyTable.js +636 -972
- data/app/assets/javascripts/dataTables/extras/dataTables.responsive.js +472 -187
- data/app/assets/javascripts/dataTables/extras/dataTables.rowReorder.js +619 -0
- data/app/assets/javascripts/dataTables/extras/dataTables.scroller.js +146 -111
- data/app/assets/javascripts/dataTables/extras/dataTables.select.js +1038 -0
- data/app/assets/javascripts/dataTables/jquery.dataTables.api.fnGetColumnData.js +0 -0
- data/app/assets/javascripts/dataTables/jquery.dataTables.api.fnReloadAjax.js +0 -0
- data/app/assets/javascripts/dataTables/jquery.dataTables.foundation.js +37 -61
- data/app/assets/javascripts/dataTables/jquery.dataTables.js +720 -387
- data/app/assets/javascripts/dataTables/jquery.dataTables.sorting.ipAddress.js +44 -0
- data/app/assets/javascripts/dataTables/jquery.dataTables.sorting.numbersHtml.js +0 -0
- data/app/assets/javascripts/dataTables/jquery.dataTables.typeDetection.numbersHtml.js +0 -0
- data/app/assets/stylesheets/dataTables/jquery.dataTables.scss +34 -66
- data/app/assets/stylesheets/dataTables/src/demo_table.css +1 -1
- data/app/assets/stylesheets/dataTables/src/demo_table_jui.css.scss +4 -4
- data/lib/jquery/datatables/rails/version.rb +1 -1
- metadata +24 -19
@@ -1,15 +1,15 @@
|
|
1
|
-
/*! Scroller 1.
|
2
|
-
* ©2011-
|
1
|
+
/*! Scroller 1.4.0
|
2
|
+
* ©2011-2015 SpryMedia Ltd - datatables.net/license
|
3
3
|
*/
|
4
4
|
|
5
5
|
/**
|
6
6
|
* @summary Scroller
|
7
7
|
* @description Virtual rendering for DataTables
|
8
|
-
* @version 1.
|
8
|
+
* @version 1.4.0
|
9
9
|
* @file dataTables.scroller.js
|
10
10
|
* @author SpryMedia Ltd (www.sprymedia.co.uk)
|
11
11
|
* @contact www.sprymedia.co.uk/contact
|
12
|
-
* @copyright Copyright 2011-
|
12
|
+
* @copyright Copyright 2011-2015 SpryMedia Ltd.
|
13
13
|
*
|
14
14
|
* This source file is free software, available under the following license:
|
15
15
|
* MIT license - http://datatables.net/license/mit
|
@@ -21,11 +21,35 @@
|
|
21
21
|
* For details please refer to: http://www.datatables.net
|
22
22
|
*/
|
23
23
|
|
24
|
-
(function(
|
24
|
+
(function( factory ){
|
25
|
+
if ( typeof define === 'function' && define.amd ) {
|
26
|
+
// AMD
|
27
|
+
define( ['jquery', 'datatables.net'], function ( $ ) {
|
28
|
+
return factory( $, window, document );
|
29
|
+
} );
|
30
|
+
}
|
31
|
+
else if ( typeof exports === 'object' ) {
|
32
|
+
// CommonJS
|
33
|
+
module.exports = function (root, $) {
|
34
|
+
if ( ! root ) {
|
35
|
+
root = window;
|
36
|
+
}
|
25
37
|
|
38
|
+
if ( ! $ || ! $.fn.dataTable ) {
|
39
|
+
$ = require('datatables.net')(root, $).$;
|
40
|
+
}
|
41
|
+
|
42
|
+
return factory( $, root, root.document );
|
43
|
+
};
|
44
|
+
}
|
45
|
+
else {
|
46
|
+
// Browser
|
47
|
+
factory( jQuery, window, document );
|
48
|
+
}
|
49
|
+
}(function( $, window, document, undefined ) {
|
50
|
+
'use strict';
|
51
|
+
var DataTable = $.fn.dataTable;
|
26
52
|
|
27
|
-
var factory = function( $, DataTable ) {
|
28
|
-
"use strict";
|
29
53
|
|
30
54
|
/**
|
31
55
|
* Scroller is a virtual rendering plug-in for DataTables which allows large
|
@@ -48,7 +72,7 @@ var factory = function( $, DataTable ) {
|
|
48
72
|
* Key features include:
|
49
73
|
* <ul class="limit_length">
|
50
74
|
* <li>Speed! The aim of Scroller for DataTables is to make rendering large data sets fast</li>
|
51
|
-
* <li>Full compatibility with deferred rendering in DataTables
|
75
|
+
* <li>Full compatibility with deferred rendering in DataTables for maximum speed</li>
|
52
76
|
* <li>Display millions of rows</li>
|
53
77
|
* <li>Integration with state saving in DataTables (scrolling position is saved)</li>
|
54
78
|
* <li>Easy to use</li>
|
@@ -57,34 +81,32 @@ var factory = function( $, DataTable ) {
|
|
57
81
|
* @class
|
58
82
|
* @constructor
|
59
83
|
* @global
|
60
|
-
* @param {object}
|
61
|
-
* @param {object} [
|
84
|
+
* @param {object} dt DataTables settings object or API instance
|
85
|
+
* @param {object} [opts={}] Configuration object for FixedColumns. Options
|
62
86
|
* are defined by {@link Scroller.defaults}
|
63
87
|
*
|
64
88
|
* @requires jQuery 1.7+
|
65
|
-
* @requires DataTables 1.
|
89
|
+
* @requires DataTables 1.10.0+
|
66
90
|
*
|
67
91
|
* @example
|
68
92
|
* $(document).ready(function() {
|
69
|
-
* $('#example').
|
70
|
-
* "
|
71
|
-
* "
|
72
|
-
* "
|
73
|
-
* "
|
93
|
+
* $('#example').DataTable( {
|
94
|
+
* "scrollY": "200px",
|
95
|
+
* "ajax": "media/dataset/large.txt",
|
96
|
+
* "dom": "frtiS",
|
97
|
+
* "deferRender": true
|
74
98
|
* } );
|
75
99
|
* } );
|
76
100
|
*/
|
77
|
-
var Scroller = function (
|
101
|
+
var Scroller = function ( dt, opts ) {
|
78
102
|
/* Sanity check - you just know it will happen */
|
79
|
-
if ( ! this instanceof Scroller )
|
80
|
-
{
|
103
|
+
if ( ! (this instanceof Scroller) ) {
|
81
104
|
alert( "Scroller warning: Scroller must be initialised with the 'new' keyword." );
|
82
105
|
return;
|
83
106
|
}
|
84
107
|
|
85
|
-
if (
|
86
|
-
|
87
|
-
oOpts = {};
|
108
|
+
if ( opts === undefined ) {
|
109
|
+
opts = {};
|
88
110
|
}
|
89
111
|
|
90
112
|
/**
|
@@ -99,7 +121,7 @@ var Scroller = function ( oDTSettings, oOpts ) {
|
|
99
121
|
* @type object
|
100
122
|
* @default Passed in as first parameter to constructor
|
101
123
|
*/
|
102
|
-
"dt":
|
124
|
+
"dt": $.fn.dataTable.Api( dt ).settings()[0],
|
103
125
|
|
104
126
|
/**
|
105
127
|
* Pixel location of the top of the drawn table in the viewport
|
@@ -193,7 +215,7 @@ var Scroller = function ( oDTSettings, oOpts ) {
|
|
193
215
|
|
194
216
|
// @todo The defaults should extend a `c` property and the internal settings
|
195
217
|
// only held in the `s` property. At the moment they are mixed
|
196
|
-
this.s = $.extend( this.s, Scroller.oDefaults,
|
218
|
+
this.s = $.extend( this.s, Scroller.oDefaults, opts );
|
197
219
|
|
198
220
|
// Workaround for row height being read from height object (see above comment)
|
199
221
|
this.s.heights.row = this.s.rowHeight;
|
@@ -211,7 +233,12 @@ var Scroller = function ( oDTSettings, oOpts ) {
|
|
211
233
|
"loader": null
|
212
234
|
};
|
213
235
|
|
214
|
-
|
236
|
+
// Attach the instance to the DataTables instance so it can be accessed in
|
237
|
+
// future. Don't initialise Scroller twice on the same table
|
238
|
+
if ( this.s.dt.oScroller ) {
|
239
|
+
return;
|
240
|
+
}
|
241
|
+
|
215
242
|
this.s.dt.oScroller = this;
|
216
243
|
|
217
244
|
/* Let's do it */
|
@@ -220,7 +247,7 @@ var Scroller = function ( oDTSettings, oOpts ) {
|
|
220
247
|
|
221
248
|
|
222
249
|
|
223
|
-
|
250
|
+
$.extend( Scroller.prototype, {
|
224
251
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
225
252
|
* Public methods
|
226
253
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
@@ -410,7 +437,7 @@ Scroller.prototype = /** @lends Scroller.prototype */{
|
|
410
437
|
|
411
438
|
if ( bRedraw === undefined || bRedraw )
|
412
439
|
{
|
413
|
-
this.s.dt.oInstance.fnDraw();
|
440
|
+
this.s.dt.oInstance.fnDraw( false );
|
414
441
|
}
|
415
442
|
},
|
416
443
|
|
@@ -438,7 +465,7 @@ Scroller.prototype = /** @lends Scroller.prototype */{
|
|
438
465
|
/* Insert a div element that we can use to force the DT scrolling container to
|
439
466
|
* the height that would be required if the whole table was being displayed
|
440
467
|
*/
|
441
|
-
this.dom.force.style.position = "
|
468
|
+
this.dom.force.style.position = "relative";
|
442
469
|
this.dom.force.style.top = "0px";
|
443
470
|
this.dom.force.style.left = "0px";
|
444
471
|
this.dom.force.style.width = "1px";
|
@@ -458,7 +485,7 @@ Scroller.prototype = /** @lends Scroller.prototype */{
|
|
458
485
|
// Add a 'loading' indicator
|
459
486
|
if ( this.s.loadingIndicator )
|
460
487
|
{
|
461
|
-
this.dom.loader = $('<div class="DTS_Loading">'+this.s.dt.oLanguage.sLoadingRecords+'</div>')
|
488
|
+
this.dom.loader = $('<div class="dataTables_processing DTS_Loading">'+this.s.dt.oLanguage.sLoadingRecords+'</div>')
|
462
489
|
.css('display', 'none');
|
463
490
|
|
464
491
|
$(this.dom.scroller.parentNode)
|
@@ -529,6 +556,10 @@ Scroller.prototype = /** @lends Scroller.prototype */{
|
|
529
556
|
this.s.topRowFloat = this.s.dt.oLoadedState.iScrollerTopRow || 0;
|
530
557
|
}
|
531
558
|
|
559
|
+
$(this.s.dt.nTable).on( 'init.dt', function () {
|
560
|
+
that.fnMeasure();
|
561
|
+
} );
|
562
|
+
|
532
563
|
/* Destructor */
|
533
564
|
this.s.dt.aoDestroyCallback.push( {
|
534
565
|
"sName": "Scroller",
|
@@ -537,6 +568,7 @@ Scroller.prototype = /** @lends Scroller.prototype */{
|
|
537
568
|
$(that.dom.scroller).off('touchstart.DTS scroll.DTS');
|
538
569
|
$(that.s.dt.nTableWrapper).removeClass('DTS');
|
539
570
|
$('div.DTS_Loading', that.dom.scroller.parentNode).remove();
|
571
|
+
$(that.s.dt.nTable).off( 'init.dt' );
|
540
572
|
|
541
573
|
that.dom.table.style.position = "";
|
542
574
|
that.dom.table.style.top = "";
|
@@ -635,9 +667,6 @@ Scroller.prototype = /** @lends Scroller.prototype */{
|
|
635
667
|
}
|
636
668
|
|
637
669
|
that.s.dt._iDisplayStart = iTopRow;
|
638
|
-
if ( that.s.dt.oApi._fnCalculateEnd ) { // Removed in 1.10
|
639
|
-
that.s.dt.oApi._fnCalculateEnd( that.s.dt );
|
640
|
-
}
|
641
670
|
that.s.dt.oApi._fnDraw( that.s.dt );
|
642
671
|
};
|
643
672
|
|
@@ -682,14 +711,7 @@ Scroller.prototype = /** @lends Scroller.prototype */{
|
|
682
711
|
// If the virtual and physical height match, then we use a linear
|
683
712
|
// transform between the two, allowing the scrollbar to be linear
|
684
713
|
if ( heights.virtual === heights.scroll ) {
|
685
|
-
|
686
|
-
|
687
|
-
if ( dir === 'virtualToPhysical' ) {
|
688
|
-
return val / coeff;
|
689
|
-
}
|
690
|
-
else if ( dir === 'physicalToVirtual' ) {
|
691
|
-
return val * coeff;
|
692
|
-
}
|
714
|
+
return val;
|
693
715
|
}
|
694
716
|
|
695
717
|
// Otherwise, we want a non-linear scrollbar to take account of the
|
@@ -868,7 +890,11 @@ Scroller.prototype = /** @lends Scroller.prototype */{
|
|
868
890
|
heights.scroll = max;
|
869
891
|
}
|
870
892
|
|
871
|
-
|
893
|
+
// Minimum height so there is always a row visible (the 'no rows found'
|
894
|
+
// if reduced to zero filtering)
|
895
|
+
this.dom.force.style.height = heights.scroll > this.s.heights.row ?
|
896
|
+
heights.scroll+'px' :
|
897
|
+
this.s.heights.row+'px';
|
872
898
|
},
|
873
899
|
|
874
900
|
|
@@ -903,18 +929,10 @@ Scroller.prototype = /** @lends Scroller.prototype */{
|
|
903
929
|
|
904
930
|
$('div.'+dt.oClasses.sScrollBody, container).append( nTable );
|
905
931
|
|
906
|
-
|
907
|
-
|
908
|
-
appendTo = origTable.parentNode;
|
909
|
-
} else {
|
910
|
-
if (!this.s.dt.nHolding) {
|
911
|
-
this.s.dt.nHolding = $( '<div></div>' ).insertBefore( this.s.dt.nTable );
|
912
|
-
}
|
913
|
-
appendTo = this.s.dt.nHolding;
|
914
|
-
}
|
915
|
-
|
916
|
-
container.appendTo( appendTo );
|
932
|
+
// If initialised using `dom`, use the holding element as the insert point
|
933
|
+
container.appendTo( this.s.dt.nHolding || origTable.parentNode );
|
917
934
|
this.s.heights.row = $('tr', tbody).eq(1).outerHeight();
|
935
|
+
|
918
936
|
container.remove();
|
919
937
|
},
|
920
938
|
|
@@ -1002,7 +1020,7 @@ Scroller.prototype = /** @lends Scroller.prototype */{
|
|
1002
1020
|
}
|
1003
1021
|
}
|
1004
1022
|
}
|
1005
|
-
};
|
1023
|
+
} );
|
1006
1024
|
|
1007
1025
|
|
1008
1026
|
|
@@ -1155,7 +1173,7 @@ Scroller.oDefaults = Scroller.defaults;
|
|
1155
1173
|
* @name Scroller.version
|
1156
1174
|
* @static
|
1157
1175
|
*/
|
1158
|
-
Scroller.version = "1.
|
1176
|
+
Scroller.version = "1.4.0";
|
1159
1177
|
|
1160
1178
|
|
1161
1179
|
|
@@ -1163,19 +1181,17 @@ Scroller.version = "1.2.2";
|
|
1163
1181
|
* Initialisation
|
1164
1182
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
1165
1183
|
|
1166
|
-
|
1167
|
-
* Register a new feature with DataTables
|
1168
|
-
*/
|
1184
|
+
// Legacy `dom` parameter initialisation support
|
1169
1185
|
if ( typeof $.fn.dataTable == "function" &&
|
1170
1186
|
typeof $.fn.dataTableExt.fnVersionCheck == "function" &&
|
1171
|
-
$.fn.dataTableExt.fnVersionCheck('1.
|
1187
|
+
$.fn.dataTableExt.fnVersionCheck('1.10.0') )
|
1172
1188
|
{
|
1173
1189
|
$.fn.dataTableExt.aoFeatures.push( {
|
1174
1190
|
"fnInit": function( oDTSettings ) {
|
1175
1191
|
var init = oDTSettings.oInit;
|
1176
1192
|
var opts = init.scroller || init.oScroller || {};
|
1177
|
-
|
1178
|
-
|
1193
|
+
|
1194
|
+
new Scroller( oDTSettings, opts );
|
1179
1195
|
},
|
1180
1196
|
"cFeature": "S",
|
1181
1197
|
"sFeature": "Scroller"
|
@@ -1183,9 +1199,28 @@ if ( typeof $.fn.dataTable == "function" &&
|
|
1183
1199
|
}
|
1184
1200
|
else
|
1185
1201
|
{
|
1186
|
-
alert( "Warning: Scroller requires DataTables 1.
|
1202
|
+
alert( "Warning: Scroller requires DataTables 1.10.0 or greater - www.datatables.net/download");
|
1187
1203
|
}
|
1188
1204
|
|
1205
|
+
// Attach a listener to the document which listens for DataTables initialisation
|
1206
|
+
// events so we can automatically initialise
|
1207
|
+
$(document).on( 'preInit.dt.dtscroller', function (e, settings) {
|
1208
|
+
if ( e.namespace !== 'dt' ) {
|
1209
|
+
return;
|
1210
|
+
}
|
1211
|
+
|
1212
|
+
var init = settings.oInit.scroller;
|
1213
|
+
var defaults = DataTable.defaults.scroller;
|
1214
|
+
|
1215
|
+
if ( init || defaults ) {
|
1216
|
+
var opts = $.extend( {}, init, defaults );
|
1217
|
+
|
1218
|
+
if ( init !== false ) {
|
1219
|
+
new Scroller( settings, opts );
|
1220
|
+
}
|
1221
|
+
}
|
1222
|
+
} );
|
1223
|
+
|
1189
1224
|
|
1190
1225
|
// Attach Scroller to DataTables so it can be accessed as an 'extra'
|
1191
1226
|
$.fn.dataTable.Scroller = Scroller;
|
@@ -1193,70 +1228,70 @@ $.fn.DataTable.Scroller = Scroller;
|
|
1193
1228
|
|
1194
1229
|
|
1195
1230
|
// DataTables 1.10 API method aliases
|
1196
|
-
|
1197
|
-
var Api = $.fn.dataTable.Api;
|
1231
|
+
var Api = $.fn.dataTable.Api;
|
1198
1232
|
|
1199
|
-
|
1200
|
-
|
1201
|
-
|
1233
|
+
Api.register( 'scroller()', function () {
|
1234
|
+
return this;
|
1235
|
+
} );
|
1202
1236
|
|
1203
|
-
|
1204
|
-
|
1237
|
+
// Undocumented and deprecated - is it actually useful at all?
|
1238
|
+
Api.register( 'scroller().rowToPixels()', function ( rowIdx, intParse, virtual ) {
|
1239
|
+
var ctx = this.context;
|
1205
1240
|
|
1206
|
-
|
1207
|
-
|
1208
|
-
|
1209
|
-
|
1210
|
-
|
1241
|
+
if ( ctx.length && ctx[0].oScroller ) {
|
1242
|
+
return ctx[0].oScroller.fnRowToPixels( rowIdx, intParse, virtual );
|
1243
|
+
}
|
1244
|
+
// undefined
|
1245
|
+
} );
|
1211
1246
|
|
1212
|
-
|
1213
|
-
|
1247
|
+
// Undocumented and deprecated - is it actually useful at all?
|
1248
|
+
Api.register( 'scroller().pixelsToRow()', function ( pixels, intParse, virtual ) {
|
1249
|
+
var ctx = this.context;
|
1214
1250
|
|
1215
|
-
|
1216
|
-
|
1251
|
+
if ( ctx.length && ctx[0].oScroller ) {
|
1252
|
+
return ctx[0].oScroller.fnPixelsToRow( pixels, intParse, virtual );
|
1253
|
+
}
|
1254
|
+
// undefined
|
1255
|
+
} );
|
1256
|
+
|
1257
|
+
// Undocumented and deprecated - use `row().scrollTo()` instead
|
1258
|
+
Api.register( 'scroller().scrollToRow()', function ( row, ani ) {
|
1259
|
+
this.iterator( 'table', function ( ctx ) {
|
1260
|
+
if ( ctx.oScroller ) {
|
1261
|
+
ctx.oScroller.fnScrollToRow( row, ani );
|
1217
1262
|
}
|
1218
|
-
// undefined
|
1219
1263
|
} );
|
1220
1264
|
|
1221
|
-
|
1222
|
-
|
1223
|
-
if ( ctx.oScroller ) {
|
1224
|
-
ctx.oScroller.fnScrollToRow( row, ani );
|
1225
|
-
}
|
1226
|
-
} );
|
1265
|
+
return this;
|
1266
|
+
} );
|
1227
1267
|
|
1228
|
-
|
1229
|
-
|
1268
|
+
Api.register( 'row().scrollTo()', function ( ani ) {
|
1269
|
+
var that = this;
|
1230
1270
|
|
1231
|
-
|
1232
|
-
|
1233
|
-
|
1234
|
-
|
1235
|
-
|
1236
|
-
|
1271
|
+
this.iterator( 'row', function ( ctx, rowIdx ) {
|
1272
|
+
if ( ctx.oScroller ) {
|
1273
|
+
var displayIdx = that
|
1274
|
+
.rows( { order: 'applied', search: 'applied' } )
|
1275
|
+
.indexes()
|
1276
|
+
.indexOf( rowIdx );
|
1237
1277
|
|
1238
|
-
|
1278
|
+
ctx.oScroller.fnScrollToRow( displayIdx, ani );
|
1279
|
+
}
|
1239
1280
|
} );
|
1240
|
-
}
|
1241
|
-
|
1242
|
-
|
1243
|
-
return Scroller;
|
1244
|
-
}; // /factory
|
1245
1281
|
|
1282
|
+
return this;
|
1283
|
+
} );
|
1246
1284
|
|
1247
|
-
|
1248
|
-
|
1249
|
-
|
1250
|
-
|
1251
|
-
|
1252
|
-
|
1253
|
-
factory( require('jquery'), require('datatables') );
|
1254
|
-
}
|
1255
|
-
else if ( jQuery && !jQuery.fn.dataTable.Scroller ) {
|
1256
|
-
// Otherwise simply initialise as normal, stopping multiple evaluation
|
1257
|
-
factory( jQuery, jQuery.fn.dataTable );
|
1258
|
-
}
|
1285
|
+
Api.register( 'scroller.measure()', function ( redraw ) {
|
1286
|
+
this.iterator( 'table', function ( ctx ) {
|
1287
|
+
if ( ctx.oScroller ) {
|
1288
|
+
ctx.oScroller.fnMeasure( redraw );
|
1289
|
+
}
|
1290
|
+
} );
|
1259
1291
|
|
1292
|
+
return this;
|
1293
|
+
} );
|
1260
1294
|
|
1261
|
-
})(window, document);
|
1262
1295
|
|
1296
|
+
return Scroller;
|
1297
|
+
}));
|
@@ -0,0 +1,1038 @@
|
|
1
|
+
/*! Select for DataTables 1.1.0
|
2
|
+
* 2015 SpryMedia Ltd - datatables.net/license/mit
|
3
|
+
*/
|
4
|
+
|
5
|
+
/**
|
6
|
+
* @summary Select for DataTables
|
7
|
+
* @description A collection of API methods, events and buttons for DataTables
|
8
|
+
* that provides selection options of the items in a DataTable
|
9
|
+
* @version 1.1.0
|
10
|
+
* @file dataTables.select.js
|
11
|
+
* @author SpryMedia Ltd (www.sprymedia.co.uk)
|
12
|
+
* @contact datatables.net/forums
|
13
|
+
* @copyright Copyright 2015 SpryMedia Ltd.
|
14
|
+
*
|
15
|
+
* This source file is free software, available under the following license:
|
16
|
+
* MIT license - http://datatables.net/license/mit
|
17
|
+
*
|
18
|
+
* This source file is distributed in the hope that it will be useful, but
|
19
|
+
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
20
|
+
* or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
|
21
|
+
*
|
22
|
+
* For details please refer to: http://www.datatables.net/extensions/select
|
23
|
+
*/
|
24
|
+
(function( factory ){
|
25
|
+
if ( typeof define === 'function' && define.amd ) {
|
26
|
+
// AMD
|
27
|
+
define( ['jquery', 'datatables.net'], function ( $ ) {
|
28
|
+
return factory( $, window, document );
|
29
|
+
} );
|
30
|
+
}
|
31
|
+
else if ( typeof exports === 'object' ) {
|
32
|
+
// CommonJS
|
33
|
+
module.exports = function (root, $) {
|
34
|
+
if ( ! root ) {
|
35
|
+
root = window;
|
36
|
+
}
|
37
|
+
|
38
|
+
if ( ! $ || ! $.fn.dataTable ) {
|
39
|
+
$ = require('datatables.net')(root, $).$;
|
40
|
+
}
|
41
|
+
|
42
|
+
return factory( $, root, root.document );
|
43
|
+
};
|
44
|
+
}
|
45
|
+
else {
|
46
|
+
// Browser
|
47
|
+
factory( jQuery, window, document );
|
48
|
+
}
|
49
|
+
}(function( $, window, document, undefined ) {
|
50
|
+
'use strict';
|
51
|
+
var DataTable = $.fn.dataTable;
|
52
|
+
|
53
|
+
|
54
|
+
// Version information for debugger
|
55
|
+
DataTable.select = {};
|
56
|
+
DataTable.select.version = '1.1.0';
|
57
|
+
|
58
|
+
/*
|
59
|
+
|
60
|
+
Select is a collection of API methods, event handlers, event emitters and
|
61
|
+
buttons (for the `Buttons` extension) for DataTables. It provides the following
|
62
|
+
features, with an overview of how they are implemented:
|
63
|
+
|
64
|
+
## Selection of rows, columns and cells. Whether an item is selected or not is
|
65
|
+
stored in:
|
66
|
+
|
67
|
+
* rows: a `_select_selected` property which contains a boolean value of the
|
68
|
+
DataTables' `aoData` object for each row
|
69
|
+
* columns: a `_select_selected` property which contains a boolean value of the
|
70
|
+
DataTables' `aoColumns` object for each column
|
71
|
+
* cells: a `_selected_cells` property which contains an array of boolean values
|
72
|
+
of the `aoData` object for each row. The array is the same length as the
|
73
|
+
columns array, with each element of it representing a cell.
|
74
|
+
|
75
|
+
This method of using boolean flags allows Select to operate when nodes have not
|
76
|
+
been created for rows / cells (DataTables' defer rendering feature).
|
77
|
+
|
78
|
+
## API methods
|
79
|
+
|
80
|
+
A range of API methods are available for triggering selection and de-selection
|
81
|
+
of rows. Methods are also available to configure the selection events that can
|
82
|
+
be triggered by an end user (such as which items are to be selected). To a large
|
83
|
+
extent, these of API methods *is* Select. It is basically a collection of helper
|
84
|
+
functions that can be used to select items in a DataTable.
|
85
|
+
|
86
|
+
Configuration of select is held in the object `_select` which is attached to the
|
87
|
+
DataTables settings object on initialisation. Select being available on a table
|
88
|
+
is not optional when Select is loaded, but its default is for selection only to
|
89
|
+
be available via the API - so the end user wouldn't be able to select rows
|
90
|
+
without additional configuration.
|
91
|
+
|
92
|
+
The `_select` object contains the following properties:
|
93
|
+
|
94
|
+
```
|
95
|
+
{
|
96
|
+
items:string - Can be `rows`, `columns` or `cells`. Defines what item
|
97
|
+
will be selected if the user is allowed to activate row
|
98
|
+
selection using the mouse.
|
99
|
+
style:string - Can be `none`, `single`, `multi` or `os`. Defines the
|
100
|
+
interaction style when selecting items
|
101
|
+
blurable:boolean - If row selection can be cleared by clicking outside of
|
102
|
+
the table
|
103
|
+
info:boolean - If the selection summary should be shown in the table
|
104
|
+
information elements
|
105
|
+
}
|
106
|
+
```
|
107
|
+
|
108
|
+
In addition to the API methods, Select also extends the DataTables selector
|
109
|
+
options for rows, columns and cells adding a `selected` option to the selector
|
110
|
+
options object, allowing the developer to select only selected items or
|
111
|
+
unselected items.
|
112
|
+
|
113
|
+
## Mouse selection of items
|
114
|
+
|
115
|
+
Clicking on items can be used to select items. This is done by a simple event
|
116
|
+
handler that will select the items using the API methods.
|
117
|
+
|
118
|
+
*/
|
119
|
+
|
120
|
+
|
121
|
+
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
122
|
+
* Local functions
|
123
|
+
*/
|
124
|
+
|
125
|
+
/**
|
126
|
+
* Add one or more cells to the selection when shift clicking in OS selection
|
127
|
+
* style cell selection.
|
128
|
+
*
|
129
|
+
* Cell range is more complicated than row and column as we want to select
|
130
|
+
* in the visible grid rather than by index in sequence. For example, if you
|
131
|
+
* click first in cell 1-1 and then shift click in 2-2 - cells 1-2 and 2-1
|
132
|
+
* should also be selected (and not 1-3, 1-4. etc)
|
133
|
+
*
|
134
|
+
* @param {DataTable.Api} dt DataTable
|
135
|
+
* @param {object} idx Cell index to select to
|
136
|
+
* @param {object} last Cell index to select from
|
137
|
+
* @private
|
138
|
+
*/
|
139
|
+
function cellRange( dt, idx, last )
|
140
|
+
{
|
141
|
+
var indexes;
|
142
|
+
var columnIndexes;
|
143
|
+
var rowIndexes;
|
144
|
+
var selectColumns = function ( start, end ) {
|
145
|
+
if ( start > end ) {
|
146
|
+
var tmp = end;
|
147
|
+
end = start;
|
148
|
+
start = tmp;
|
149
|
+
}
|
150
|
+
|
151
|
+
var record = false;
|
152
|
+
return dt.columns( ':visible' ).indexes().filter( function (i) {
|
153
|
+
if ( i === start ) {
|
154
|
+
record = true;
|
155
|
+
}
|
156
|
+
|
157
|
+
if ( i === end ) { // not else if, as start might === end
|
158
|
+
record = false;
|
159
|
+
return true;
|
160
|
+
}
|
161
|
+
|
162
|
+
return record;
|
163
|
+
} );
|
164
|
+
};
|
165
|
+
|
166
|
+
var selectRows = function ( start, end ) {
|
167
|
+
var indexes = dt.rows( { search: 'applied' } ).indexes();
|
168
|
+
|
169
|
+
// Which comes first - might need to swap
|
170
|
+
if ( indexes.indexOf( start ) > indexes.indexOf( end ) ) {
|
171
|
+
var tmp = end;
|
172
|
+
end = start;
|
173
|
+
start = tmp;
|
174
|
+
}
|
175
|
+
|
176
|
+
var record = false;
|
177
|
+
return indexes.filter( function (i) {
|
178
|
+
if ( i === start ) {
|
179
|
+
record = true;
|
180
|
+
}
|
181
|
+
|
182
|
+
if ( i === end ) {
|
183
|
+
record = false;
|
184
|
+
return true;
|
185
|
+
}
|
186
|
+
|
187
|
+
return record;
|
188
|
+
} );
|
189
|
+
};
|
190
|
+
|
191
|
+
if ( ! dt.cells( { selected: true } ).any() && ! last ) {
|
192
|
+
// select from the top left cell to this one
|
193
|
+
columnIndexes = selectColumns( 0, idx.column );
|
194
|
+
rowIndexes = selectRows( 0 , idx.row );
|
195
|
+
}
|
196
|
+
else {
|
197
|
+
// Get column indexes between old and new
|
198
|
+
columnIndexes = selectColumns( last.column, idx.column );
|
199
|
+
rowIndexes = selectRows( last.row , idx.row );
|
200
|
+
}
|
201
|
+
|
202
|
+
indexes = dt.cells( rowIndexes, columnIndexes ).flatten();
|
203
|
+
|
204
|
+
if ( ! dt.cells( idx, { selected: true } ).any() ) {
|
205
|
+
// Select range
|
206
|
+
dt.cells( indexes ).select();
|
207
|
+
}
|
208
|
+
else {
|
209
|
+
// Deselect range
|
210
|
+
dt.cells( indexes ).deselect();
|
211
|
+
}
|
212
|
+
}
|
213
|
+
|
214
|
+
/**
|
215
|
+
* Disable mouse selection by removing the selectors
|
216
|
+
*
|
217
|
+
* @param {DataTable.Api} dt DataTable to remove events from
|
218
|
+
* @private
|
219
|
+
*/
|
220
|
+
function disableMouseSelection( dt )
|
221
|
+
{
|
222
|
+
var ctx = dt.settings()[0];
|
223
|
+
var selector = ctx._select.selector;
|
224
|
+
|
225
|
+
$( dt.table().body() )
|
226
|
+
.off( 'mousedown.dtSelect', selector )
|
227
|
+
.off( 'mouseup.dtSelect', selector )
|
228
|
+
.off( 'click.dtSelect', selector );
|
229
|
+
|
230
|
+
$('body').off( 'click.dtSelect' );
|
231
|
+
}
|
232
|
+
|
233
|
+
/**
|
234
|
+
* Attach mouse listeners to the table to allow mouse selection of items
|
235
|
+
*
|
236
|
+
* @param {DataTable.Api} dt DataTable to remove events from
|
237
|
+
* @private
|
238
|
+
*/
|
239
|
+
function enableMouseSelection ( dt )
|
240
|
+
{
|
241
|
+
var body = $( dt.table().body() );
|
242
|
+
var ctx = dt.settings()[0];
|
243
|
+
var selector = ctx._select.selector;
|
244
|
+
|
245
|
+
body
|
246
|
+
.on( 'mousedown.dtSelect', selector, function(e) {
|
247
|
+
// Disallow text selection for shift clicking on the table so multi
|
248
|
+
// element selection doesn't look terrible!
|
249
|
+
if ( e.shiftKey ) {
|
250
|
+
body
|
251
|
+
.css( '-moz-user-select', 'none' )
|
252
|
+
.one('selectstart.dtSelect', selector, function () {
|
253
|
+
return false;
|
254
|
+
} );
|
255
|
+
}
|
256
|
+
} )
|
257
|
+
.on( 'mouseup.dtSelect', selector, function(e) {
|
258
|
+
// Allow text selection to occur again, Mozilla style (tested in FF
|
259
|
+
// 35.0.1 - still required)
|
260
|
+
body.css( '-moz-user-select', '' );
|
261
|
+
} )
|
262
|
+
.on( 'click.dtSelect', selector, function ( e ) {
|
263
|
+
var items = dt.select.items();
|
264
|
+
var idx;
|
265
|
+
|
266
|
+
var ctx = dt.settings()[0];
|
267
|
+
|
268
|
+
// Ignore clicks inside a sub-table
|
269
|
+
if ( $(e.target).closest('tbody')[0] != body[0] ) {
|
270
|
+
return;
|
271
|
+
}
|
272
|
+
|
273
|
+
var cell = $(e.target).closest('td, th');
|
274
|
+
var cellIndex = dt.cell( cell ).index();
|
275
|
+
|
276
|
+
// Check the cell actually belongs to the host DataTable (so child rows,
|
277
|
+
// etc, are ignored)
|
278
|
+
if ( ! dt.cell( cell ).any() ) {
|
279
|
+
return;
|
280
|
+
}
|
281
|
+
|
282
|
+
if ( items === 'row' ) {
|
283
|
+
idx = cellIndex.row;
|
284
|
+
typeSelect( e, dt, ctx, 'row', idx );
|
285
|
+
}
|
286
|
+
else if ( items === 'column' ) {
|
287
|
+
idx = dt.cell( cell ).index().column;
|
288
|
+
typeSelect( e, dt, ctx, 'column', idx );
|
289
|
+
}
|
290
|
+
else if ( items === 'cell' ) {
|
291
|
+
idx = dt.cell( cell ).index();
|
292
|
+
typeSelect( e, dt, ctx, 'cell', idx );
|
293
|
+
}
|
294
|
+
|
295
|
+
ctx._select_lastCell = cellIndex;
|
296
|
+
} );
|
297
|
+
|
298
|
+
// Blurable
|
299
|
+
$('body').on( 'click.dtSelect', function ( e ) {
|
300
|
+
if ( ctx._select.blurable ) {
|
301
|
+
// If the click was inside the DataTables container, don't blur
|
302
|
+
if ( $(e.target).parents().filter( dt.table().container() ).length ) {
|
303
|
+
return;
|
304
|
+
}
|
305
|
+
|
306
|
+
// Don't blur in Editor form
|
307
|
+
if ( $(e.target).parents('div.DTE').length ) {
|
308
|
+
return;
|
309
|
+
}
|
310
|
+
|
311
|
+
clear( ctx, true );
|
312
|
+
}
|
313
|
+
} );
|
314
|
+
}
|
315
|
+
|
316
|
+
/**
|
317
|
+
* Trigger an event on a DataTable
|
318
|
+
*
|
319
|
+
* @param {DataTable.Api} api DataTable to trigger events on
|
320
|
+
* @param {boolean} selected true if selected, false if deselected
|
321
|
+
* @param {string} type Item type acting on
|
322
|
+
* @param {boolean} any Require that there are values before
|
323
|
+
* triggering
|
324
|
+
* @private
|
325
|
+
*/
|
326
|
+
function eventTrigger ( api, type, args, any )
|
327
|
+
{
|
328
|
+
if ( any && ! api.flatten().length ) {
|
329
|
+
return;
|
330
|
+
}
|
331
|
+
|
332
|
+
args.unshift( api );
|
333
|
+
|
334
|
+
$(api.table().node()).triggerHandler( type+'.dt', args );
|
335
|
+
}
|
336
|
+
|
337
|
+
/**
|
338
|
+
* Update the information element of the DataTable showing information about the
|
339
|
+
* items selected. This is done by adding tags to the existing text
|
340
|
+
*
|
341
|
+
* @param {DataTable.Api} api DataTable to update
|
342
|
+
* @private
|
343
|
+
*/
|
344
|
+
function info ( api )
|
345
|
+
{
|
346
|
+
var ctx = api.settings()[0];
|
347
|
+
|
348
|
+
if ( ! ctx._select.info || ! ctx.aanFeatures.i ) {
|
349
|
+
return;
|
350
|
+
}
|
351
|
+
|
352
|
+
var output = $('<span class="select-info"/>');
|
353
|
+
var add = function ( name, num ) {
|
354
|
+
output.append( $('<span class="select-item"/>').append( api.i18n(
|
355
|
+
'select.'+name+'s',
|
356
|
+
{ _: '%d '+name+'s selected', 0: '', 1: '1 '+name+' selected' },
|
357
|
+
num
|
358
|
+
) ) );
|
359
|
+
};
|
360
|
+
|
361
|
+
add( 'row', api.rows( { selected: true } ).flatten().length );
|
362
|
+
add( 'column', api.columns( { selected: true } ).flatten().length );
|
363
|
+
add( 'cell', api.cells( { selected: true } ).flatten().length );
|
364
|
+
|
365
|
+
// Internal knowledge of DataTables to loop over all information elements
|
366
|
+
$.each( ctx.aanFeatures.i, function ( i, el ) {
|
367
|
+
el = $(el);
|
368
|
+
|
369
|
+
var exisiting = el.children('span.select-info');
|
370
|
+
if ( exisiting.length ) {
|
371
|
+
exisiting.remove();
|
372
|
+
}
|
373
|
+
|
374
|
+
if ( output.text() !== '' ) {
|
375
|
+
el.append( output );
|
376
|
+
}
|
377
|
+
} );
|
378
|
+
}
|
379
|
+
|
380
|
+
/**
|
381
|
+
* Initialisation of a new table. Attach event handlers and callbacks to allow
|
382
|
+
* Select to operate correctly.
|
383
|
+
*
|
384
|
+
* This will occur _after_ the initial DataTables initialisation, although
|
385
|
+
* before Ajax data is rendered, if there is ajax data
|
386
|
+
*
|
387
|
+
* @param {DataTable.settings} ctx Settings object to operate on
|
388
|
+
* @private
|
389
|
+
*/
|
390
|
+
function init ( ctx ) {
|
391
|
+
var api = new DataTable.Api( ctx );
|
392
|
+
|
393
|
+
// Row callback so that classes can be added to rows and cells if the item
|
394
|
+
// was selected before the element was created. This will happen with the
|
395
|
+
// `deferRender` option enabled.
|
396
|
+
//
|
397
|
+
// This method of attaching to `aoRowCreatedCallback` is a hack until
|
398
|
+
// DataTables has proper events for row manipulation If you are reviewing
|
399
|
+
// this code to create your own plug-ins, please do not do this!
|
400
|
+
ctx.aoRowCreatedCallback.push( {
|
401
|
+
fn: function ( row, data, index ) {
|
402
|
+
var i, ien;
|
403
|
+
var d = ctx.aoData[ index ];
|
404
|
+
|
405
|
+
// Row
|
406
|
+
if ( d._select_selected ) {
|
407
|
+
$( row ).addClass( ctx._select.className );
|
408
|
+
}
|
409
|
+
|
410
|
+
// Cells and columns - if separated out, we would need to do two
|
411
|
+
// loops, so it makes sense to combine them into a single one
|
412
|
+
for ( i=0, ien=ctx.aoColumns.length ; i<ien ; i++ ) {
|
413
|
+
if ( ctx.aoColumns[i]._select_selected || (d._selected_cells && d._selected_cells[i]) ) {
|
414
|
+
$(d.anCells[i]).addClass( ctx._select.className );
|
415
|
+
}
|
416
|
+
}
|
417
|
+
},
|
418
|
+
sName: 'select-deferRender'
|
419
|
+
} );
|
420
|
+
|
421
|
+
// On Ajax reload we want to reselect all rows which are currently selected,
|
422
|
+
// if there is an rowId (i.e. a unique value to identify each row with)
|
423
|
+
api.on( 'preXhr.dt.dtSelect', function () {
|
424
|
+
// note that column selection doesn't need to be cached and then
|
425
|
+
// reselected, as they are already selected
|
426
|
+
var rows = api.rows( { selected: true } ).ids( true ).filter( function ( d ) {
|
427
|
+
return d !== undefined;
|
428
|
+
} );
|
429
|
+
|
430
|
+
var cells = api.cells( { selected: true } ).eq(0).map( function ( cellIdx ) {
|
431
|
+
var id = api.row( cellIdx.row ).id( true );
|
432
|
+
return id ?
|
433
|
+
{ row: id, column: cellIdx.column } :
|
434
|
+
undefined;
|
435
|
+
} ).filter( function ( d ) {
|
436
|
+
return d !== undefined;
|
437
|
+
} );
|
438
|
+
|
439
|
+
// On the next draw, reselect the currently selected items
|
440
|
+
api.one( 'draw.dt.dtSelect', function () {
|
441
|
+
api.rows( rows ).select();
|
442
|
+
|
443
|
+
// `cells` is not a cell index selector, so it needs a loop
|
444
|
+
if ( cells.any() ) {
|
445
|
+
cells.each( function ( id ) {
|
446
|
+
api.cells( id.row, id.column ).select();
|
447
|
+
} );
|
448
|
+
}
|
449
|
+
} );
|
450
|
+
} );
|
451
|
+
|
452
|
+
// Update the table information element with selected item summary
|
453
|
+
api.on( 'draw.dtSelect.dt select.dtSelect.dt deselect.dtSelect.dt', function () {
|
454
|
+
info( api );
|
455
|
+
} );
|
456
|
+
|
457
|
+
// Clean up and release
|
458
|
+
api.on( 'destroy.dtSelect', function () {
|
459
|
+
disableMouseSelection( api );
|
460
|
+
api.off( '.dtSelect' );
|
461
|
+
} );
|
462
|
+
}
|
463
|
+
|
464
|
+
/**
|
465
|
+
* Add one or more items (rows or columns) to the selection when shift clicking
|
466
|
+
* in OS selection style
|
467
|
+
*
|
468
|
+
* @param {DataTable.Api} dt DataTable
|
469
|
+
* @param {string} type Row or column range selector
|
470
|
+
* @param {object} idx Item index to select to
|
471
|
+
* @param {object} last Item index to select from
|
472
|
+
* @private
|
473
|
+
*/
|
474
|
+
function rowColumnRange( dt, type, idx, last )
|
475
|
+
{
|
476
|
+
// Add a range of rows from the last selected row to this one
|
477
|
+
var indexes = dt[type+'s']( { search: 'applied' } ).indexes();
|
478
|
+
var idx1 = $.inArray( last, indexes );
|
479
|
+
var idx2 = $.inArray( idx, indexes );
|
480
|
+
|
481
|
+
if ( ! dt[type+'s']( { selected: true } ).any() && idx1 === -1 ) {
|
482
|
+
// select from top to here - slightly odd, but both Windows and Mac OS
|
483
|
+
// do this
|
484
|
+
indexes.splice( $.inArray( idx, indexes )+1, indexes.length );
|
485
|
+
}
|
486
|
+
else {
|
487
|
+
// reverse so we can shift click 'up' as well as down
|
488
|
+
if ( idx1 > idx2 ) {
|
489
|
+
var tmp = idx2;
|
490
|
+
idx2 = idx1;
|
491
|
+
idx1 = tmp;
|
492
|
+
}
|
493
|
+
|
494
|
+
indexes.splice( idx2+1, indexes.length );
|
495
|
+
indexes.splice( 0, idx1 );
|
496
|
+
}
|
497
|
+
|
498
|
+
if ( ! dt[type]( idx, { selected: true } ).any() ) {
|
499
|
+
// Select range
|
500
|
+
dt[type+'s']( indexes ).select();
|
501
|
+
}
|
502
|
+
else {
|
503
|
+
// Deselect range - need to keep the clicked on row selected
|
504
|
+
indexes.splice( $.inArray( idx, indexes ), 1 );
|
505
|
+
dt[type+'s']( indexes ).deselect();
|
506
|
+
}
|
507
|
+
}
|
508
|
+
|
509
|
+
/**
|
510
|
+
* Clear all selected items
|
511
|
+
*
|
512
|
+
* @param {DataTable.settings} ctx Settings object of the host DataTable
|
513
|
+
* @param {boolean} [force=false] Force the de-selection to happen, regardless
|
514
|
+
* of selection style
|
515
|
+
* @private
|
516
|
+
*/
|
517
|
+
function clear( ctx, force )
|
518
|
+
{
|
519
|
+
if ( force || ctx._select.style === 'single' ) {
|
520
|
+
var api = new DataTable.Api( ctx );
|
521
|
+
|
522
|
+
api.rows( { selected: true } ).deselect();
|
523
|
+
api.columns( { selected: true } ).deselect();
|
524
|
+
api.cells( { selected: true } ).deselect();
|
525
|
+
}
|
526
|
+
}
|
527
|
+
|
528
|
+
/**
|
529
|
+
* Select items based on the current configuration for style and items.
|
530
|
+
*
|
531
|
+
* @param {object} e Mouse event object
|
532
|
+
* @param {DataTables.Api} dt DataTable
|
533
|
+
* @param {DataTable.settings} ctx Settings object of the host DataTable
|
534
|
+
* @param {string} type Items to select
|
535
|
+
* @param {int|object} idx Index of the item to select
|
536
|
+
* @private
|
537
|
+
*/
|
538
|
+
function typeSelect ( e, dt, ctx, type, idx )
|
539
|
+
{
|
540
|
+
var style = dt.select.style();
|
541
|
+
var isSelected = dt[type]( idx, { selected: true } ).any();
|
542
|
+
|
543
|
+
if ( style === 'os' ) {
|
544
|
+
if ( e.ctrlKey || e.metaKey ) {
|
545
|
+
// Add or remove from the selection
|
546
|
+
dt[type]( idx ).select( ! isSelected );
|
547
|
+
}
|
548
|
+
else if ( e.shiftKey ) {
|
549
|
+
if ( type === 'cell' ) {
|
550
|
+
cellRange( dt, idx, ctx._select_lastCell || null );
|
551
|
+
}
|
552
|
+
else {
|
553
|
+
rowColumnRange( dt, type, idx, ctx._select_lastCell ?
|
554
|
+
ctx._select_lastCell[type] :
|
555
|
+
null
|
556
|
+
);
|
557
|
+
}
|
558
|
+
}
|
559
|
+
else {
|
560
|
+
// No cmd or shift click - deselect if selected, or select
|
561
|
+
// this row only
|
562
|
+
var selected = dt[type+'s']( { selected: true } );
|
563
|
+
|
564
|
+
if ( isSelected && selected.flatten().length === 1 ) {
|
565
|
+
dt[type]( idx ).deselect();
|
566
|
+
}
|
567
|
+
else {
|
568
|
+
selected.deselect();
|
569
|
+
dt[type]( idx ).select();
|
570
|
+
}
|
571
|
+
}
|
572
|
+
}
|
573
|
+
else {
|
574
|
+
dt[ type ]( idx ).select( ! isSelected );
|
575
|
+
}
|
576
|
+
}
|
577
|
+
|
578
|
+
|
579
|
+
|
580
|
+
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
581
|
+
* DataTables selectors
|
582
|
+
*/
|
583
|
+
|
584
|
+
// row and column are basically identical just assigned to different properties
|
585
|
+
// and checking a different array, so we can dynamically create the functions to
|
586
|
+
// reduce the code size
|
587
|
+
$.each( [
|
588
|
+
{ type: 'row', prop: 'aoData' },
|
589
|
+
{ type: 'column', prop: 'aoColumns' }
|
590
|
+
], function ( i, o ) {
|
591
|
+
DataTable.ext.selector[ o.type ].push( function ( settings, opts, indexes ) {
|
592
|
+
var selected = opts.selected;
|
593
|
+
var data;
|
594
|
+
var out = [];
|
595
|
+
|
596
|
+
if ( selected === undefined ) {
|
597
|
+
return indexes;
|
598
|
+
}
|
599
|
+
|
600
|
+
for ( var i=0, ien=indexes.length ; i<ien ; i++ ) {
|
601
|
+
data = settings[ o.prop ][ indexes[i] ];
|
602
|
+
|
603
|
+
if ( (selected === true && data._select_selected === true) ||
|
604
|
+
(selected === false && ! data._select_selected )
|
605
|
+
) {
|
606
|
+
out.push( indexes[i] );
|
607
|
+
}
|
608
|
+
}
|
609
|
+
|
610
|
+
return out;
|
611
|
+
} );
|
612
|
+
} );
|
613
|
+
|
614
|
+
DataTable.ext.selector.cell.push( function ( settings, opts, cells ) {
|
615
|
+
var selected = opts.selected;
|
616
|
+
var rowData;
|
617
|
+
var out = [];
|
618
|
+
|
619
|
+
if ( selected === undefined ) {
|
620
|
+
return cells;
|
621
|
+
}
|
622
|
+
|
623
|
+
for ( var i=0, ien=cells.length ; i<ien ; i++ ) {
|
624
|
+
rowData = settings.aoData[ cells[i].row ];
|
625
|
+
|
626
|
+
if ( (selected === true && rowData._selected_cells && rowData._selected_cells[ cells[i].column ] === true) ||
|
627
|
+
(selected === false && ( ! rowData._selected_cells || ! rowData._selected_cells[ cells[i].column ] ) )
|
628
|
+
) {
|
629
|
+
out.push( cells[i] );
|
630
|
+
}
|
631
|
+
}
|
632
|
+
|
633
|
+
return out;
|
634
|
+
} );
|
635
|
+
|
636
|
+
|
637
|
+
|
638
|
+
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
639
|
+
* DataTables API
|
640
|
+
*
|
641
|
+
* For complete documentation, please refer to the docs/api directory or the
|
642
|
+
* DataTables site
|
643
|
+
*/
|
644
|
+
|
645
|
+
// Local variables to improve compression
|
646
|
+
var apiRegister = DataTable.Api.register;
|
647
|
+
var apiRegisterPlural = DataTable.Api.registerPlural;
|
648
|
+
|
649
|
+
apiRegister( 'select()', function () {} );
|
650
|
+
|
651
|
+
apiRegister( 'select.blurable()', function ( flag ) {
|
652
|
+
if ( flag === undefined ) {
|
653
|
+
return this.context[0]._select.blurable;
|
654
|
+
}
|
655
|
+
|
656
|
+
return this.iterator( 'table', function ( ctx ) {
|
657
|
+
ctx._select.blurable = flag;
|
658
|
+
} );
|
659
|
+
} );
|
660
|
+
|
661
|
+
apiRegister( 'select.info()', function ( flag ) {
|
662
|
+
if ( info === undefined ) {
|
663
|
+
return this.context[0]._select.info;
|
664
|
+
}
|
665
|
+
|
666
|
+
return this.iterator( 'table', function ( ctx ) {
|
667
|
+
ctx._select.info = flag;
|
668
|
+
} );
|
669
|
+
} );
|
670
|
+
|
671
|
+
apiRegister( 'select.items()', function ( items ) {
|
672
|
+
if ( items === undefined ) {
|
673
|
+
return this.context[0]._select.items;
|
674
|
+
}
|
675
|
+
|
676
|
+
return this.iterator( 'table', function ( ctx ) {
|
677
|
+
ctx._select.items = items;
|
678
|
+
|
679
|
+
eventTrigger( new DataTable.Api( ctx ), 'selectItems', [ items ] );
|
680
|
+
} );
|
681
|
+
} );
|
682
|
+
|
683
|
+
// Takes effect from the _next_ selection. None disables future selection, but
|
684
|
+
// does not clear the current selection. Use the `deselect` methods for that
|
685
|
+
apiRegister( 'select.style()', function ( style ) {
|
686
|
+
if ( style === undefined ) {
|
687
|
+
return this.context[0]._select.style;
|
688
|
+
}
|
689
|
+
|
690
|
+
return this.iterator( 'table', function ( ctx ) {
|
691
|
+
ctx._select.style = style;
|
692
|
+
|
693
|
+
if ( ! ctx._select_init ) {
|
694
|
+
init( ctx );
|
695
|
+
}
|
696
|
+
|
697
|
+
// Add / remove mouse event handlers. They aren't required when only
|
698
|
+
// API selection is available
|
699
|
+
var dt = new DataTable.Api( ctx );
|
700
|
+
disableMouseSelection( dt );
|
701
|
+
|
702
|
+
if ( style !== 'api' ) {
|
703
|
+
enableMouseSelection( dt );
|
704
|
+
}
|
705
|
+
|
706
|
+
eventTrigger( new DataTable.Api( ctx ), 'selectStyle', [ style ] );
|
707
|
+
} );
|
708
|
+
} );
|
709
|
+
|
710
|
+
apiRegister( 'select.selector()', function ( selector ) {
|
711
|
+
if ( selector === undefined ) {
|
712
|
+
return this.context[0]._select.selector;
|
713
|
+
}
|
714
|
+
|
715
|
+
return this.iterator( 'table', function ( ctx ) {
|
716
|
+
disableMouseSelection( new DataTable.Api( ctx ) );
|
717
|
+
|
718
|
+
ctx._select.selector = selector;
|
719
|
+
|
720
|
+
if ( ctx._select.style !== 'api' ) {
|
721
|
+
enableMouseSelection( new DataTable.Api( ctx ) );
|
722
|
+
}
|
723
|
+
} );
|
724
|
+
} );
|
725
|
+
|
726
|
+
|
727
|
+
|
728
|
+
apiRegisterPlural( 'rows().select()', 'row().select()', function ( select ) {
|
729
|
+
var api = this;
|
730
|
+
|
731
|
+
if ( select === false ) {
|
732
|
+
return this.deselect();
|
733
|
+
}
|
734
|
+
|
735
|
+
this.iterator( 'row', function ( ctx, idx ) {
|
736
|
+
clear( ctx );
|
737
|
+
|
738
|
+
ctx.aoData[ idx ]._select_selected = true;
|
739
|
+
$( ctx.aoData[ idx ].nTr ).addClass( ctx._select.className );
|
740
|
+
} );
|
741
|
+
|
742
|
+
this.iterator( 'table', function ( ctx, i ) {
|
743
|
+
eventTrigger( api, 'select', [ 'row', api[i] ], true );
|
744
|
+
} );
|
745
|
+
|
746
|
+
return this;
|
747
|
+
} );
|
748
|
+
|
749
|
+
apiRegisterPlural( 'columns().select()', 'column().select()', function ( select ) {
|
750
|
+
var api = this;
|
751
|
+
|
752
|
+
if ( select === false ) {
|
753
|
+
return this.deselect();
|
754
|
+
}
|
755
|
+
|
756
|
+
this.iterator( 'column', function ( ctx, idx ) {
|
757
|
+
clear( ctx );
|
758
|
+
|
759
|
+
ctx.aoColumns[ idx ]._select_selected = true;
|
760
|
+
|
761
|
+
var column = new DataTable.Api( ctx ).column( idx );
|
762
|
+
|
763
|
+
$( column.header() ).addClass( ctx._select.className );
|
764
|
+
$( column.footer() ).addClass( ctx._select.className );
|
765
|
+
|
766
|
+
column.nodes().to$().addClass( ctx._select.className );
|
767
|
+
} );
|
768
|
+
|
769
|
+
this.iterator( 'table', function ( ctx, i ) {
|
770
|
+
eventTrigger( api, 'select', [ 'column', api[i] ], true );
|
771
|
+
} );
|
772
|
+
|
773
|
+
return this;
|
774
|
+
} );
|
775
|
+
|
776
|
+
apiRegisterPlural( 'cells().select()', 'cell().select()', function ( select ) {
|
777
|
+
var api = this;
|
778
|
+
|
779
|
+
if ( select === false ) {
|
780
|
+
return this.deselect();
|
781
|
+
}
|
782
|
+
|
783
|
+
this.iterator( 'cell', function ( ctx, rowIdx, colIdx ) {
|
784
|
+
clear( ctx );
|
785
|
+
|
786
|
+
var data = ctx.aoData[ rowIdx ];
|
787
|
+
|
788
|
+
if ( data._selected_cells === undefined ) {
|
789
|
+
data._selected_cells = [];
|
790
|
+
}
|
791
|
+
|
792
|
+
data._selected_cells[ colIdx ] = true;
|
793
|
+
|
794
|
+
if ( data.anCells ) {
|
795
|
+
$( data.anCells[ colIdx ] ).addClass( ctx._select.className );
|
796
|
+
}
|
797
|
+
} );
|
798
|
+
|
799
|
+
this.iterator( 'table', function ( ctx, i ) {
|
800
|
+
eventTrigger( api, 'select', [ 'cell', api[i] ], true );
|
801
|
+
} );
|
802
|
+
|
803
|
+
return this;
|
804
|
+
} );
|
805
|
+
|
806
|
+
|
807
|
+
apiRegisterPlural( 'rows().deselect()', 'row().deselect()', function () {
|
808
|
+
var api = this;
|
809
|
+
|
810
|
+
this.iterator( 'row', function ( ctx, idx ) {
|
811
|
+
ctx.aoData[ idx ]._select_selected = false;
|
812
|
+
$( ctx.aoData[ idx ].nTr ).removeClass( ctx._select.className );
|
813
|
+
} );
|
814
|
+
|
815
|
+
this.iterator( 'table', function ( ctx, i ) {
|
816
|
+
eventTrigger( api, 'deselect', [ 'row', api[i] ], true );
|
817
|
+
} );
|
818
|
+
|
819
|
+
return this;
|
820
|
+
} );
|
821
|
+
|
822
|
+
apiRegisterPlural( 'columns().deselect()', 'column().deselect()', function () {
|
823
|
+
var api = this;
|
824
|
+
|
825
|
+
this.iterator( 'column', function ( ctx, idx ) {
|
826
|
+
ctx.aoColumns[ idx ]._select_selected = false;
|
827
|
+
|
828
|
+
var api = new DataTable.Api( ctx );
|
829
|
+
var column = api.column( idx );
|
830
|
+
|
831
|
+
$( column.header() ).removeClass( ctx._select.className );
|
832
|
+
$( column.footer() ).removeClass( ctx._select.className );
|
833
|
+
|
834
|
+
// Need to loop over each cell, rather than just using
|
835
|
+
// `column().nodes()` as cells which are individually selected should
|
836
|
+
// not have the `selected` class removed from them
|
837
|
+
api.cells( null, idx ).indexes().each( function (cellIdx) {
|
838
|
+
var data = ctx.aoData[ cellIdx.row ];
|
839
|
+
var cellSelected = data._selected_cells;
|
840
|
+
|
841
|
+
if ( data.anCells && (! cellSelected || ! cellSelected[ cellIdx.column ]) ) {
|
842
|
+
$( data.anCells[ cellIdx.column ] ).removeClass( ctx._select.className );
|
843
|
+
}
|
844
|
+
} );
|
845
|
+
} );
|
846
|
+
|
847
|
+
this.iterator( 'table', function ( ctx, i ) {
|
848
|
+
eventTrigger( api, 'deselect', [ 'column', api[i] ], true );
|
849
|
+
} );
|
850
|
+
|
851
|
+
return this;
|
852
|
+
} );
|
853
|
+
|
854
|
+
apiRegisterPlural( 'cells().deselect()', 'cell().deselect()', function () {
|
855
|
+
var api = this;
|
856
|
+
|
857
|
+
this.iterator( 'cell', function ( ctx, rowIdx, colIdx ) {
|
858
|
+
var data = ctx.aoData[ rowIdx ];
|
859
|
+
|
860
|
+
data._selected_cells[ colIdx ] = false;
|
861
|
+
|
862
|
+
// Remove class only if the cells exist, and the cell is not column
|
863
|
+
// selected, in which case the class should remain (since it is selected
|
864
|
+
// in the column)
|
865
|
+
if ( data.anCells && ! ctx.aoColumns[ colIdx ]._select_selected ) {
|
866
|
+
$( data.anCells[ colIdx ] ).removeClass( ctx._select.className );
|
867
|
+
}
|
868
|
+
} );
|
869
|
+
|
870
|
+
this.iterator( 'table', function ( ctx, i ) {
|
871
|
+
eventTrigger( api, 'deselect', [ 'cell', api[i] ], true );
|
872
|
+
} );
|
873
|
+
|
874
|
+
return this;
|
875
|
+
} );
|
876
|
+
|
877
|
+
|
878
|
+
|
879
|
+
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
880
|
+
* Buttons
|
881
|
+
*/
|
882
|
+
function i18n( label, def ) {
|
883
|
+
return function (dt) {
|
884
|
+
return dt.i18n( 'buttons.'+label, def );
|
885
|
+
};
|
886
|
+
}
|
887
|
+
|
888
|
+
$.extend( DataTable.ext.buttons, {
|
889
|
+
selected: {
|
890
|
+
text: i18n( 'selected', 'Selected' ),
|
891
|
+
className: 'buttons-selected',
|
892
|
+
init: function ( dt, button, config ) {
|
893
|
+
var that = this;
|
894
|
+
|
895
|
+
// .DT namespace listeners are removed by DataTables automatically
|
896
|
+
// on table destroy
|
897
|
+
dt.on( 'draw.dt.DT select.dt.DT deselect.dt.DT', function () {
|
898
|
+
var enable = that.rows( { selected: true } ).any() ||
|
899
|
+
that.columns( { selected: true } ).any() ||
|
900
|
+
that.cells( { selected: true } ).any();
|
901
|
+
|
902
|
+
that.enable( enable );
|
903
|
+
} );
|
904
|
+
|
905
|
+
this.disable();
|
906
|
+
}
|
907
|
+
},
|
908
|
+
selectedSingle: {
|
909
|
+
text: i18n( 'selectedSingle', 'Selected single' ),
|
910
|
+
className: 'buttons-selected-single',
|
911
|
+
init: function ( dt, button, config ) {
|
912
|
+
var that = this;
|
913
|
+
|
914
|
+
dt.on( 'draw.dt.DT select.dt.DT deselect.dt.DT', function () {
|
915
|
+
var count = dt.rows( { selected: true } ).flatten().length +
|
916
|
+
dt.columns( { selected: true } ).flatten().length +
|
917
|
+
dt.cells( { selected: true } ).flatten().length;
|
918
|
+
|
919
|
+
that.enable( count === 1 );
|
920
|
+
} );
|
921
|
+
|
922
|
+
this.disable();
|
923
|
+
}
|
924
|
+
},
|
925
|
+
selectAll: {
|
926
|
+
text: i18n( 'selectAll', 'Select all' ),
|
927
|
+
className: 'buttons-select-all',
|
928
|
+
action: function () {
|
929
|
+
var items = this.select.items();
|
930
|
+
this[ items+'s' ]().select();
|
931
|
+
}
|
932
|
+
},
|
933
|
+
selectNone: {
|
934
|
+
text: i18n( 'selectNone', 'Deselect all' ),
|
935
|
+
className: 'buttons-select-none',
|
936
|
+
action: function () {
|
937
|
+
clear( this.settings()[0], true );
|
938
|
+
}
|
939
|
+
}
|
940
|
+
} );
|
941
|
+
|
942
|
+
$.each( [ 'Row', 'Column', 'Cell' ], function ( i, item ) {
|
943
|
+
var lc = item.toLowerCase();
|
944
|
+
|
945
|
+
DataTable.ext.buttons[ 'select'+item+'s' ] = {
|
946
|
+
text: i18n( 'select'+item+'s', 'Select '+lc+'s' ),
|
947
|
+
className: 'buttons-select-'+lc+'s',
|
948
|
+
action: function () {
|
949
|
+
this.select.items( lc );
|
950
|
+
},
|
951
|
+
init: function ( dt, button, config ) {
|
952
|
+
var that = this;
|
953
|
+
|
954
|
+
dt.on( 'selectItems.dt.DT', function ( e, ctx, items ) {
|
955
|
+
that.active( items === lc );
|
956
|
+
} );
|
957
|
+
}
|
958
|
+
};
|
959
|
+
} );
|
960
|
+
|
961
|
+
|
962
|
+
|
963
|
+
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
964
|
+
* Initialisation
|
965
|
+
*/
|
966
|
+
|
967
|
+
// DataTables creation - check if the buttons have been defined for this table,
|
968
|
+
// they will have been if the `B` option was used in `dom`, otherwise we should
|
969
|
+
// create the buttons instance here so they can be inserted into the document
|
970
|
+
// using the API
|
971
|
+
$(document).on( 'preInit.dt.dtSelect', function (e, ctx, json) {
|
972
|
+
if ( e.namespace !== 'dt' ) {
|
973
|
+
return;
|
974
|
+
}
|
975
|
+
|
976
|
+
var opts = ctx.oInit.select || DataTable.defaults.select;
|
977
|
+
var dt = new DataTable.Api( ctx );
|
978
|
+
|
979
|
+
// Set defaults
|
980
|
+
var items = 'row';
|
981
|
+
var style = 'api';
|
982
|
+
var blurable = false;
|
983
|
+
var info = true;
|
984
|
+
var selector = 'td, th';
|
985
|
+
var className = 'selected';
|
986
|
+
|
987
|
+
ctx._select = {};
|
988
|
+
|
989
|
+
// Initialisation customisations
|
990
|
+
if ( opts === true ) {
|
991
|
+
style = 'os';
|
992
|
+
}
|
993
|
+
else if ( typeof opts === 'string' ) {
|
994
|
+
style = opts;
|
995
|
+
}
|
996
|
+
else if ( $.isPlainObject( opts ) ) {
|
997
|
+
if ( opts.blurable !== undefined ) {
|
998
|
+
blurable = opts.blurable;
|
999
|
+
}
|
1000
|
+
|
1001
|
+
if ( opts.info !== undefined ) {
|
1002
|
+
info = opts.info;
|
1003
|
+
}
|
1004
|
+
|
1005
|
+
if ( opts.items !== undefined ) {
|
1006
|
+
items = opts.items;
|
1007
|
+
}
|
1008
|
+
|
1009
|
+
if ( opts.style !== undefined ) {
|
1010
|
+
style = opts.style;
|
1011
|
+
}
|
1012
|
+
|
1013
|
+
if ( opts.selector !== undefined ) {
|
1014
|
+
selector = opts.selector;
|
1015
|
+
}
|
1016
|
+
|
1017
|
+
if ( opts.className !== undefined ) {
|
1018
|
+
className = opts.className;
|
1019
|
+
}
|
1020
|
+
}
|
1021
|
+
|
1022
|
+
dt.select.selector( selector );
|
1023
|
+
dt.select.items( items );
|
1024
|
+
dt.select.style( style );
|
1025
|
+
dt.select.blurable( blurable );
|
1026
|
+
dt.select.info( info );
|
1027
|
+
ctx._select.className = className;
|
1028
|
+
|
1029
|
+
// If the init options haven't enabled select, but there is a selectable
|
1030
|
+
// class name, then enable
|
1031
|
+
if ( $( dt.table().node() ).hasClass( 'selectable' ) ) {
|
1032
|
+
dt.select.style( 'os' );
|
1033
|
+
}
|
1034
|
+
} );
|
1035
|
+
|
1036
|
+
|
1037
|
+
return DataTable.select;
|
1038
|
+
}));
|