PageSourceSearch

https://www.tasteofamritsar.com.au/vendor/js/footable.js?v=1783000289

js tasteofamritsar.com.au collected 2026-09-26 19:30:16 UTC 39,700 bytes, 824 lines download raw bytes

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