jquery-datatables-rails 2.2.1 → 2.2.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,11 +1,11 @@
1
- /*! KeyTable 1.2.0
1
+ /*! KeyTable 1.2.1
2
2
  * ©2010-2014 SpryMedia Ltd - datatables.net/license
3
3
  */
4
4
 
5
5
  /**
6
6
  * @summary KeyTable
7
7
  * @description Spreadsheet like keyboard navigation for DataTables
8
- * @version 1.2.0
8
+ * @version 1.2.1
9
9
  * @file dataTables.keyTable.js
10
10
  * @author SpryMedia Ltd (www.sprymedia.co.uk)
11
11
  * @contact www.sprymedia.co.uk/contact
@@ -1147,7 +1147,7 @@ KeyTable = function ( oInit )
1147
1147
  };
1148
1148
 
1149
1149
 
1150
- KeyTable.version = "1.2.0";
1150
+ KeyTable.version = "1.2.1";
1151
1151
 
1152
1152
 
1153
1153
  $.fn.dataTable.KeyTable = KeyTable;
@@ -1160,7 +1160,11 @@ return KeyTable;
1160
1160
 
1161
1161
  // Define as an AMD module if possible
1162
1162
  if ( typeof define === 'function' && define.amd ) {
1163
- define( 'datatables-keytable', ['jquery', 'datatables'], factory );
1163
+ define( ['jquery', 'datatables'], factory );
1164
+ }
1165
+ else if ( typeof exports === 'object' ) {
1166
+ // Node/CommonJS
1167
+ factory( require('jquery'), require('datatables') );
1164
1168
  }
1165
1169
  else if ( jQuery && !jQuery.fn.dataTable.KeyTable ) {
1166
1170
  // Otherwise simply initialise as normal, stopping multiple evaluation
@@ -1,665 +1,751 @@
1
+ /*! Responsive 1.0.1
2
+ * 2014 SpryMedia Ltd - datatables.net/license
3
+ */
4
+
1
5
  /**
2
- * File: datatables.responsive.js
3
- * Version: 0.2.0
4
- * Author: Seen Sai Yang
5
- * Info: https://github.com/Comanche/datatables-responsive
6
+ * @summary Responsive
7
+ * @description Responsive tables plug-in for DataTables
8
+ * @version 1.0.1
9
+ * @file dataTables.responsive.js
10
+ * @author SpryMedia Ltd (www.sprymedia.co.uk)
11
+ * @contact www.sprymedia.co.uk/contact
12
+ * @copyright Copyright 2014 SpryMedia Ltd.
6
13
  *
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.
14
+ * This source file is free software, available under the following license:
15
+ * MIT license - http://datatables.net/license/mit
11
16
  *
12
17
  * This source file is distributed in the hope that it will be useful, but
13
18
  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14
19
  * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
15
20
  *
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
21
+ * For details please refer to: http://www.datatables.net
20
22
  */
21
23
 
22
- 'use strict';
24
+ (function(window, document, undefined) {
25
+
26
+
27
+ var factory = function( $, DataTable ) {
28
+ "use strict";
23
29
 
24
30
  /**
25
- * Constructor for responsive datables helper.
26
- *
27
- * This helper class makes datatables responsive to the window size.
31
+ * Responsive is a plug-in for the DataTables library that makes use of
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.
28
36
  *
29
- * The parameter, breakpoints, is an object for each breakpoint key/value pair
30
- * with the following format: { breakpoint_name: pixel_width_at_breakpoint }.
37
+ * Responsive for DataTables has two modes of operation, which can used
38
+ * individually or combined:
31
39
  *
32
- * An example is as follows:
40
+ * * Class name based control - columns assigned class names that match the
41
+ * breakpoint logic can be shown / hidden as required for each breakpoint.
42
+ * * Automatic control - columns are automatically hidden when there is no
43
+ * room left to display them. Columns removed from the right.
33
44
  *
34
- * {
35
- * tablet: 1024,
36
- * phone: 480
37
- * }
45
+ * In additional to column visibility control, Responsive also has built into
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:
38
49
  *
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.
50
+ * * Inline - when the control element that the user can use to show / hide
51
+ * child rows is displayed inside the first column of the table.
52
+ * * Column - where a whole column is dedicated to be the show / hide control.
42
53
  *
43
- * The parameter, options, is an object of options supported by the responsive
44
- * helper. The following options are supported:
54
+ * Initialisation of Responsive is performed by:
45
55
  *
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
- * }
52
- *
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.
58
- */
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
- }
137
-
138
- /**
139
- * Responsive datatables helper init function.
140
- * Builds breakpoint limits for columns and begins to listen to window resize
141
- * event.
56
+ * * Adding the class `responsive` or `dt-responsive` to the table. In this case
57
+ * Responsive will automatically be initialised with the default configuration
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.
142
62
  *
143
- * See constructor for the breakpoints parameter.
63
+ * @class
64
+ * @param {object} settings DataTables settings object for the host table
65
+ * @param {object} [opts] Configuration options
66
+ * @requires jQuery 1.7+
67
+ * @requires DataTables 1.10.1+
144
68
  *
145
- * @param {Object} breakpoints
146
- * @param {Object} options
69
+ * @example
70
+ * $('#example').DataTable( {
71
+ * responsive: true
72
+ * } );
73
+ * } );
147
74
  */
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);
75
+ var Responsive = function ( settings, opts ) {
76
+ // Sanity check that we are using DataTables 1.10 or newer
77
+ if ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.1' ) ) {
78
+ throw 'DataTables Responsive requires DataTables 1.10.1 or newer';
79
+ }
80
+ else if ( settings.responsive ) {
81
+ return;
82
+ }
83
+
84
+ this.s = {
85
+ dt: new DataTable.Api( settings ),
86
+ columns: []
87
+ };
88
+
89
+ // details is an object, but for simplicity the user can give it as a string
90
+ if ( opts && typeof opts.details === 'string' ) {
91
+ opts.details = { type: opts.details };
92
+ }
93
+
94
+ this.c = $.extend( true, {}, Responsive.defaults, opts );
95
+ settings.responsive = this;
96
+ this._constructor();
157
97
  };
158
98
 
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.columns(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
- }
99
+ Responsive.prototype = {
100
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
101
+ * Constructor
102
+ */
103
+
104
+ /**
105
+ * Initialise the Responsive instance
106
+ *
107
+ * @private
108
+ */
109
+ _constructor: function ()
110
+ {
111
+ var that = this;
112
+ var dt = this.s.dt;
113
+
114
+ dt.settings()[0]._responsive = this;
115
+
116
+ // Use DataTables' private throttle function to avoid processor thrashing
117
+ $(window).on( 'resize.dtr orientationchange.dtr', dt.settings()[0].oApi._fnThrottle( function () {
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
+ }
255
588
  };
256
589
 
257
- /**
258
- * Sets or removes window resize handler.
259
- *
260
- * @param {Boolean} bindFlag
261
- */
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
- };
276
590
 
277
591
  /**
278
- * Respond window size change. This helps make datatables responsive.
592
+ * List of default breakpoints. Each item in the array is an object with two
593
+ * properties:
594
+ *
595
+ * * `name` - the breakpoint name.
596
+ * * `width` - the breakpoint width
597
+ *
598
+ * @name Responsive.breakpoints
599
+ * @static
279
600
  */
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
- };
601
+ Responsive.breakpoints = [
602
+ { name: 'desktop', width: Infinity },
603
+ { name: 'tablet-l', width: 1024 },
604
+ { name: 'tablet-p', width: 768 },
605
+ { name: 'mobile-l', width: 480 },
606
+ { name: 'mobile-p', width: 320 }
607
+ ];
357
608
 
358
- /**
359
- * Show/hide datatables columns.
360
- */
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
- }
383
- };
384
609
 
385
610
  /**
386
- * Create the expand icon on the column with the data-class="expand" attribute
387
- * defined for it's header.
611
+ * Responsive default settings for initialisation
388
612
  *
389
- * @param {Object} tr table row object
613
+ * @namespace
614
+ * @name Responsive.defaults
615
+ * @static
390
616
  */
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
- }
617
+ Responsive.defaults = {
618
+ /**
619
+ * List of breakpoints for the instance. Note that this means that each
620
+ * instance can have its own breakpoints. Additionally, the breakpoints
621
+ * cannot be changed once an instance has been creased.
622
+ *
623
+ * @type {Array}
624
+ * @default Takes the value of `Responsive.breakpoints`
625
+ */
626
+ breakpoints: Responsive.breakpoints,
627
+
628
+ /**
629
+ * Enable / disable auto hiding calculations. It can help to increase
630
+ * performance slightly if you disable this option, but all columns would
631
+ * need to have breakpoint classes assigned to them
632
+ *
633
+ * @type {Boolean}
634
+ * @default `true`
635
+ */
636
+ auto: true,
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
+ }
426
682
  };
427
683
 
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
435
- */
436
- ResponsiveDatatablesHelper.prototype.showRowDetailEventHandler = function (event) {
437
- var responsiveDatatablesHelperInstance = event.data.responsiveDatatablesHelperInstance;
438
- if (responsiveDatatablesHelperInstance.disabled) {
439
- return;
440
- }
441
-
442
- var td = $(this);
443
-
444
- // Nothing to do if there are no columns hidden.
445
- if (!td.closest('table').hasClass('has-columns-hidden')) {
446
- return;
447
- }
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
684
 
459
- tr.toggleClass('detail-show');
685
+ /*
686
+ * API
687
+ */
688
+ var Api = $.fn.dataTable.Api;
460
689
 
461
- // Prevent click event from bubbling up to higher-level DOM elements.
462
- event.stopPropagation();
463
- };
690
+ // Doesn't do anything - work around for a bug in DT... Not documented
691
+ Api.register( 'responsive()', function () {
692
+ return this;
693
+ } );
464
694
 
465
- /**
466
- * Show row details.
467
- *
468
- * @param {ResponsiveDatatablesHelper} responsiveDatatablesHelperInstance instance of ResponsiveDatatablesHelper
469
- * @param {Object} tr jQuery wrapped set
470
- */
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
- };
695
+ Api.register( 'responsive.recalc()', function ( rowIdx, intParse, virtual ) {
696
+ this.iterator( 'table', function ( ctx ) {
697
+ if ( ctx._responsive ) {
698
+ ctx._responsive._resizeAuto();
699
+ ctx._responsive._resize();
700
+ }
701
+ } );
702
+ } );
534
703
 
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
- };
556
704
 
557
705
  /**
558
- * Enable/disable responsive behavior and restores changes made.
706
+ * Version information
559
707
  *
560
- * @param {Boolean} disable, default is true
708
+ * @name Responsive.version
709
+ * @static
561
710
  */
562
- ResponsiveDatatablesHelper.prototype.disable = function (disable) {
563
- this.disabled = (disable === undefined) || disable;
711
+ Responsive.version = '1.0.1';
564
712
 
565
- if (this.disabled) {
566
- // Remove windows resize handler.
567
- this.setWindowsResizeHandler(false);
568
713
 
569
- // Remove all trs that have row details.
570
- $('tbody tr.row-detail', this.tableElement).remove();
714
+ $.fn.dataTable.Responsive = Responsive;
715
+ $.fn.DataTable.Responsive = Responsive;
571
716
 
572
- // Remove all trs that are marked to have row details shown.
573
- $('tbody tr', this.tableElement).removeClass('detail-show');
717
+ // Attach a listener to the document which listens for DataTables initialisation
718
+ // events so we can automatically initialise
719
+ $(document).on( 'init.dt.dtr', function (e, settings, json) {
720
+ if ( $(settings.nTable).hasClass( 'responsive' ) ||
721
+ $(settings.nTable).hasClass( 'dt-responsive' ) ||
722
+ settings.oInit.responsive
723
+ ) {
724
+ var init = settings.oInit.responsive;
574
725
 
575
- // Remove all expander icons.
576
- $('tbody tr span.responsiveExpander', this.tableElement).remove();
726
+ if ( init !== false ) {
727
+ new Responsive( settings, $.isPlainObject( init ) ? init : {} );
728
+ }
729
+ }
730
+ } );
577
731
 
578
- this.columnsHiddenIndexes = [];
579
- this.columnsShownIndexes = this.columnIndexes;
580
- this.showHideColumns();
581
- this.tableElement.removeClass('has-columns-hidden');
582
-
583
- this.tableElement.off('click', 'span.responsiveExpander', this.showRowDetailEventHandler);
584
- } else {
585
- // Add windows resize handler.
586
- this.setWindowsResizeHandler();
587
- }
588
- };
732
+ return Responsive;
733
+ }; // /factory
589
734
 
590
- /**
591
- * Get state from cookie.
592
- */
593
- ResponsiveDatatablesHelper.prototype.getState = function () {
594
- try {
595
- var value = JSON.parse(decodeURIComponent(this.getCookie(this.cookieName)));
596
- if (value) {
597
- this.columnIndexes = value.columnIndexes;
598
- this.breakpoints = value.breakpoints;
599
- this.expandColumn = value.expandColumn;
600
- this.lastBreakpoint = value.lastBreakpoint;
601
- this.lastStateExists = true;
602
- }
603
- } catch (e) {
604
- }
605
- };
606
735
 
607
- /**
608
- * Saves state to cookie.
609
- */
610
- ResponsiveDatatablesHelper.prototype.setState = function () {
611
- var d1 = this.difference(this.lastColumnsHiddenIndexes, this.columnsHiddenIndexes).length;
612
- var d2 = this.difference(this.columnsHiddenIndexes, this.lastColumnsHiddenIndexes).length;
613
-
614
- if (d1 + d2 > 0) {
615
- var value = encodeURIComponent(JSON.stringify({
616
- columnIndexes: this.columnIndexes,
617
- columnsHiddenIndexes: this.columnsHiddenIndexes,
618
- breakpoints: this.breakpoints,
619
- expandColumn: this.expandColumn,
620
- lastBreakpoint: this.lastBreakpoint
621
- }));
622
-
623
- this.setCookie(this.cookieName, value, 2 * 60 * 60 * 1000);
624
- this.lastColumnsHiddenIndexes = this.columnsHiddenIndexes.slice(0);
625
- }
626
- };
736
+ // Define as an AMD module if possible
737
+ if ( typeof define === 'function' && define.amd ) {
738
+ define( ['jquery', 'datatables'], factory );
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
+ }
627
748
 
628
- /**
629
- * Get cookie.
630
- */
631
- ResponsiveDatatablesHelper.prototype.getCookie = function (cname) {
632
- var name = cname + "=";
633
- var ca = document.cookie.split(';');
634
- for (var i = 0; i < ca.length; i++) {
635
- var c = ca[i].trim();
636
- if (c.indexOf(name) == 0) return c.substring(name.length, c.length);
637
- }
638
- return "";
639
- };
640
749
 
641
- /**
642
- * Set cookie.
643
- */
644
- ResponsiveDatatablesHelper.prototype.setCookie = function (cname, cvalue, cexp) {
645
- var d = new Date();
646
- d.setTime(d.getTime() + cexp);
647
- var expires = "expires=" + d.toGMTString();
648
- document.cookie = cname + "=" + cvalue + "; " + expires;
649
- };
750
+ })(window, document);
650
751
 
651
- /**
652
- * Get Difference.
653
- */
654
- ResponsiveDatatablesHelper.prototype.difference = function (a, b) {
655
- var arr = [], i, hash = {};
656
- for (i = b.length - 1; i >= 0; i--) {
657
- hash[b[i]] = true;
658
- }
659
- for (i = a.length - 1; i >= 0; i--) {
660
- if (hash[a[i]] !== true) {
661
- arr.push(a[i]);
662
- }
663
- }
664
- return arr;
665
- };