PageSourceSearch

https://upb.ro/wp-content/plugins/modern-events-calendar-lite/asse…/featherlight/featherlight.js?ver=6.5.5

js upb.ro collected 2026-09-24 08:59:20 UTC 30,811 bytes, 667 lines download raw bytes

1/**
2 * Featherlight - ultra slim jQuery lightbox
3 * Version 1.7.14-UMD - http://noelboss.github.io/featherlight/
4 *
5 * Copyright 2019, Noël Raoul Bossart (http://www.noelboss.com)
6 * MIT Licensed.
7**/
8(function (factory) {
9    if (typeof define === 'function' && define.amd) {
10        // AMD. Register as an anonymous module.
11        define(['jquery'], factory);
12    } else if (typeof module === 'object' && module.exports) {
13        // Node/CommonJS
14        module.exports = function (root, jQuery) {
15            if (jQuery === undefined) {
16                // require('jQuery') returns a factory that requires window to
17                // build a jQuery instance, we normalize how we use modules
18                // that require this pattern but the window provided is a noop
19                // if it's defined (how jquery works)
20                if (typeof window !== 'undefined') {
21                    jQuery = require('jquery');
22                } else {
23                    jQuery = require('jquery')(root);
24                }
25            }
26            factory(jQuery);
27            return jQuery;
28        };
29    } else {
30        // Browser globals
31        factory(jQuery);
32    }
33})(function ($) {
34    "use strict";
35
36    if ('undefined' === typeof $) {
37        if ('console' in window) { window.console.info('Too much lightness, Featherlight needs jQuery.'); }
38        return;
39    }
40    if ($.fn.jquery.match(/-ajax/)) {
41        if ('console' in window) { window.console.info('Featherlight needs regular jQuery, not the slim version.'); }
42        return;
43    }
44	/* Featherlight is exported as $.featherlight.
45	   It is a function used to open a featherlight lightbox.
46	   [tech]
47	   Featherlight uses prototype inheritance.
48	   Each opened lightbox will have a corresponding object.
49	   That object may have some attributes that override the
50	   prototype's.
51	   Extensions created with Featherlight.extend will have their
52	   own prototype that inherits from Featherlight's prototype,
53	   thus attributes can be overriden either at the object level,
54	   or at the extension level.
55	   To create callbacks that chain themselves instead of overriding,
56	   use chainCallbacks.
57	   For those familiar with CoffeeScript, this correspond to
58	   Featherlight being a class and the Gallery being a class
59	   extending Featherlight.
60	   The chainCallbacks is used since we don't have access to
61	   CoffeeScript's `super`.
62	*/
63
64    function Featherlight($content, config) {
65        if (this instanceof Featherlight) {  /* called with new */
66            this.id = Featherlight.id++;
67            this.setup($content, config);
68            this.chainCallbacks(Featherlight._callbackChain);
69        } else {
70            var fl = new Featherlight($content, config);
71            fl.open();
72            return fl;
73        }
74    }
75
76    var opened = [],
77        pruneOpened = function (remove) {
78            opened = $.grep(opened, function (fl) {
79                return fl !== remove && fl.$instance.closest('body').length > 0;
80            });
81            return opened;
82        };
83
84    // Removes keys of `set` from `obj` and returns the removed key/values.
85    function slice(obj, set) {
86        var r = {};
87        for (var key in obj) {
88            if (key in set) {
89                r[key] = obj[key];
90                delete obj[key];
91            }
92        }
93        return r;
94    }
95
96    // NOTE: List of available [iframe attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe).
97    var iFrameAttributeSet = {
98        allow: 1, allowfullscreen: 1, frameborder: 1, height: 1, longdesc: 1, marginheight: 1, marginwidth: 1,
99        mozallowfullscreen: 1, name: 1, referrerpolicy: 1, sandbox: 1, scrolling: 1, src: 1, srcdoc: 1, style: 1,
100        webkitallowfullscreen: 1, width: 1
101    };
102
103    // Converts camelCased attributes to dasherized versions for given prefix:
104    //   parseAttrs({hello: 1, hellFrozeOver: 2}, 'hell') => {froze-over: 2}
105    function parseAttrs(obj, prefix) {
106        var attrs = {},
107            regex = new RegExp('^' + prefix + '([A-Z])(.*)');
108        for (var key in obj) {
109            var match = key.match(regex);
110            if (match) {
111                var dasherized = (match[1] + match[2].replace(/([A-Z])/g, '-$1')).toLowerCase();
112                attrs[dasherized] = obj[key];
113            }
114        }
115        return attrs;
116    }
117
118    /* document wide key handler */
119    var eventMap = { keyup: 'onKeyUp', resize: 'onResize' };
120
121    var globalEventHandler = function (event) {
122        $.each(Featherlight.opened().reverse(), function () {
123            if (!event.isDefaultPrevented()) {
124                if (false === this[eventMap[event.type]](event)) {
125                    event.preventDefault(); event.stopPropagation(); return false;
126                }
127            }
128        });
129    };
130
131    var toggleGlobalEvents = function (set) {
132        if (set !== Featherlight._globalHandlerInstalled) {
133            Featherlight._globalHandlerInstalled = set;
134            var events = $.map(eventMap, function (_, name) { return name + '.' + Featherlight.prototype.namespace; }).join(' ');
135            $(window)[set ? 'on' : 'off'](events, globalEventHandler);
136        }
137    };
138
139    Featherlight.prototype = {
140        constructor: Featherlight,
141        /*** defaults ***/
142        /* extend featherlight with defaults and methods */
143        namespace: 'featherlight',        /* Name of the events and css class prefix */
144        targetAttr: 'data-featherlight',   /* Attribute of the triggered element that contains the selector to the lightbox content */
145        variant: null,                  /* Class that will be added to change look of the lightbox */
146        resetCss: false,                 /* Reset all css */
147        background: null,                  /* Custom DOM for the background, wrapper and the closebutton */
148        openTrigger: 'click',               /* Event that triggers the lightbox */
149        closeTrigger: 'click',               /* Event that triggers the closing of the lightbox */
150        filter: null,                  /* Selector to filter events. Think $(...).on('click', filter, eventHandler) */
151        root: 'body',                /* Where to append featherlights */
152        openSpeed: 250,                   /* Duration of opening animation */
153        closeSpeed: 250,                   /* Duration of closing animation */
154        closeOnClick: 'background',          /* Close lightbox on click ('background', 'anywhere' or false) */
155        closeOnEsc: true,                  /* Close lightbox when pressing esc */
156        closeIcon: '✕',            /* Close icon */
157        loading: '',                    /* Content to show while initial content is loading */
158        persist: false,                 /* If set, the content will persist and will be shown again when opened again. 'shared' is a special value when binding multiple elements for them to share the same content */
159        otherClose: null,                  /* Selector for alternate close buttons (e.g. "a.close") */
160        beforeOpen: $.noop,                /* Called before open. can return false to prevent opening of lightbox. Gets event as parameter, this contains all data */
161        beforeContent: $.noop,                /* Called when content is loaded. Gets event as parameter, this contains all data */
162        beforeClose: $.noop,                /* Called before close. can return false to prevent closing of lightbox. Gets event as parameter, this contains all data */
163        afterOpen: $.noop,                /* Called after open. Gets event as parameter, this contains all data */
164        afterContent: $.noop,                /* Called after content is ready and has been set. Gets event as parameter, this contains all data */
165        afterClose: $.noop,                /* Called after close. Gets event as parameter, this contains all data */
166        onKeyUp: $.noop,                /* Called on key up for the frontmost featherlight */
167        onResize: $.noop,                /* Called after new content and when a window is resized */
168        type: null,                  /* Specify type of lightbox. If unset, it will check for the targetAttrs value. */
169        contentFilters: ['jquery', 'image', 'html', 'ajax', 'iframe', 'text'], /* List of content filters to use to determine the content */
170
171        /*** methods ***/
172        /* setup iterates over a single instance of featherlight and prepares the background and binds the events */
173        setup: function (target, config) {
174            /* all arguments are optional */
175            if (typeof target === 'object' && target instanceof $ === false && !config) {
176                config = target;
177                target = undefined;
178            }
179
180            var self = $.extend(this, config, { target: target }),
181                css = !self.resetCss ? self.namespace : self.namespace + '-reset', /* by adding -reset to the classname, we reset all the default css */
182                $background = $(self.background || [
183                    '<div class="' + css + '-loading ' + css + '">',
184                    '<div class="' + css + '-content">',
185                    '<button class="' + css + '-close-icon ' + self.namespace + '-close" aria-label="Close">',
186                    self.closeIcon,
187                    '</button>',
188                    '<div class="' + self.namespace + '-inner">' + self.loading + '</div>',
189                    '</div>',
190                    '</div>'].join('')),
191                closeButtonSelector = '.' + self.namespace + '-close' + (self.otherClose ? ',' + self.otherClose : '');
192
193            self.$instance = $background.clone().addClass(self.variant); /* clone DOM for the background, wrapper and the close button */
194
195            /* close when click on background/anywhere/null or closebox */
196            self.$instance.on(self.closeTrigger + '.' + self.namespace, function (event) {
197                if (event.isDefaultPrevented()) {
198                    return;
199                }
200                var $target = $(event.target);
201                if (('background' === self.closeOnClick && $target.is('.' + self.namespace))
202                    || 'anywhere' === self.closeOnClick
203                    || $target.closest(closeButtonSelector).length) {
204                    self.close(event);
205                    event.preventDefault();
206                }
207            });
208
209            return this;
210        },
211
212        /* this method prepares the content and converts it into a 
212jQuery object or a promise */
213        getContent: function () {
214            if (this.persist !== false && this.$content) {
215                return this.$content;
216            }
217            var self = this,
218                filters = this.constructor.contentFilters,
219                readTargetAttr = function (name) { return self.$currentTarget && self.$currentTarget.attr(name); },
220                targetValue = readTargetAttr(self.targetAttr),
221                data = self.target || targetValue || '';
222
223            /* Find which filter applies */
224            var filter = filters[self.type]; /* check explicit type like {type: 'image'} */
225
226            /* check explicit type like data-featherlight="image" */
227            if (!filter && data in filters) {
228                filter = filters[data];
229                data = self.target && targetValue;
230            }
231            data = data || readTargetAttr('href') || '';
232
233            /* check explicity type & content like {image: 'photo.jpg'} */
234            if (!filter) {
235                for (var filterName in filters) {
236                    if (self[filterName]) {
237                        filter = filters[filterName];
238                        data = self[filterName];
239                    }
240                }
241            }
242
243            /* otherwise it's implicit, run checks */
244            if (!filter) {
245                var target = data;
246                data = null;
247                $.each(self.contentFilters, function () {
248                    filter = filters[this];
249                    if (filter.test) {
250                        data = filter.test(target);
251                    }
252                    if (!data && filter.regex && target.match && target.match(filter.regex)) {
253                        data = target;
254                    }
255                    return !data;
256                });
257                if (!data) {
258                    if ('console' in window) { window.console.error('Featherlight: no content filter found ' + (target ? ' for "' + target + '"' : ' (no target specified)')); }
259                    return false;
260                }
261            }
262            /* Process it */
263            return filter.process.call(self, data);
264        },
265
266        /* sets the content of $instance to $content */
267        setContent: function ($content) {
268            this.$instance.removeClass(this.namespace + '-loading');
269
270            /* we need a special class for the iframe */
271            this.$instance.toggleClass(this.namespace + '-iframe', $content.is('iframe'));
272
273            /* replace content by appending to existing one before it is removed
274               this insures that featherlight-inner remain at the same relative
275               position to any other items added to featherlight-content */
276            this.$instance.find('.' + this.namespace + '-inner')
277                .not($content)                /* excluded new content, important if persisted */
278                .slice(1).remove().end()      /* In the unexpected event where there are many inner elements, remove all but the first one */
279                .replaceWith($.contains(this.$instance[0], $content[0]) ? '' : $content);
280
281            this.$content = $content.addClass(this.namespace + '-inner');
282
283            return this;
284        },
285
286		/* opens the lightbox. "this" contains $instance with the lightbox, and with the config.
287			Returns a promise that is resolved after is successfully opened. */
288        open: function (event) {
289            var self = this;
290            self.$instance.hide().appendTo(self.root);
291            if ((!event || !event.isDefaultPrevented())
292                && self.beforeOpen(event) !== false) {
293
294                if (event) {
295                    event.preventDefault();
296                }
297                var $content = self.getContent();
298
299                if ($content) {
300                    opened.push(self);
301
302                    toggleGlobalEvents(true);
303
304                    self.$instance.fadeIn(self.openSpeed);
305                    self.beforeContent(event);
306
307                    /* Set content and show */
308                    return $.when($content)
309                        .always(function ($openendContent) {
310                            if ($openendContent) {
311                                self.setContent($openendContent);
312                                self.afterContent(event);
313                            }
314                        })
315                        .then(self.$instance.promise())
316                        /* Call afterOpen after fadeIn is done */
317                        .done(function () { self.afterOpen(event); });
318                }
319            }
320            self.$instance.detach();
321            return $.Deferred().reject().promise();
322        },
323
324		/* closes the lightbox. "this" contains $instance with the lightbox, and with the config
325			returns a promise, resolved after the lightbox is successfully closed. */
326        close: function (event) {
327            var self = this,
328                deferred = $.Deferred();
329
330            if (self.beforeClose(event) === false) {
331                deferred.reject();
332            } else {
333
334                if (0 === pruneOpened(self).length) {
335                    toggleGlobalEvents(false);
336                }
337
338                self.$instance.fadeOut(self.closeSpeed, function () {
339                    self.$instance.detach();
340                    self.afterClose(event);
341                    deferred.resolve();
342                });
343            }
344            return deferred.promise();
345        },
346
347		/* resizes the content so it fits in visible area and keeps the same aspect ratio.
348				Does nothing if either the width or the height is not specified.
349				Called automatically on window resize.
350				Override if you want different behavior. */
351        resize: function (w, h) {
352            if (w && h) {
353                /* Reset apparent image size first so container grows */
354                this.$content.css('width', '').css('height', '');
355                /* Calculate the worst ratio so that dimensions fit */
356                /* Note: -1 to avoid rounding errors */
357                var ratio = Math.max(
358                    w / (this.$content.parent().width() - 1),
359                    h / (this.$content.parent().height() - 1));
360                /* Resize content */
361                if (ratio > 1) {
362                    ratio = h / Math.floor(h / ratio); /* Round ratio down so height calc works */
363                    this.$content.css('width', '' + w / ratio + 'px').css('height', '' + h / ratio + 'px');
364                }
365            }
366        },
367
368		/* Utility function to chain callbacks
369		   [Warning: guru-level]
370		   Used be extensions that want to let users specify callbacks but
371		   also need themselves to use the callbacks.
372		   The argument 'chain' has callback names as keys and function(super, event)
373		   as values. That function is meant to call `super` at some point.
374		*/
375        chainCallbacks: function (chain) {
376            for (var name in chain) {
377                this[name] = $.proxy(chain[name], this, $.proxy(this[name], this));
378            }
379        }
380    };
381
382    $.extend(Featherlight, {
383        id: 0,                                    /* Used to id single featherlight instances */
384        autoBind: '[data-featherlight]',    /* Will automatically bind elements matching this selector. Clear or set before onReady */
385        defaults: Featherlight.prototype,   /* You can access and override all defaults using $.featherlight.defaults, which is just a synonym for $.featherlight.prototype */
386        /* Contains the logic to determine content */
387        contentFilters: {
388            jquery: {
389                regex: /^[#.]\w/,         /* Anything that starts with a class name or identifiers */
390                test: function (elem) { return elem instanceof $ && elem; },
391                process: function (elem) { return this.persist !== false ? $(elem) : $(elem).clone(true); }
392            },
393            image: {
394                regex: /\.(png|jpg|jpeg|gif|tiff?|bmp|svg)(\?\S*)?$/i,
395                process: function (url) {
396                    var self = this,
397                        deferred = $.Deferred(),
398                        img = new Image(),
399                        $img = $('<img src="' + url + '" alt="" class="' + self.namespace + '-image" />');
400                    img.onload = function () {
401                        /* Store naturalWidth & height for IE8 */
402                        $img.naturalWidth = img.width; $img.naturalHeight = img.height;
403                        deferred.resolve($img);
404                    };
405                    img.onerror = function () { deferred.reject($img); };
406                    img.src = url;
407                    return deferred.promise();
408                }
409            },
410            html: {
411                regex: /^\s*<[\w!][^<]*>/, /* Anything that starts with some kind of valid tag */
412                process: function (html) { return $(html); }
413            },
414            ajax: {
415                regex: /./,            /* At this point, any content is assumed to be an URL */
416                process: function (url) {
417                    var self = this,
418                        deferred = $.Deferred();
419                    /* we are using load so one can specify a target with: url.html #targetelement */
420                    var $container = $('<div></div>').load(url, function (response, status) {
421                        if (status !== "error") {
422                            deferred.resolve($container.contents());
423                        }
424                        deferred.reject();
425                    });
426                    return deferred.promise();
427                }
428            },
429            iframe: {
430                process: function (url) {
431                    var deferred = new $.Deferred();
432                    var $content = $('<iframe/>');
433                    var css = parseAttrs(this, 'iframe');
434                    var attrs = slice(css, iFrameAttributeSet);
435                    $content.hide()
436                        .attr('src', url)
437                        .attr(attrs)
438                        .css(css)
439                        .on('load', function () { deferred.resolve($content.show()); })
440                        // We can't move an <iframe> and avoid reloading it,
441                        // so let's put it in place ourselves right now:
442                        .appendTo(this.$instance.find('.' + this.namespace + '-content'));
443                    return deferred.promise();
444                }
445            },
446            text: {
447                process: function (text) { return $('<div>', { text: text }); }
448            }
449        },
450
451        functionAttributes: ['beforeOpen', 'afterOpen', 'beforeContent', 'afterContent', 'beforeClose', 'afterClose'],
452
453        /*** class methods ***/
454        /* read element's attributes starting with data-featherlight- */
455        readElementConfig: function (element, namespace) {
456            var Klass = this,
457                regexp = new RegExp('^data-' + namespace + '-(.*)'),
458                config = {};
459            if (element && element.attributes) {
460                $.each(element.attributes, function () {
461                    var match = this.name.match(regexp);
462                    if (match) {
463                        var val = this.value,
464                            name = $.camelCase(match[1]);
465                        if ($.inArray(name, Klass.functionAttributes) >= 0) {  /* jshint -W054 */
466                            val = new Function(val);                           /* jshint +W054 */
467                        } else {
468                            try { val = JSON.parse(val); }
469                            catch (e) { }
470                        }
471                        config[name] = val;
472                    }
473                });
474            }
475            return config;
476        },
477
478		/* Used to create a Featherlight extension
479		   [Warning: guru-level]
480		   Creates the extension's prototype that in turn
481		   inherits Featherlight's prototype.
482		   Could be used to extend an extension too...
483		   This is pretty high level wizardy, it comes pretty much straight
484		   from CoffeeScript and won't teach you anything about Featherlight
485		   as it's not really specific to this library.
486		   My suggestion: move along and keep your sanity.
487		*/
488        extend: function (child, defaults) {
489            /* Setup class hierarchy, adapted from CoffeeScript */
490            var Ctor = function () { this.constructor = child; };
491            Ctor.prototype = this.prototype;
492            child.prototype = new Ctor();
493            child.__super__ = this.prototype;
494            /* Copy class methods & attributes */
495            $.extend(child, this, defaults);
496            child.defaults = child.prototype;
497            return child;
498        },
499
500        attach: function ($source, $content, config) {
501            var Klass = this;
502            if (typeof $content === 'object' && $content instanceof $ === false && !config) {
503                config = $content;
504                $content = undefined;
505            }
506            /* make a copy */
507            config = $.extend({}, config);
508
509            /* Only for openTrigger, filter & namespace... */
510            var namespace = config.namespace || Klass.defaults.namespace,
511                tempConfig = $.extend({}, Klass.defaults, Klass.readElementConfig($source[0], namespace), c
511onfig),
512                sharedPersist;
513            var handler = function (event) {
514                var $target = $(event.currentTarget);
515                /* ... since we might as well compute the config on the actual target */
516                var elemConfig = $.extend(
517                    { $source: $source, $currentTarget: $target },
518                    Klass.readElementConfig($source[0], tempConfig.namespace),
519                    Klass.readElementConfig(event.currentTarget, tempConfig.namespace),
520                    config);
521                var fl = sharedPersist || $target.data('featherlight-persisted') || new Klass($content, elemConfig);
522                if (fl.persist === 'shared') {
523                    sharedPersist = fl;
524                } else if (fl.persist !== false) {
525                    $target.data('featherlight-persisted', fl);
526                }
527                if (elemConfig.$currentTarget.blur) {
528                    elemConfig.$currentTarget.blur(); // Otherwise 'enter' key might trigger the dialog again
529                }
530                fl.open(event);
531            };
532
533            $source.on(tempConfig.openTrigger + '.' + tempConfig.namespace, tempConfig.filter, handler);
534
535            return { filter: tempConfig.filter, handler: handler };
536        },
537
538        current: function () {
539            var all = this.opened();
540            return all[all.length - 1] || null;
541        },
542
543        opened: function () {
544            var klass = this;
545            pruneOpened();
546            return $.grep(opened, function (fl) { return fl instanceof klass; });
547        },
548
549        close: function (event) {
550            var cur = this.current();
551            if (cur) { return cur.close(event); }
552        },
553
554		/* Does the auto binding on startup.
555		   Meant only to be used by Featherlight and its extensions
556		*/
557        _onReady: function () {
558            var Klass = this;
559            if (Klass.autoBind) {
560                var $autobound = $(Klass.autoBind);
561                /* Bind existing elements */
562                $autobound.each(function () {
563                    Klass.attach($(this));
564                });
565                /* If a click propagates to the document level, then we have an item that was added later on */
566                $(document).on('click', Klass.autoBind, function (evt) {
567                    if (evt.isDefaultPrevented()) {
568                        return;
569                    }
570                    var $cur = $(evt.currentTarget);
571                    var len = $autobound.length;
572                    $autobound = $autobound.add($cur);
573                    if (len === $autobound.length) {
574                        return; /* already bound */
575                    }
576                    /* Bind featherlight */
577                    var data = Klass.attach($cur);
578                    /* Dispatch event directly */
579                    if (!data.filter || $(evt.target).parentsUntil($cur, data.filter).length > 0) {
580                        data.handler(evt);
581                    }
582                });
583            }
584        },
585
586		/* Featherlight uses the onKeyUp callback to intercept the escape key.
587		   Private to Featherlight.
588		*/
589        _callbackChain: {
590            onKeyUp: function (_super, event) {
591                if (27 === event.keyCode) {
592                    if (this.closeOnEsc) {
593                        $.featherlight.close(event);
594                    }
595                    return false;
596                } else {
597                    return _super(event);
598                }
599            },
600
601            beforeOpen: function (_super, event) {
602                // Used to disable scrolling
603                $(document.documentElement).addClass('with-featherlight');
604
605                // Remember focus:
606                this._previouslyActive = document.activeElement;
607
608                // Disable tabbing:
609                // See http://stackoverflow.com/questions/1599660/which-html-elements-can-receive-focus
610                this._$previouslyTabbable = $("a, input, select, textarea, iframe, button, iframe, [contentEditable=true]")
611                    .not('[tabindex]')
612                    .not(this.$instance.find('button'));
613
614                this._$previouslyWithTabIndex = $('[tabindex]').not('[tabindex="-1"]');
615                this._previousWithTabIndices = this._$previouslyWithTabIndex.map(function (_i, elem) {
616                    return $(elem).attr('tabindex');
617                });
618
619                this._$previouslyWithTabIndex.add(this._$previouslyTabbable).attr('tabindex', -1);
620
621                if (document.activeElement.blur) {
622                    document.activeElement.blur();
623                }
624                return _super(event);
625            },
626
627            afterClose: function (_super, event) {
628                var r = _super(event);
629                // Restore focus
630                var self = this;
631                this._$previouslyTabbable.removeAttr('tabindex');
632                this._$previouslyWithTabIndex.each(function (i, elem) {
633                    $(elem).attr('tabindex', self._previousWithTabIndices[i]);
634                });
635                this._previouslyActive.focus();
636                // Restore scroll
637                if (Featherlight.opened().length === 0) {
638                    $(document.documentElement).removeClass('with-featherlight');
639                }
640                return r;
641            },
642
643            onResize: function (_super, event) {
644                this.resize(this.$content.naturalWidth, this.$content.naturalHeight);
645                return _super(event);
646            },
647
648            afterContent: function (_super, event) {
649                var r = _super(event);
650                this.$instance.find('[autofocus]:not([disabled])').focus();
651                this.onResize(event);
652                return r;
653            }
654        }
655    });
656
657    $.featherlight = Featherlight;
658
659    /* bind jQuery elements to trigger featherlight */
660    $.fn.featherlight = function ($content, config) {
661        Featherlight.attach(this, $content, config);
662        return this;
663    };
664
665    /* bind featherlight on ready if config autoBind is set */
666    $(document).ready(function () { Featherlight._onReady(); });
667});

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.