jquery-datatables-rails 2.2.2 → 2.2.3
Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 809f7c045592c04bbd407dc7d2f7296807fd3f78
|
4
|
+
data.tar.gz: 67c2a1f408d9d8cddce1c6334af9849d4cdb5ac8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 518fbe26ee4fa7e56c165f28e0e24788fd1af7a76c9f00cb1b0ca0c2292349a158a25fdf48094a28a4106f118fdce3c8200406bf1efd3021dd6358b796d2b65f
|
7
|
+
data.tar.gz: b5240c8f4ac85ac8a560f3455dde501ab9c3e19fce8fca500935d2afe7d10ef9e89c2b0e3df42b238781d4e5dc176c9d8b39a156f604105925dc0883c5e13119
|
@@ -1,751 +1,650 @@
|
|
1
|
-
/*! Responsive 1.0.1
|
2
|
-
* 2014 SpryMedia Ltd - datatables.net/license
|
3
|
-
*/
|
4
|
-
|
5
1
|
/**
|
6
|
-
*
|
7
|
-
*
|
8
|
-
*
|
9
|
-
*
|
10
|
-
* @author SpryMedia Ltd (www.sprymedia.co.uk)
|
11
|
-
* @contact www.sprymedia.co.uk/contact
|
12
|
-
* @copyright Copyright 2014 SpryMedia Ltd.
|
2
|
+
* File: datatables.responsive.js
|
3
|
+
* Version: 0.2.0
|
4
|
+
* Author: Seen Sai Yang
|
5
|
+
* Info: https://github.com/Comanche/datatables-responsive
|
13
6
|
*
|
14
|
-
*
|
15
|
-
*
|
7
|
+
* Copyright 2013 Seen Sai Yang, all rights reserved.
|
8
|
+
*
|
9
|
+
* This source file is free software, under either the GPL v2 license or a
|
10
|
+
* BSD style license.
|
16
11
|
*
|
17
12
|
* This source file is distributed in the hope that it will be useful, but
|
18
13
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
19
14
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
|
20
15
|
*
|
21
|
-
*
|
16
|
+
* You should have received a copy of the GNU General Public License and the
|
17
|
+
* BSD license along with this program. These licenses are also available at:
|
18
|
+
* https://raw.github.com/Comanche/datatables-responsive/master/license-gpl2.txt
|
19
|
+
* https://raw.github.com/Comanche/datatables-responsive/master/license-bsd.txt
|
22
20
|
*/
|
23
21
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
var factory = function( $, DataTable ) {
|
28
|
-
"use strict";
|
22
|
+
'use strict';
|
29
23
|
|
30
24
|
/**
|
31
|
-
*
|
32
|
-
* DataTables' ability to change the visibility of columns, changing the
|
33
|
-
* visibility of columns so the displayed columns fit into the table container.
|
34
|
-
* The end result is that complex tables will be dynamically adjusted to fit
|
35
|
-
* into the viewport, be it on a desktop, tablet or mobile browser.
|
25
|
+
* Constructor for responsive datables helper.
|
36
26
|
*
|
37
|
-
*
|
38
|
-
* individually or combined:
|
27
|
+
* This helper class makes datatables responsive to the window size.
|
39
28
|
*
|
40
|
-
*
|
41
|
-
*
|
42
|
-
* * Automatic control - columns are automatically hidden when there is no
|
43
|
-
* room left to display them. Columns removed from the right.
|
29
|
+
* The parameter, breakpoints, is an object for each breakpoint key/value pair
|
30
|
+
* with the following format: { breakpoint_name: pixel_width_at_breakpoint }.
|
44
31
|
*
|
45
|
-
*
|
46
|
-
* options to use DataTables' child row display to show / hide the information
|
47
|
-
* from the table that has been hidden. There are also two modes of operation
|
48
|
-
* for this child row display:
|
32
|
+
* An example is as follows:
|
49
33
|
*
|
50
|
-
*
|
51
|
-
*
|
52
|
-
*
|
34
|
+
* {
|
35
|
+
* tablet: 1024,
|
36
|
+
* phone: 480
|
37
|
+
* }
|
53
38
|
*
|
54
|
-
*
|
39
|
+
* These breakpoint name may be used as possible values for the data-hide
|
40
|
+
* attribute. The data-hide attribute is optional and may be defined for each
|
41
|
+
* th element in the table header.
|
55
42
|
*
|
56
|
-
*
|
57
|
-
*
|
58
|
-
* options when the DataTable is created.
|
59
|
-
* * Using the `responsive` option in the DataTables configuration options. This
|
60
|
-
* can also be used to specify the configuration options, or simply set to
|
61
|
-
* `true` to use the defaults.
|
43
|
+
* The parameter, options, is an object of options supported by the responsive
|
44
|
+
* helper. The following options are supported:
|
62
45
|
*
|
63
|
-
*
|
64
|
-
*
|
65
|
-
*
|
66
|
-
*
|
67
|
-
*
|
46
|
+
* {
|
47
|
+
* hideEmptyColumnsInRowDetail - Boolean, default: false.
|
48
|
+
* clickOn - icon|cell|row, default: icon
|
49
|
+
* showDetail - function called when detail row shown
|
50
|
+
* hideDetail - function called when detail row hidden
|
51
|
+
* }
|
68
52
|
*
|
69
|
-
*
|
70
|
-
*
|
71
|
-
*
|
72
|
-
*
|
73
|
-
*
|
53
|
+
* @param {Object|string} tableSelector jQuery wrapped set or selector for
|
54
|
+
* datatables container element.
|
55
|
+
* @param {Object} breakpoints Object defining the responsive
|
56
|
+
* breakpoint for datatables.
|
57
|
+
* @param {Object} options Object of options.
|
74
58
|
*/
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
59
|
+
function ResponsiveDatatablesHelper(tableSelector, breakpoints, options) {
|
60
|
+
if (typeof tableSelector === 'string') {
|
61
|
+
this.tableElement = $(tableSelector);
|
62
|
+
} else {
|
63
|
+
this.tableElement = tableSelector;
|
64
|
+
}
|
65
|
+
|
66
|
+
// Get data table API.
|
67
|
+
this.api = this.tableElement.dataTable().api();
|
68
|
+
|
69
|
+
// State of column indexes and which are shown or hidden.
|
70
|
+
this.columnIndexes = [];
|
71
|
+
this.columnsShownIndexes = [];
|
72
|
+
this.columnsHiddenIndexes = [];
|
73
|
+
this.currentBreakpoint = '';
|
74
|
+
this.lastBreakpoint = '';
|
75
|
+
this.lastColumnsHiddenIndexes = [];
|
76
|
+
|
77
|
+
// Save state
|
78
|
+
var fileName = window.location.pathname.split("/").pop();
|
79
|
+
var context = this.api.settings().context[0];
|
80
|
+
|
81
|
+
this.tableId = context.sTableId;
|
82
|
+
this.saveState = context.oInit.bStateSave;
|
83
|
+
this.cookieName = 'DataTablesResponsiveHelper_' + this.tableId + (fileName ? '_' + fileName : '');
|
84
|
+
this.lastStateExists = false;
|
85
|
+
|
86
|
+
// Index of the th in the header tr that stores where the attribute
|
87
|
+
// data-class="expand"
|
88
|
+
// is defined.
|
89
|
+
this.expandColumn = undefined;
|
90
|
+
// Stores original breakpoint defitions
|
91
|
+
this.origBreakpointsDefs = undefined;
|
92
|
+
// Stores the break points defined in the table header.
|
93
|
+
// Each th in the header tr may contain an optional attribute like
|
94
|
+
// data-hide="phone,tablet"
|
95
|
+
// These attributes and the breakpoints object will be used to create this
|
96
|
+
// object.
|
97
|
+
this.breakpoints = {
|
98
|
+
/**
|
99
|
+
* We will be generating data in the following format:
|
100
|
+
* phone : {
|
101
|
+
* lowerLimit : undefined,
|
102
|
+
* upperLimit : 320,
|
103
|
+
* columnsToHide: []
|
104
|
+
* },
|
105
|
+
* tablet: {
|
106
|
+
* lowerLimit : 320,
|
107
|
+
* upperLimit : 724,
|
108
|
+
* columnsToHide: []
|
109
|
+
* }
|
110
|
+
*/
|
111
|
+
};
|
112
|
+
|
113
|
+
// Store default options
|
114
|
+
this.options = {
|
115
|
+
hideEmptyColumnsInRowDetail: false,
|
116
|
+
clickOn: 'icon',
|
117
|
+
showDetail: null,
|
118
|
+
hideDetail: null
|
119
|
+
};
|
120
|
+
|
121
|
+
// Expand icon template
|
122
|
+
this.expandIconTemplate = '<span class="responsiveExpander"></span>';
|
123
|
+
|
124
|
+
// Row template
|
125
|
+
this.rowTemplate = '<tr class="row-detail"><td><ul><!--column item--></ul></td></tr>';
|
126
|
+
this.rowLiTemplate = '<li><span class="columnTitle"><!--column title--></span>: <span class="columnValue"><!--column value--></span></li>';
|
127
|
+
|
128
|
+
// Responsive behavior on/off flag
|
129
|
+
this.disabled = true;
|
130
|
+
|
131
|
+
// Skip next windows width change flag
|
132
|
+
this.skipNextWindowsWidthChange = false;
|
133
|
+
|
134
|
+
// Initialize settings
|
135
|
+
this.init(breakpoints, options);
|
136
|
+
}
|
98
137
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
that._resize();
|
119
|
-
} ) );
|
120
|
-
|
121
|
-
// Destroy event handler
|
122
|
-
dt.on( 'destroy.dtr', function () {
|
123
|
-
$(window).off( 'resize.dtr orientationchange.dtr' );
|
124
|
-
} );
|
125
|
-
|
126
|
-
// Reorder the breakpoints array here in case they have been added out
|
127
|
-
// of order
|
128
|
-
this.c.breakpoints.sort( function (a, b) {
|
129
|
-
return a.width < b.width ? 1 :
|
130
|
-
a.width > b.width ? -1 : 0;
|
131
|
-
} );
|
132
|
-
|
133
|
-
this._classLogic();
|
134
|
-
this._resizeAuto();
|
135
|
-
|
136
|
-
// First pass - draw the table for the current viewport size
|
137
|
-
this._resize();
|
138
|
-
|
139
|
-
// Details handler
|
140
|
-
var details = this.c.details;
|
141
|
-
if ( details.type ) {
|
142
|
-
that._detailsInit();
|
143
|
-
this._detailsVis();
|
144
|
-
|
145
|
-
dt.on( 'column-visibility.dtr', function () {
|
146
|
-
that._detailsVis();
|
147
|
-
} );
|
148
|
-
|
149
|
-
$(dt.table().node()).addClass( 'dtr-'+details.type );
|
150
|
-
}
|
151
|
-
},
|
152
|
-
|
153
|
-
|
154
|
-
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
155
|
-
* Private methods
|
156
|
-
*/
|
157
|
-
|
158
|
-
/**
|
159
|
-
* Calculate the visibility for the columns in a table for a given
|
160
|
-
* breakpoint. The result is pre-determined based on the class logic if
|
161
|
-
* class names are used to control all columns, but the width of the table
|
162
|
-
* is also used if there are columns which are to be automatically shown
|
163
|
-
* and hidden.
|
164
|
-
*
|
165
|
-
* @param {string} breakpoint Breakpoint name to use for the calculation
|
166
|
-
* @return {array} Array of boolean values initiating the visibility of each
|
167
|
-
* column.
|
168
|
-
* @private
|
169
|
-
*/
|
170
|
-
_columnsVisiblity: function ( breakpoint )
|
171
|
-
{
|
172
|
-
var dt = this.s.dt;
|
173
|
-
var columns = this.s.columns;
|
174
|
-
var i, ien;
|
175
|
-
|
176
|
-
// Class logic - determine which columns are in this breakpoint based
|
177
|
-
// on the classes. If no class control (i.e. `auto`) then `-` is used
|
178
|
-
// to indicate this to the rest of the function
|
179
|
-
var display = $.map( columns, function ( col ) {
|
180
|
-
return col.auto && col.minWidth === null ?
|
181
|
-
false :
|
182
|
-
col.auto === true ?
|
183
|
-
'-' :
|
184
|
-
col.includeIn.indexOf( breakpoint ) !== -1;
|
185
|
-
} );
|
186
|
-
|
187
|
-
// Auto column control - first pass: how much width is taken by the
|
188
|
-
// ones that must be included from the non-auto columns
|
189
|
-
var requiredWidth = 0;
|
190
|
-
for ( i=0, ien=display.length ; i<ien ; i++ ) {
|
191
|
-
if ( display[i] === true ) {
|
192
|
-
requiredWidth += columns[i].minWidth;
|
193
|
-
}
|
194
|
-
}
|
195
|
-
|
196
|
-
// Second pass, use up any remaining width for other columns
|
197
|
-
var widthAvailable = dt.table().container().offsetWidth;
|
198
|
-
var usedWidth = widthAvailable - requiredWidth;
|
199
|
-
|
200
|
-
for ( i=0, ien=display.length ; i<ien ; i++ ) {
|
201
|
-
// Control column needs to always be included. This makes it sub-
|
202
|
-
// optimal in terms of using the available with, but to stop layout
|
203
|
-
// thrashing or overflow
|
204
|
-
if ( columns[i].control ) {
|
205
|
-
usedWidth -= columns[i].minWidth;
|
206
|
-
}
|
207
|
-
else if ( display[i] === '-' ) {
|
208
|
-
// Otherwise, remove the width
|
209
|
-
display[i] = usedWidth - columns[i].minWidth < 0 ?
|
210
|
-
false :
|
211
|
-
true;
|
212
|
-
|
213
|
-
// Continue counting down the width, so a smaller column to the
|
214
|
-
// left won't be shown
|
215
|
-
usedWidth -= columns[i].minWidth;
|
216
|
-
}
|
217
|
-
}
|
218
|
-
|
219
|
-
// Determine if the 'control' column should be shown (if there is one).
|
220
|
-
// This is the case when there is a hidden column (that is not the
|
221
|
-
// control column). The two loops look inefficient here, but they are
|
222
|
-
// trivial and will fly through. We need to know the outcome from the
|
223
|
-
// first , before the action in the second can be taken
|
224
|
-
var showControl = false;
|
225
|
-
|
226
|
-
for ( i=0, ien=columns.length ; i<ien ; i++ ) {
|
227
|
-
if ( ! columns[i].control && ! display[i] ) {
|
228
|
-
showControl = true;
|
229
|
-
break;
|
230
|
-
}
|
231
|
-
}
|
232
|
-
|
233
|
-
for ( i=0, ien=columns.length ; i<ien ; i++ ) {
|
234
|
-
if ( columns[i].control ) {
|
235
|
-
display[i] = showControl;
|
236
|
-
}
|
237
|
-
}
|
238
|
-
|
239
|
-
return display;
|
240
|
-
},
|
241
|
-
|
242
|
-
|
243
|
-
/**
|
244
|
-
* Create the internal `columns` array with information about the columns
|
245
|
-
* for the table. This includes determining which breakpoints the column
|
246
|
-
* will appear in, based upon class names in the column, which makes up the
|
247
|
-
* vast majority of this method.
|
248
|
-
*
|
249
|
-
* @private
|
250
|
-
*/
|
251
|
-
_classLogic: function ()
|
252
|
-
{
|
253
|
-
var that = this;
|
254
|
-
var calc = {};
|
255
|
-
var breakpoints = this.c.breakpoints;
|
256
|
-
var columns = this.s.dt.columns().eq(0).map( function (i) {
|
257
|
-
return {
|
258
|
-
className: this.column(i).header().className,
|
259
|
-
includeIn: [],
|
260
|
-
auto: false,
|
261
|
-
control: false
|
262
|
-
};
|
263
|
-
} );
|
264
|
-
|
265
|
-
// Simply add a breakpoint to `includeIn` array, ensuring that there are
|
266
|
-
// no duplicates
|
267
|
-
var add = function ( colIdx, name ) {
|
268
|
-
var includeIn = columns[ colIdx ].includeIn;
|
269
|
-
|
270
|
-
if ( includeIn.indexOf( name ) === -1 ) {
|
271
|
-
includeIn.push( name );
|
272
|
-
}
|
273
|
-
};
|
274
|
-
|
275
|
-
var column = function ( colIdx, name, operator, matched ) {
|
276
|
-
var size, i, ien;
|
277
|
-
|
278
|
-
if ( ! operator ) {
|
279
|
-
columns[ colIdx ].includeIn.push( name );
|
280
|
-
}
|
281
|
-
else if ( operator === 'max-' ) {
|
282
|
-
// Add this breakpoint and all smaller
|
283
|
-
size = that._find( name ).width;
|
284
|
-
|
285
|
-
for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) {
|
286
|
-
if ( breakpoints[i].width <= size ) {
|
287
|
-
add( colIdx, breakpoints[i].name );
|
288
|
-
}
|
289
|
-
}
|
290
|
-
}
|
291
|
-
else if ( operator === 'min-' ) {
|
292
|
-
// Add this breakpoint and all larger
|
293
|
-
size = that._find( name ).width;
|
294
|
-
|
295
|
-
for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) {
|
296
|
-
if ( breakpoints[i].width >= size ) {
|
297
|
-
add( colIdx, breakpoints[i].name );
|
298
|
-
}
|
299
|
-
}
|
300
|
-
}
|
301
|
-
else if ( operator === 'not-' ) {
|
302
|
-
// Add all but this breakpoint (xxx need extra information)
|
303
|
-
|
304
|
-
for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) {
|
305
|
-
if ( breakpoints[i].name.indexOf( matched ) === -1 ) {
|
306
|
-
add( colIdx, breakpoints[i].name );
|
307
|
-
}
|
308
|
-
}
|
309
|
-
}
|
310
|
-
};
|
311
|
-
|
312
|
-
// Loop over each column and determine if it has a responsive control
|
313
|
-
// class
|
314
|
-
columns.each( function ( col, i ) {
|
315
|
-
var classNames = col.className.split(' ');
|
316
|
-
var hasClass = false;
|
317
|
-
|
318
|
-
// Split the class name up so multiple rules can be applied if needed
|
319
|
-
for ( var k=0, ken=classNames.length ; k<ken ; k++ ) {
|
320
|
-
var className = $.trim( classNames[k] );
|
321
|
-
|
322
|
-
if ( className === 'all' ) {
|
323
|
-
// Include in all
|
324
|
-
hasClass = true;
|
325
|
-
col.includeIn = $.map( breakpoints, function (a) {
|
326
|
-
return a.name;
|
327
|
-
} );
|
328
|
-
return;
|
329
|
-
}
|
330
|
-
else if ( className === 'none' ) {
|
331
|
-
// Include in none (default) and no auto
|
332
|
-
hasClass = true;
|
333
|
-
return;
|
334
|
-
}
|
335
|
-
else if ( className === 'control' ) {
|
336
|
-
// Special column that is only visible, when one of the other
|
337
|
-
// columns is hidden. This is used for the details control
|
338
|
-
hasClass = true;
|
339
|
-
col.control = true;
|
340
|
-
return;
|
341
|
-
}
|
342
|
-
|
343
|
-
$.each( breakpoints, function ( j, breakpoint ) {
|
344
|
-
// Does this column have a class that matches this breakpoint?
|
345
|
-
var brokenPoint = breakpoint.name.split('-');
|
346
|
-
var re = new RegExp( '(min\\-|max\\-|not\\-)?('+brokenPoint[0]+')(\\-[_a-zA-Z0-9])?' );
|
347
|
-
var match = className.match( re );
|
348
|
-
|
349
|
-
if ( match ) {
|
350
|
-
hasClass = true;
|
351
|
-
|
352
|
-
if ( match[2] === brokenPoint[0] && match[3] === '-'+brokenPoint[1] ) {
|
353
|
-
// Class name matches breakpoint name fully
|
354
|
-
column( i, breakpoint.name, match[1], match[2]+match[3] );
|
355
|
-
}
|
356
|
-
else if ( match[2] === brokenPoint[0] && ! match[3] ) {
|
357
|
-
// Class name matched primary breakpoint name with no qualifier
|
358
|
-
column( i, breakpoint.name, match[1], match[2] );
|
359
|
-
}
|
360
|
-
}
|
361
|
-
} );
|
362
|
-
}
|
363
|
-
|
364
|
-
// If there was no control class, then automatic sizing is used
|
365
|
-
if ( ! hasClass ) {
|
366
|
-
col.auto = true;
|
367
|
-
}
|
368
|
-
} );
|
369
|
-
|
370
|
-
this.s.columns = columns;
|
371
|
-
},
|
372
|
-
|
373
|
-
|
374
|
-
/**
|
375
|
-
* Initialisation for the details handler
|
376
|
-
*
|
377
|
-
* @private
|
378
|
-
*/
|
379
|
-
_detailsInit: function ()
|
380
|
-
{
|
381
|
-
var that = this;
|
382
|
-
var dt = this.s.dt;
|
383
|
-
var details = this.c.details;
|
384
|
-
|
385
|
-
// The inline type always uses the first child as the target
|
386
|
-
if ( details.type === 'inline' ) {
|
387
|
-
details.target = 'td:first-child';
|
388
|
-
}
|
389
|
-
|
390
|
-
// type.target can be a string jQuery selector or a column index
|
391
|
-
var target = details.target;
|
392
|
-
var selector = typeof target === 'string' ? target : 'td';
|
393
|
-
|
394
|
-
// Click handler to show / hide the details rows when they are available
|
395
|
-
$( dt.table().body() ).on( 'click', selector, function (e) {
|
396
|
-
// If the table is not collapsed (i.e. there is no hidden columns)
|
397
|
-
// then take no action
|
398
|
-
if ( ! $(dt.table().node()).hasClass('collapsed' ) ) {
|
399
|
-
return;
|
400
|
-
}
|
401
|
-
|
402
|
-
// For column index, we determine if we should act or not in the
|
403
|
-
// handler - otherwise it is already okay
|
404
|
-
if ( typeof target === 'number' ) {
|
405
|
-
var targetIdx = target < 0 ?
|
406
|
-
dt.columns().eq(0).length + target :
|
407
|
-
target;
|
408
|
-
|
409
|
-
if ( dt.cell( this ).index().column !== targetIdx ) {
|
410
|
-
return;
|
411
|
-
}
|
412
|
-
}
|
413
|
-
|
414
|
-
// $().closest() includes itself in its check
|
415
|
-
var row = dt.row( $(this).closest('tr') );
|
416
|
-
|
417
|
-
if ( row.child.isShown() ) {
|
418
|
-
row.child( false );
|
419
|
-
$( row.node() ).removeClass( 'parent' );
|
420
|
-
}
|
421
|
-
else {
|
422
|
-
var info = that.c.details.renderer( dt, row[0] );
|
423
|
-
row.child( info, 'child' ).show();
|
424
|
-
$( row.node() ).addClass( 'parent' );
|
425
|
-
}
|
426
|
-
} );
|
427
|
-
},
|
428
|
-
|
429
|
-
|
430
|
-
/**
|
431
|
-
* Update the child rows in the table whenever the column visibility changes
|
432
|
-
*
|
433
|
-
* @private
|
434
|
-
*/
|
435
|
-
_detailsVis: function ()
|
436
|
-
{
|
437
|
-
var that = this;
|
438
|
-
var dt = this.s.dt;
|
439
|
-
|
440
|
-
var hiddenColumns = dt.columns(':hidden').indexes().flatten();
|
441
|
-
var haveHidden = true;
|
442
|
-
|
443
|
-
if ( hiddenColumns.length === 0 || ( hiddenColumns.length === 1 && this.s.columns[ hiddenColumns[0] ].control ) ) {
|
444
|
-
haveHidden = false;
|
445
|
-
}
|
446
|
-
|
447
|
-
if ( haveHidden ) {
|
448
|
-
// Got hidden columns
|
449
|
-
$( dt.table().node() ).addClass('collapsed');
|
450
|
-
|
451
|
-
// Show all existing child rows
|
452
|
-
dt.rows().eq(0).each( function (idx) {
|
453
|
-
var row = dt.row( idx );
|
454
|
-
|
455
|
-
if ( row.child() ) {
|
456
|
-
var info = that.c.details.renderer( dt, row[0] );
|
457
|
-
|
458
|
-
// The renderer can return false to have no child row
|
459
|
-
if ( info === false ) {
|
460
|
-
row.child.hide();
|
461
|
-
}
|
462
|
-
else {
|
463
|
-
row.child( info, 'child' ).show();
|
464
|
-
}
|
465
|
-
}
|
466
|
-
} );
|
467
|
-
}
|
468
|
-
else {
|
469
|
-
// No hidden columns
|
470
|
-
$( dt.table().node() ).removeClass('collapsed');
|
471
|
-
|
472
|
-
// Hide all existing child rows
|
473
|
-
dt.rows().eq(0).each( function (idx) {
|
474
|
-
dt.row( idx ).child.hide();
|
475
|
-
} );
|
476
|
-
}
|
477
|
-
},
|
478
|
-
|
479
|
-
|
480
|
-
/**
|
481
|
-
* Find a breakpoint object from a name
|
482
|
-
* @param {string} name Breakpoint name to find
|
483
|
-
* @return {object} Breakpoint description object
|
484
|
-
*/
|
485
|
-
_find: function ( name )
|
486
|
-
{
|
487
|
-
var breakpoints = this.c.breakpoints;
|
488
|
-
|
489
|
-
for ( var i=0, ien=breakpoints.length ; i<ien ; i++ ) {
|
490
|
-
if ( breakpoints[i].name === name ) {
|
491
|
-
return breakpoints[i];
|
492
|
-
}
|
493
|
-
}
|
494
|
-
},
|
495
|
-
|
496
|
-
|
497
|
-
/**
|
498
|
-
* Alter the table display for a resized viewport. This involves first
|
499
|
-
* determining what breakpoint the window currently is in, getting the
|
500
|
-
* column visibilities to apply and then setting them.
|
501
|
-
*
|
502
|
-
* @private
|
503
|
-
*/
|
504
|
-
_resize: function ()
|
505
|
-
{
|
506
|
-
var dt = this.s.dt;
|
507
|
-
var width = $(window).width();
|
508
|
-
var breakpoints = this.c.breakpoints;
|
509
|
-
var breakpoint = breakpoints[0].name;
|
510
|
-
|
511
|
-
// Determine what breakpoint we are currently at
|
512
|
-
for ( var i=breakpoints.length-1 ; i>=0 ; i-- ) {
|
513
|
-
if ( width <= breakpoints[i].width ) {
|
514
|
-
breakpoint = breakpoints[i].name;
|
515
|
-
break;
|
516
|
-
}
|
517
|
-
}
|
518
|
-
|
519
|
-
// Show the columns for that break point
|
520
|
-
var columns = this._columnsVisiblity( breakpoint );
|
521
|
-
|
522
|
-
dt.columns().eq(0).each( function ( colIdx, i ) {
|
523
|
-
dt.column( colIdx ).visible( columns[i] );
|
524
|
-
} );
|
525
|
-
},
|
526
|
-
|
527
|
-
|
528
|
-
/**
|
529
|
-
* Determine the width of each column in the table so the auto column hiding
|
530
|
-
* has that information to work with. This method is never going to be 100%
|
531
|
-
* perfect since column widths can change slightly per page, but without
|
532
|
-
* seriously compromising performance this is quite effective.
|
533
|
-
*
|
534
|
-
* @private
|
535
|
-
*/
|
536
|
-
_resizeAuto: function ()
|
537
|
-
{
|
538
|
-
var dt = this.s.dt;
|
539
|
-
var columns = this.s.columns;
|
540
|
-
|
541
|
-
// Are we allowed to do auto sizing?
|
542
|
-
if ( ! this.c.auto ) {
|
543
|
-
return;
|
544
|
-
}
|
545
|
-
|
546
|
-
// Are there any columns that actually need auto-sizing, or do they all
|
547
|
-
// have classes defined
|
548
|
-
if ( $.inArray( true, $.map( columns, function (c) { return c.auto; } ) ) === -1 ) {
|
549
|
-
return;
|
550
|
-
}
|
551
|
-
|
552
|
-
// Clone the table with the current data in it
|
553
|
-
var tableWidth = dt.table().node().offsetWidth;
|
554
|
-
var columnWidths = dt.columns;
|
555
|
-
var clonedTable = dt.table().node().cloneNode( false );
|
556
|
-
var clonedHeader = $( dt.table().header().cloneNode( false ) ).appendTo( clonedTable );
|
557
|
-
var clonedBody = $( dt.table().body().cloneNode( false ) ).appendTo( clonedTable );
|
558
|
-
|
559
|
-
// This is a bit slow, but we need to get a clone of each row that
|
560
|
-
// includes all columns. As such, try to do this as little as possible.
|
561
|
-
dt.rows( { page: 'current' } ).indexes().each( function ( idx ) {
|
562
|
-
var clone = dt.row( idx ).node().cloneNode( true );
|
563
|
-
|
564
|
-
if ( dt.columns( ':hidden' ).flatten().length ) {
|
565
|
-
$(clone).append( dt.cells( idx, ':hidden' ).nodes().to$().clone() );
|
566
|
-
}
|
567
|
-
|
568
|
-
$(clone).appendTo( clonedBody );
|
569
|
-
} );
|
570
|
-
|
571
|
-
var cells = dt.columns().header().to$().clone( false ).wrapAll('tr').appendTo( clonedHeader );
|
572
|
-
var inserted = $('<div/>')
|
573
|
-
.css( {
|
574
|
-
width: 1,
|
575
|
-
height: 1,
|
576
|
-
overflow: 'hidden'
|
577
|
-
} )
|
578
|
-
.append( clonedTable )
|
579
|
-
.insertBefore( dt.table().node() );
|
580
|
-
|
581
|
-
// The cloned header now contains the smallest that each column can be
|
582
|
-
dt.columns().eq(0).each( function ( idx ) {
|
583
|
-
columns[idx].minWidth = cells[ idx ].offsetWidth || 0;
|
584
|
-
} );
|
585
|
-
|
586
|
-
inserted.remove();
|
587
|
-
}
|
138
|
+
/**
|
139
|
+
* Responsive datatables helper init function.
|
140
|
+
* Builds breakpoint limits for columns and begins to listen to window resize
|
141
|
+
* event.
|
142
|
+
*
|
143
|
+
* See constructor for the breakpoints parameter.
|
144
|
+
*
|
145
|
+
* @param {Object} breakpoints
|
146
|
+
* @param {Object} options
|
147
|
+
*/
|
148
|
+
ResponsiveDatatablesHelper.prototype.init = function (breakpoints, options) {
|
149
|
+
this.origBreakpointsDefs = breakpoints;
|
150
|
+
this.initBreakpoints();
|
151
|
+
|
152
|
+
// Enable responsive behavior.
|
153
|
+
this.disable(false);
|
154
|
+
|
155
|
+
// Extend options
|
156
|
+
$.extend(this.options, options);
|
588
157
|
};
|
589
158
|
|
159
|
+
ResponsiveDatatablesHelper.prototype.initBreakpoints = function () {
|
160
|
+
// Get last state if it exists
|
161
|
+
if (this.saveState) {
|
162
|
+
this.getState();
|
163
|
+
}
|
164
|
+
|
165
|
+
if (!this.lastStateExists) {
|
166
|
+
/** Generate breakpoints in the format we need. ***********************/
|
167
|
+
// First, we need to create a sorted array of the breakpoints given.
|
168
|
+
var breakpointsSorted = [];
|
169
|
+
|
170
|
+
for (var prop in this.origBreakpointsDefs) {
|
171
|
+
breakpointsSorted.push({
|
172
|
+
name: prop,
|
173
|
+
upperLimit: this.origBreakpointsDefs[prop],
|
174
|
+
columnsToHide: []
|
175
|
+
});
|
176
|
+
}
|
177
|
+
|
178
|
+
breakpointsSorted.sort(function (a, b) {
|
179
|
+
return a.upperLimit - b.upperLimit;
|
180
|
+
});
|
181
|
+
|
182
|
+
// Set lower and upper limits for each breakpoint.
|
183
|
+
var lowerLimit = 0;
|
184
|
+
for (var i = 0; i < breakpointsSorted.length; i++) {
|
185
|
+
breakpointsSorted[i].lowerLimit = lowerLimit;
|
186
|
+
lowerLimit = breakpointsSorted[i].upperLimit;
|
187
|
+
}
|
188
|
+
|
189
|
+
// Add the default breakpoint which shows all (has no upper limit).
|
190
|
+
breakpointsSorted.push({
|
191
|
+
name : 'always',
|
192
|
+
lowerLimit : lowerLimit,
|
193
|
+
upperLimit : Infinity,
|
194
|
+
columnsToHide: []
|
195
|
+
});
|
196
|
+
|
197
|
+
// Copy the sorted breakpoint array into the breakpoints object using the
|
198
|
+
// name as the key.
|
199
|
+
this.breakpoints = {};
|
200
|
+
var i, l;
|
201
|
+
for (i = 0, l = breakpointsSorted.length; i < l; i++) {
|
202
|
+
this.breakpoints[breakpointsSorted[i].name] = breakpointsSorted[i];
|
203
|
+
}
|
204
|
+
|
205
|
+
/** Create range of visible columns and their indexes *****************/
|
206
|
+
// We need the range of all visible column indexes to calculate the
|
207
|
+
// columns to show:
|
208
|
+
// Columns to show = all visible columns - columns to hide
|
209
|
+
var columns = this.api.columns().header();
|
210
|
+
var visibleColumnsHeadersTds = [];
|
211
|
+
for (i = 0, l = columns.length; i < l; i++) {
|
212
|
+
if (this.api.column(i).visible()) {
|
213
|
+
this.columnIndexes.push(i);
|
214
|
+
visibleColumnsHeadersTds.push(columns[i]);
|
215
|
+
}
|
216
|
+
}
|
217
|
+
|
218
|
+
/** Sort columns into breakpoints respectively ************************/
|
219
|
+
// Read column headers' attributes and get needed info
|
220
|
+
for (var index = 0; index < visibleColumnsHeadersTds.length; index++) {
|
221
|
+
// Get the column with the attribute data-class="expand" so we know
|
222
|
+
// where to display the expand icon.
|
223
|
+
var col = $(visibleColumnsHeadersTds[index]);
|
224
|
+
|
225
|
+
if (col.attr('data-class') === 'expand') {
|
226
|
+
this.expandColumn = this.columnIndexes[index];
|
227
|
+
}
|
228
|
+
|
229
|
+
// The data-hide attribute has the breakpoints that this column
|
230
|
+
// is associated with.
|
231
|
+
// If it's defined, get the data-hide attribute and sort this
|
232
|
+
// column into the appropriate breakpoint's columnsToHide array.
|
233
|
+
var dataHide = col.attr('data-hide');
|
234
|
+
if (dataHide !== undefined) {
|
235
|
+
var splitBreakingPoints = dataHide.split(/,\s*/);
|
236
|
+
for (var i = 0; i < splitBreakingPoints.length; i++) {
|
237
|
+
var bp = splitBreakingPoints[i];
|
238
|
+
if (bp === 'always') {
|
239
|
+
// A column with an 'always' breakpoint is always hidden.
|
240
|
+
// Loop through all breakpoints and add it to each except the
|
241
|
+
// default breakpoint.
|
242
|
+
for (var prop in this.breakpoints) {
|
243
|
+
if (this.breakpoints[prop].name !== 'default') {
|
244
|
+
this.breakpoints[prop].columnsToHide.push(this.columnIndexes[index]);
|
245
|
+
}
|
246
|
+
}
|
247
|
+
} else if (this.breakpoints[bp] !== undefined) {
|
248
|
+
// Translate visible column index to internal column index.
|
249
|
+
this.breakpoints[bp].columnsToHide.push(this.columnIndexes[index]);
|
250
|
+
}
|
251
|
+
}
|
252
|
+
}
|
253
|
+
}
|
254
|
+
}
|
255
|
+
};
|
590
256
|
|
591
257
|
/**
|
592
|
-
*
|
593
|
-
* properties:
|
258
|
+
* Sets or removes window resize handler.
|
594
259
|
*
|
595
|
-
*
|
596
|
-
* * `width` - the breakpoint width
|
597
|
-
*
|
598
|
-
* @name Responsive.breakpoints
|
599
|
-
* @static
|
260
|
+
* @param {Boolean} bindFlag
|
600
261
|
*/
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
262
|
+
ResponsiveDatatablesHelper.prototype.setWindowsResizeHandler = function(bindFlag) {
|
263
|
+
if (bindFlag === undefined) {
|
264
|
+
bindFlag = true;
|
265
|
+
}
|
266
|
+
|
267
|
+
if (bindFlag) {
|
268
|
+
var that = this;
|
269
|
+
$(window).bind("resize", function () {
|
270
|
+
that.respond();
|
271
|
+
});
|
272
|
+
} else {
|
273
|
+
$(window).unbind("resize");
|
274
|
+
}
|
275
|
+
};
|
608
276
|
|
277
|
+
/**
|
278
|
+
* Respond window size change. This helps make datatables responsive.
|
279
|
+
*/
|
280
|
+
ResponsiveDatatablesHelper.prototype.respond = function () {
|
281
|
+
if (this.disabled) {
|
282
|
+
return;
|
283
|
+
}
|
284
|
+
var that = this;
|
285
|
+
|
286
|
+
// Get new windows width
|
287
|
+
var newWindowWidth = $(window).width();
|
288
|
+
|
289
|
+
// Loop through breakpoints to see which columns need to be shown/hidden.
|
290
|
+
var newColumnsToHide = [];
|
291
|
+
|
292
|
+
for (var prop in this.breakpoints) {
|
293
|
+
var element = this.breakpoints[prop];
|
294
|
+
if ((!element.lowerLimit || newWindowWidth > element.lowerLimit) && (!element.upperLimit || newWindowWidth <= element.upperLimit)) {
|
295
|
+
this.currentBreakpoint = element.name;
|
296
|
+
newColumnsToHide = element.columnsToHide;
|
297
|
+
}
|
298
|
+
}
|
299
|
+
|
300
|
+
// Find out if a column show/hide should happen.
|
301
|
+
// Skip column show/hide if this window width change follows immediately
|
302
|
+
// after a previous column show/hide. This will help prevent a loop.
|
303
|
+
var columnShowHide = false;
|
304
|
+
if (!this.skipNextWindowsWidthChange) {
|
305
|
+
// Check difference in length
|
306
|
+
if (this.lastBreakpoint.length === 0 && newColumnsToHide.length) {
|
307
|
+
// No previous breakpoint and new breakpoint
|
308
|
+
columnShowHide = true;
|
309
|
+
} else if (this.lastBreakpoint != this.currentBreakpoint) {
|
310
|
+
// Different breakpoints
|
311
|
+
columnShowHide = true;
|
312
|
+
} else if (this.columnsHiddenIndexes.length !== newColumnsToHide.length) {
|
313
|
+
// Difference in number of hidden columns
|
314
|
+
columnShowHide = true;
|
315
|
+
} else {
|
316
|
+
// Possible same number of columns but check for difference in columns
|
317
|
+
var d1 = this.difference(this.columnsHiddenIndexes, newColumnsToHide).length;
|
318
|
+
var d2 = this.difference(newColumnsToHide, this.columnsHiddenIndexes).length;
|
319
|
+
columnShowHide = d1 + d2 > 0;
|
320
|
+
}
|
321
|
+
}
|
322
|
+
|
323
|
+
if (columnShowHide) {
|
324
|
+
// Showing/hiding a column at breakpoint may cause a windows width
|
325
|
+
// change. Let's flag to skip the column show/hide that may be
|
326
|
+
// caused by the next windows width change.
|
327
|
+
this.skipNextWindowsWidthChange = true;
|
328
|
+
this.columnsHiddenIndexes = newColumnsToHide;
|
329
|
+
this.columnsShownIndexes = this.difference(this.columnIndexes, this.columnsHiddenIndexes);
|
330
|
+
this.showHideColumns();
|
331
|
+
this.lastBreakpoint = this.currentBreakpoint;
|
332
|
+
this.setState();
|
333
|
+
this.skipNextWindowsWidthChange = false;
|
334
|
+
}
|
335
|
+
|
336
|
+
|
337
|
+
// We don't skip this part.
|
338
|
+
// If one or more columns have been hidden, add the has-columns-hidden class to table.
|
339
|
+
// This class will show what state the table is in.
|
340
|
+
if (this.columnsHiddenIndexes.length) {
|
341
|
+
this.tableElement.addClass('has-columns-hidden');
|
342
|
+
|
343
|
+
// Show details for each row that is tagged with the class .detail-show.
|
344
|
+
$('tr.detail-show', this.tableElement).each(function (index, element) {
|
345
|
+
var tr = $(element);
|
346
|
+
if (tr.next('.row-detail').length === 0) {
|
347
|
+
ResponsiveDatatablesHelper.prototype.showRowDetail(that, tr);
|
348
|
+
}
|
349
|
+
});
|
350
|
+
} else {
|
351
|
+
this.tableElement.removeClass('has-columns-hidden');
|
352
|
+
$('tr.row-detail').each(function (event) {
|
353
|
+
ResponsiveDatatablesHelper.prototype.hideRowDetail(that, $(this).prev());
|
354
|
+
});
|
355
|
+
}
|
356
|
+
};
|
609
357
|
|
610
358
|
/**
|
611
|
-
*
|
612
|
-
*
|
613
|
-
* @namespace
|
614
|
-
* @name Responsive.defaults
|
615
|
-
* @static
|
359
|
+
* Show/hide datatables columns.
|
616
360
|
*/
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
* Details control. If given as a string value, the `type` property of the
|
640
|
-
* default object is set to that value, and the defaults used for the rest
|
641
|
-
* of the object - this is for ease of implementation.
|
642
|
-
*
|
643
|
-
* The object consists of the following properties:
|
644
|
-
*
|
645
|
-
* * `renderer` - function that is called for display of the child row data.
|
646
|
-
* The default function will show the data from the hidden columns
|
647
|
-
* * `target` - Used as the selector for what objects to attach the child
|
648
|
-
* open / close to
|
649
|
-
* * `type` - `false` to disable the details display, `inline` or `column`
|
650
|
-
* for the two control types
|
651
|
-
*
|
652
|
-
* @type {Object|string}
|
653
|
-
*/
|
654
|
-
details: {
|
655
|
-
renderer: function ( api, rowIdx ) {
|
656
|
-
var data = api.cells( rowIdx, ':hidden' ).eq(0).map( function ( cell ) {
|
657
|
-
var header = $( api.column( cell.column ).header() );
|
658
|
-
|
659
|
-
if ( header.hasClass( 'control' ) ) {
|
660
|
-
return '';
|
661
|
-
}
|
662
|
-
|
663
|
-
return '<li>'+
|
664
|
-
'<span class="dtr-title">'+
|
665
|
-
header.text()+':'+
|
666
|
-
'</span> '+
|
667
|
-
'<span class="dtr-data">'+
|
668
|
-
api.cell( cell ).data()+
|
669
|
-
'</span>'+
|
670
|
-
'</li>';
|
671
|
-
} ).toArray().join('');
|
672
|
-
|
673
|
-
return data ?
|
674
|
-
$('<ul/>').append( data ) :
|
675
|
-
false;
|
676
|
-
},
|
677
|
-
|
678
|
-
target: 0,
|
679
|
-
|
680
|
-
type: 'inline'
|
681
|
-
}
|
361
|
+
ResponsiveDatatablesHelper.prototype.showHideColumns = function () {
|
362
|
+
// Calculate the columns to show
|
363
|
+
// Show columns that may have been previously hidden.
|
364
|
+
for (var i = 0, l = this.columnsShownIndexes.length; i < l; i++) {
|
365
|
+
this.api.column(this.columnsShownIndexes[i]).visible(true);
|
366
|
+
}
|
367
|
+
|
368
|
+
// Hide columns that may have been previously shown.
|
369
|
+
for (var i = 0, l = this.columnsHiddenIndexes.length; i < l; i++) {
|
370
|
+
this.api.column(this.columnsHiddenIndexes[i]).visible(false);
|
371
|
+
}
|
372
|
+
|
373
|
+
// Rebuild details to reflect shown/hidden column changes.
|
374
|
+
var that = this;
|
375
|
+
$('tr.row-detail').each(function () {
|
376
|
+
ResponsiveDatatablesHelper.prototype.hideRowDetail(that, $(this).prev());
|
377
|
+
});
|
378
|
+
if (this.tableElement.hasClass('has-columns-hidden')) {
|
379
|
+
$('tr.detail-show', this.tableElement).each(function (index, element) {
|
380
|
+
ResponsiveDatatablesHelper.prototype.showRowDetail(that, $(element));
|
381
|
+
});
|
382
|
+
}
|
682
383
|
};
|
683
384
|
|
385
|
+
/**
|
386
|
+
* Create the expand icon on the column with the data-class="expand" attribute
|
387
|
+
* defined for it's header.
|
388
|
+
*
|
389
|
+
* @param {Object} tr table row object
|
390
|
+
*/
|
391
|
+
ResponsiveDatatablesHelper.prototype.createExpandIcon = function (tr) {
|
392
|
+
if (this.disabled) {
|
393
|
+
return;
|
394
|
+
}
|
395
|
+
|
396
|
+
// Get the td for tr with the same index as the th in the header tr
|
397
|
+
// that has the data-class="expand" attribute defined.
|
398
|
+
var tds = $('td', tr);
|
399
|
+
// Loop through tds and create an expand icon on the td that has a column
|
400
|
+
// index equal to the expand column given.
|
401
|
+
for (var i = 0, l = tds.length; i < l; i++) {
|
402
|
+
var td = tds[i];
|
403
|
+
var tdIndex = this.api.cell(td).index().column;
|
404
|
+
td = $(td);
|
405
|
+
if (tdIndex === this.expandColumn) {
|
406
|
+
// Create expand icon if there isn't one already.
|
407
|
+
if ($('span.responsiveExpander', td).length == 0) {
|
408
|
+
td.prepend(this.expandIconTemplate);
|
409
|
+
|
410
|
+
// Respond to click event on expander icon.
|
411
|
+
switch (this.options.clickOn) {
|
412
|
+
case 'cell':
|
413
|
+
td.on('click', {responsiveDatatablesHelperInstance: this}, this.showRowDetailEventHandler);
|
414
|
+
break;
|
415
|
+
case 'row':
|
416
|
+
$(tr).on('click', {responsiveDatatablesHelperInstance: this}, this.showRowDetailEventHandler);
|
417
|
+
break;
|
418
|
+
default:
|
419
|
+
td.on('click', 'span.responsiveExpander', {responsiveDatatablesHelperInstance: this}, this.showRowDetailEventHandler);
|
420
|
+
break;
|
421
|
+
}
|
422
|
+
}
|
423
|
+
break;
|
424
|
+
}
|
425
|
+
}
|
426
|
+
};
|
684
427
|
|
685
|
-
|
686
|
-
*
|
428
|
+
/**
|
429
|
+
* Show row detail event handler.
|
430
|
+
*
|
431
|
+
* This handler is used to handle the click event of the expand icon defined in
|
432
|
+
* the table row data element.
|
433
|
+
*
|
434
|
+
* @param {Object} event jQuery event object
|
687
435
|
*/
|
688
|
-
|
436
|
+
ResponsiveDatatablesHelper.prototype.showRowDetailEventHandler = function (event) {
|
437
|
+
var responsiveDatatablesHelperInstance = event.data.responsiveDatatablesHelperInstance;
|
438
|
+
if (responsiveDatatablesHelperInstance.disabled) {
|
439
|
+
return;
|
440
|
+
}
|
689
441
|
|
690
|
-
|
691
|
-
Api.register( 'responsive()', function () {
|
692
|
-
return this;
|
693
|
-
} );
|
442
|
+
var td = $(this);
|
694
443
|
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
ctx._responsive._resize();
|
700
|
-
}
|
701
|
-
} );
|
702
|
-
} );
|
444
|
+
// Nothing to do if there are no columns hidden.
|
445
|
+
if (!td.closest('table').hasClass('has-columns-hidden')) {
|
446
|
+
return;
|
447
|
+
}
|
703
448
|
|
449
|
+
// Get the parent tr of which this td belongs to.
|
450
|
+
var tr = td.closest('tr');
|
451
|
+
|
452
|
+
// Show/hide row details
|
453
|
+
if (tr.hasClass('detail-show')) {
|
454
|
+
ResponsiveDatatablesHelper.prototype.hideRowDetail(responsiveDatatablesHelperInstance, tr);
|
455
|
+
} else {
|
456
|
+
ResponsiveDatatablesHelper.prototype.showRowDetail(responsiveDatatablesHelperInstance, tr);
|
457
|
+
}
|
458
|
+
|
459
|
+
tr.toggleClass('detail-show');
|
460
|
+
|
461
|
+
// Prevent click event from bubbling up to higher-level DOM elements.
|
462
|
+
event.stopPropagation();
|
463
|
+
};
|
704
464
|
|
705
465
|
/**
|
706
|
-
*
|
466
|
+
* Show row details.
|
707
467
|
*
|
708
|
-
* @
|
709
|
-
* @
|
468
|
+
* @param {ResponsiveDatatablesHelper} responsiveDatatablesHelperInstance instance of ResponsiveDatatablesHelper
|
469
|
+
* @param {Object} tr jQuery wrapped set
|
710
470
|
*/
|
711
|
-
|
471
|
+
ResponsiveDatatablesHelper.prototype.showRowDetail = function (responsiveDatatablesHelperInstance, tr) {
|
472
|
+
// Get column because we need their titles.
|
473
|
+
var api = responsiveDatatablesHelperInstance.api;
|
474
|
+
var columns = api.columns().header();
|
475
|
+
|
476
|
+
// Create the new tr.
|
477
|
+
var newTr = $(responsiveDatatablesHelperInstance.rowTemplate);
|
478
|
+
|
479
|
+
// Get the ul that we'll insert li's into.
|
480
|
+
var ul = $('ul', newTr);
|
481
|
+
|
482
|
+
// Loop through hidden columns and create an li for each of them.
|
483
|
+
for (var i = 0; i < responsiveDatatablesHelperInstance.columnsHiddenIndexes.length; i++) {
|
484
|
+
var index = responsiveDatatablesHelperInstance.columnsHiddenIndexes[i];
|
485
|
+
|
486
|
+
// Get row td
|
487
|
+
var rowIndex = api.row(tr).index();
|
488
|
+
var td = api.cell(rowIndex, index).node();
|
489
|
+
|
490
|
+
// Don't create li if contents are empty (depends on hideEmptyColumnsInRowDetail option).
|
491
|
+
if (!responsiveDatatablesHelperInstance.options.hideEmptyColumnsInRowDetail || td.innerHTML.trim().length) {
|
492
|
+
var li = $(responsiveDatatablesHelperInstance.rowLiTemplate);
|
493
|
+
var hiddenColumnName = $(columns[index]).attr('data-name');
|
494
|
+
$('.columnTitle', li).html(hiddenColumnName !== undefined ? hiddenColumnName : columns[index].innerHTML);
|
495
|
+
var contents = $(td).contents();
|
496
|
+
var clonedContents = contents.clone();
|
497
|
+
|
498
|
+
// Select elements' selectedIndex are not cloned. Do it manually.
|
499
|
+
for (var n = 0, m = contents.length; n < m; n++) {
|
500
|
+
var node = contents[n];
|
501
|
+
if (node.nodeType === Node.ELEMENT_NODE && node.tagName === 'SELECT') {
|
502
|
+
clonedContents[n].selectedIndex = node.selectedIndex
|
503
|
+
}
|
504
|
+
}
|
505
|
+
|
506
|
+
// Set the column contents and save the original td source.
|
507
|
+
$('.columnValue', li).append(clonedContents).data('originalTdSource', td);
|
508
|
+
|
509
|
+
// Copy index to data attribute, so we'll know where to put the value when the tr.row-detail is removed.
|
510
|
+
li.attr('data-column', index);
|
511
|
+
|
512
|
+
// Copy td class to new li.
|
513
|
+
var tdClass = $(td).attr('class');
|
514
|
+
if (tdClass !== 'undefined' && tdClass !== false && tdClass !== '') {
|
515
|
+
li.addClass(tdClass)
|
516
|
+
}
|
517
|
+
|
518
|
+
ul.append(li);
|
519
|
+
}
|
520
|
+
}
|
521
|
+
|
522
|
+
// Create tr colspan attribute.
|
523
|
+
var colspan = responsiveDatatablesHelperInstance.columnIndexes.length - responsiveDatatablesHelperInstance.columnsHiddenIndexes.length;
|
524
|
+
newTr.find('> td').attr('colspan', colspan);
|
525
|
+
|
526
|
+
// Append the new tr after the current tr.
|
527
|
+
tr.after(newTr);
|
528
|
+
|
529
|
+
// call the showDetail function if needbe
|
530
|
+
if (responsiveDatatablesHelperInstance.options.showDetail){
|
531
|
+
responsiveDatatablesHelperInstance.options.showDetail(newTr);
|
532
|
+
}
|
533
|
+
};
|
712
534
|
|
535
|
+
/**
|
536
|
+
* Hide row details.
|
537
|
+
*
|
538
|
+
* @param {ResponsiveDatatablesHelper} responsiveDatatablesHelperInstance instance of ResponsiveDatatablesHelper
|
539
|
+
* @param {Object} tr jQuery wrapped set
|
540
|
+
*/
|
541
|
+
ResponsiveDatatablesHelper.prototype.hideRowDetail = function (responsiveDatatablesHelperInstance, tr) {
|
542
|
+
// If the value of an input has changed while in row detail, we need to copy its state back
|
543
|
+
// to the DataTables object so that value will persist when the tr.row-detail is removed.
|
544
|
+
var rowDetail = tr.next('.row-detail');
|
545
|
+
if (responsiveDatatablesHelperInstance.options.hideDetail){
|
546
|
+
responsiveDatatablesHelperInstance.options.hideDetail(rowDetail);
|
547
|
+
}
|
548
|
+
rowDetail.find('li').each(function () {
|
549
|
+
var columnValueContainer = $(this).find('span.columnValue');
|
550
|
+
var tdContents = columnValueContainer.contents();
|
551
|
+
var td = columnValueContainer.data('originalTdSource');
|
552
|
+
$(td).empty().append(tdContents);
|
553
|
+
});
|
554
|
+
rowDetail.remove();
|
555
|
+
};
|
713
556
|
|
714
|
-
|
715
|
-
|
557
|
+
/**
|
558
|
+
* Enable/disable responsive behavior and restores changes made.
|
559
|
+
*
|
560
|
+
* @param {Boolean} disable, default is true
|
561
|
+
*/
|
562
|
+
ResponsiveDatatablesHelper.prototype.disable = function (disable) {
|
563
|
+
this.disabled = (disable === undefined) || disable;
|
716
564
|
|
717
|
-
|
718
|
-
//
|
719
|
-
|
720
|
-
if ( $(settings.nTable).hasClass( 'responsive' ) ||
|
721
|
-
$(settings.nTable).hasClass( 'dt-responsive' ) ||
|
722
|
-
settings.oInit.responsive
|
723
|
-
) {
|
724
|
-
var init = settings.oInit.responsive;
|
565
|
+
if (this.disabled) {
|
566
|
+
// Remove windows resize handler.
|
567
|
+
this.setWindowsResizeHandler(false);
|
725
568
|
|
726
|
-
|
727
|
-
|
728
|
-
}
|
729
|
-
}
|
730
|
-
} );
|
569
|
+
// Remove all trs that have row details.
|
570
|
+
$('tbody tr.row-detail', this.tableElement).remove();
|
731
571
|
|
732
|
-
|
733
|
-
|
572
|
+
// Remove all trs that are marked to have row details shown.
|
573
|
+
$('tbody tr', this.tableElement).removeClass('detail-show');
|
734
574
|
|
575
|
+
// Remove all expander icons.
|
576
|
+
$('tbody tr span.responsiveExpander', this.tableElement).remove();
|
735
577
|
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
else if ( typeof exports === 'object' ) {
|
741
|
-
// Node/CommonJS
|
742
|
-
factory( require('jquery'), require('datatables') );
|
743
|
-
}
|
744
|
-
else if ( jQuery && !jQuery.fn.dataTable.Responsive ) {
|
745
|
-
// Otherwise simply initialise as normal, stopping multiple evaluation
|
746
|
-
factory( jQuery, jQuery.fn.dataTable );
|
747
|
-
}
|
578
|
+
this.columnsHiddenIndexes = [];
|
579
|
+
this.columnsShownIndexes = this.columnIndexes;
|
580
|
+
this.showHideColumns();
|
581
|
+
this.tableElement.removeClass('has-columns-hidden');
|
748
582
|
|
583
|
+
this.tableElement.off('click', 'span.responsiveExpander', this.showRowDetailEventHandler);
|
584
|
+
} else {
|
585
|
+
// Add windows resize handler.
|
586
|
+
this.setWindowsResizeHandler();
|
587
|
+
}
|
588
|
+
};
|
749
589
|
|
750
|
-
|
590
|
+
/**
|
591
|
+
* Get state from cookie.
|
592
|
+
*/
|
593
|
+
ResponsiveDatatablesHelper.prototype.getState = function () {
|
594
|
+
if (typeof(Storage)) {
|
595
|
+
// Use local storage
|
596
|
+
var value = JSON.parse(localStorage.getItem(this.cookieName));
|
597
|
+
if (value) {
|
598
|
+
this.columnIndexes = value.columnIndexes;
|
599
|
+
this.breakpoints = value.breakpoints;
|
600
|
+
this.expandColumn = value.expandColumn;
|
601
|
+
this.lastBreakpoint = value.lastBreakpoint;
|
602
|
+
this.lastStateExists = true;
|
603
|
+
}
|
604
|
+
} else {
|
605
|
+
// No local storage.
|
606
|
+
}
|
607
|
+
};
|
751
608
|
|
609
|
+
/**
|
610
|
+
* Saves state to cookie.
|
611
|
+
*/
|
612
|
+
ResponsiveDatatablesHelper.prototype.setState = function () {
|
613
|
+
if (typeof(Storage)) {
|
614
|
+
// Use local storage
|
615
|
+
var d1 = this.difference(this.lastColumnsHiddenIndexes, this.columnsHiddenIndexes).length;
|
616
|
+
var d2 = this.difference(this.columnsHiddenIndexes, this.lastColumnsHiddenIndexes).length;
|
617
|
+
|
618
|
+
if (d1 + d2 > 0) {
|
619
|
+
var tt;
|
620
|
+
var value = {
|
621
|
+
columnIndexes: this.columnIndexes, // array
|
622
|
+
columnsHiddenIndexes: this.columnsHiddenIndexes, // array
|
623
|
+
breakpoints: this.breakpoints, // object
|
624
|
+
expandColumn: this.expandColumn, // int|undefined
|
625
|
+
lastBreakpoint: this.lastBreakpoint // string
|
626
|
+
};
|
627
|
+
|
628
|
+
localStorage.setItem(this.cookieName, JSON.stringify(value));
|
629
|
+
this.lastColumnsHiddenIndexes = this.columnsHiddenIndexes.slice(0);
|
630
|
+
}
|
631
|
+
} else {
|
632
|
+
// No local storage.
|
633
|
+
}
|
634
|
+
};
|
635
|
+
|
636
|
+
/**
|
637
|
+
* Get Difference.
|
638
|
+
*/
|
639
|
+
ResponsiveDatatablesHelper.prototype.difference = function (a, b) {
|
640
|
+
var arr = [], i, hash = {};
|
641
|
+
for (i = b.length - 1; i >= 0; i--) {
|
642
|
+
hash[b[i]] = true;
|
643
|
+
}
|
644
|
+
for (i = a.length - 1; i >= 0; i--) {
|
645
|
+
if (hash[a[i]] !== true) {
|
646
|
+
arr.push(a[i]);
|
647
|
+
}
|
648
|
+
}
|
649
|
+
return arr;
|
650
|
+
};
|