jquery-datatables 1.10.19.1 → 1.10.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/.gitattributes +1 -0
  3. data/README.md +28 -1
  4. data/app/assets/javascripts/datatables/dataTables.uikit.js +2 -2
  5. data/app/assets/javascripts/datatables/extensions/AutoFill/dataTables.autoFill.js +42 -29
  6. data/app/assets/javascripts/datatables/extensions/Buttons/buttons.bootstrap.js +1 -1
  7. data/app/assets/javascripts/datatables/extensions/Buttons/buttons.bootstrap4.js +8 -2
  8. data/app/assets/javascripts/datatables/extensions/Buttons/buttons.colVis.js +6 -3
  9. data/app/assets/javascripts/datatables/extensions/Buttons/buttons.foundation.js +5 -4
  10. data/app/assets/javascripts/datatables/extensions/Buttons/buttons.html5.js +58 -6
  11. data/app/assets/javascripts/datatables/extensions/Buttons/buttons.print.js +16 -5
  12. data/app/assets/javascripts/datatables/extensions/Buttons/buttons.semanticui.js +1 -1
  13. data/app/assets/javascripts/datatables/extensions/Buttons/dataTables.buttons.js +267 -152
  14. data/app/assets/javascripts/datatables/extensions/ColReorder/colReorder.foundation.js +1 -1
  15. data/app/assets/javascripts/datatables/extensions/ColReorder/dataTables.colReorder.js +121 -52
  16. data/app/assets/javascripts/datatables/extensions/FixedColumns/dataTables.fixedColumns.js +32 -5
  17. data/app/assets/javascripts/datatables/extensions/KeyTable/dataTables.keyTable.js +166 -63
  18. data/app/assets/javascripts/datatables/extensions/KeyTable/keyTable.foundation.js +1 -1
  19. data/app/assets/javascripts/datatables/extensions/RowGroup/dataTables.rowGroup.js +105 -53
  20. data/app/assets/javascripts/datatables/extensions/RowGroup/rowGroup.foundation.js +1 -1
  21. data/app/assets/javascripts/datatables/extensions/RowGroup/{rowGroup.semanicui.js → rowGroup.semanticui.js} +0 -0
  22. data/app/assets/javascripts/datatables/extensions/RowReorder/dataTables.rowReorder.js +10 -9
  23. data/app/assets/javascripts/datatables/extensions/RowReorder/rowReorder.foundation.js +1 -1
  24. data/app/assets/javascripts/datatables/extensions/Scroller/dataTables.scroller.js +519 -636
  25. data/app/assets/javascripts/datatables/extensions/Scroller/scroller.foundation.js +1 -1
  26. data/app/assets/javascripts/datatables/extensions/Select/dataTables.select.js +49 -18
  27. data/app/assets/javascripts/datatables/extensions/Select/select.foundation.js +1 -1
  28. data/app/assets/javascripts/datatables/jquery.dataTables.js +97 -60
  29. data/app/assets/javascripts/datatables/plugins/api/average.js +7 -6
  30. data/app/assets/javascripts/datatables/plugins/api/sum.js +7 -6
  31. data/app/assets/javascripts/datatables/plugins/pagination/ellipses.js +160 -0
  32. data/app/assets/javascripts/datatables/plugins/pagination/extjs.js +137 -0
  33. data/app/assets/javascripts/datatables/plugins/pagination/four_button.js +110 -0
  34. data/app/assets/javascripts/datatables/plugins/pagination/full_numbers_no_ellipses.js +59 -0
  35. data/app/assets/javascripts/datatables/plugins/pagination/input.js +22 -19
  36. data/app/assets/javascripts/datatables/plugins/pagination/scrolling.js +130 -0
  37. data/app/assets/javascripts/datatables/plugins/pagination/select.js +97 -0
  38. data/app/assets/javascripts/datatables/plugins/pagination/simple_incremental_bootstrap.js +154 -0
  39. data/app/assets/javascripts/datatables/plugins/pagination/simple_numbers_no_ellipses.js +59 -0
  40. data/app/assets/javascripts/datatables/plugins/search/dataTables.alphabetSearch.js +440 -399
  41. data/app/assets/javascripts/datatables/plugins/sorting/enum.js +51 -0
  42. data/app/assets/javascripts/datatables/plugins/type-detection/date-dd-MMM-yyyy.js +63 -0
  43. data/app/assets/javascripts/datatables/plugins/type-detection/date-de.js +125 -0
  44. data/app/assets/javascripts/datatables/plugins/type-detection/date-eu.js +64 -0
  45. data/app/assets/javascripts/datatables/plugins/type-detection/date-euro.js +48 -0
  46. data/app/assets/javascripts/datatables/plugins/type-detection/date-uk.js +35 -12
  47. data/app/assets/javascripts/datatables/plugins/type-detection/datetime-moment.js +74 -0
  48. data/app/assets/javascripts/datatables/plugins/type-detection/datetime-us.js +86 -0
  49. data/app/assets/javascripts/datatables/plugins/type-detection/file-size.js +37 -13
  50. data/app/assets/javascripts/datatables/plugins/type-detection/ip-address.js +113 -11
  51. data/app/assets/javascripts/datatables/plugins/type-detection/numString.js +63 -0
  52. data/app/assets/javascripts/datatables/plugins/type-detection/percent.js +34 -0
  53. data/app/assets/javascripts/datatables/plugins/type-detection/time-elapsed-dhms.js +42 -0
  54. data/app/assets/javascripts/datatables/plugins/type-detection/time.js +56 -0
  55. data/app/assets/javascripts/datatables/plugins/type-detection/title-numeric.js +40 -0
  56. data/app/assets/javascripts/datatables/plugins/type-detection/title-string.js +36 -0
  57. data/app/assets/stylesheets/datatables/extensions/AutoFill/autoFill.dataTables.scss +10 -3
  58. data/app/assets/stylesheets/datatables/extensions/Buttons/buttons.bootstrap.scss +12 -3
  59. data/app/assets/stylesheets/datatables/extensions/Buttons/buttons.bootstrap4.scss +13 -6
  60. data/app/assets/stylesheets/datatables/extensions/Buttons/buttons.dataTables.scss +2 -0
  61. data/app/assets/stylesheets/datatables/extensions/Buttons/buttons.foundation.scss +5 -1
  62. data/app/assets/stylesheets/datatables/extensions/Buttons/buttons.jqueryui.scss +1 -0
  63. data/app/assets/stylesheets/datatables/extensions/Buttons/buttons.semanticui.scss +2 -1
  64. data/app/assets/stylesheets/datatables/extensions/Buttons/common.scss +10 -0
  65. data/app/assets/stylesheets/datatables/extensions/Buttons/mixins.scss +42 -30
  66. data/app/assets/stylesheets/datatables/extensions/FixedColumns/fixedColumns.bootstrap.scss +11 -7
  67. data/app/assets/stylesheets/datatables/extensions/FixedColumns/fixedColumns.foundation.scss +1 -0
  68. data/app/assets/stylesheets/datatables/extensions/KeyTable/keyTable.dataTables.scss +13 -5
  69. data/app/assets/stylesheets/datatables/extensions/RowGroup/rowGroup.dataTables.scss +20 -2
  70. data/app/assets/stylesheets/datatables/extensions/Scroller/scroller.dataTables.scss +15 -2
  71. data/lib/jquery-datatables/version.rb +1 -1
  72. metadata +26 -12
  73. data/app/assets/javascripts/datatables/dataTables.bootstrap2.js +0 -162
  74. data/app/assets/javascripts/datatables/extensions/ColReorder/colReorder.semanicui.js +0 -38
  75. data/app/assets/javascripts/datatables/extensions/FixedColumns/fixedColumns.semanicui.js +0 -38
  76. data/app/assets/javascripts/datatables/extensions/FixedHeader/fixedHeader.semanicui.js +0 -38
  77. data/app/assets/javascripts/datatables/extensions/KeyTable/keyTable.semanicui.js +0 -38
  78. data/app/assets/javascripts/datatables/extensions/RowReorder/rowReorder.semanicui.js +0 -38
  79. data/app/assets/stylesheets/datatables/dataTables.bootstrap2.scss +0 -178
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Plug-in offers the same functionality as `simple_numbers` pagination type
3
+ * (see `pagingType` option) but without ellipses.
4
+ *
5
+ * See [example](http://www.gyrocode.com/articles/jquery-datatables-pagination-without-ellipses) for demonstration.
6
+ *
7
+ * @name Simple Numbers - No Ellipses
8
+ * @summary Same pagination as 'simple_numbers' but without ellipses
9
+ * @author [Michael Ryvkin](http://www.gyrocode.com)
10
+ *
11
+ * @example
12
+ * $(document).ready(function() {
13
+ * $('#example').dataTable( {
14
+ * "pagingType": "simple_numbers_no_ellipses"
15
+ * } );
16
+ * } );
17
+ */
18
+
19
+ $.fn.DataTable.ext.pager.simple_numbers_no_ellipses = function(page, pages){
20
+ var numbers = [];
21
+ var buttons = $.fn.DataTable.ext.pager.numbers_length;
22
+ var half = Math.floor( buttons / 2 );
23
+
24
+ var _range = function ( len, start ){
25
+ var end;
26
+
27
+ if ( typeof start === "undefined" ){
28
+ start = 0;
29
+ end = len;
30
+
31
+ } else {
32
+ end = start;
33
+ start = len;
34
+ }
35
+
36
+ var out = [];
37
+ for ( var i = start ; i < end; i++ ){ out.push(i); }
38
+
39
+ return out;
40
+ };
41
+
42
+
43
+ if ( pages <= buttons ) {
44
+ numbers = _range( 0, pages );
45
+
46
+ } else if ( page <= half ) {
47
+ numbers = _range( 0, buttons);
48
+
49
+ } else if ( page >= pages - 1 - half ) {
50
+ numbers = _range( pages - buttons, pages );
51
+
52
+ } else {
53
+ numbers = _range( page - half, page + half + 1);
54
+ }
55
+
56
+ numbers.DT_el = 'span';
57
+
58
+ return [ 'previous', numbers, 'next' ];
59
+ };
@@ -1,399 +1,440 @@
1
- /*! AlphabetSearch for DataTables v1.2.4
2
- * 2014 SpryMedia Ltd - datatables.net/license
3
- * Gyrocode - MIT License
4
- */
5
-
6
- /**
7
- * @summary AlphabetSearch
8
- * @description Show an set of alphabet buttons alongside a table providing
9
- * search input options
10
- * @version 1.2.4
11
- * @file dataTables.alphabetSearch.js
12
- * @author SpryMedia Ltd (www.sprymedia.co.uk)
13
- * @contact www.sprymedia.co.uk/contact
14
- * @copyright Copyright 2014 SpryMedia Ltd.
15
- * @author Gyrocode (www.gyrocode.com)
16
- * @contact www.gyrocode.com/contacts
17
- * @copyright Copyright (c) Gyrocode
18
- *
19
- * License MIT - http://datatables.net/license/mit
20
- *
21
- * For more detailed information please see:
22
- * https://www.gyrocode.com/projects/jquery-datatables-alphabetsearch/
23
- */
24
- (function(){
25
-
26
-
27
- // Search function
28
- $.fn.dataTable.Api.register( 'alphabetSearch()', function ( searchTerm ) {
29
- this.iterator( 'table', function ( context ) {
30
- context.alphabetSearch.letter = searchTerm;
31
- } );
32
-
33
- return this;
34
- } );
35
-
36
- // Recalculate the alphabet display for updated data
37
- $.fn.dataTable.Api.register( 'alphabetSearch.recalc()', function () {
38
- this.iterator( 'table', function ( context ) {
39
- draw(
40
- new $.fn.dataTable.Api( context ),
41
- $('div.alphabet', this.table().container()),
42
- context
43
- );
44
- } );
45
-
46
- return this;
47
- } );
48
-
49
-
50
- // Search plug-in
51
- $.fn.dataTable.ext.search.push( function ( context, searchData ) {
52
- // Ensure that table has alphabet search feature enabled
53
- if ( ! context.hasOwnProperty('alphabetSearch') ) {
54
- return true;
55
- }
56
-
57
- // Ensure that there is a search applied to this table before running it
58
- if ( ! context.alphabetSearch.letterSearch ) {
59
- return true;
60
- }
61
-
62
- var letter = searchData[context.alphabetSearch.column]
63
- .toString()
64
- .replace(/<.*?>/g, '')
65
- .charAt(0).toUpperCase();
66
-
67
-
68
- if(context.alphabetSearch.letterSearch !== '#'){
69
- if ( letter === context.alphabetSearch.letterSearch ) {
70
- return true;
71
- }
72
- } else {
73
- if(/\d/.test(letter)){
74
- return true;
75
- }
76
- }
77
-
78
- return false;
79
- } );
80
-
81
-
82
- // Order plug-in
83
- //
84
- // NOTES: If sorting by alphabetized column
85
- // there would be two calls to this method
86
- $.fn.dataTable.ext.order['alphabetSearch'] = function ( context, col )
87
- {
88
- var order_col = this.api().order()[0][0];
89
- var order_method = this.api().order()[0][1];
90
-
91
- // If sorting by column other than the one being alphabetized
92
- if(order_col !== context.alphabetSearch.column){
93
- context.alphabetSearch.pass = 0;
94
- }
95
-
96
- var data = this.api().column( col, { order: 'index' } ).data().map( function (value, index) {
97
- var letter = value.replace(/<.*?>/g, '').charAt(0).toUpperCase();
98
-
99
- // If sorting by alphabetized column
100
- return (order_col === context.alphabetSearch.column)
101
- ? (
102
- // If first pass
103
- ( !context.alphabetSearch.pass )
104
- // Ignore
105
- ?
106
- ''
107
- // Otherwise, if it's a second pass
108
- :
109
- (
110
- // If method is ascending sort
111
- ( order_method === 'asc' )
112
- // Return first letter
113
- ? letter
114
- : String.fromCharCode(65535 - letter.charCodeAt(0))
115
- )
116
- )
117
- // Otherwise, if sorting by column other than the one being alphabetized,
118
- // return first letter
119
- : letter;
120
- } );
121
-
122
- // If sorting by alphabetized column
123
- if(order_col === context.alphabetSearch.column){
124
- // If pass is not defined, set it to 0
125
- if(!context.alphabetSearchPass){ context.alphabetSearch.pass = 0; }
126
- // Increment pass counter and reset it to 0 if it's a second pass
127
- context.alphabetSearch.pass = (context.alphabetSearch.pass + 1) % 2;
128
- }
129
-
130
- return data;
131
- };
132
-
133
-
134
- // Private support methods
135
- function bin ( data ) {
136
- var letter, bins = {};
137
-
138
- for ( var i=0, ien=data.length ; i<ien ; i++ ) {
139
- letter = data[i]
140
- .toString()
141
- .replace(/<.*?>/g, '')
142
- .charAt(0).toUpperCase();
143
-
144
- if(/\d/.test(letter)){ letter = '#'; }
145
-
146
- if ( bins[letter] ) {
147
- bins[letter]++;
148
- }
149
- else {
150
- bins[letter] = 1;
151
- }
152
- }
153
-
154
- return bins;
155
- }
156
-
157
- function draw ( table, alphabet, context )
158
- {
159
- alphabet.empty();
160
-
161
- if(context.oLanguage.alphabetSearch.infoDisplay !== ''){
162
- $('<span class="alphabet-info-display"></span>')
163
- .html(context.oLanguage.alphabetSearch.infoDisplay)
164
- .appendTo( alphabet );
165
- }
166
-
167
- var columnData = table.column(context.alphabetSearch.column, { search: 'applied' } ).data();
168
- var bins = bin( columnData );
169
-
170
- var alphabetList = $('<ul/>');
171
-
172
- $('<a/>')
173
- .attr( 'href', 'javascript:;' )
174
- .data( 'letter', '' )
175
- .data( 'match-count', columnData.length )
176
- .addClass(
177
- ((!context.alphabetSearch.letter) ? 'active' : '')
178
- )
179
- .html( '<span>' + context.oLanguage.alphabetSearch.infoAll + '</span>' )
180
- .wrap( '<li/>' )
181
- .parent()
182
- .appendTo( alphabetList );
183
-
184
- for ( var i=0 ; i<context.oLanguage.alphabetSearch.alphabet.length ; i++ ) {
185
- var letter = context.oLanguage.alphabetSearch.alphabet[i];
186
-
187
- $('<a/>')
188
- .attr( 'href', 'javascript:;' )
189
- .data( 'letter', letter )
190
- .data( 'match-count', bins[letter] || 0 )
191
- .addClass(
192
- (! bins[letter] ? 'empty' : '')
193
- + ((context.alphabetSearch.letter === letter) ? ' active' : '')
194
- )
195
- .html( '<span>' + letter + '</span>' )
196
- .wrap( '<li/>' )
197
- .parent()
198
- .appendTo( alphabetList );
199
- }
200
-
201
- alphabetList.appendTo( alphabet );
202
-
203
- $('<div class="alphabet-info"></div>')
204
- .appendTo( alphabet );
205
-
206
-
207
- // Perform second rendering
208
- // needed to filter search results by letter
209
- // NOTE: Future optimization is needed to avoid rendering twice
210
- // when no search is performed
211
-
212
- // If letter is selected
213
- if(context.alphabetSearch.letter){
214
- // Apply filtering by letter
215
- context.alphabetSearch.letterSearch = context.alphabetSearch.letter;
216
-
217
- // Redraw table
218
- table.draw();
219
-
220
- // Remove filtering by letter
221
- context.alphabetSearch.letterSearch = '';
222
- }
223
-
224
- // Handle search event here only once
225
- // when alphabet panel has been drawn
226
- // because we are performing two-step rendering
227
- // that could trigger search hanlder when not needed
228
- table.one('search', function (e, context) {
229
- var api = new $.fn.dataTable.Api( context );
230
-
231
- // Redraw alphabet panel
232
- api.alphabetSearch.recalc();
233
- });
234
- }
235
-
236
-
237
- $.fn.dataTable.AlphabetSearch = function ( context ) {
238
- var table = new $.fn.dataTable.Api( context );
239
- var alphabet = $('<div class="alphabet"/>');
240
-
241
- // Language
242
- context.oLanguage.alphabetSearch =
243
- $.extend(
244
- {
245
- 'alphabet': '#ABCDEFGHIJKLMNOPQRSTUVWXYZ',
246
- 'infoDisplay': 'Display:',
247
- 'infoAll': 'All'
248
- },
249
- ((context.oLanguage.alphabetSearch)
250
- ? context.oLanguage.alphabetSearch
251
- : {}
252
- )
253
- );
254
- // Convert alphabet to uppercase
255
- context.oLanguage.alphabetSearch.alphabet.toUpperCase();
256
-
257
- context.alphabetSearch =
258
- $.extend(
259
- {
260
- column: 0
261
- },
262
- $.isPlainObject(context.oInit.alphabetSearch) ? context.oInit.alphabetSearch : {},
263
- {
264
- letter: '',
265
- letterSearch: '',
266
- pass: 0
267
- }
268
- );
269
-
270
- // Set required "orderDataType" ("sSortDataType") for a column
271
- if(context.alphabetSearch.column >= 0 && context.alphabetSearch.column < context.aoColumns.length){
272
- context.aoColumns[context.alphabetSearch.column].sSortDataType = 'alphabetSearch';
273
- }
274
-
275
- // Add column containing names to a list of columns
276
- // where ordering will be always applied to the table
277
- if( context.hasOwnProperty('aaSortingFixed')
278
- && typeof context.aaSortingFixed === 'object' )
279
- {
280
- if( $.isArray(context.aaSortingFixed) ){
281
- if( context.aaSortingFixed.length && !$.isArray( context.aaSortingFixed[0] ) ) {
282
- // 1D array
283
- context.aaSortingFixed = [[context.alphabetSearch.column, 'asc'], context.aaSortingFixed];
284
-
285
- } else {
286
- // 2D array
287
- context.aaSortingFixed.unshift([context.alphabetSearch.column, 'asc']);
288
- }
289
- } else {
290
- if( !context.aaSortingFixed.hasOwnProperty('pre') ){
291
- context.aaSortingFixed.pre = [];
292
- }
293
-
294
- if( context.aaSortingFixed.pre.length && !$.isArray( context.aaSortingFixed.pre[0] ) ) {
295
- // 1D array
296
- context.aaSortingFixed.pre = [[context.alphabetSearch.column, 'asc'], context.aaSortingFixed.pre];
297
-
298
- } else {
299
- // 2D array
300
- context.aaSortingFixed.pre.unshift([context.alphabetSearch.column, 'asc']);
301
- }
302
- }
303
-
304
- } else {
305
- context.aaSortingFixed = [context.alphabetSearch.column, 'asc'];
306
- }
307
-
308
-
309
- draw( table, alphabet, context );
310
-
311
-
312
- // Trigger a search
313
- alphabet.on( 'click', 'a', function (e) {
314
- // Prevent default behavior
315
- e.preventDefault();
316
-
317
- alphabet.find( '.active' ).removeClass( 'active' );
318
- $(this).addClass( 'active' );
319
-
320
- table
321
- .alphabetSearch( $(this).data('letter') )
322
- .draw();
323
- } );
324
-
325
- // Mouse events to show helper information
326
- alphabet
327
- .on( 'mouseenter', 'a', function () {
328
- var $el = $(this);
329
- var el_pos = $el.position();
330
-
331
- var $alphabet_info = $('.alphabet-info', alphabet);
332
-
333
- $alphabet_info.html( $el.data('match-count') );
334
-
335
- // Display helper centered horizontally under the letter
336
- $alphabet_info
337
- .css( {
338
- opacity: 1,
339
- left: el_pos.left + Math.round(($el.outerWidth() - $alphabet_info.outerWidth())/2),
340
- top: $(this).position().top + $el.outerHeight()
341
- } );
342
- } )
343
- .on( 'mouseleave', 'a', function () {
344
- alphabet
345
- .find('div.alphabet-info')
346
- .css('opacity', 0);
347
- } );
348
-
349
- table.on('draw', function (e, context) {
350
- var api = new $.fn.dataTable.Api( context );
351
-
352
- // Total number of column nodes
353
- var col_total = api.columns().nodes().length;
354
-
355
- var rows = api.rows({ page: 'current' }).nodes();
356
- var group_last = null;
357
-
358
- api.column(context.alphabetSearch.column, { page: 'current' }).data().each(function (name, index){
359
- var group = name.replace(/<.*?>/g, '').charAt(0).toUpperCase();
360
-
361
- if (group_last !== group) {
362
- $(rows).eq(index).before(
363
- '<tr class="alphabet-group"><td colspan="' + col_total + '">' + group + '</td></tr>'
364
- );
365
-
366
- group_last = group;
367
- }
368
- });
369
-
370
- // If there are no rows found and letter is selected
371
- if(!rows.length && context.alphabetSearch){
372
- var letter = context.alphabetSearch.letter;
373
-
374
- $(api.table().body()).prepend(
375
- '<tr class="alphabet-group"><td colspan="' + col_total + '">' + letter + '</td></tr>'
376
- );
377
- }
378
- });
379
-
380
- // API method to get the alphabet container node
381
- this.node = function () {
382
- return alphabet;
383
- };
384
- };
385
-
386
- $.fn.DataTable.AlphabetSearch = $.fn.dataTable.AlphabetSearch;
387
-
388
-
389
- // Register a search plug-in
390
- $.fn.dataTable.ext.feature.push( {
391
- fnInit: function ( settings ) {
392
- var search = new $.fn.dataTable.AlphabetSearch( settings );
393
- return search.node();
394
- },
395
- cFeature: 'A'
396
- } );
397
-
398
-
399
- }());
1
+ /*! AlphabetSearch for DataTables v1.2.7
2
+ * 2014 SpryMedia Ltd - datatables.net/license
3
+ * Gyrocode LLC - MIT License
4
+ */
5
+
6
+ /**
7
+ * @summary AlphabetSearch
8
+ * @description Show an set of alphabet buttons alongside a table providing
9
+ * search input options
10
+ * @version 1.2.7
11
+ * @file dataTables.alphabetSearch.js
12
+ * @author SpryMedia Ltd (www.sprymedia.co.uk)
13
+ * @contact www.sprymedia.co.uk/contact
14
+ * @copyright Copyright 2014 SpryMedia Ltd.
15
+ * @author Gyrocode LLC (www.gyrocode.com)
16
+ * @contact www.gyrocode.com/contacts
17
+ * @copyright Copyright (c) Gyrocode LLC
18
+ *
19
+ * License MIT - http://datatables.net/license/mit
20
+ *
21
+ * For more detailed information please see:
22
+ * https://www.gyrocode.com/projects/jquery-datatables-alphabetsearch/
23
+ */
24
+ (function($){
25
+
26
+
27
+ // Search function
28
+ $.fn.dataTable.Api.register( 'alphabetSearch()', function ( searchTerm ) {
29
+ this.iterator( 'table', function ( context ) {
30
+ context.alphabetSearch.letter = searchTerm;
31
+ } );
32
+
33
+ return this;
34
+ } );
35
+
36
+ // Recalculate the alphabet display for updated data
37
+ $.fn.dataTable.Api.register( 'alphabetSearch.recalc()', function () {
38
+ this.iterator( 'table', function ( context ) {
39
+ draw(
40
+ new $.fn.dataTable.Api( context ),
41
+ $('div.alphabet', this.table().container()),
42
+ context
43
+ );
44
+ } );
45
+
46
+ return this;
47
+ } );
48
+
49
+
50
+ // Search plug-in
51
+ $.fn.dataTable.ext.search.push( function ( context, searchData ) {
52
+ // Ensure that table has alphabet search feature enabled
53
+ if ( ! context.hasOwnProperty('alphabetSearch') ) {
54
+ return true;
55
+ }
56
+
57
+ // Ensure that there is a search applied to this table before running it
58
+ if ( ! context.alphabetSearch.letterSearch ) {
59
+ return true;
60
+ }
61
+
62
+ var letter = searchData[context.alphabetSearch.column]
63
+ .toString()
64
+ .replace(/<.*?>/g, '')
65
+ .charAt(0).toUpperCase();
66
+
67
+
68
+ if(context.alphabetSearch.letterSearch !== '#'){
69
+ if ( letter === context.alphabetSearch.letterSearch ) {
70
+ return true;
71
+ }
72
+ } else {
73
+ if(/\d/.test(letter)){
74
+ return true;
75
+ }
76
+ }
77
+
78
+ return false;
79
+ } );
80
+
81
+
82
+ // Order plug-in
83
+ //
84
+ // NOTE: If sorting by alphabetized column there would be two calls to this method.
85
+ $.fn.dataTable.ext.order['alphabetSearch'] = function ( context, col )
86
+ {
87
+ var orderColumn = this.api().order()[0][0];
88
+ var orderMethod = this.api().order()[0][1];
89
+
90
+ // If sorting by column other than the one being alphabetized
91
+ if(orderColumn !== context.alphabetSearch.column){
92
+ context.alphabetSearch.pass = 0;
93
+ }
94
+
95
+ var data = this.api().column( col, { order: 'index' } ).data().map( function (value, index) {
96
+ var text = value.toString().replace(/<.*?>/g, '');
97
+ var letter = text.charAt(0).toUpperCase();
98
+
99
+ // If sorting by alphabetized column
100
+ if(orderColumn === context.alphabetSearch.column) {
101
+
102
+ // If this is a first pass
103
+ if(context.alphabetSearch.pass === 0){
104
+ // Ignore
105
+ return '';
106
+
107
+ // Otherwise, if this is a second pass
108
+ } else {
109
+ // When sorting in ascending order
110
+ if (orderMethod === 'asc'){
111
+ // Return actual content
112
+ return text;
113
+
114
+ // Otherwise, when sorting in descending order
115
+ } else {
116
+ var textReversed = '';
117
+
118
+ // If letter search is applied to the table
119
+ if(context.alphabetSearch.letterSearch) {
120
+ // Reverse (take characters from the oposite side of the character table) all characters.
121
+ //
122
+ // NOTE: Allows to sort alphabetized column in descending order
123
+ // by returning reversed text
124
+ // to compensate fixed ascending order applied during initialization.
125
+ //
126
+ // TODO: Better solution would be to find a way to manipulate first element
127
+ // of the context.aaSortingFixed array before each sort.
128
+
129
+ for(var i = 0; i < text.length; i++){
130
+ textReversed += String.fromCharCode(65535 - text.charCodeAt(i));
131
+ }
132
+
133
+ // Otherwise, if letter search is not applied to the table
134
+ } else {
135
+ // Reverse (take characters from the oposite side of the character table) first character.
136
+ //
137
+ // NOTE: Allows to sort group of rows by first letter in descending order
138
+ // but preserve ascending order within each group.
139
+
140
+ for(var i = 0; i < text.length; i++){
141
+ textReversed += (i) ? text.charAt(i) : String.fromCharCode(65535 - text.charCodeAt(i));
142
+ }
143
+ }
144
+
145
+ return textReversed;
146
+ }
147
+ }
148
+
149
+ // Otherwise, if sorting by column other than the one being alphabetized,
150
+ } else {
151
+ // Return first letter only
152
+ return letter;
153
+ }
154
+ } );
155
+
156
+ // If sorting by alphabetized column
157
+ if(orderColumn === context.alphabetSearch.column){
158
+ // If pass is not defined, set it to 0
159
+ if(!context.alphabetSearch.pass){ context.alphabetSearch.pass = 0; }
160
+ // Increment pass counter and reset it to 0 if it's a second pass
161
+ context.alphabetSearch.pass = (context.alphabetSearch.pass + 1) % 2;
162
+ }
163
+
164
+ return data;
165
+ };
166
+
167
+
168
+ // Private support methods
169
+ function bin ( data ) {
170
+ var letter, bins = {};
171
+
172
+ for ( var i=0, ien=data.length ; i<ien ; i++ ) {
173
+ letter = data[i]
174
+ .toString()
175
+ .replace(/<.*?>/g, '')
176
+ .charAt(0).toUpperCase();
177
+
178
+ if(/\d/.test(letter)){ letter = '#'; }
179
+
180
+ if ( bins[letter] ) {
181
+ bins[letter]++;
182
+ }
183
+ else {
184
+ bins[letter] = 1;
185
+ }
186
+ }
187
+
188
+ return bins;
189
+ }
190
+
191
+ function draw ( table, alphabet, context )
192
+ {
193
+ alphabet.empty();
194
+
195
+ if(context.oLanguage.alphabetSearch.infoDisplay !== ''){
196
+ $('<span class="alphabet-info-display"></span>')
197
+ .html(context.oLanguage.alphabetSearch.infoDisplay)
198
+ .appendTo( alphabet );
199
+ }
200
+
201
+ var columnData = table.column(context.alphabetSearch.column, { search: 'applied' } ).data();
202
+ var bins = bin( columnData );
203
+
204
+ var alphabetList = $('<ul/>');
205
+
206
+ $('<a/>')
207
+ .attr( 'href', 'javascript:;' )
208
+ .data( 'letter', '' )
209
+ .data( 'match-count', columnData.length )
210
+ .addClass(
211
+ ((!context.alphabetSearch.letter) ? 'active' : '')
212
+ )
213
+ .html( '<span>' + context.oLanguage.alphabetSearch.infoAll + '</span>' )
214
+ .wrap( '<li/>' )
215
+ .parent()
216
+ .appendTo( alphabetList );
217
+
218
+ for ( var i=0 ; i<context.oLanguage.alphabetSearch.alphabet.length ; i++ ) {
219
+ var letter = context.oLanguage.alphabetSearch.alphabet[i];
220
+
221
+ $('<a/>')
222
+ .attr( 'href', 'javascript:;' )
223
+ .data( 'letter', letter )
224
+ .data( 'match-count', bins[letter] || 0 )
225
+ .addClass(
226
+ (! bins[letter] ? 'empty' : '')
227
+ + ((context.alphabetSearch.letter === letter) ? ' active' : '')
228
+ )
229
+ .html( '<span>' + letter + '</span>' )
230
+ .wrap( '<li/>' )
231
+ .parent()
232
+ .appendTo( alphabetList );
233
+ }
234
+
235
+ alphabetList.appendTo( alphabet );
236
+
237
+ $('<div class="alphabet-info"></div>')
238
+ .appendTo( alphabet );
239
+
240
+
241
+ // Perform second rendering
242
+ // needed to filter search results by letter
243
+ // NOTE: Future optimization is needed to avoid rendering twice
244
+ // when no search is performed
245
+
246
+ // If letter is selected
247
+ if(context.alphabetSearch.letter){
248
+ // Apply filtering by letter
249
+ context.alphabetSearch.letterSearch = context.alphabetSearch.letter;
250
+
251
+ // Redraw table
252
+ table.draw();
253
+
254
+ // Remove filtering by letter
255
+ context.alphabetSearch.letterSearch = '';
256
+ }
257
+
258
+ // Handle search event here only once
259
+ // when alphabet panel has been drawn
260
+ // because we are performing two-step rendering
261
+ // that could trigger search hanlder when not needed
262
+ table.one('search.dt.dtAlphabetSearch', function (e, context) {
263
+ var api = new $.fn.dataTable.Api( context );
264
+
265
+ // Redraw alphabet panel
266
+ api.alphabetSearch.recalc();
267
+ });
268
+ }
269
+
270
+
271
+ $.fn.dataTable.AlphabetSearch = function ( context ) {
272
+ var table = new $.fn.dataTable.Api( context );
273
+ var alphabet = $('<div class="alphabet"/>');
274
+
275
+ // Language
276
+ context.oLanguage.alphabetSearch =
277
+ $.extend(
278
+ {
279
+ 'alphabet': '#ABCDEFGHIJKLMNOPQRSTUVWXYZ',
280
+ 'infoDisplay': 'Display:',
281
+ 'infoAll': 'All'
282
+ },
283
+ ((context.oLanguage.alphabetSearch)
284
+ ? context.oLanguage.alphabetSearch
285
+ : {}
286
+ )
287
+ );
288
+ // Convert alphabet to uppercase
289
+ context.oLanguage.alphabetSearch.alphabet.toUpperCase();
290
+
291
+ context.alphabetSearch =
292
+ $.extend(
293
+ {
294
+ column: 0
295
+ },
296
+ $.isPlainObject(context.oInit.alphabetSearch) ? context.oInit.alphabetSearch : {},
297
+ {
298
+ letter: '',
299
+ letterSearch: '',
300
+ pass: 0
301
+ }
302
+ );
303
+
304
+ // Set required "orderDataType" ("sSortDataType") for a column
305
+ if(context.alphabetSearch.column >= 0 && context.alphabetSearch.column < context.aoColumns.length){
306
+ context.aoColumns[context.alphabetSearch.column].sSortDataType = 'alphabetSearch';
307
+ }
308
+
309
+ // Add column containing names to a list of columns
310
+ // where ordering will be always applied to the table
311
+ if( context.hasOwnProperty('aaSortingFixed')
312
+ && typeof context.aaSortingFixed === 'object' )
313
+ {
314
+ if( $.isArray(context.aaSortingFixed) ){
315
+ if( context.aaSortingFixed.length && !$.isArray( context.aaSortingFixed[0] ) ) {
316
+ // 1D array
317
+ context.aaSortingFixed = [[context.alphabetSearch.column, 'asc'], context.aaSortingFixed];
318
+
319
+ } else {
320
+ // 2D array
321
+ context.aaSortingFixed.unshift([context.alphabetSearch.column, 'asc']);
322
+ }
323
+ } else {
324
+ if( !context.aaSortingFixed.hasOwnProperty('pre') ){
325
+ context.aaSortingFixed.pre = [];
326
+ }
327
+
328
+ if( context.aaSortingFixed.pre.length && !$.isArray( context.aaSortingFixed.pre[0] ) ) {
329
+ // 1D array
330
+ context.aaSortingFixed.pre = [[context.alphabetSearch.column, 'asc'], context.aaSortingFixed.pre];
331
+
332
+ } else {
333
+ // 2D array
334
+ context.aaSortingFixed.pre.unshift([context.alphabetSearch.column, 'asc']);
335
+ }
336
+ }
337
+
338
+ } else {
339
+ context.aaSortingFixed = [context.alphabetSearch.column, 'asc'];
340
+ }
341
+
342
+
343
+ draw( table, alphabet, context );
344
+
345
+
346
+ // Trigger a search
347
+ alphabet.on( 'click', 'a', function (e) {
348
+ // Prevent default behavior
349
+ e.preventDefault();
350
+
351
+ alphabet.find( '.active' ).removeClass( 'active' );
352
+ $(this).addClass( 'active' );
353
+
354
+ table
355
+ .alphabetSearch( $(this).data('letter') )
356
+ .draw();
357
+ } );
358
+
359
+ // Mouse events to show helper information
360
+ alphabet
361
+ .on( 'mouseenter', 'a', function () {
362
+ var $el = $(this);
363
+ var el_pos = $el.position();
364
+
365
+ var $alphabet_info = $('.alphabet-info', alphabet);
366
+
367
+ $alphabet_info.html( $el.data('match-count') );
368
+
369
+ // Display helper centered horizontally under the letter
370
+ $alphabet_info
371
+ .css( {
372
+ opacity: 1,
373
+ left: el_pos.left + Math.round(($el.outerWidth() - $alphabet_info.outerWidth())/2),
374
+ top: $(this).position().top + $el.outerHeight()
375
+ } );
376
+ } )
377
+ .on( 'mouseleave', 'a', function () {
378
+ alphabet
379
+ .find('div.alphabet-info')
380
+ .css('opacity', 0);
381
+ } );
382
+
383
+ // Handle table draw event
384
+ table.on('draw.dt.dtAlphabetSearch', function (e, context) {
385
+ var api = new $.fn.dataTable.Api( context );
386
+
387
+ // Total number of column nodes
388
+ var col_total = api.columns().nodes().length;
389
+
390
+ var rows = api.rows({ page: 'current' }).nodes();
391
+ var group_last = null;
392
+
393
+ api.column(context.alphabetSearch.column, { page: 'current' }).data().each(function (name, index){
394
+ var group = name.toString().replace(/<.*?>/g, '').charAt(0).toUpperCase();
395
+
396
+ if (group_last !== group) {
397
+ $(rows).eq(index).before(
398
+ '<tr class="alphabet-group"><td colspan="' + col_total + '">' + group + '</td></tr>'
399
+ );
400
+
401
+ group_last = group;
402
+ }
403
+ });
404
+
405
+ // If there are no rows found and letter is selected
406
+ if(!rows.length && context.alphabetSearch){
407
+ var letter = context.alphabetSearch.letter;
408
+
409
+ $(api.table().body()).prepend(
410
+ '<tr class="alphabet-group"><td colspan="' + col_total + '">' + letter + '</td></tr>'
411
+ );
412
+ }
413
+ });
414
+
415
+ // Handle table destroy event
416
+ table.on('destroy.dt.dtAlphabetSearch', function(e, context){
417
+ var api = new $.fn.dataTable.Api( context );
418
+ api.off('.dtAlphabetSearch');
419
+ });
420
+
421
+ // API method to get the alphabet container node
422
+ this.node = function () {
423
+ return alphabet;
424
+ };
425
+ };
426
+
427
+ $.fn.DataTable.AlphabetSearch = $.fn.dataTable.AlphabetSearch;
428
+
429
+
430
+ // Register a search plug-in
431
+ $.fn.dataTable.ext.feature.push( {
432
+ fnInit: function ( settings ) {
433
+ var search = new $.fn.dataTable.AlphabetSearch( settings );
434
+ return search.node();
435
+ },
436
+ cFeature: 'A'
437
+ } );
438
+
439
+
440
+ }(jQuery));