PageSourceSearch

https://www.gpw.pl/html/js/footable.js

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