PageSourceSearch

https://www.robinsonpetshop.it/app/plugins/rewardsystem/assets/js/footable.js?ver=31.3.0

js robinsonpetshop.it collected 2026-09-26 19:19:34 UTC 36,685 bytes, 784 lines download raw bytes

1/*!
2 * FooTable - Awesome Responsive Tables
3 * Version : 2.0.1.4
4 * http://fooplugins.com/plugins/footable-jquery/
5 *
6 * Requires jQuery - http://jquery.com/
7 *
8 * Copyright 2014 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: 16 Feb 2014
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                numeric: function (cell) {
27                    var val = $(cell).data('value') || $(cell).text().replace(/[^0-9.\-]/g, '');
28                    val = parseFloat(val);
29                    if (isNaN(val)) val = 0;
30                    return val;
31                }
32            },
33            addRowToggle: true,
34            calculateWidthOverride: null,
35            toggleSelector: ' > tbody > tr:not(.footable-row-detail)', //the selector to show/hide the detail row
36            columnDataSelector: '> thead > tr:last-child > th, > thead > tr:last-child > td', //the selector used to find the column data in the thead
37            detailSeparator: ':', //the separator character used when building up the detail row
38            toggleHTMLElement: '<span />', // override this if you want to insert a click target rather than use a background image.
39            createGroupedDetail: function (data) {
40                var groups = { '_none': { 'name': null, 'data': [] } };
41                for (var i = 0; i < data.length; i++) {
42                    var groupid = data[i].group;
43                    if (groupid !== null) {
44                        if (!(groupid in groups))
45                            groups[groupid] = { 'name': data[i].groupName || data[i].group, 'data': [] };
46
47                        groups[groupid].data.push(data[i]);
48                    } else {
49                        groups._none.data.push(data[i]);
50                    }
51                }
52                return groups;
53            },
54            createDetail: function (element, data, createGroupedDetail, separatorChar, classes) {
55                /// <summary>This function is used by FooTable to generate the detail view seen when expanding a collapsed row.</summary>
56                /// <param name="element">This is the div that contains all the detail row information, anything could be added to it.</param>
57                /// <param name="data">
58                ///  This is an array of objects containing the cell information for the current row.
59                ///  These objects look like the below:
60                ///    obj = {
61                ///      'name': String, // The name of the column
62                ///      'value': Object, // The value parsed from the cell using the parsers. This could be a string, a number or whatever the parser outputs.
63                ///      '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.
64                ///      'group': String, // This is the identifier used in the data-group attribute of the column.
65                ///      'groupName': String // This is the actual name of the group the column belongs to.
66                ///    }
67                /// </param>
68                /// <param name="createGroupedDetail">The grouping function to group the data</param>
69                /// <param name="separatorChar">The separator charactor used</param>
70                /// <param name="classes">The array of class names used to build up the detail row</param>
71
72                var groups = createGroupedDetail(data);
73                for (var group in groups) {
74                    if (groups[group].data.length === 0) continue;
75                    if (group !== '_none') element.append('<div class="' + classes.detailInnerGroup + '">' + groups[group].name + '</div>');
76
77                    for (var j = 0; j < groups[group].data.length; j++) {
78                        var separator = (groups[group].data[j].name) ? separatorChar : '';
79                        element.append('<div class="' + classes.detailInnerRow + '"><div class="' + classes.detailInnerName + '">' + groups[group].data[j].name + separator + '</div><div class="' + classes.detailInnerValue + '">' + groups[group].data[j].display + '</div></div>');
80                    }
81                }
82            },
83            classes: {
84                main: 'footable',
85                loading: 'footable-loading',
86                loaded: 'footable-loaded',
87                toggle: 'footable-toggle',
88                disabled: 'footable-disabled',
89                detail: 'footable-row-detail',
90                detailCell: 'footable-row-detail-cell',
91                detailInner: 'footable-row-detail-inner',
92                detailInnerRow: 'footable-row-detail-row',
93                detailInnerGroup: 'footable-row-detail-group',
94                detailInnerName: 'footable-row-detail-name',
95                detailInnerValue: 'footable-row-detail-value',
96                detailShow: 'footable-detail-show'
97            },
98            triggers: {
99                initialize: 'footable_initialize',                      //trigger this event to force FooTable to reinitialize
100                resize: 'footable_resize',                              //trigger this event to force FooTable to resize
101                redraw: 'footable_redraw',								//trigger this event to force FooTable to redraw
102                toggleRow: 'footable_toggle_row',                       //trigger this event to force FooTable to toggle a row
103                expandFirstRow: 'footable_expand_first_row',            //trigger this event to force FooTable to expand the first row
104                expandAll: 'footable_expand_all',                       //trigger this event to force FooTable to expand all rows
105                collapseAll: 'footable_collapse_all'                    //trigger this event to force FooTable to collapse all rows
106            },
107            events: {
108                alreadyInitialized: 'footable_already_initialized',     //fires when the FooTable has already been initialized
109                initializing: 'footable_initializing',                  //fires before FooTable starts initializing
110                initialized: 'footable_initialized',                    //fires after FooTable has finished initializing
111                resizing: 'footable_resizing',                          //fires before FooTable resizes
112                resized: 'footable_resized',                            //fires after FooTable has resized
113                redrawn: 'footable_redrawn',                            //fires after FooTable has redrawn
114                breakpoint: 'footable_breakpoint',                      //fires inside the resize function, when a breakpoint is hit
115                columnData: 'footable_column_data',                     //fires when setting up column data. Plugins should use this event to capture their own info about a column
116                rowDetailUpdating: 'footable_row_detail_updating',      //fires before a detail row is updated
117                rowDetailUpdated: 'footable_row_detail_updated',        //fires when a detail row is being updated
118                rowCollapsed: 'footable_row_collapsed',                 //fires when a row is collapsed
119                rowExpanded: 'footable_row_expanded',                   //fires when a row is expanded
120                rowRemoved: 'footable_row_removed',                     //fires when a row is removed
121                reset: 'footable_reset'                                 //fires when FooTable is reset
122            },
123            debug: false, // Whether or not to log information to the console.
124            log: null
125        },
126
127        version: {
128            major: 0, minor: 5,
129            toString: function () {
130                return w.footable.version.major + '.' + w.footable.version.minor;
131            },
132            parse: function (str) {
133                version = /(\d+)\.?(\d+)?\.?(\d+)?/.exec(str);
134                return {
135                    major: parseInt(version[1], 10) || 0,
136                    minor: parseInt(version[2], 10) || 0,
137                    patch: parseInt(version[3], 10) || 0
138                };
139            }
140        },
141
142        plugins: {
143            _validate: function (plugin) {
144                ///<summary>Simple validation of the <paramref name="plugin"/> to make sure any members called by FooTable actually exist.</summary>
145                ///<param name="plugin">The object defining the plugin, this should implement a string property called "name" and a function called "init".</param>
146
147                if (!$.isFunction(plugin)) {
148                  if (w.footable.options.debug === true) console.error('Validation failed, expected type "function", received type "{0}".', typeof plugin);
149                  return false;
150                }
151                var p = new plugin();
152                if (typeof p['name'] !== 'string') {
153                    if (w.footable.options.debug === true) console.error('Validation failed, plugin does not implement a string property called "name".', p);
154                    return false;
155                }
156                if (!$.isFunction(p['init'])) {
157                    if (w.footable.options.debug === true) console.error('Validation failed, plugin "' + p['name'] + '" does not implement a function called "init".', p);
158                    return false;
159                }
160                if (w.footable.options.debug === true) console.log('Validation succeeded for plugin "' + p['name'] + '".', p);
161                return true;
162            },
163            registered: [], // An array containing all registered plugins.
164            register: function (plugin, options) {
165                ///<summary>Registers a <paramref name="plugin"/> and its default <paramref name="options"/> with FooTable.</summary>
166                ///<param name="plugin">The plugin that should implement a string property called "name" and a function called "init".</param>
167                ///<param name="options">The default options to merge with the FooTable's base options.</param>
168
169                if (w.footable.plugins._validate(plugin)) {
170                    w.footable.plugins.registered.push(plugin);
171                    if (typeof options === 'object') $.extend(true, w.footable.options, options);
172                }
173            },
174            load: function(instance){
175              var loaded = [], registered, i;
176              for(i = 0; i < w.footable.plugins.registered.length; i++){
177                try {
178                  registered = w.footable.plugins.registered[i];
179                  loaded.push(new registered(instance));
180                } catch (err) {
181                  if (w.footable.options.debug === true) console.error(err);
182                }
183              }
184              return loaded;
185            },
186            init: function (instance) {
187                ///<summary>Loops through all registered plugins and calls the "init" method supplying the current <paramref name="instance"/> of the FooTable as the first parameter.</summary>
188                ///<param name="instance">The current instance of the FooTable that the plugin is being initialized for.</param>
189
190                for (var i = 0; i < instance.plugins.length; i++) {
191                    try {
192                      instance.plugins[i]['init'](instance);
193                    } catch (err) {
194                        if (w.footable.options.debug === true) console.error(err);
195                    }
196                }
197            }
198        }
199    };
200
201    var instanceCount = 0;
202
203    $.fn.footable = function (options) {
204        ///<summary>The main constructor call to initialize the plugin using the supplied <paramref name="options"/>.</summary>
205        ///<param name="options">
206        ///<para>A JSON object containing user defined options for the plugin to use. Any options not supplied will have a default value assigned.</para>
207        ///<para>Check the documentation or the default options object above for more information on available options.
207</para>
208        ///</param>
209
210        options = options || {};
211        var o = $.extend(true, {}, w.footable.options, options); //merge user and default options
212        return this.each(function () {
213            instanceCount++;
214            var footable = new Footable(this, o, instanceCount);
215			$(this).data('footable', footable);
216        });
217    };
218
219    //helper for using timeouts
220    function Timer() {
221        ///<summary>Simple timer object created around a timeout.</summary>
222        var t = this;
223        t.id = null;
224        t.busy = false;
225        t.start = function (code, milliseconds) {
226            ///<summary>Starts the timer and waits the specified amount of <paramref name="milliseconds"/> before executing the supplied <paramref name="code"/>.</summary>
227            ///<param name="code">The code to execute once the timer runs out.</param>
228            ///<param name="milliseconds">The time in milliseconds to wait before executing the supplied <paramref name="code"/>.</param>
229
230            if (t.busy) {
231                return;
232            }
233            t.stop();
234            t.id = setTimeout(function () {
235                code();
236                t.id = null;
237                t.busy = false;
238            }, milliseconds);
239            t.busy = true;
240        };
241        t.stop = function () {
242            ///<summary>Stops the timer if its runnning and resets it back to its starting state.</summary>
243
244            if (t.id !== null) {
245                clearTimeout(t.id);
246                t.id = null;
247                t.busy = false;
248            }
249        };
250    }
251
252    function Footable(t, o, id) {
253        ///<summary>Inits a new instance of the plugin.</summary>
254        ///<param name="t">The main table element to apply this plugin to.</param>
255        ///<param name="o">The options supplied to the plugin. Check the defaults object to see all available options.</param>
256        ///<param name="id">The id to assign to this instance of the plugin.</param>
257
258        var ft = this;
259        ft.id = id;
260        ft.table = t;
261        ft.options = o;
262        ft.breakpoints = [];
263        ft.breakpointNames = '';
264        ft.columns = {};
265        ft.plugins = w.footable.plugins.load(ft);
266
267        var opt = ft.options,
268            cls = opt.classes,
269            evt = opt.events,
270            trg = opt.triggers,
271            indexOffset = 0;
272
273        // This object simply houses all the timers used in the FooTable.
274        ft.timers = {
275            resize: new Timer(),
276            register: function (name) {
277                ft.timers[name] = new Timer();
278                return ft.timers[name];
279            }
280        };
281
282        ft.init = function () {
283            var $window = $(w), $table = $(ft.table);
284
285            w.footable.plugins.init(ft);
286
287            if ($table.hasClass(cls.loaded)) {
288                //already loaded FooTable for the table, so don't init again
289                ft.raise(evt.alreadyInitialized);
290                return;
291            }
292
293            //raise the initializing event
294            ft.raise(evt.initializing);
295
296            $table.addClass(cls.loading);
297
298            // Get the column data once for the life time of the plugin
299            $table.find(opt.columnDataSelector).each(function () {
300                var data = ft.getColumnData(this);
301                ft.columns[data.index] = data;
302            });
303
304            // Create a nice friendly array to work with out of the breakpoints object.
305            for (var name in opt.breakpoints) {
306                ft.breakpoints.push({ 'name': name, 'width': opt.breakpoints[name] });
307                ft.breakpointNames += (name + ' ');
308            }
309
310            // Sort the breakpoints so the smallest is checked first
311            ft.breakpoints.sort(function (a, b) {
312                return a['width'] - b['width'];
313            });
314
315            $table
316                .unbind(trg.initialize)
317                //bind to FooTable initialize trigger
318                .bind(trg.initialize, function () {
319                    //remove previous "state" (to "force" a resize)
320                    $table.removeData('footable_info');
321                    $table.data('breakpoint', '');
322
323                    //trigger the FooTable resize
324                    $table.trigger(trg.resize);
325
326                    //remove the loading class
327                    $table.removeClass(cls.loading);
328
329                    //add the FooTable and loaded class
330                    $table.addClass(cls.loaded).addClass(cls.main);
331
332                    //raise the initialized event
333                    ft.raise(evt.initialized);
334                })
335                .unbind(trg.redraw)
336                //bind to FooTable redraw trigger
337                .bind(trg.redraw, function () {
338                    ft.redraw();
339                })
340                .unbind(trg.resize)
341                //bind to FooTable resize trigger
342                .bind(trg.resize, function () {
343                    ft.resize();
344                })
345                .unbind(trg.expandFirstRow)
346                //bind to FooTable expandFirstRow trigger
347                .bind(trg.expandFirstRow, function () {
348                    $table.find(opt.toggleSelector).first().not('.' + cls.detailShow).trigger(trg.toggleRow);
349                })
350                .unbind(trg.expandAll)
351                //bind to FooTable expandFirstRow trigger
352                .bind(trg.expandAll, function () {
353                    $table.find(opt.toggleSelector).not('.' + cls.detailShow).trigger(trg.toggleRow);
354                })
355                .unbind(trg.collapseAll)
356                //bind to FooTable expandFirstRow trigger
357                .bind(trg.collapseAll, function () {
358                    $table.find('.' + cls.detailShow).trigger(trg.toggleRow);
359                });
360
361            //trigger a FooTable initialize
362            $table.trigger(trg.initialize);
363
364            //bind to window resize
365            $window
366                .bind('resize.footable', function () {
367                    ft.timers.resize.stop();
368                    ft.timers.resize.start(function () {
369                        ft.raise(trg.resize);
370                    }, opt.delay);
371                });
372        };
373
374        ft.addRowToggle = function () {
375            if (!opt.addRowToggle) return;
376
377            var $table = $(ft.table),
378                hasToggleColumn = false;
379
380            //first remove all toggle spans
381            $table.find('span.' + cls.toggle).remove();
382
383            for (var c in ft.columns) {
384                var col = ft.columns[c];
385                if (col.toggle) {
386                    hasToggleColumn = true;
387                    var selector = '> tbody > tr:not(.' + cls.detail + ',.' + cls.disabled + ') > td:nth-child(' + (parseInt(col.index, 10) + 1) + ')';
388                    $table.find(selector).not('.' + cls.detailCell).prepend($(opt.toggleHTMLElement).addClass(cls.toggle));
389                    return;
390                }
391            }
392            //check if we have an toggle column. If not then add it to the first column just to be safe
393            if (!hasToggleColumn) {
394                $table
395                    .find('> tbody > tr:not(.' + cls.detail + ',.' + cls.disabled + ') > td:first-child')
396                    .not('.' + cls.detailCell)
397                    .prepend($(opt.toggleHTMLElement).addClass(cls.toggle));
398            }
399        };
400
401        ft.setColumnClasses = function () {
402            $table = $(ft.table);
403            for (var c in ft.columns) {
404                var col = ft.columns[c];
405                if (col.className !== null) {
406                    var selector = '', first = true;
407                    $.each(col.matches, function (m, match) { //support for colspans
408                        if (!first) selector += ', ';
409                        selector += '> tbody > tr:not(.' + cls.detail + ') > td:nth-child(' + (parseInt(match, 10) + 1) + ')';
410                        first = false;
411                    });
412                    //add the className to the cells specified by data-class="blah"
413                    $table.find(selector).not('.' + cls.detailCell).addClass(col.className);
414                }
415            }
416        };
417
418        //moved this out into it's own function so that it can be called from other add-ons
419        ft.bindToggleSelectors = function () {
420            var $table = $(ft.table);
421
422            if (!ft.hasAnyBreakpointColumn()) return;
423
424            $table.find(opt.toggleSelector).unbind(trg.toggleRow).bind(trg.toggleRow, function (e) {
425                var $row = $(this).is('tr') ? $(this) : $(this).parents('tr:first');
426                ft.toggleDetail($row);
427            });
428
429            $table.find(opt.toggleSelector).unbind('click.footable').bind('click.footable', function (e) {
430                if ($table.is('.breakpoint') && $(e.target).is('td,.'+ cls.toggle)) {
431                    $(this).trigger(trg.toggleRow);
432                }
433            });
434        };
435
436        ft.parse = function (cell, column) {
437            var parser = opt.parsers[column.type] || opt.parsers.alpha;
438            return parser(cell);
439        };
440
441        ft.getColumnData = function (th) {
442            var $th = $(th), hide = $th.data('hide'), index = $th.index();
443            hide = hide || '';
444            hide = jQuery.map(hide.split(','), function (a) {
445                return jQuery.trim(a);
446            });
447            var data = {
448                'index': index,
449                'hide': { },
450                'type': $th.data('type') || 'alpha',
451                'name': $th.data('name') || $.trim($th.text()),
452                'ignore': $th.data('ignore') || false,
453                'toggle': $th.data('toggle') || false,
454                'className': $th.data('class') || null,
455                'matches': [],
456                'names': { },
457                'group': $th.data('group') || null,
458                'groupName': null
459            };
460
461            if (data.group !== null) {
462                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();
463                data.groupName = ft.parse($group, { 'type': 'alpha' });
464            }
465
466            var pcolspan = parseInt($th.prev().attr('colspan') || 0, 10);
467            indexOffset += pcolspan > 1 ? pcolspan - 1 : 0;
468            var colspan = parseInt($th.attr('colspan') || 0, 10), curindex = data.index + indexOffset;
469            if (colspan > 1) {
470                var names = $th.data('names');
471                names = names || '';
472                names = names.split(',');
473                for (var i = 0; i < colspan; i++) {
474                    data.matches.push(i + curindex);
475                    if (i < names.length) data.names[i + curindex] = names[i];
476                }
477            } else {
478                data.matches.push(curindex);
479            }
480
481            data.hide['default'] = ($th.data('hide') === "all") || ($.inArray('default', hide) >= 0);
482
483            var hasBreakpoint = false;
484            for (var name in opt.breakpoints) {
485                data.hide[name] = ($th.data('hide') === "all") || ($.inArray(name, hide) >= 0);
486                hasBreakpoint = hasBreakpoint || data.hide[name];
487            }
488            data.hasBreakpoint = hasBreakpoint;
489            var e = ft.raise(evt.columnData, { 'column': { 'data': data, 'th': th } });
490            return e.column.data;
491        };
492
493        ft.getViewportWidth = function () {
494            return window.innerWidth || (document.body ? document.body.offsetWidth : 0);
495        };
496
497        ft.calculateWidth = function ($table, info) {
498            if (jQuery.isFunction(opt.calculateWidthOverride)) {
499                return opt.calculateWidthOverride($table, info);
500            }
501            if (info.viewportWidth < info.width) info.width = info.viewportWidth;
502            if (info.parentWidth < info.width) info.width = info.parentWidth;
503            return info;
504        };
505
506        ft.hasBreakpointColumn = function (breakpoint) {
507            for (var c in ft.columns) {
508                if (ft.columns[c].hide[breakpoint]) {
509                    if (ft.columns[c].ignore) {
510                        continue;
511                    }
512                    return true;
513                }
514            }
515            return false;
516        };
517
518        ft.hasAnyBreakpointColumn = function () {
519            for (var c in ft.columns) {
520                if (ft.columns[c].hasBreakpoint) {
521                    return true;
522                }
523            }
524            return false;
525        };
526
527        ft.resize = function () {
528            var $table = $(ft.table);
529
530            if (!$table.is(':visible')) {
531                return;
532            } //we only care about FooTables that are visible
533
534            if (!ft.hasAnyBreakpointColumn()) {
535                return;
536            } //we only care about FooTables that have breakpoints
537
538            var info = {
539                'width': $table.width(),                  //the table width
540                'viewportWidth': ft.getViewportWidth(),   //the width of the viewport
541                'parentWidth': $table.parent().width()    //the width of the parent
542            };
543
544            info = ft.calculateWidth($table, info);
545
546            var pinfo = $table.data('footable_info');
547            $table.data('footable_info', info);
548            ft.raise(evt.resizing, { 'old': pinfo, 'info': info });
549
550            // This (if) statement is here purely to make sure events aren't raised twice as mobile safari seems to do
551            if (!pinfo || (pinfo && pinfo.width && pinfo.width !== info.width)) {
552
553                var current = null, breakpoint;
554                for (var i = 0; i < ft.breakpoints.length; i++) {
555                    breakpoint = ft.breakpoints[i];
556                    if (breakpoint && breakpoint.width && info.width <= breakpoint.width) {
557                        current = breakpoint;
558                        break;
559                    }
560                }
561
562                var breakpointName = (current === null ? 'default' : current['name']),
563                    hasBreakpointFired = ft.hasBreakpointColumn(breakpointName),
564                    previousBreakpoint = $table.data('breakpoint');
565
566                $table
567                    .data('breakpoint', breakpointName)
568                    .removeClass('default breakpoint').removeClass(ft.breakpointNames)
569                    .addClass(breakpointName + (hasBreakpointFired ? ' breakpoint' : ''));
570
571                //only do something if the breakpoint has changed
572                if (breakpointName !== previousBreakpoint) {
573                    //trigger a redraw
574                    $table.trigger(trg.redraw);
575                    //raise a breakpoint event
576                    ft.raise(evt.breakpoint, { 'breakpoint': breakpointName, 'info': info });
577                }
578            }
579
580            ft.raise(evt.resized, { 'old': pinfo, 'info': info });
581        };
582
583        ft.redraw = function () {
584            //add the toggler to each row
585            ft.addRowToggle();
586
587            //bind the toggle selector click events
588            ft.bindToggleSelectors();
589
590            //set any cell classes defined for the columns
591            ft.setColumnClasses();
592
593            var $table = $(ft.table),
594                breakpointName = $table.data('breakpoint'),
595                hasBreakpointFired = ft.hasBreakpointColumn(breakpointName);
596
597            $table
598                .find('> tbody > tr:not(.' + cls.detail + ')').data('detail_created', false).end()
599                .find('> thead > tr:last-child > th')
600                .each(function () {
601                    var data = ft.columns[$(this).index()], selector = '', first = true;
602                    $.each(data.matches, function (m, match) {
603                        if (!first) {
604                            selector += ', ';
605                        }
606                        var count = match + 1;
607                        selector += '> tbody > tr:not(.' + cls.detail + ') > td:nth-child(' + count + ')';
608                        selector += ', > tfoot > tr:not(.' + cls.detail + ') > td:nth-child(' + count + ')';
609                        selector += ', > colgroup > col:nth-child(' + count + ')';
610                        first = false;
611                    });
612
613                    selector += ', > thead > tr[data-group-row="true"] > th[data-group="' + data.group + '"]';
614                    var $column = $table.find(selector).add(this);
615                    if (breakpointName !== '') {
616                      if (data.hide[breakpointName] === false) $column.addClass('footable-visible').show();
617                      else $column.removeClass('footable-visible').hide();
618                    }
619
620                    if ($table.find('> thead > tr.footable-group-row').length === 1) {
621                        var $groupcols = $table.find('> thead > tr:last-child > th[data-group="' + data.group + '"]:visible, > thead > tr:last-child > th[data-group="' + data.group + '"]:visible'),
622                            $group = $table.find('> thead > tr.footable-group-row > th[data-group="' + data.group + '"], > thead > tr.footable-group-row > td[data-group="' + data.group + '"]'),
623                            groupspan = 0;
624
625                        $.each($groupcols, function () {
626                            groupspan += parseInt($(this).attr('colspan') || 1, 10);
627                        });
628
629                        if (groupspan > 0) $group.attr('colspan', groupspan).show();
630                        else $group.hide();
631                    }
632                })
633                .end()
634                .find('> tbody > tr.' + cls.detailShow).each(function () {
635                    ft.createOrUpdateDetailRow(this);
636                });
637
638            $table.find('> tbody > tr.' + cls.detailShow + ':visible').each(function () {
639                var $next = $(this).next();
640                if ($next.hasClass(cls.detail)) {
641                    if (!hasBreakpointFired) $next.hide();
642                    else $next.show();
643                }
644            });
645
646            // adding .footable-first-column and .footable-last-column to the first and last th and td of each row in order to allow
647            // for styling if the first or last column is hidden (which won't work using :first-child or :last-child)
648            $table.find('> thead > tr > th.footable-last-column, > tbody > tr > td.footable-last-column').removeClass('footable-last-column');
649            $table.find('> thead > tr > th.footable-first-column, > tbody > tr > td.footable-first-column').removeClass('footable-first-column');
650            $table.find('> thead > tr, > tbody > tr')
651                .find('> th.footable-visible:last, > td.footable-visible:last')
652                .addClass('footable-last-column')
653                .end()
654                .find('> th.footable-visible:first, > td.footable-visible:first')
655                .addClass('footable-first-column');
656
657            ft.raise(evt.redrawn);
658        };
659
660        ft.toggleDetail = function (row) {
661            var $row = (row.jquery) ? row : $(row),
662                $next = $row.next();
663
664            //check if the row is already expanded
665            if ($row.hasClass(cls.detailShow)) {
666                $row.removeClass(cls.detailShow);
667
668                //only hide the next row if it's a detail row
669                if ($next.hasClass(cls.detail)) $next.hide();
670
671                ft.raise(evt.rowCollapsed, { 'row': $row[0] });
672
673            } else {
674                ft.createOrUpdateDetailRow($row[0]);
675                $row.addClass(cls.detailShow)
676					.next().show();
677
678                ft.raise(evt.rowExpanded, { 'row': $row[0] });
679            }
680        };
681
682        ft.removeRow = function (row) {
683            var $row = (row.jquery) ? row : $(row);
684            if ($row.hasClass(cls.detail)) {
685                $row = $row.prev();
686            }
687            var $next = $row.next();
688            if ($row.data('detail_created') === true) {
689                //remove the detail row
690                $next.remove();
691            }
692            $row.remove();
693
694            //raise event
695            ft.raise(evt.rowRemoved);
696        };
697
698        ft.appendRow = function (row) {
699            var $row = (row.jquery) ? row : $(row);
700            $(ft.table).find('tbody').append($row);
701
702            //redraw the table
703            ft.redraw();
704        };
705
706        ft.getColumnFromTdIndex = function (index) {
707            /// <summary>Returns the correct column data for the supplied index taking into account colspans.
707</summary>
708            /// <param name="index">The index to retrieve the column data for.</param>
709            /// <returns type="json">A JSON object containing the column data for the supplied index.</returns>
710            var result = null;
711            for (var column in ft.columns) {
712                if ($.inArray(index, ft.columns[column].matches) >= 0) {
713                    result = ft.columns[column];
714                    break;
715                }
716            }
717            return result;
718        };
719
720        ft.createOrUpdateDetailRow = function (actualRow) {
721            var $row = $(actualRow), $next = $row.next(), $detail, values = [];
722            if ($row.data('detail_created') === true) return true;
723
724            if ($row.is(':hidden')) return false; //if the row is hidden for some reason (perhaps filtered) then get out of here
725            ft.raise(evt.rowDetailUpdating, { 'row': $row, 'detail': $next });
726            $row.find('> td:hidden').each(function () {
727                var index = $(this).index(), column = ft.getColumnFromTdIndex(index), name = column.name;
728                if (column.ignore === true) return true;
729
730                if (index in column.names) name = column.names[index];
731                values.push({ 'name': name, 'value': ft.parse(this, column), 'display': $.trim($(this).html()), 'group': column.group, 'groupName': column.groupName });
732                return true;
733            });
734            if (values.length === 0) return false; //return if we don't have any data to show
735            var colspan = $row.find('> td:visible').length;
736            var exists = $next.hasClass(cls.detail);
737            if (!exists) { // Create
738                $next = $('<tr class="' + cls.detail + '"><td class="' + cls.detailCell + '"><div class="' + cls.detailInner + '"></div></td></tr>');
739                $row.after($next);
740            }
741            $next.find('> td:first').attr('colspan', colspan);
742            $detail = $next.find('.' + cls.detailInner).empty();
743            opt.createDetail($detail, values, opt.createGroupedDetail, opt.detailSeparator, cls);
744            $row.data('detail_created', true);
745            ft.raise(evt.rowDetailUpdated, { 'row': $row, 'detail': $next });
746            return !exists;
747        };
748
749        ft.raise = function (eventName, args) {
750
751            if (ft.options.debug === true && $.isFunction(ft.options.log)) ft.options.log(eventName, 'event');
752
753            args = args || { };
754            var def = { 'ft': ft };
755            $.extend(true, def, args);
756            var e = $.Event(eventName, def);
757            if (!e.ft) {
758                $.extend(true, e, def);
759            } //pre jQuery 1.6 which did not allow data to be passed to event object constructor
760            $(ft.table).trigger(e);
761            return e;
762        };
763
764        //reset the state of FooTable
765        ft.reset = function() {
766            var $table = $(ft.table);
767            $table.removeData('footable_info')
768                .data('breakpoint', '')
769                .removeClass(cls.loading)
770                .removeClass(cls.loaded);
771
772            $table.find(opt.toggleSelector).unbind(trg.toggleRow).unbind('click.footable');
773
774            $table.find('> tbody > tr').removeClass(cls.detailShow);
775
776            $table.find('> tbody > tr.' + cls.detail).remove();
777
778            ft.raise(evt.reset);
779        };
780
781        ft.init();
782        return ft;
783    }
784})(jQuery, window);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.