foo_table-rails 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,546 @@
1
+ /*!
2
+ * FooTable - Awesome Responsive Tables
3
+ * Version : 0.5
4
+ * http://themergency.com/footable
5
+ *
6
+ * Requires jQuery - http://jquery.com/
7
+ *
8
+ * Copyright 2012 Steven Usher & Brad Vincent
9
+ * Released under the MIT license
10
+ * You are free to use FooTable in commercial projects as long as this copyright header is left intact.
11
+ *
12
+ * Date: 22 Apr 2013
13
+ */
14
+ (function ($, w, undefined) {
15
+ w.footable = {
16
+ options: {
17
+ delay: 100, // The number of millseconds to wait before triggering the react event
18
+ breakpoints: { // The different screen resolution breakpoints
19
+ phone: 480,
20
+ tablet: 1024
21
+ },
22
+ parsers: { // The default parser to parse the value out of a cell (values are used in building up row detail)
23
+ alpha: function (cell) {
24
+ return $(cell).data('value') || $.trim($(cell).text());
25
+ }
26
+ },
27
+ calculateWidthAndHeightOverride: null,
28
+ toggleSelector: ' > tbody > tr:not(.footable-row-detail)', //the selector to show/hide the detail row
29
+ columnDataSelector: '> thead > tr:last-child > th, > thead > tr:last-child > td', //the selector used to find the column data in the thead
30
+ createDetail: function (element, data) {
31
+ /// <summary>This function is used by FooTable to generate the detail view seen when expanding a collapsed row.</summary>
32
+ /// <param name="element">This is the div that contains all the detail row information, anything could be added to it.</param>
33
+ /// <param name="data">
34
+ /// This is an array of objects containing the cell information for the current row.
35
+ /// These objects look like the below:
36
+ /// obj = {
37
+ /// 'name': String, // The name of the column
38
+ /// 'value': Object, // The value parsed from the cell using the parsers. This could be a string, a number or whatever the parser outputs.
39
+ /// 'display': String, // This is the actual HTML from the cell, so if you have images etc you want moved this is the one to use and is the default value used.
40
+ /// 'group': String, // This is the identifier used in the data-group attribute of the column.
41
+ /// 'groupName': String // This is the actual name of the group the column belongs to.
42
+ /// }
43
+ /// </param>
44
+
45
+ var groups = { '_none': { 'name': null, 'data': [] } };
46
+ for (var i = 0; i < data.length; i++) {
47
+ var groupid = data[i].group;
48
+ if (groupid != null) {
49
+ if (!(groupid in groups))
50
+ groups[groupid] = { 'name': data[i].groupName, 'data': [] };
51
+
52
+ groups[groupid].data.push(data[i]);
53
+ } else {
54
+ groups._none.data.push(data[i]);
55
+ }
56
+ }
57
+
58
+ for (var group in groups) {
59
+ if (groups[group].data.length == 0) continue;
60
+ if (group != '_none') element.append('<h4>' + groups[group].name + '</h4>');
61
+
62
+ for (var j = 0; j < groups[group].data.length; j++) {
63
+ element.append('<div><strong>' + groups[group].data[j].name + '</strong> : ' + groups[group].data[j].display + '</div>');
64
+ }
65
+ }
66
+ },
67
+ classes: {
68
+ loading: 'footable-loading',
69
+ loaded: 'footable-loaded',
70
+ sorted: 'footable-sorted',
71
+ descending: 'footable-sorted-desc',
72
+ indicator: 'footable-sort-indicator'
73
+ },
74
+ debug: false // Whether or not to log information to the console.
75
+ },
76
+
77
+ version: {
78
+ major: 0, minor: 5,
79
+ toString: function () {
80
+ return w.footable.version.major + '.' + w.footable.version.minor;
81
+ },
82
+ parse: function (str) {
83
+ version = /(\d+)\.?(\d+)?\.?(\d+)?/.exec(str);
84
+ return {
85
+ major: parseInt(version[1]) || 0,
86
+ minor: parseInt(version[2]) || 0,
87
+ patch: parseInt(version[3]) || 0
88
+ };
89
+ }
90
+ },
91
+
92
+ plugins: {
93
+ _validate: function (plugin) {
94
+ ///<summary>Simple validation of the <paramref name="plugin"/> to make sure any members called by Foobox actually exist.</summary>
95
+ ///<param name="plugin">The object defining the plugin, this should implement a string property called "name" and a function called "init".</param>
96
+
97
+ if (typeof plugin['name'] !== 'string') {
98
+ if (w.footable.options.debug == true) console.error('Validation failed, plugin does not implement a string property called "name".', plugin);
99
+ return false;
100
+ }
101
+ if (!$.isFunction(plugin['init'])) {
102
+ if (w.footable.options.debug == true) console.error('Validation failed, plugin "' + plugin['name'] + '" does not implement a function called "init".', plugin);
103
+ return false;
104
+ }
105
+ if (w.footable.options.debug == true) console.log('Validation succeeded for plugin "' + plugin['name'] + '".', plugin);
106
+ return true;
107
+ },
108
+ registered: [], // An array containing all registered plugins.
109
+ register: function (plugin, options) {
110
+ ///<summary>Registers a <paramref name="plugin"/> and its default <paramref name="options"/> with Foobox.</summary>
111
+ ///<param name="plugin">The plugin that should implement a string property called "name" and a function called "init".</param>
112
+ ///<param name="options">The default options to merge with the Foobox's base options.</param>
113
+
114
+ if (w.footable.plugins._validate(plugin)) {
115
+ w.footable.plugins.registered.push(plugin);
116
+ if (options != undefined && typeof options === 'object') $.extend(true, w.footable.options, options);
117
+ if (w.footable.options.debug == true) console.log('Plugin "' + plugin['name'] + '" has been registered with the Foobox.', plugin);
118
+ }
119
+ },
120
+ init: function (instance) {
121
+ ///<summary>Loops through all registered plugins and calls the "init" method supplying the current <paramref name="instance"/> of the Foobox as the first parameter.</summary>
122
+ ///<param name="instance">The current instance of the Foobox that the plugin is being initialized for.</param>
123
+
124
+ for (var i = 0; i < w.footable.plugins.registered.length; i++) {
125
+ try {
126
+ w.footable.plugins.registered[i]['init'](instance);
127
+ } catch (err) {
128
+ if (w.footable.options.debug == true) console.error(err);
129
+ }
130
+ }
131
+ }
132
+ }
133
+ };
134
+
135
+ var instanceCount = 0;
136
+
137
+ $.fn.footable = function (options) {
138
+ ///<summary>The main constructor call to initialize the plugin using the supplied <paramref name="options"/>.</summary>
139
+ ///<param name="options">
140
+ ///<para>A JSON object containing user defined options for the plugin to use. Any options not supplied will have a default value assigned.</para>
141
+ ///<para>Check the documentation or the default options object above for more information on available options.</para>
142
+ ///</param>
143
+
144
+ options = options || {};
145
+ var o = $.extend(true, {}, w.footable.options, options); //merge user and default options
146
+ return this.each(function () {
147
+ instanceCount++;
148
+ this.footable = new Footable(this, o, instanceCount);
149
+ });
150
+ };
151
+
152
+ //helper for using timeouts
153
+ function Timer() {
154
+ ///<summary>Simple timer object created around a timeout.</summary>
155
+ var t = this;
156
+ t.id = null;
157
+ t.busy = false;
158
+ t.start = function (code, milliseconds) {
159
+ ///<summary>Starts the timer and waits the specified amount of <paramref name="milliseconds"/> before executing the supplied <paramref name="code"/>.</summary>
160
+ ///<param name="code">The code to execute once the timer runs out.</param>
161
+ ///<param name="milliseconds">The time in milliseconds to wait before executing the supplied <paramref name="code"/>.</param>
162
+
163
+ if (t.busy) {
164
+ return;
165
+ }
166
+ t.stop();
167
+ t.id = setTimeout(function () {
168
+ code();
169
+ t.id = null;
170
+ t.busy = false;
171
+ }, milliseconds);
172
+ t.busy = true;
173
+ };
174
+ t.stop = function () {
175
+ ///<summary>Stops the timer if its runnning and resets it back to its starting state.</summary>
176
+
177
+ if (t.id != null) {
178
+ clearTimeout(t.id);
179
+ t.id = null;
180
+ t.busy = false;
181
+ }
182
+ };
183
+ };
184
+
185
+ function Footable(t, o, id) {
186
+ ///<summary>Inits a new instance of the plugin.</summary>
187
+ ///<param name="t">The main table element to apply this plugin to.</param>
188
+ ///<param name="o">The options supplied to the plugin. Check the defaults object to see all available options.</param>
189
+ ///<param name="id">The id to assign to this instance of the plugin.</param>
190
+
191
+ var ft = this;
192
+ ft.id = id;
193
+ ft.table = t;
194
+ ft.options = o;
195
+ ft.breakpoints = [];
196
+ ft.breakpointNames = '';
197
+ ft.columns = {};
198
+
199
+ var opt = ft.options;
200
+ var cls = opt.classes;
201
+ var indexOffset = 0;
202
+
203
+ // This object simply houses all the timers used in the footable.
204
+ ft.timers = {
205
+ resize: new Timer(),
206
+ register: function (name) {
207
+ ft.timers[name] = new Timer();
208
+ return ft.timers[name];
209
+ }
210
+ };
211
+
212
+ w.footable.plugins.init(ft);
213
+
214
+ ft.init = function () {
215
+ var $window = $(w), $table = $(ft.table);
216
+
217
+ if ($table.hasClass(cls.loaded)) {
218
+ //already loaded FooTable for the table, so don't init again
219
+ ft.raise('footable_already_initialized');
220
+ return;
221
+ }
222
+
223
+ $table.addClass(cls.loading);
224
+
225
+ // Get the column data once for the life time of the plugin
226
+ $table.find(opt.columnDataSelector).each(function () {
227
+ var data = ft.getColumnData(this);
228
+ ft.columns[data.index] = data;
229
+
230
+ if (data.className != null) {
231
+ var selector = '', first = true;
232
+ $.each(data.matches, function (m, match) { //support for colspans
233
+ if (!first) {
234
+ selector += ', ';
235
+ }
236
+ selector += '> tbody > tr:not(.footable-row-detail) > td:nth-child(' + (parseInt(match) + 1) + ')';
237
+ first = false;
238
+ });
239
+ //add the className to the cells specified by data-class="blah"
240
+ $table.find(selector).not('.footable-cell-detail').addClass(data.className);
241
+ }
242
+ });
243
+
244
+ // Create a nice friendly array to work with out of the breakpoints object.
245
+ for (var name in opt.breakpoints) {
246
+ ft.breakpoints.push({ 'name': name, 'width': opt.breakpoints[name] });
247
+ ft.breakpointNames += (name + ' ');
248
+ }
249
+
250
+ // Sort the breakpoints so the smallest is checked first
251
+ ft.breakpoints.sort(function (a, b) {
252
+ return a['width'] - b['width'];
253
+ });
254
+
255
+ //bind the toggle selector click events
256
+ ft.bindToggleSelectors();
257
+
258
+ ft.raise('footable_initializing');
259
+
260
+ $table.bind('footable_initialized', function () {
261
+ //resize the footable onload
262
+ ft.resize();
263
+
264
+ //remove the loading class
265
+ $table.removeClass(cls.loading);
266
+
267
+ //hides all elements within the table that have the attribute data-hide="init"
268
+ //what does this do? LOL
269
+ $table.find('[data-init="hide"]').hide();
270
+ $table.find('[data-init="show"]').show();
271
+
272
+ //add the loaded class
273
+ $table.addClass(cls.loaded);
274
+ });
275
+
276
+ $table.bind('footable_resize', function () {
277
+ ft.resize();
278
+ });
279
+
280
+ $window
281
+ .bind('resize.footable', function () {
282
+ ft.timers.resize.stop();
283
+ ft.timers.resize.start(function () {
284
+ ft.resize();
285
+ }, opt.delay);
286
+ });
287
+
288
+ ft.raise('footable_initialized');
289
+ };
290
+
291
+ //moved this out into it's own function so that it can be called from other add-ons
292
+ ft.bindToggleSelectors = function () {
293
+ var $table = $(ft.table);
294
+ $table.find(opt.toggleSelector).unbind('click.footable').bind('click.footable', function (e) {
295
+ if ($table.is('.breakpoint') && $(e.target).is('td')) {
296
+ var $row = $(this).is('tr') ? $(this) : $(this).parents('tr:first');
297
+ ft.toggleDetail($row.get(0));
298
+ }
299
+ });
300
+ };
301
+
302
+ ft.parse = function (cell, column) {
303
+ var parser = opt.parsers[column.type] || opt.parsers.alpha;
304
+ return parser(cell);
305
+ };
306
+
307
+ ft.getColumnData = function (th) {
308
+ var $th = $(th), hide = $th.data('hide'), index = $th.index();
309
+ hide = hide || '';
310
+ hide = hide.split(',');
311
+ var data = {
312
+ 'index': index,
313
+ 'hide': { },
314
+ 'type': $th.data('type') || 'alpha',
315
+ 'name': $th.data('name') || $.trim($th.text()),
316
+ 'ignore': $th.data('ignore') || false,
317
+ 'className': $th.data('class') || null,
318
+ 'matches': [],
319
+ 'names': { },
320
+ 'group': $th.data('group') || null,
321
+ 'groupName': null
322
+ };
323
+
324
+ if (data.group != null) {
325
+ var $group = $(ft.table).find('> thead > tr.footable-group-row > th[data-group="' + data.group + '"], > thead > tr.footable-group-row > td[data-group="' + data.group + '"]').first();
326
+ data.groupName = ft.parse($group, { 'type': 'alpha' });
327
+ }
328
+
329
+ var pcolspan = parseInt($th.prev().attr('colspan') || 0);
330
+ indexOffset += pcolspan > 1 ? pcolspan - 1 : 0;
331
+ var colspan = parseInt($th.attr('colspan') || 0), curindex = data.index + indexOffset;
332
+ if (colspan > 1) {
333
+ var names = $th.data('names');
334
+ names = names || '';
335
+ names = names.split(',');
336
+ for (var i = 0; i < colspan; i++) {
337
+ data.matches.push(i + curindex);
338
+ if (i < names.length) data.names[i + curindex] = names[i];
339
+ }
340
+ } else {
341
+ data.matches.push(curindex);
342
+ }
343
+
344
+ data.hide['default'] = ($th.data('hide') === "all") || ($.inArray('default', hide) >= 0);
345
+
346
+ for (var name in opt.breakpoints) {
347
+ data.hide[name] = ($th.data('hide') === "all") || ($.inArray(name, hide) >= 0);
348
+ }
349
+ var e = ft.raise('footable_column_data', { 'column': { 'data': data, 'th': th } });
350
+ return e.column.data;
351
+ };
352
+
353
+ ft.getViewportWidth = function () {
354
+ return window.innerWidth || (document.body ? document.body.offsetWidth : 0);
355
+ };
356
+
357
+ ft.getViewportHeight = function () {
358
+ return window.innerHeight || (document.body ? document.body.offsetHeight : 0);
359
+ };
360
+
361
+ ft.calculateWidthAndHeight = function ($table, info) {
362
+ if (jQuery.isFunction(opt.calculateWidthAndHeightOverride)) {
363
+ return opt.calculateWidthAndHeightOverride($table, info);
364
+ }
365
+ if (info.viewportWidth < info.width) info.width = info.viewportWidth;
366
+ if (info.viewportHeight < info.height) info.height = info.viewportHeight;
367
+
368
+ return info;
369
+ };
370
+
371
+ ft.hasBreakpointColumn = function (breakpoint) {
372
+ for (var c in ft.columns) {
373
+ if (ft.columns[c].hide[breakpoint]) {
374
+ return true;
375
+ }
376
+ }
377
+ return false;
378
+ };
379
+
380
+ ft.resize = function () {
381
+ var $table = $(ft.table);
382
+ var info = {
383
+ 'width': $table.width(), //the table width
384
+ 'height': $table.height(), //the table height
385
+ 'viewportWidth': ft.getViewportWidth(), //the width of the viewport
386
+ 'viewportHeight': ft.getViewportHeight(), //the width of the viewport
387
+ 'orientation': null
388
+ };
389
+ info.orientation = info.viewportWidth > info.viewportHeight ? 'landscape' : 'portrait';
390
+
391
+ info = ft.calculateWidthAndHeight($table, info);
392
+
393
+ var pinfo = $table.data('footable_info');
394
+ $table.data('footable_info', info);
395
+ ft.raise('footable_resizing', { 'old': pinfo, 'info': info });
396
+
397
+ // This (if) statement is here purely to make sure events aren't raised twice as mobile safari seems to do
398
+ if (!pinfo || ((pinfo && pinfo.width && pinfo.width != info.width) || (pinfo && pinfo.height && pinfo.height != info.height))) {
399
+ var current = null, breakpoint;
400
+ for (var i = 0; i < ft.breakpoints.length; i++) {
401
+ breakpoint = ft.breakpoints[i];
402
+ if (breakpoint && breakpoint.width && info.width <= breakpoint.width) {
403
+ current = breakpoint;
404
+ break;
405
+ }
406
+ }
407
+
408
+ var breakpointName = (current == null ? 'default' : current['name']);
409
+
410
+ var hasBreakpointFired = ft.hasBreakpointColumn(breakpointName);
411
+
412
+ $table
413
+ .removeClass('default breakpoint').removeClass(ft.breakpointNames)
414
+ .addClass(breakpointName + (hasBreakpointFired ? ' breakpoint' : ''))
415
+ .find('> thead > tr:last-child > th')
416
+ .each(function () {
417
+ var data = ft.columns[$(this).index()], selector = '', first = true;
418
+ $.each(data.matches, function (m, match) {
419
+ if (!first) {
420
+ selector += ', ';
421
+ }
422
+ var count = match + 1;
423
+ selector += '> tbody > tr:not(.footable-row-detail) > td:nth-child(' + count + ')';
424
+ selector += ', > tfoot > tr:not(.footable-row-detail) > td:nth-child(' + count + ')';
425
+ selector += ', > colgroup > col:nth-child(' + count + ')';
426
+ first = false;
427
+ });
428
+
429
+ selector += ', > thead > tr[data-group-row="true"] > th[data-group="' + data.group + '"]';
430
+ var $column = $table.find(selector).add(this);
431
+ if (data.hide[breakpointName] == false) $column.show();
432
+ else $column.hide();
433
+
434
+ if ($table.find('> thead > tr.footable-group-row').length == 1) {
435
+ var $groupcols = $table.find('> thead > tr:last-child > th[data-group="' + data.group + '"]:visible, > thead > tr:last-child > th[data-group="' + data.group + '"]:visible'),
436
+ $group = $table.find('> thead > tr.footable-group-row > th[data-group="' + data.group + '"], > thead > tr.footable-group-row > td[data-group="' + data.group + '"]'),
437
+ groupspan = 0;
438
+
439
+ $.each($groupcols, function () {
440
+ groupspan += parseInt($(this).attr('colspan') || 1);
441
+ });
442
+
443
+ if (groupspan > 0) $group.attr('colspan', groupspan).show();
444
+ else $group.hide();
445
+ }
446
+ })
447
+ .end()
448
+ .find('> tbody > tr.footable-detail-show').each(function () {
449
+ ft.createOrUpdateDetailRow(this);
450
+ });
451
+
452
+ $table.find('> tbody > tr.footable-detail-show:visible').each(function () {
453
+ var $next = $(this).next();
454
+ if ($next.hasClass('footable-row-detail')) {
455
+ if (breakpointName == 'default' && !hasBreakpointFired) $next.hide();
456
+ else $next.show();
457
+ }
458
+ });
459
+
460
+ // adding .footable-first-column and .footable-last-column to the first and last th and td of each row in order to allow
461
+ // for styling if the first or last column is hidden (which won't work using :first-child or :last-child)
462
+ $table.find('> thead > tr > th.footable-last-column, > tbody > tr > td.footable-last-column').removeClass('footable-last-column');
463
+ $table.find('> thead > tr > th.footable-first-column, > tbody > tr > td.footable-first-column').removeClass('footable-first-column');
464
+ $table.find('> thead > tr, > tbody > tr')
465
+ .find('> th:visible:last, > td:visible:last')
466
+ .addClass('footable-last-column')
467
+ .end()
468
+ .find('> th:visible:first, > td:visible:first')
469
+ .addClass('footable-first-column');
470
+
471
+ ft.raise('footable_breakpoint_' + breakpointName, { 'info': info });
472
+ }
473
+
474
+ ft.raise('footable_resized', { 'old': pinfo, 'info': info });
475
+ };
476
+
477
+ ft.toggleDetail = function (actualRow) {
478
+ var $row = $(actualRow),
479
+ created = ft.createOrUpdateDetailRow($row.get(0)),
480
+ $next = $row.next();
481
+
482
+ if (!created && $next.is(':visible')) {
483
+ $row.removeClass('footable-detail-show');
484
+ //only hide the next row if it's a detail row
485
+ if ($next.hasClass('footable-row-detail')) $next.hide();
486
+ } else {
487
+ $row.addClass('footable-detail-show');
488
+ $next.show();
489
+ }
490
+ };
491
+
492
+ ft.getColumnFromTdIndex = function (index) {
493
+ /// <summary>Returns the correct column data for the supplied index taking into account colspans.</summary>
494
+ /// <param name="index">The index to retrieve the column data for.</param>
495
+ /// <returns type="json">A JSON object containing the column data for the supplied index.</returns>
496
+ var result = null;
497
+ for (var column in ft.columns) {
498
+ if ($.inArray(index, ft.columns[column].matches) >= 0) {
499
+ result = ft.columns[column];
500
+ break;
501
+ }
502
+ }
503
+ return result;
504
+ };
505
+
506
+ ft.createOrUpdateDetailRow = function (actualRow) {
507
+ var $row = $(actualRow), $next = $row.next(), $detail, values = [];
508
+ if ($row.is(':hidden')) return false; //if the row is hidden for some readon (perhaps filtered) then get out of here
509
+ ft.raise('footable_rowdetailupdated', { 'row': $row, 'detail': $next });
510
+ $row.find('> td:hidden').each(function () {
511
+ var index = $(this).index(), column = ft.getColumnFromTdIndex(index), name = column.name;
512
+ if (column.ignore == true) return true;
513
+
514
+ if (index in column.names) name = column.names[index];
515
+ values.push({ 'name': name, 'value': ft.parse(this, column), 'display': $.trim($(this).html()), 'group': column.group, 'groupName': column.groupName });
516
+ return true;
517
+ });
518
+ if (values.length == 0) return false; //return if we don't have any data to show
519
+ var colspan = $row.find('> td:visible').length;
520
+ var exists = $next.hasClass('footable-row-detail');
521
+ if (!exists) { // Create
522
+ $next = $('<tr class="footable-row-detail"><td class="footable-cell-detail"><div class="footable-row-detail-inner"></div></td></tr>');
523
+ $row.after($next);
524
+ }
525
+ $next.find('> td:first').attr('colspan', colspan);
526
+ $detail = $next.find('.footable-row-detail-inner').empty();
527
+ opt.createDetail($detail, values);
528
+ return !exists;
529
+ };
530
+
531
+ ft.raise = function (eventName, args) {
532
+ args = args || { };
533
+ var def = { 'ft': ft };
534
+ $.extend(true, def, args);
535
+ var e = $.Event(eventName, def);
536
+ if (!e.ft) {
537
+ $.extend(true, e, def);
538
+ } //pre jQuery 1.6 which did not allow data to be passed to event object constructor
539
+ $(ft.table).trigger(e);
540
+ return e;
541
+ };
542
+
543
+ ft.init();
544
+ return ft;
545
+ };
546
+ })(jQuery, window);
@@ -0,0 +1,104 @@
1
+ (function ($, w, undefined) {
2
+ if (w.footable == undefined || w.footable == null)
3
+ throw new Error('Please check and make sure footable.js is included in the page and is loaded prior to this script.');
4
+
5
+ var jQversion = w.footable.version.parse($.fn.jquery);
6
+ if (jQversion.major == 1 && jQversion.minor < 8) { // For older versions of jQuery, anything below 1.8
7
+ $.expr[':'].ftcontains = function (a, i, m) {
8
+ return $(a).html().toUpperCase().indexOf(m[3].toUpperCase()) >= 0;
9
+ };
10
+ } else { // For jQuery 1.8 and above
11
+ $.expr[':'].ftcontains = $.expr.createPseudo(function (arg) {
12
+ return function (elem) {
13
+ return $(elem).html().toUpperCase().indexOf(arg.toUpperCase()) >= 0;
14
+ };
15
+ });
16
+ }
17
+
18
+ var defaults = {
19
+ filter: {
20
+ enabled: true,
21
+ input: '.footable-filter',
22
+ timeout: 300,
23
+ minimum: 2,
24
+ disableEnter: false
25
+ }
26
+ };
27
+
28
+ function Filter() {
29
+ var p = this;
30
+ p.name = 'Footable Filter';
31
+ p.init = function (ft) {
32
+ if (ft.options.filter.enabled == true) {
33
+ ft.timers.register('filter');
34
+ $(ft.table).bind({
35
+ 'footable_initialized': function (e) {
36
+ var $table = $(e.ft.table);
37
+ var data = {
38
+ 'input': $table.data('filter') || e.ft.options.filter.input,
39
+ 'timeout': $table.data('filter-timeout') || e.ft.options.filter.timeout,
40
+ 'minimum': $table.data('filter-minimum') || e.ft.options.filter.minimum,
41
+ 'disableEnter': $table.data('filter-disable-enter') || e.ft.options.filter.disableEnter
42
+ };
43
+ if (data.disableEnter) {
44
+ $(data.input).keypress(function (event) {
45
+ if (window.event)
46
+ return (window.event.keyCode != 13);
47
+ else
48
+ return (event.which != 13);
49
+ });
50
+ }
51
+ $table.bind('footable_clear_filter', function () {
52
+ $(data.input).val('');
53
+ p.clearFilter(e.ft);
54
+ });
55
+ $(data.input).keyup(function (eve) {
56
+ e.ft.timers.filter.stop();
57
+ if (eve.which == 27) { $(data.input).val(''); }
58
+ e.ft.timers.filter.start(function () {
59
+ e.ft.raise('footable_filtering');
60
+ var val = $(data.input).val() || '';
61
+ if (val.length < data.minimum) {
62
+ p.clearFilter(e.ft);
63
+ } else {
64
+ var filters = val.split(' ');
65
+ $table.find('> tbody > tr').hide().addClass('footable-filtered');
66
+ var rows = $table.find('> tbody > tr:not(.footable-row-detail)');
67
+ $.each(filters, function (i, f) {
68
+ if (f && f.length)
69
+ rows = rows.filter('*:ftcontains("' + f + '")');
70
+ });
71
+ rows.each(function () {
72
+ p.showRow(this, e.ft);
73
+ $(this).removeClass('footable-filtered');
74
+ });
75
+ e.ft.raise('footable_filtered', { filter : val });
76
+ }
77
+ }, data.timeout);
78
+ });
79
+ }
80
+ });
81
+ }
82
+ };
83
+
84
+ p.clearFilter = function (ft) {
85
+ $(ft.table).find('> tbody > tr:not(.footable-row-detail)').removeClass('footable-filtered').each(function () {
86
+ p.showRow(this, ft);
87
+ });
88
+ ft.raise('footable_filtered', { cleared : true });
89
+ };
90
+
91
+ p.showRow = function (row, ft) {
92
+ var $row = $(row), $next = $row.next(), $table = $(ft.table);
93
+ if ($row.is(':visible')) return; //already visible - do nothing
94
+ if ($table.hasClass('breakpoint') && $row.hasClass('footable-detail-show') && $next.hasClass('footable-row-detail')) {
95
+ $row.add($next).show();
96
+ ft.createOrUpdateDetailRow(row);
97
+ }
98
+ else $row.show();
99
+ };
100
+ };
101
+
102
+ w.footable.plugins.register(new Filter(), defaults);
103
+
104
+ })(jQuery, window);