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
@@ -0,0 +1,1607 @@
|
|
1
|
+
/*! Buttons for DataTables 1.1.0
|
2
|
+
* ©2015 SpryMedia Ltd - datatables.net/license
|
3
|
+
*/
|
4
|
+
|
5
|
+
(function( factory ){
|
6
|
+
if ( typeof define === 'function' && define.amd ) {
|
7
|
+
// AMD
|
8
|
+
define( ['jquery', 'datatables.net'], function ( $ ) {
|
9
|
+
return factory( $, window, document );
|
10
|
+
} );
|
11
|
+
}
|
12
|
+
else if ( typeof exports === 'object' ) {
|
13
|
+
// CommonJS
|
14
|
+
module.exports = function (root, $) {
|
15
|
+
if ( ! root ) {
|
16
|
+
root = window;
|
17
|
+
}
|
18
|
+
|
19
|
+
if ( ! $ || ! $.fn.dataTable ) {
|
20
|
+
$ = require('datatables.net')(root, $).$;
|
21
|
+
}
|
22
|
+
|
23
|
+
return factory( $, root, root.document );
|
24
|
+
};
|
25
|
+
}
|
26
|
+
else {
|
27
|
+
// Browser
|
28
|
+
factory( jQuery, window, document );
|
29
|
+
}
|
30
|
+
}(function( $, window, document, undefined ) {
|
31
|
+
'use strict';
|
32
|
+
var DataTable = $.fn.dataTable;
|
33
|
+
|
34
|
+
|
35
|
+
// Used for namespacing events added to the document by each instance, so they
|
36
|
+
// can be removed on destroy
|
37
|
+
var _instCounter = 0;
|
38
|
+
|
39
|
+
// Button namespacing counter for namespacing events on individual buttons
|
40
|
+
var _buttonCounter = 0;
|
41
|
+
|
42
|
+
var _dtButtons = DataTable.ext.buttons;
|
43
|
+
|
44
|
+
/**
|
45
|
+
* [Buttons description]
|
46
|
+
* @param {[type]}
|
47
|
+
* @param {[type]}
|
48
|
+
*/
|
49
|
+
var Buttons = function( dt, config )
|
50
|
+
{
|
51
|
+
// Allow a boolean true for defaults
|
52
|
+
if ( config === true ) {
|
53
|
+
config = {};
|
54
|
+
}
|
55
|
+
|
56
|
+
// For easy configuration of buttons an array can be given
|
57
|
+
if ( $.isArray( config ) ) {
|
58
|
+
config = { buttons: config };
|
59
|
+
}
|
60
|
+
|
61
|
+
this.c = $.extend( true, {}, Buttons.defaults, config );
|
62
|
+
|
63
|
+
// Don't want a deep copy for the buttons
|
64
|
+
if ( config.buttons ) {
|
65
|
+
this.c.buttons = config.buttons;
|
66
|
+
}
|
67
|
+
|
68
|
+
this.s = {
|
69
|
+
dt: new DataTable.Api( dt ),
|
70
|
+
buttons: [],
|
71
|
+
subButtons: [],
|
72
|
+
listenKeys: '',
|
73
|
+
namespace: 'dtb'+(_instCounter++)
|
74
|
+
};
|
75
|
+
|
76
|
+
this.dom = {
|
77
|
+
container: $('<'+this.c.dom.container.tag+'/>')
|
78
|
+
.addClass( this.c.dom.container.className )
|
79
|
+
};
|
80
|
+
|
81
|
+
this._constructor();
|
82
|
+
};
|
83
|
+
|
84
|
+
|
85
|
+
$.extend( Buttons.prototype, {
|
86
|
+
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
87
|
+
* Public methods
|
88
|
+
*/
|
89
|
+
|
90
|
+
/**
|
91
|
+
* Get the action of a button
|
92
|
+
* @param {int|string} Button index
|
93
|
+
* @return {function}
|
94
|
+
*//**
|
95
|
+
* Set the action of a button
|
96
|
+
* @param {int|string} Button index
|
97
|
+
* @param {function} Function to set
|
98
|
+
* @return {Buttons} Self for chaining
|
99
|
+
*/
|
100
|
+
action: function ( idx, action )
|
101
|
+
{
|
102
|
+
var button = this._indexToButton( idx ).conf;
|
103
|
+
|
104
|
+
if ( action === undefined ) {
|
105
|
+
return button.action;
|
106
|
+
}
|
107
|
+
|
108
|
+
button.action = action;
|
109
|
+
|
110
|
+
return this;
|
111
|
+
},
|
112
|
+
|
113
|
+
/**
|
114
|
+
* Add an active class to the button to make to look active
|
115
|
+
* @param {int|string} Button index
|
116
|
+
* @param {boolean} [flag=true] Enable / disable flag
|
117
|
+
* @return {Buttons} Self for chaining
|
118
|
+
*/
|
119
|
+
active: function ( idx, flag ) {
|
120
|
+
var button = this._indexToButton( idx );
|
121
|
+
button.node.toggleClass(
|
122
|
+
this.c.dom.button.active,
|
123
|
+
flag === undefined ? true : flag
|
124
|
+
);
|
125
|
+
|
126
|
+
return this;
|
127
|
+
},
|
128
|
+
|
129
|
+
/**
|
130
|
+
* Add a new button
|
131
|
+
* @param {int|string} Button index for where to insert the button
|
132
|
+
* @param {object} Button configuration object, base string name or function
|
133
|
+
* @return {Buttons} Self for chaining
|
134
|
+
*/
|
135
|
+
add: function ( idx, config )
|
136
|
+
{
|
137
|
+
if ( typeof idx === 'string' && idx.indexOf('-') !== -1 ) {
|
138
|
+
var idxs = idx.split('-');
|
139
|
+
this.c.buttons[idxs[0]*1].buttons.splice( idxs[1]*1, 0, config );
|
140
|
+
}
|
141
|
+
else {
|
142
|
+
this.c.buttons.splice( idx*1, 0, config );
|
143
|
+
}
|
144
|
+
|
145
|
+
this.dom.container.empty();
|
146
|
+
this._buildButtons( this.c.buttons );
|
147
|
+
|
148
|
+
return this;
|
149
|
+
},
|
150
|
+
|
151
|
+
/**
|
152
|
+
* Get the container node for the buttons
|
153
|
+
* @return {jQuery} Buttons node
|
154
|
+
*/
|
155
|
+
container: function ()
|
156
|
+
{
|
157
|
+
return this.dom.container;
|
158
|
+
},
|
159
|
+
|
160
|
+
/**
|
161
|
+
* Disable a button
|
162
|
+
* @param {int|string} Button index
|
163
|
+
* @return {Buttons} Self for chaining
|
164
|
+
*/
|
165
|
+
disable: function ( idx ) {
|
166
|
+
var button = this._indexToButton( idx );
|
167
|
+
button.node.addClass( this.c.dom.button.disabled );
|
168
|
+
|
169
|
+
return this;
|
170
|
+
},
|
171
|
+
|
172
|
+
/**
|
173
|
+
* Destroy the instance, cleaning up event handlers and removing DOM
|
174
|
+
* elements
|
175
|
+
* @return {Buttons} Self for chaining
|
176
|
+
*/
|
177
|
+
destroy: function ()
|
178
|
+
{
|
179
|
+
// Key event listener
|
180
|
+
$('body').off( 'keyup.'+this.s.namespace );
|
181
|
+
|
182
|
+
// Individual button destroy (so they can remove their own events if
|
183
|
+
// needed
|
184
|
+
var buttons = this.s.buttons;
|
185
|
+
var subButtons = this.s.subButtons;
|
186
|
+
var i, ien, j, jen;
|
187
|
+
|
188
|
+
for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
|
189
|
+
this.removePrep( i );
|
190
|
+
|
191
|
+
for ( j=0, jen=subButtons[i].length ; j<jen ; j++ ) {
|
192
|
+
this.removePrep( i+'-'+j );
|
193
|
+
}
|
194
|
+
}
|
195
|
+
|
196
|
+
this.removeCommit();
|
197
|
+
|
198
|
+
// Container
|
199
|
+
this.dom.container.remove();
|
200
|
+
|
201
|
+
// Remove from the settings object collection
|
202
|
+
var buttonInsts = this.s.dt.settings()[0];
|
203
|
+
|
204
|
+
for ( i=0, ien=buttonInsts.length ; i<ien ; i++ ) {
|
205
|
+
if ( buttonInsts.inst === this ) {
|
206
|
+
buttonInsts.splice( i, 1 );
|
207
|
+
break;
|
208
|
+
}
|
209
|
+
}
|
210
|
+
|
211
|
+
return this;
|
212
|
+
},
|
213
|
+
|
214
|
+
/**
|
215
|
+
* Enable / disable a button
|
216
|
+
* @param {int|string} Button index
|
217
|
+
* @param {boolean} [flag=true] Enable / disable flag
|
218
|
+
* @return {Buttons} Self for chaining
|
219
|
+
*/
|
220
|
+
enable: function ( idx, flag )
|
221
|
+
{
|
222
|
+
if ( flag === false ) {
|
223
|
+
return this.disable( idx );
|
224
|
+
}
|
225
|
+
|
226
|
+
var button = this._indexToButton( idx );
|
227
|
+
button.node.removeClass( this.c.dom.button.disabled );
|
228
|
+
|
229
|
+
return this;
|
230
|
+
},
|
231
|
+
|
232
|
+
/**
|
233
|
+
* Get the instance name for the button set selector
|
234
|
+
* @return {string} Instance name
|
235
|
+
*/
|
236
|
+
name: function ()
|
237
|
+
{
|
238
|
+
return this.c.name;
|
239
|
+
},
|
240
|
+
|
241
|
+
/**
|
242
|
+
* Get a button's node
|
243
|
+
* @param {int|string} Button index
|
244
|
+
* @return {jQuery} Button element
|
245
|
+
*/
|
246
|
+
node: function ( idx )
|
247
|
+
{
|
248
|
+
var button = this._indexToButton( idx );
|
249
|
+
return button.node;
|
250
|
+
},
|
251
|
+
|
252
|
+
/**
|
253
|
+
* Tidy up any buttons that have been scheduled for removal. This is
|
254
|
+
* required so multiple buttons can be removed without upsetting the button
|
255
|
+
* indexes while removing them.
|
256
|
+
* @param {int|string} Button index
|
257
|
+
* @return {Buttons} Self for chaining
|
258
|
+
*/
|
259
|
+
removeCommit: function ()
|
260
|
+
{
|
261
|
+
var buttons = this.s.buttons;
|
262
|
+
var subButtons = this.s.subButtons;
|
263
|
+
var i, ien, j;
|
264
|
+
|
265
|
+
for ( i=buttons.length-1 ; i>=0 ; i-- ) {
|
266
|
+
if ( buttons[i] === null ) {
|
267
|
+
buttons.splice( i, 1 );
|
268
|
+
subButtons.splice( i, 1 );
|
269
|
+
this.c.buttons.splice( i, 1 );
|
270
|
+
}
|
271
|
+
}
|
272
|
+
|
273
|
+
for ( i=0, ien=subButtons.length ; i<ien ; i++ ) {
|
274
|
+
for ( j=subButtons[i].length-1 ; j>=0 ; j-- ) {
|
275
|
+
if ( subButtons[i][j] === null ) {
|
276
|
+
subButtons[i].splice( j, 1 );
|
277
|
+
this.c.buttons[i].buttons.splice( j, 1 );
|
278
|
+
}
|
279
|
+
}
|
280
|
+
}
|
281
|
+
|
282
|
+
return this;
|
283
|
+
},
|
284
|
+
|
285
|
+
/**
|
286
|
+
* Scheduled a button for removal. This is required so multiple buttons can
|
287
|
+
* be removed without upsetting the button indexes while removing them.
|
288
|
+
* @return {Buttons} Self for chaining
|
289
|
+
*/
|
290
|
+
removePrep: function ( idx )
|
291
|
+
{
|
292
|
+
var button;
|
293
|
+
var dt = this.s.dt;
|
294
|
+
|
295
|
+
if ( typeof idx === 'number' || idx.indexOf('-') === -1 ) {
|
296
|
+
// Top level button
|
297
|
+
button = this.s.buttons[ idx*1 ];
|
298
|
+
|
299
|
+
if ( button.conf.destroy ) {
|
300
|
+
button.conf.destroy.call( dt.button(idx), dt, button, button.conf );
|
301
|
+
}
|
302
|
+
|
303
|
+
button.node.remove();
|
304
|
+
this._removeKey( button.conf );
|
305
|
+
this.s.buttons[ idx*1 ] = null;
|
306
|
+
}
|
307
|
+
else {
|
308
|
+
// Collection button
|
309
|
+
var idxs = idx.split('-');
|
310
|
+
button = this.s.subButtons[ idxs[0]*1 ][ idxs[1]*1 ];
|
311
|
+
|
312
|
+
if ( button.conf.destroy ) {
|
313
|
+
button.conf.destroy.call( dt.button(idx), dt, button, button.conf );
|
314
|
+
}
|
315
|
+
|
316
|
+
button.node.remove();
|
317
|
+
this._removeKey( button.conf );
|
318
|
+
this.s.subButtons[ idxs[0]*1 ][ idxs[1]*1 ] = null;
|
319
|
+
}
|
320
|
+
|
321
|
+
return this;
|
322
|
+
},
|
323
|
+
|
324
|
+
/**
|
325
|
+
* Get the text for a button
|
326
|
+
* @param {int|string} Button index
|
327
|
+
* @return {string} Button text
|
328
|
+
*//**
|
329
|
+
* Set the text for a button
|
330
|
+
* @param {int|string|function} Button index
|
331
|
+
* @param {string} Text
|
332
|
+
* @return {Buttons} Self for chaining
|
333
|
+
*/
|
334
|
+
text: function ( idx, label )
|
335
|
+
{
|
336
|
+
var button = this._indexToButton( idx );
|
337
|
+
var buttonLiner = this.c.dom.collection.buttonLiner;
|
338
|
+
var linerTag = typeof idx === 'string' && idx.indexOf( '-' ) !== -1 && buttonLiner && buttonLiner.tag ?
|
339
|
+
buttonLiner.tag :
|
340
|
+
this.c.dom.buttonLiner.tag;
|
341
|
+
var dt = this.s.dt;
|
342
|
+
var text = function ( opt ) {
|
343
|
+
return typeof opt === 'function' ?
|
344
|
+
opt( dt, button.node, button.conf ) :
|
345
|
+
opt;
|
346
|
+
};
|
347
|
+
|
348
|
+
if ( label === undefined ) {
|
349
|
+
return text( button.conf.text );
|
350
|
+
}
|
351
|
+
|
352
|
+
button.conf.text = label;
|
353
|
+
|
354
|
+
if ( linerTag ) {
|
355
|
+
button.node.children( linerTag ).html( text(label) );
|
356
|
+
}
|
357
|
+
else {
|
358
|
+
button.node.html( text(label) );
|
359
|
+
}
|
360
|
+
|
361
|
+
return this;
|
362
|
+
},
|
363
|
+
|
364
|
+
/**
|
365
|
+
* Calculate button index from a node
|
366
|
+
* @param {node} Button node (_not_ a jQuery object)
|
367
|
+
* @return {string} Index. Undefined if not found
|
368
|
+
*/
|
369
|
+
toIndex: function ( node )
|
370
|
+
{
|
371
|
+
var i, ien, j, jen;
|
372
|
+
var buttons = this.s.buttons;
|
373
|
+
var subButtons = this.s.subButtons;
|
374
|
+
|
375
|
+
// Loop the main buttons first
|
376
|
+
for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
|
377
|
+
if ( buttons[i].node[0] === node ) {
|
378
|
+
return i+'';
|
379
|
+
}
|
380
|
+
}
|
381
|
+
|
382
|
+
// Then the sub-buttons
|
383
|
+
for ( i=0, ien=subButtons.length ; i<ien ; i++ ) {
|
384
|
+
for ( j=0, jen=subButtons[i].length ; j<jen ; j++ ) {
|
385
|
+
if ( subButtons[i][j].node[0] === node ) {
|
386
|
+
return i+'-'+j;
|
387
|
+
}
|
388
|
+
}
|
389
|
+
}
|
390
|
+
},
|
391
|
+
|
392
|
+
|
393
|
+
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
394
|
+
* Constructor
|
395
|
+
*/
|
396
|
+
|
397
|
+
/**
|
398
|
+
* Buttons constructor
|
399
|
+
* @private
|
400
|
+
*/
|
401
|
+
_constructor: function ()
|
402
|
+
{
|
403
|
+
var that = this;
|
404
|
+
var dt = this.s.dt;
|
405
|
+
var dtSettings = dt.settings()[0];
|
406
|
+
|
407
|
+
if ( ! dtSettings._buttons ) {
|
408
|
+
dtSettings._buttons = [];
|
409
|
+
}
|
410
|
+
|
411
|
+
dtSettings._buttons.push( {
|
412
|
+
inst: this,
|
413
|
+
name: this.c.name
|
414
|
+
} );
|
415
|
+
|
416
|
+
this._buildButtons( this.c.buttons );
|
417
|
+
|
418
|
+
dt.on( 'destroy', function () {
|
419
|
+
that.destroy();
|
420
|
+
} );
|
421
|
+
|
422
|
+
// Global key event binding to listen for button keys
|
423
|
+
$('body').on( 'keyup.'+this.s.namespace, function ( e ) {
|
424
|
+
if ( ! document.activeElement || document.activeElement === document.body ) {
|
425
|
+
// SUse a string of characters for fast lookup of if we need to
|
426
|
+
// handle this
|
427
|
+
var character = String.fromCharCode(e.keyCode).toLowerCase();
|
428
|
+
|
429
|
+
if ( that.s.listenKeys.toLowerCase().indexOf( character ) !== -1 ) {
|
430
|
+
that._keypress( character, e );
|
431
|
+
}
|
432
|
+
}
|
433
|
+
} );
|
434
|
+
},
|
435
|
+
|
436
|
+
|
437
|
+
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
438
|
+
* Private methods
|
439
|
+
*/
|
440
|
+
|
441
|
+
/**
|
442
|
+
* Add a new button to the key press listener
|
443
|
+
* @param {object} Resolved button configuration object
|
444
|
+
* @private
|
445
|
+
*/
|
446
|
+
_addKey: function ( conf )
|
447
|
+
{
|
448
|
+
if ( conf.key ) {
|
449
|
+
this.s.listenKeys += $.isPlainObject( conf.key ) ?
|
450
|
+
conf.key.key :
|
451
|
+
conf.key;
|
452
|
+
}
|
453
|
+
},
|
454
|
+
|
455
|
+
/**
|
456
|
+
* Create buttons from an array of buttons
|
457
|
+
* @param {array} Buttons to create
|
458
|
+
* @param {jQuery} Container node into which the created button should be
|
459
|
+
* inserted.
|
460
|
+
* @param {int} Counter for sub-buttons to be stored in a collection
|
461
|
+
* @private
|
462
|
+
*/
|
463
|
+
_buildButtons: function ( buttons, container, collectionCounter )
|
464
|
+
{
|
465
|
+
var dt = this.s.dt;
|
466
|
+
|
467
|
+
if ( ! container ) {
|
468
|
+
container = this.dom.container;
|
469
|
+
this.s.buttons = [];
|
470
|
+
this.s.subButtons = [];
|
471
|
+
}
|
472
|
+
|
473
|
+
for ( var i=0, ien=buttons.length ; i<ien ; i++ ) {
|
474
|
+
var conf = this._resolveExtends( buttons[i] );
|
475
|
+
|
476
|
+
if ( ! conf ) {
|
477
|
+
continue;
|
478
|
+
}
|
479
|
+
|
480
|
+
// If the configuration is an array, then expand the buttons at this
|
481
|
+
// point
|
482
|
+
if ( $.isArray( conf ) ) {
|
483
|
+
this._buildButtons( conf, container, collectionCounter );
|
484
|
+
continue;
|
485
|
+
}
|
486
|
+
|
487
|
+
var button = this._buildButton(
|
488
|
+
conf,
|
489
|
+
collectionCounter!==undefined ? true : false
|
490
|
+
);
|
491
|
+
|
492
|
+
if ( ! button ) {
|
493
|
+
continue;
|
494
|
+
}
|
495
|
+
|
496
|
+
var buttonNode = button.node;
|
497
|
+
container.append( button.inserter );
|
498
|
+
|
499
|
+
if ( collectionCounter === undefined ) {
|
500
|
+
this.s.buttons.push( {
|
501
|
+
node: buttonNode,
|
502
|
+
conf: conf,
|
503
|
+
inserter: button.inserter
|
504
|
+
} );
|
505
|
+
this.s.subButtons.push( [] );
|
506
|
+
}
|
507
|
+
else {
|
508
|
+
this.s.subButtons[ collectionCounter ].push( {
|
509
|
+
node: buttonNode,
|
510
|
+
conf: conf,
|
511
|
+
inserter: button.inserter
|
512
|
+
} );
|
513
|
+
}
|
514
|
+
|
515
|
+
if ( conf.buttons ) {
|
516
|
+
var collectionDom = this.c.dom.collection;
|
517
|
+
conf._collection = $('<'+collectionDom.tag+'/>')
|
518
|
+
.addClass( collectionDom.className );
|
519
|
+
|
520
|
+
this._buildButtons( conf.buttons, conf._collection, i );
|
521
|
+
}
|
522
|
+
|
523
|
+
// init call is made here, rather than buildButton as it needs to
|
524
|
+
// have been added to the buttons / subButtons array first
|
525
|
+
if ( conf.init ) {
|
526
|
+
conf.init.call( dt.button( buttonNode ), dt, buttonNode, conf );
|
527
|
+
}
|
528
|
+
}
|
529
|
+
},
|
530
|
+
|
531
|
+
/**
|
532
|
+
* Create an individual button
|
533
|
+
* @param {object} config Resolved button configuration
|
534
|
+
* @param {boolean} collectionButton `true` if a collection button
|
535
|
+
* @return {jQuery} Created button node (jQuery)
|
536
|
+
* @private
|
537
|
+
*/
|
538
|
+
_buildButton: function ( config, collectionButton )
|
539
|
+
{
|
540
|
+
var that = this;
|
541
|
+
var buttonDom = this.c.dom.button;
|
542
|
+
var linerDom = this.c.dom.buttonLiner;
|
543
|
+
var collectionDom = this.c.dom.collection;
|
544
|
+
var dt = this.s.dt;
|
545
|
+
var text = function ( opt ) {
|
546
|
+
return typeof opt === 'function' ?
|
547
|
+
opt( dt, button, config ) :
|
548
|
+
opt;
|
549
|
+
};
|
550
|
+
|
551
|
+
if ( collectionButton && collectionDom.button ) {
|
552
|
+
buttonDom = collectionDom.button;
|
553
|
+
}
|
554
|
+
|
555
|
+
if ( collectionButton && collectionDom.buttonLiner ) {
|
556
|
+
linerDom = collectionDom.buttonLiner;
|
557
|
+
}
|
558
|
+
|
559
|
+
// Make sure that the button is available based on whatever requirements
|
560
|
+
// it has. For example, Flash buttons require Flash
|
561
|
+
if ( config.available && ! config.available( dt, config ) ) {
|
562
|
+
return false;
|
563
|
+
}
|
564
|
+
|
565
|
+
var button = $('<'+buttonDom.tag+'/>')
|
566
|
+
.addClass( buttonDom.className )
|
567
|
+
.attr( 'tabindex', this.s.dt.settings()[0].iTabIndex )
|
568
|
+
.attr( 'aria-controls', this.s.dt.table().node().id )
|
569
|
+
.on( 'click.dtb', function (e) {
|
570
|
+
e.preventDefault();
|
571
|
+
|
572
|
+
if ( ! button.hasClass( buttonDom.disabled ) && config.action ) {
|
573
|
+
config.action.call( dt.button( button ), e, dt, button, config );
|
574
|
+
}
|
575
|
+
|
576
|
+
button.blur();
|
577
|
+
} )
|
578
|
+
.on( 'keyup.dtb', function (e) {
|
579
|
+
if ( e.keyCode === 13 ) {
|
580
|
+
if ( ! button.hasClass( buttonDom.disabled ) && config.action ) {
|
581
|
+
config.action.call( dt.button( button ), e, dt, button, config );
|
582
|
+
}
|
583
|
+
}
|
584
|
+
} );
|
585
|
+
|
586
|
+
if ( linerDom.tag ) {
|
587
|
+
button.append(
|
588
|
+
$('<'+linerDom.tag+'/>')
|
589
|
+
.html( text( config.text ) )
|
590
|
+
.addClass( linerDom.className )
|
591
|
+
);
|
592
|
+
}
|
593
|
+
else {
|
594
|
+
button.html( text( config.text ) );
|
595
|
+
}
|
596
|
+
|
597
|
+
if ( config.enabled === false ) {
|
598
|
+
button.addClass( buttonDom.disabled );
|
599
|
+
}
|
600
|
+
|
601
|
+
if ( config.className ) {
|
602
|
+
button.addClass( config.className );
|
603
|
+
}
|
604
|
+
|
605
|
+
if ( config.titleAttr ) {
|
606
|
+
button.attr( 'title', config.titleAttr );
|
607
|
+
}
|
608
|
+
|
609
|
+
if ( ! config.namespace ) {
|
610
|
+
config.namespace = '.dt-button-'+(_buttonCounter++);
|
611
|
+
}
|
612
|
+
|
613
|
+
var buttonContainer = this.c.dom.buttonContainer;
|
614
|
+
var inserter;
|
615
|
+
if ( buttonContainer ) {
|
616
|
+
inserter = $('<'+buttonContainer.tag+'/>')
|
617
|
+
.addClass( buttonContainer.className )
|
618
|
+
.append( button );
|
619
|
+
}
|
620
|
+
else {
|
621
|
+
inserter = button;
|
622
|
+
}
|
623
|
+
|
624
|
+
this._addKey( config );
|
625
|
+
|
626
|
+
return {
|
627
|
+
node: button,
|
628
|
+
inserter: inserter
|
629
|
+
};
|
630
|
+
},
|
631
|
+
|
632
|
+
/**
|
633
|
+
* Get a button's host information from a button index
|
634
|
+
* @param {int|string} Button index
|
635
|
+
* @return {object} Button information - object contains `node` and `conf`
|
636
|
+
* properties
|
637
|
+
* @private
|
638
|
+
*/
|
639
|
+
_indexToButton: function ( idx )
|
640
|
+
{
|
641
|
+
if ( typeof idx === 'number' || idx.indexOf('-') === -1 ) {
|
642
|
+
return this.s.buttons[ idx*1 ];
|
643
|
+
}
|
644
|
+
|
645
|
+
var idxs = idx.split('-');
|
646
|
+
return this.s.subButtons[ idxs[0]*1 ][ idxs[1]*1 ];
|
647
|
+
},
|
648
|
+
|
649
|
+
/**
|
650
|
+
* Handle a key press - determine if any button's key configured matches
|
651
|
+
* what was typed and trigger the action if so.
|
652
|
+
* @param {string} The character pressed
|
653
|
+
* @param {object} Key event that triggered this call
|
654
|
+
* @private
|
655
|
+
*/
|
656
|
+
_keypress: function ( character, e )
|
657
|
+
{
|
658
|
+
var i, ien, j, jen;
|
659
|
+
var buttons = this.s.buttons;
|
660
|
+
var subButtons = this.s.subButtons;
|
661
|
+
var run = function ( conf, node ) {
|
662
|
+
if ( ! conf.key ) {
|
663
|
+
return;
|
664
|
+
}
|
665
|
+
|
666
|
+
if ( conf.key === character ) {
|
667
|
+
node.click();
|
668
|
+
}
|
669
|
+
else if ( $.isPlainObject( conf.key ) ) {
|
670
|
+
if ( conf.key.key !== character ) {
|
671
|
+
return;
|
672
|
+
}
|
673
|
+
|
674
|
+
if ( conf.key.shiftKey && ! e.shiftKey ) {
|
675
|
+
return;
|
676
|
+
}
|
677
|
+
|
678
|
+
if ( conf.key.altKey && ! e.altKey ) {
|
679
|
+
return;
|
680
|
+
}
|
681
|
+
|
682
|
+
if ( conf.key.ctrlKey && ! e.ctrlKey ) {
|
683
|
+
return;
|
684
|
+
}
|
685
|
+
|
686
|
+
if ( conf.key.metaKey && ! e.metaKey ) {
|
687
|
+
return;
|
688
|
+
}
|
689
|
+
|
690
|
+
// Made it this far - it is good
|
691
|
+
node.click();
|
692
|
+
}
|
693
|
+
};
|
694
|
+
|
695
|
+
// Loop the main buttons first
|
696
|
+
for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
|
697
|
+
run( buttons[i].conf, buttons[i].node );
|
698
|
+
}
|
699
|
+
|
700
|
+
// Then the sub-buttons
|
701
|
+
for ( i=0, ien=subButtons.length ; i<ien ; i++ ) {
|
702
|
+
for ( j=0, jen=subButtons[i].length ; j<jen ; j++ ) {
|
703
|
+
run( subButtons[i][j].conf, subButtons[i][j].node );
|
704
|
+
}
|
705
|
+
}
|
706
|
+
},
|
707
|
+
|
708
|
+
/**
|
709
|
+
* Remove a key from the key listener for this instance (to be used when a
|
710
|
+
* button is removed)
|
711
|
+
* @param {object} Button configuration
|
712
|
+
*/
|
713
|
+
_removeKey: function ( conf )
|
714
|
+
{
|
715
|
+
if ( conf.key ) {
|
716
|
+
var character = $.isPlainObject( conf.key ) ?
|
717
|
+
conf.key.key :
|
718
|
+
conf.key;
|
719
|
+
|
720
|
+
// Remove only one character, as multiple buttons could have the
|
721
|
+
// same listening key
|
722
|
+
var a = this.s.listenKeys.split('');
|
723
|
+
var idx = $.inArray( character, a );
|
724
|
+
a.splice( idx, 1 );
|
725
|
+
this.s.listenKeys = a.join('');
|
726
|
+
}
|
727
|
+
},
|
728
|
+
|
729
|
+
/**
|
730
|
+
* Resolve a button configuration
|
731
|
+
* @param {string|function|object} Button config to resolve
|
732
|
+
* @return {object} Button configuration
|
733
|
+
*/
|
734
|
+
_resolveExtends: function ( conf )
|
735
|
+
{
|
736
|
+
var dt = this.s.dt;
|
737
|
+
var i, ien;
|
738
|
+
var toConfObject = function ( base ) {
|
739
|
+
var loop = 0;
|
740
|
+
|
741
|
+
// Loop until we have resolved to a button configuration, or an
|
742
|
+
// array of button configurations (which will be iterated
|
743
|
+
// separately)
|
744
|
+
while ( ! $.isPlainObject(base) && ! $.isArray(base) ) {
|
745
|
+
if ( base === undefined ) {
|
746
|
+
return;
|
747
|
+
}
|
748
|
+
|
749
|
+
if ( typeof base === 'function' ) {
|
750
|
+
base = base( dt, conf );
|
751
|
+
|
752
|
+
if ( ! base ) {
|
753
|
+
return false;
|
754
|
+
}
|
755
|
+
}
|
756
|
+
else if ( typeof base === 'string' ) {
|
757
|
+
if ( ! _dtButtons[ base ] ) {
|
758
|
+
throw 'Unknown button type: '+base;
|
759
|
+
}
|
760
|
+
|
761
|
+
base = _dtButtons[ base ];
|
762
|
+
}
|
763
|
+
|
764
|
+
loop++;
|
765
|
+
if ( loop > 30 ) {
|
766
|
+
// Protect against misconfiguration killing the browser
|
767
|
+
throw 'Buttons: Too many iterations';
|
768
|
+
}
|
769
|
+
}
|
770
|
+
|
771
|
+
return $.isArray( base ) ?
|
772
|
+
base :
|
773
|
+
$.extend( {}, base );
|
774
|
+
};
|
775
|
+
|
776
|
+
conf = toConfObject( conf );
|
777
|
+
|
778
|
+
while ( conf && conf.extend ) {
|
779
|
+
// Use `toConfObject` in case the button definition being extended
|
780
|
+
// is itself a string or a function
|
781
|
+
if ( ! _dtButtons[ conf.extend ] ) {
|
782
|
+
throw 'Cannot extend unknown button type: '+conf.extend;
|
783
|
+
}
|
784
|
+
|
785
|
+
var objArray = toConfObject( _dtButtons[ conf.extend ] );
|
786
|
+
if ( $.isArray( objArray ) ) {
|
787
|
+
return objArray;
|
788
|
+
}
|
789
|
+
else if ( ! objArray ) {
|
790
|
+
// This is a little brutal as it might be possible to have a
|
791
|
+
// valid button without the extend, but if there is no extend
|
792
|
+
// then the host button would be acting in an undefined state
|
793
|
+
return false;
|
794
|
+
}
|
795
|
+
|
796
|
+
// Stash the current class name
|
797
|
+
var originalClassName = objArray.className;
|
798
|
+
|
799
|
+
conf = $.extend( {}, objArray, conf );
|
800
|
+
|
801
|
+
// The extend will have overwritten the original class name if the
|
802
|
+
// `conf` object also assigned a class, but we want to concatenate
|
803
|
+
// them so they are list that is combined from all extended buttons
|
804
|
+
if ( originalClassName && conf.className !== originalClassName ) {
|
805
|
+
conf.className = originalClassName+' '+conf.className;
|
806
|
+
}
|
807
|
+
|
808
|
+
// Buttons to be added to a collection -gives the ability to define
|
809
|
+
// if buttons should be added to the start or end of a collection
|
810
|
+
var postfixButtons = conf.postfixButtons;
|
811
|
+
if ( postfixButtons ) {
|
812
|
+
if ( ! conf.buttons ) {
|
813
|
+
conf.buttons = [];
|
814
|
+
}
|
815
|
+
|
816
|
+
for ( i=0, ien=postfixButtons.length ; i<ien ; i++ ) {
|
817
|
+
conf.buttons.push( postfixButtons[i] );
|
818
|
+
}
|
819
|
+
|
820
|
+
conf.postfixButtons = null;
|
821
|
+
}
|
822
|
+
|
823
|
+
var prefixButtons = conf.prefixButtons;
|
824
|
+
if ( prefixButtons ) {
|
825
|
+
if ( ! conf.buttons ) {
|
826
|
+
conf.buttons = [];
|
827
|
+
}
|
828
|
+
|
829
|
+
for ( i=0, ien=prefixButtons.length ; i<ien ; i++ ) {
|
830
|
+
conf.buttons.splice( i, 0, prefixButtons[i] );
|
831
|
+
}
|
832
|
+
|
833
|
+
conf.prefixButtons = null;
|
834
|
+
}
|
835
|
+
|
836
|
+
// Although we want the `conf` object to overwrite almost all of
|
837
|
+
// the properties of the object being extended, the `extend`
|
838
|
+
// property should come from the object being extended
|
839
|
+
conf.extend = objArray.extend;
|
840
|
+
}
|
841
|
+
|
842
|
+
return conf;
|
843
|
+
}
|
844
|
+
} );
|
845
|
+
|
846
|
+
|
847
|
+
|
848
|
+
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
849
|
+
* Statics
|
850
|
+
*/
|
851
|
+
|
852
|
+
/**
|
853
|
+
* Show / hide a background layer behind a collection
|
854
|
+
* @param {boolean} Flag to indicate if the background should be shown or
|
855
|
+
* hidden
|
856
|
+
* @param {string} Class to assign to the background
|
857
|
+
* @static
|
858
|
+
*/
|
859
|
+
Buttons.background = function ( show, className, fade ) {
|
860
|
+
if ( fade === undefined ) {
|
861
|
+
fade = 400;
|
862
|
+
}
|
863
|
+
|
864
|
+
if ( show ) {
|
865
|
+
$('<div/>')
|
866
|
+
.addClass( className )
|
867
|
+
.css( 'display', 'none' )
|
868
|
+
.appendTo( 'body' )
|
869
|
+
.fadeIn( fade );
|
870
|
+
}
|
871
|
+
else {
|
872
|
+
$('body > div.'+className)
|
873
|
+
.fadeOut( fade, function () {
|
874
|
+
$(this).remove();
|
875
|
+
} );
|
876
|
+
}
|
877
|
+
};
|
878
|
+
|
879
|
+
/**
|
880
|
+
* Instance selector - select Buttons instances based on an instance selector
|
881
|
+
* value from the buttons assigned to a DataTable. This is only useful if
|
882
|
+
* multiple instances are attached to a DataTable.
|
883
|
+
* @param {string|int|array} Instance selector - see `instance-selector`
|
884
|
+
* documentation on the DataTables site
|
885
|
+
* @param {array} Button instance array that was attached to the DataTables
|
886
|
+
* settings object
|
887
|
+
* @return {array} Buttons instances
|
888
|
+
* @static
|
889
|
+
*/
|
890
|
+
Buttons.instanceSelector = function ( group, buttons )
|
891
|
+
{
|
892
|
+
if ( ! group ) {
|
893
|
+
return $.map( buttons, function ( v ) {
|
894
|
+
return v.inst;
|
895
|
+
} );
|
896
|
+
}
|
897
|
+
|
898
|
+
var ret = [];
|
899
|
+
var names = $.map( buttons, function ( v ) {
|
900
|
+
return v.name;
|
901
|
+
} );
|
902
|
+
|
903
|
+
// Flatten the group selector into an array of single options
|
904
|
+
var process = function ( input ) {
|
905
|
+
if ( $.isArray( input ) ) {
|
906
|
+
for ( var i=0, ien=input.length ; i<ien ; i++ ) {
|
907
|
+
process( input[i] );
|
908
|
+
}
|
909
|
+
return;
|
910
|
+
}
|
911
|
+
|
912
|
+
if ( typeof input === 'string' ) {
|
913
|
+
if ( input.indexOf( ',' ) !== -1 ) {
|
914
|
+
// String selector, list of names
|
915
|
+
process( input.split(',') );
|
916
|
+
}
|
917
|
+
else {
|
918
|
+
// String selector individual name
|
919
|
+
var idx = $.inArray( $.trim(input), names );
|
920
|
+
|
921
|
+
if ( idx !== -1 ) {
|
922
|
+
ret.push( buttons[ idx ].inst );
|
923
|
+
}
|
924
|
+
}
|
925
|
+
}
|
926
|
+
else if ( typeof input === 'number' ) {
|
927
|
+
// Index selector
|
928
|
+
ret.push( buttons[ input ].inst );
|
929
|
+
}
|
930
|
+
};
|
931
|
+
|
932
|
+
process( group );
|
933
|
+
|
934
|
+
return ret;
|
935
|
+
};
|
936
|
+
|
937
|
+
/**
|
938
|
+
* Button selector - select one or more buttons from a selector input so some
|
939
|
+
* operation can be performed on them.
|
940
|
+
* @param {array} Button instances array that the selector should operate on
|
941
|
+
* @param {string|int|node|jQuery|array} Button selector - see
|
942
|
+
* `button-selector` documentation on the DataTables site
|
943
|
+
* @return {array} Array of objects containing `inst` and `idx` properties of
|
944
|
+
* the selected buttons so you know which instance each button belongs to.
|
945
|
+
* @static
|
946
|
+
*/
|
947
|
+
Buttons.buttonSelector = function ( insts, selector )
|
948
|
+
{
|
949
|
+
var ret = [];
|
950
|
+
var run = function ( selector, inst ) {
|
951
|
+
var i, ien, j, jen;
|
952
|
+
var buttons = [];
|
953
|
+
|
954
|
+
$.each( inst.s.buttons, function (i, v) {
|
955
|
+
if ( v !== null ) {
|
956
|
+
buttons.push( {
|
957
|
+
node: v.node[0],
|
958
|
+
name: v.name
|
959
|
+
} );
|
960
|
+
}
|
961
|
+
} );
|
962
|
+
|
963
|
+
$.each( inst.s.subButtons, function (i, v) {
|
964
|
+
$.each( v, function (j, w) {
|
965
|
+
if ( w !== null ) {
|
966
|
+
buttons.push( {
|
967
|
+
node: w.node[0],
|
968
|
+
name: w.name
|
969
|
+
} );
|
970
|
+
}
|
971
|
+
} );
|
972
|
+
} );
|
973
|
+
|
974
|
+
var nodes = $.map( buttons, function (v) {
|
975
|
+
return v.node;
|
976
|
+
} );
|
977
|
+
|
978
|
+
if ( $.isArray( selector ) || selector instanceof $ ) {
|
979
|
+
for ( i=0, ien=selector.length ; i<ien ; i++ ) {
|
980
|
+
run( selector[i], inst );
|
981
|
+
}
|
982
|
+
return;
|
983
|
+
}
|
984
|
+
|
985
|
+
if ( selector === null || selector === undefined || selector === '*' ) {
|
986
|
+
// Select all
|
987
|
+
for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
|
988
|
+
ret.push( {
|
989
|
+
inst: inst,
|
990
|
+
idx: inst.toIndex( buttons[i].node )
|
991
|
+
} );
|
992
|
+
}
|
993
|
+
}
|
994
|
+
else if ( typeof selector === 'number' ) {
|
995
|
+
// Main button index selector
|
996
|
+
ret.push( {
|
997
|
+
inst: inst,
|
998
|
+
idx: selector
|
999
|
+
} );
|
1000
|
+
}
|
1001
|
+
else if ( typeof selector === 'string' ) {
|
1002
|
+
if ( selector.indexOf( ',' ) !== -1 ) {
|
1003
|
+
// Split
|
1004
|
+
var a = selector.split(',');
|
1005
|
+
|
1006
|
+
for ( i=0, ien=a.length ; i<ien ; i++ ) {
|
1007
|
+
run( $.trim(a[i]), inst );
|
1008
|
+
}
|
1009
|
+
}
|
1010
|
+
else if ( selector.match( /^\d+(\-\d+)?$/ ) ) {
|
1011
|
+
// Sub-button index selector
|
1012
|
+
ret.push( {
|
1013
|
+
inst: inst,
|
1014
|
+
idx: selector
|
1015
|
+
} );
|
1016
|
+
}
|
1017
|
+
else if ( selector.indexOf( ':name' ) !== -1 ) {
|
1018
|
+
// Button name selector
|
1019
|
+
var name = selector.replace( ':name', '' );
|
1020
|
+
|
1021
|
+
for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
|
1022
|
+
if ( buttons[i].name === name ) {
|
1023
|
+
ret.push( {
|
1024
|
+
inst: inst,
|
1025
|
+
idx: inst.toIndex( buttons[i].node )
|
1026
|
+
} );
|
1027
|
+
}
|
1028
|
+
}
|
1029
|
+
}
|
1030
|
+
else {
|
1031
|
+
// jQuery selector on the nodes
|
1032
|
+
$( nodes ).filter( selector ).each( function () {
|
1033
|
+
ret.push( {
|
1034
|
+
inst: inst,
|
1035
|
+
idx: inst.toIndex( this )
|
1036
|
+
} );
|
1037
|
+
} );
|
1038
|
+
}
|
1039
|
+
}
|
1040
|
+
else if ( typeof selector === 'object' && selector.nodeName ) {
|
1041
|
+
// Node selector
|
1042
|
+
var idx = $.inArray( selector, nodes );
|
1043
|
+
|
1044
|
+
if ( idx !== -1 ) {
|
1045
|
+
ret.push( {
|
1046
|
+
inst: inst,
|
1047
|
+
idx: inst.toIndex( nodes[ idx ] )
|
1048
|
+
} );
|
1049
|
+
}
|
1050
|
+
}
|
1051
|
+
};
|
1052
|
+
|
1053
|
+
|
1054
|
+
for ( var i=0, ien=insts.length ; i<ien ; i++ ) {
|
1055
|
+
var inst = insts[i];
|
1056
|
+
|
1057
|
+
run( selector, inst );
|
1058
|
+
}
|
1059
|
+
|
1060
|
+
return ret;
|
1061
|
+
};
|
1062
|
+
|
1063
|
+
|
1064
|
+
/**
|
1065
|
+
* Buttons defaults. For full documentation, please refer to the docs/option
|
1066
|
+
* directory or the DataTables site.
|
1067
|
+
* @type {Object}
|
1068
|
+
* @static
|
1069
|
+
*/
|
1070
|
+
Buttons.defaults = {
|
1071
|
+
buttons: [ 'copy', 'excel', 'csv', 'pdf', 'print' ],
|
1072
|
+
name: 'main',
|
1073
|
+
tabIndex: 0,
|
1074
|
+
dom: {
|
1075
|
+
container: {
|
1076
|
+
tag: 'div',
|
1077
|
+
className: 'dt-buttons'
|
1078
|
+
},
|
1079
|
+
collection: {
|
1080
|
+
tag: 'div',
|
1081
|
+
className: 'dt-button-collection'
|
1082
|
+
},
|
1083
|
+
button: {
|
1084
|
+
tag: 'a',
|
1085
|
+
className: 'dt-button',
|
1086
|
+
active: 'active',
|
1087
|
+
disabled: 'disabled'
|
1088
|
+
},
|
1089
|
+
buttonLiner: {
|
1090
|
+
tag: 'span',
|
1091
|
+
className: ''
|
1092
|
+
}
|
1093
|
+
}
|
1094
|
+
};
|
1095
|
+
|
1096
|
+
/**
|
1097
|
+
* Version information
|
1098
|
+
* @type {string}
|
1099
|
+
* @static
|
1100
|
+
*/
|
1101
|
+
Buttons.version = '1.1.0';
|
1102
|
+
|
1103
|
+
|
1104
|
+
$.extend( _dtButtons, {
|
1105
|
+
collection: {
|
1106
|
+
text: function ( dt, button, config ) {
|
1107
|
+
return dt.i18n( 'buttons.collection', 'Collection' );
|
1108
|
+
},
|
1109
|
+
className: 'buttons-collection',
|
1110
|
+
action: function ( e, dt, button, config ) {
|
1111
|
+
var background;
|
1112
|
+
var host = button;
|
1113
|
+
var hostOffset = host.offset();
|
1114
|
+
var tableContainer = $( dt.table().container() );
|
1115
|
+
var multiLevel = false;
|
1116
|
+
|
1117
|
+
// Remove any old collection
|
1118
|
+
if ( $('div.dt-button-background').length ) {
|
1119
|
+
multiLevel = $('div.dt-button-collection').offset();
|
1120
|
+
$(document).trigger( 'click.dtb-collection' );
|
1121
|
+
}
|
1122
|
+
|
1123
|
+
config._collection
|
1124
|
+
.addClass( config.collectionLayout )
|
1125
|
+
.css( 'display', 'none' )
|
1126
|
+
.appendTo( 'body' )
|
1127
|
+
.fadeIn( config.fade );
|
1128
|
+
|
1129
|
+
var position = config._collection.css( 'position' );
|
1130
|
+
|
1131
|
+
if ( multiLevel && position === 'absolute' ) {
|
1132
|
+
config._collection.css( {
|
1133
|
+
top: multiLevel.top + 5, // magic numbers for a little offset
|
1134
|
+
left: multiLevel.left + 5
|
1135
|
+
} );
|
1136
|
+
}
|
1137
|
+
else if ( position === 'absolute' ) {
|
1138
|
+
config._collection.css( {
|
1139
|
+
top: hostOffset.top + host.outerHeight(),
|
1140
|
+
left: hostOffset.left
|
1141
|
+
} );
|
1142
|
+
|
1143
|
+
var listRight = hostOffset.left + config._collection.outerWidth();
|
1144
|
+
var tableRight = tableContainer.offset().left + tableContainer.width();
|
1145
|
+
if ( listRight > tableRight ) {
|
1146
|
+
config._collection.css( 'left', hostOffset.left - ( listRight - tableRight ) );
|
1147
|
+
}
|
1148
|
+
}
|
1149
|
+
else {
|
1150
|
+
// Fix position - centre on screen
|
1151
|
+
var top = config._collection.height() / 2;
|
1152
|
+
if ( top > $(window).height() / 2 ) {
|
1153
|
+
top = $(window).height() / 2;
|
1154
|
+
}
|
1155
|
+
|
1156
|
+
config._collection.css( 'marginTop', top*-1 );
|
1157
|
+
}
|
1158
|
+
|
1159
|
+
if ( config.background ) {
|
1160
|
+
Buttons.background( true, config.backgroundClassName, config.fade );
|
1161
|
+
}
|
1162
|
+
|
1163
|
+
// Need to break the 'thread' for the collection button being
|
1164
|
+
// activated by a click - it would also trigger this event
|
1165
|
+
setTimeout( function () {
|
1166
|
+
// This is bonkers, but if we don't have a click listener on the
|
1167
|
+
// background element, iOS Safari will ignore the body click
|
1168
|
+
// listener below. An empty function here is all that is
|
1169
|
+
// required to make it work...
|
1170
|
+
$('div.dt-button-background').on( 'click.dtb-collection', function () {} );
|
1171
|
+
|
1172
|
+
$('body').on( 'click.dtb-collection', function (e) {
|
1173
|
+
if ( ! $(e.target).parents().andSelf().filter( config._collection ).length ) {
|
1174
|
+
config._collection
|
1175
|
+
.fadeOut( config.fade, function () {
|
1176
|
+
config._collection.detach();
|
1177
|
+
} );
|
1178
|
+
|
1179
|
+
$('div.dt-button-background').off( 'click.dtb-collection' );
|
1180
|
+
Buttons.background( false, config.backgroundClassName, config.fade );
|
1181
|
+
|
1182
|
+
$('body').off( 'click.dtb-collection' );
|
1183
|
+
}
|
1184
|
+
} );
|
1185
|
+
}, 10 );
|
1186
|
+
},
|
1187
|
+
background: true,
|
1188
|
+
collectionLayout: '',
|
1189
|
+
backgroundClassName: 'dt-button-background',
|
1190
|
+
fade: 400
|
1191
|
+
},
|
1192
|
+
copy: function ( dt, conf ) {
|
1193
|
+
if ( _dtButtons.copyHtml5 ) {
|
1194
|
+
return 'copyHtml5';
|
1195
|
+
}
|
1196
|
+
if ( _dtButtons.copyFlash && _dtButtons.copyFlash.available( dt, conf ) ) {
|
1197
|
+
return 'copyFlash';
|
1198
|
+
}
|
1199
|
+
},
|
1200
|
+
csv: function ( dt, conf ) {
|
1201
|
+
// Common option that will use the HTML5 or Flash export buttons
|
1202
|
+
if ( _dtButtons.csvHtml5 && _dtButtons.csvHtml5.available( dt, conf ) ) {
|
1203
|
+
return 'csvHtml5';
|
1204
|
+
}
|
1205
|
+
if ( _dtButtons.csvFlash && _dtButtons.csvFlash.available( dt, conf ) ) {
|
1206
|
+
return 'csvFlash';
|
1207
|
+
}
|
1208
|
+
},
|
1209
|
+
excel: function ( dt, conf ) {
|
1210
|
+
// Common option that will use the HTML5 or Flash export buttons
|
1211
|
+
if ( _dtButtons.excelHtml5 && _dtButtons.excelHtml5.available( dt, conf ) ) {
|
1212
|
+
return 'excelHtml5';
|
1213
|
+
}
|
1214
|
+
if ( _dtButtons.excelFlash && _dtButtons.excelFlash.available( dt, conf ) ) {
|
1215
|
+
return 'excelFlash';
|
1216
|
+
}
|
1217
|
+
},
|
1218
|
+
pdf: function ( dt, conf ) {
|
1219
|
+
// Common option that will use the HTML5 or Flash export buttons
|
1220
|
+
if ( _dtButtons.pdfHtml5 && _dtButtons.pdfHtml5.available( dt, conf ) ) {
|
1221
|
+
return 'pdfHtml5';
|
1222
|
+
}
|
1223
|
+
if ( _dtButtons.pdfFlash && _dtButtons.pdfFlash.available( dt, conf ) ) {
|
1224
|
+
return 'pdfFlash';
|
1225
|
+
}
|
1226
|
+
},
|
1227
|
+
pageLength: function ( dt, conf ) {
|
1228
|
+
var lengthMenu = dt.settings()[0].aLengthMenu;
|
1229
|
+
var vals = $.isArray( lengthMenu[0] ) ? lengthMenu[0] : lengthMenu;
|
1230
|
+
var lang = $.isArray( lengthMenu[0] ) ? lengthMenu[1] : lengthMenu;
|
1231
|
+
var text = function ( dt ) {
|
1232
|
+
return dt.i18n( 'buttons.pageLength', {
|
1233
|
+
"-1": 'Show all rows',
|
1234
|
+
_: 'Show %d rows'
|
1235
|
+
}, dt.page.len() );
|
1236
|
+
};
|
1237
|
+
|
1238
|
+
return {
|
1239
|
+
extend: 'collection',
|
1240
|
+
text: text,
|
1241
|
+
className: 'buttons-page-length',
|
1242
|
+
buttons: $.map( vals, function ( val, i ) {
|
1243
|
+
return {
|
1244
|
+
text: lang[i],
|
1245
|
+
action: function ( e, dt, button, conf ) {
|
1246
|
+
dt.page.len( val ).draw();
|
1247
|
+
},
|
1248
|
+
init: function ( dt, node, conf ) {
|
1249
|
+
var that = this;
|
1250
|
+
var fn = function () {
|
1251
|
+
that.active( dt.page.len() === val );
|
1252
|
+
};
|
1253
|
+
|
1254
|
+
dt.on( 'length.dt'+conf.namespace, fn );
|
1255
|
+
fn();
|
1256
|
+
},
|
1257
|
+
destroy: function ( dt, node, conf ) {
|
1258
|
+
dt.off( 'length.dt'+conf.namespace );
|
1259
|
+
}
|
1260
|
+
};
|
1261
|
+
} ),
|
1262
|
+
init: function ( dt, node, conf ) {
|
1263
|
+
var that = this;
|
1264
|
+
dt.on( 'length.dt'+conf.namespace, function () {
|
1265
|
+
that.text( text( dt ) );
|
1266
|
+
} );
|
1267
|
+
},
|
1268
|
+
destroy: function ( dt, node, conf ) {
|
1269
|
+
dt.off( 'length.dt'+conf.namespace );
|
1270
|
+
}
|
1271
|
+
};
|
1272
|
+
}
|
1273
|
+
} );
|
1274
|
+
|
1275
|
+
|
1276
|
+
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
1277
|
+
* DataTables API
|
1278
|
+
*
|
1279
|
+
* For complete documentation, please refer to the docs/api directory or the
|
1280
|
+
* DataTables site
|
1281
|
+
*/
|
1282
|
+
|
1283
|
+
// Buttons group and individual button selector
|
1284
|
+
DataTable.Api.register( 'buttons()', function ( group, selector ) {
|
1285
|
+
// Argument shifting
|
1286
|
+
if ( selector === undefined ) {
|
1287
|
+
selector = group;
|
1288
|
+
group = undefined;
|
1289
|
+
}
|
1290
|
+
|
1291
|
+
return this.iterator( true, 'table', function ( ctx ) {
|
1292
|
+
if ( ctx._buttons ) {
|
1293
|
+
return Buttons.buttonSelector(
|
1294
|
+
Buttons.instanceSelector( group, ctx._buttons ),
|
1295
|
+
selector
|
1296
|
+
);
|
1297
|
+
}
|
1298
|
+
}, true );
|
1299
|
+
} );
|
1300
|
+
|
1301
|
+
// Individual button selector
|
1302
|
+
DataTable.Api.register( 'button()', function ( group, selector ) {
|
1303
|
+
// just run buttons() and truncate
|
1304
|
+
var buttons = this.buttons( group, selector );
|
1305
|
+
|
1306
|
+
if ( buttons.length > 1 ) {
|
1307
|
+
buttons.splice( 1, buttons.length );
|
1308
|
+
}
|
1309
|
+
|
1310
|
+
return buttons;
|
1311
|
+
} );
|
1312
|
+
|
1313
|
+
// Active buttons
|
1314
|
+
DataTable.Api.register( ['buttons().active()', 'button().active()'], function ( flag ) {
|
1315
|
+
return this.each( function ( set ) {
|
1316
|
+
set.inst.active( set.idx, flag );
|
1317
|
+
} );
|
1318
|
+
} );
|
1319
|
+
|
1320
|
+
// Get / set button action
|
1321
|
+
DataTable.Api.registerPlural( 'buttons().action()', 'button().action()', function ( action ) {
|
1322
|
+
if ( action === undefined ) {
|
1323
|
+
return this.map( function ( set ) {
|
1324
|
+
return set.inst.action( set.idx );
|
1325
|
+
} );
|
1326
|
+
}
|
1327
|
+
|
1328
|
+
return this.each( function ( set ) {
|
1329
|
+
set.inst.action( set.idx, action );
|
1330
|
+
} );
|
1331
|
+
} );
|
1332
|
+
|
1333
|
+
// Enable / disable buttons
|
1334
|
+
DataTable.Api.register( ['buttons().enable()', 'button().enable()'], function ( flag ) {
|
1335
|
+
return this.each( function ( set ) {
|
1336
|
+
set.inst.enable( set.idx, flag );
|
1337
|
+
} );
|
1338
|
+
} );
|
1339
|
+
|
1340
|
+
// Disable buttons
|
1341
|
+
DataTable.Api.register( ['buttons().disable()', 'button().disable()'], function () {
|
1342
|
+
return this.each( function ( set ) {
|
1343
|
+
set.inst.disable( set.idx );
|
1344
|
+
} );
|
1345
|
+
} );
|
1346
|
+
|
1347
|
+
// Get button nodes
|
1348
|
+
DataTable.Api.registerPlural( 'buttons().nodes()', 'button().node()', function () {
|
1349
|
+
var jq = $();
|
1350
|
+
|
1351
|
+
// jQuery will automatically reduce duplicates to a single entry
|
1352
|
+
$( this.each( function ( set ) {
|
1353
|
+
jq = jq.add( set.inst.node( set.idx ) );
|
1354
|
+
} ) );
|
1355
|
+
|
1356
|
+
return jq;
|
1357
|
+
} );
|
1358
|
+
|
1359
|
+
// Get / set button text (i.e. the button labels)
|
1360
|
+
DataTable.Api.registerPlural( 'buttons().text()', 'button().text()', function ( label ) {
|
1361
|
+
if ( label === undefined ) {
|
1362
|
+
return this.map( function ( set ) {
|
1363
|
+
return set.inst.text( set.idx );
|
1364
|
+
} );
|
1365
|
+
}
|
1366
|
+
|
1367
|
+
return this.each( function ( set ) {
|
1368
|
+
set.inst.text( set.idx, label );
|
1369
|
+
} );
|
1370
|
+
} );
|
1371
|
+
|
1372
|
+
// Trigger a button's action
|
1373
|
+
DataTable.Api.registerPlural( 'buttons().trigger()', 'button().trigger()', function () {
|
1374
|
+
return this.each( function ( set ) {
|
1375
|
+
set.inst.node( set.idx ).trigger( 'click' );
|
1376
|
+
} );
|
1377
|
+
} );
|
1378
|
+
|
1379
|
+
// Get the container elements for the button sets selected
|
1380
|
+
DataTable.Api.registerPlural( 'buttons().containers()', 'buttons().container()', function () {
|
1381
|
+
var jq = $();
|
1382
|
+
|
1383
|
+
// jQuery will automatically reduce duplicates to a single entry
|
1384
|
+
$( this.each( function ( set ) {
|
1385
|
+
jq = jq.add( set.inst.container() );
|
1386
|
+
} ) );
|
1387
|
+
|
1388
|
+
return jq;
|
1389
|
+
} );
|
1390
|
+
|
1391
|
+
// Add a new button
|
1392
|
+
DataTable.Api.register( 'button().add()', function ( idx, conf ) {
|
1393
|
+
if ( this.length === 1 ) {
|
1394
|
+
this[0].inst.add( idx, conf );
|
1395
|
+
}
|
1396
|
+
|
1397
|
+
return this.button( idx );
|
1398
|
+
} );
|
1399
|
+
|
1400
|
+
// Destroy the button sets selected
|
1401
|
+
DataTable.Api.register( 'buttons().destroy()', function ( idx ) {
|
1402
|
+
this.pluck( 'inst' ).unique().each( function ( inst ) {
|
1403
|
+
inst.destroy();
|
1404
|
+
} );
|
1405
|
+
|
1406
|
+
return this;
|
1407
|
+
} );
|
1408
|
+
|
1409
|
+
// Remove a button
|
1410
|
+
DataTable.Api.registerPlural( 'buttons().remove()', 'buttons().remove()', function () {
|
1411
|
+
// Need to split into prep and commit so the indexes remain constant during the remove
|
1412
|
+
this.each( function ( set ) {
|
1413
|
+
set.inst.removePrep( set.idx );
|
1414
|
+
} );
|
1415
|
+
|
1416
|
+
this.pluck( 'inst' ).unique().each( function ( inst ) {
|
1417
|
+
inst.removeCommit();
|
1418
|
+
} );
|
1419
|
+
|
1420
|
+
return this;
|
1421
|
+
} );
|
1422
|
+
|
1423
|
+
// Information box that can be used by buttons
|
1424
|
+
var _infoTimer;
|
1425
|
+
DataTable.Api.register( 'buttons.info()', function ( title, message, time ) {
|
1426
|
+
var that = this;
|
1427
|
+
|
1428
|
+
if ( title === false ) {
|
1429
|
+
$('#datatables_buttons_info').fadeOut( function () {
|
1430
|
+
$(this).remove();
|
1431
|
+
} );
|
1432
|
+
clearTimeout( _infoTimer );
|
1433
|
+
_infoTimer = null;
|
1434
|
+
|
1435
|
+
return this;
|
1436
|
+
}
|
1437
|
+
|
1438
|
+
if ( _infoTimer ) {
|
1439
|
+
clearTimeout( _infoTimer );
|
1440
|
+
}
|
1441
|
+
|
1442
|
+
if ( $('#datatables_buttons_info').length ) {
|
1443
|
+
$('#datatables_buttons_info').remove();
|
1444
|
+
}
|
1445
|
+
|
1446
|
+
title = title ? '<h2>'+title+'</h2>' : '';
|
1447
|
+
|
1448
|
+
$('<div id="datatables_buttons_info" class="dt-button-info"/>')
|
1449
|
+
.html( title )
|
1450
|
+
.append( $('<div/>')[ typeof message === 'string' ? 'html' : 'append' ]( message ) )
|
1451
|
+
.css( 'display', 'none' )
|
1452
|
+
.appendTo( 'body' )
|
1453
|
+
.fadeIn();
|
1454
|
+
|
1455
|
+
if ( time !== undefined && time !== 0 ) {
|
1456
|
+
_infoTimer = setTimeout( function () {
|
1457
|
+
that.buttons.info( false );
|
1458
|
+
}, time );
|
1459
|
+
}
|
1460
|
+
|
1461
|
+
return this;
|
1462
|
+
} );
|
1463
|
+
|
1464
|
+
// Get data from the table for export - this is common to a number of plug-in
|
1465
|
+
// buttons so it is included in the Buttons core library
|
1466
|
+
DataTable.Api.register( 'buttons.exportData()', function ( options ) {
|
1467
|
+
if ( this.context.length ) {
|
1468
|
+
return _exportData( new DataTable.Api( this.context[0] ), options );
|
1469
|
+
}
|
1470
|
+
} );
|
1471
|
+
|
1472
|
+
|
1473
|
+
var _exportTextarea = $('<textarea/>')[0];
|
1474
|
+
var _exportData = function ( dt, inOpts )
|
1475
|
+
{
|
1476
|
+
var config = $.extend( true, {}, {
|
1477
|
+
rows: null,
|
1478
|
+
columns: '',
|
1479
|
+
modifier: {
|
1480
|
+
search: 'applied',
|
1481
|
+
order: 'applied'
|
1482
|
+
},
|
1483
|
+
orthogonal: 'display',
|
1484
|
+
stripHtml: true,
|
1485
|
+
stripNewlines: true,
|
1486
|
+
decodeEntities: true,
|
1487
|
+
trim: true,
|
1488
|
+
format: {
|
1489
|
+
header: function ( d ) {
|
1490
|
+
return strip( d );
|
1491
|
+
},
|
1492
|
+
footer: function ( d ) {
|
1493
|
+
return strip( d );
|
1494
|
+
},
|
1495
|
+
body: function ( d ) {
|
1496
|
+
return strip( d );
|
1497
|
+
}
|
1498
|
+
}
|
1499
|
+
}, inOpts );
|
1500
|
+
|
1501
|
+
var strip = function ( str ) {
|
1502
|
+
if ( typeof str !== 'string' ) {
|
1503
|
+
return str;
|
1504
|
+
}
|
1505
|
+
|
1506
|
+
if ( config.stripHtml ) {
|
1507
|
+
str = str.replace( /<.*?>/g, '' );
|
1508
|
+
}
|
1509
|
+
|
1510
|
+
if ( config.trim ) {
|
1511
|
+
str = str.replace( /^\s+|\s+$/g, '' );
|
1512
|
+
}
|
1513
|
+
|
1514
|
+
if ( config.stripNewlines ) {
|
1515
|
+
str = str.replace( /\n/g, ' ' );
|
1516
|
+
}
|
1517
|
+
|
1518
|
+
if ( config.decodeEntities ) {
|
1519
|
+
_exportTextarea.innerHTML = str;
|
1520
|
+
str = _exportTextarea.value;
|
1521
|
+
}
|
1522
|
+
|
1523
|
+
return str;
|
1524
|
+
};
|
1525
|
+
|
1526
|
+
|
1527
|
+
var header = dt.columns( config.columns ).indexes().map( function (idx, i) {
|
1528
|
+
return config.format.header( dt.column( idx ).header().innerHTML, idx );
|
1529
|
+
} ).toArray();
|
1530
|
+
|
1531
|
+
var footer = dt.table().footer() ?
|
1532
|
+
dt.columns( config.columns ).indexes().map( function (idx, i) {
|
1533
|
+
var el = dt.column( idx ).footer();
|
1534
|
+
return config.format.footer( el ? el.innerHTML : '', idx );
|
1535
|
+
} ).toArray() :
|
1536
|
+
null;
|
1537
|
+
|
1538
|
+
var rowIndexes = dt.rows( config.rows, config.modifier ).indexes().toArray();
|
1539
|
+
var cells = dt
|
1540
|
+
.cells( rowIndexes, config.columns )
|
1541
|
+
.render( config.orthogonal )
|
1542
|
+
.toArray();
|
1543
|
+
var columns = header.length;
|
1544
|
+
var rows = columns > 0 ? cells.length / columns : 0;
|
1545
|
+
var body = new Array( rows );
|
1546
|
+
var cellCounter = 0;
|
1547
|
+
|
1548
|
+
for ( var i=0, ien=rows ; i<ien ; i++ ) {
|
1549
|
+
var row = new Array( columns );
|
1550
|
+
|
1551
|
+
for ( var j=0 ; j<columns ; j++ ) {
|
1552
|
+
row[j] = config.format.body( cells[ cellCounter ], j, i );
|
1553
|
+
cellCounter++;
|
1554
|
+
}
|
1555
|
+
|
1556
|
+
body[i] = row;
|
1557
|
+
}
|
1558
|
+
|
1559
|
+
return {
|
1560
|
+
header: header,
|
1561
|
+
footer: footer,
|
1562
|
+
body: body
|
1563
|
+
};
|
1564
|
+
};
|
1565
|
+
|
1566
|
+
|
1567
|
+
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
1568
|
+
* DataTables interface
|
1569
|
+
*/
|
1570
|
+
|
1571
|
+
// Attach to DataTables objects for global access
|
1572
|
+
$.fn.dataTable.Buttons = Buttons;
|
1573
|
+
$.fn.DataTable.Buttons = Buttons;
|
1574
|
+
|
1575
|
+
|
1576
|
+
|
1577
|
+
// DataTables creation - check if the buttons have been defined for this table,
|
1578
|
+
// they will have been if the `B` option was used in `dom`, otherwise we should
|
1579
|
+
// create the buttons instance here so they can be inserted into the document
|
1580
|
+
// using the API. Listen for `init` for compatibility with pre 1.10.10, but to
|
1581
|
+
// be removed in future.
|
1582
|
+
$(document).on( 'init.dt plugin-init.dt', function (e, settings, json) {
|
1583
|
+
if ( e.namespace !== 'dt' ) {
|
1584
|
+
return;
|
1585
|
+
}
|
1586
|
+
|
1587
|
+
var opts = settings.oInit.buttons || DataTable.defaults.buttons;
|
1588
|
+
|
1589
|
+
if ( opts && ! settings._buttons ) {
|
1590
|
+
new Buttons( settings, opts ).container();
|
1591
|
+
}
|
1592
|
+
} );
|
1593
|
+
|
1594
|
+
// DataTables `dom` feature option
|
1595
|
+
DataTable.ext.feature.push( {
|
1596
|
+
fnInit: function( settings ) {
|
1597
|
+
var api = new DataTable.Api( settings );
|
1598
|
+
var opts = api.init().buttons || DataTable.defaults.buttons;
|
1599
|
+
|
1600
|
+
return new Buttons( api, opts ).container();
|
1601
|
+
},
|
1602
|
+
cFeature: "B"
|
1603
|
+
} );
|
1604
|
+
|
1605
|
+
|
1606
|
+
return Buttons;
|
1607
|
+
}));
|