PageSourceSearch

https://www.usd113.org/javascripts/jquery/plugins/lightGallery-fes.js

js usd113.org collected 2026-10-08 16:45:17 UTC 45,724 bytes, 1,383 lines download raw bytes

1/*! lightgallery - v1.6.12 - 2019-02-19
2* http://sachinchoolur.github.io/lightGallery/
3* Copyright (c) 2019 Sachin N; Licensed GPLv3 */
4(function (root, factory) {
5  if (typeof define === 'function' && define.amd) {
6    // AMD. Register as an anonymous module unless amdModuleId is set
7    define(['jquery'], function (a0) {
8      return (factory(a0));
9    });
10  } else if (typeof module === 'object' && module.exports) {
11    // Node. Does not work with strict CommonJS, but
12    // only CommonJS-like environments that support module.exports,
13    // like Node.
14    module.exports = factory(require('jquery'));
15  } else {
16    factory(root["jQuery"]);
17  }
18}(this, function ($) {
19
20(function() {
21    'use strict';
22
23    var defaults = {
24
25        mode: 'lg-slide',
26
27        // Ex : 'ease'
28        cssEasing: 'ease',
29
30        //'for jquery animation'
31        easing: 'linear',
32        speed: 600,
33        height: '100%',
34        width: '100%',
35        addClass: '',
36        startClass: 'lg-start-zoom',
37        backdropDuration: 150,
38        hideBarsDelay: 6000,
39
40        useLeft: false,
41
42        closable: true,
43        loop: true,
44        escKey: true,
45        keyPress: true,
46        controls: true,
47        slideEndAnimatoin: true,
48        hideControlOnEnd: false,
49        mousewheel: true,
50
51        getCaptionFromTitleOrAlt: true,
52
53        // .lg-item || '.lg-sub-html'
54        appendSubHtmlTo: '.lg-sub-html',
55
56        subHtmlSelectorRelative: false,
57
58        /**
59         * @desc number of preload slides
60         * will exicute only after the current slide is fully loaded.
61         *
62         * @ex you clicked on 4th image and if preload = 1 then 3rd slide and 5th
63         * slide will be loaded in the background after the 4th slide is fully loaded..
64         * if preload is 2 then 2nd 3rd 5th 6th slides will be preloaded.. ... ...
65         *
66         */
67        preload: 1,
68        showAfterLoad: true,
69        selector: '',
70        selectWithin: '',
71        nextHtml: '',
72        prevHtml: '',
73
74        // 0, 1
75        index: false,
76
77        iframeMaxWidth: '100%',
78
79        download: true,
80        counter: true,
81        appendCounterTo: '.lg-toolbar',
82
83        swipeThreshold: 50,
84        enableSwipe: true,
85        enableDrag: true,
86
87        dynamic: false,
88        dynamicEl: [],
89        galleryId: 1
90    };
91
92    function Plugin(element, options) {
93
94        // Current lightGallery element
95        this.el = element;
96
97        // Current jquery element
98        this.$el = $(element);
99
100        // lightGallery settings
101        this.s = $.extend({}, defaults, options);
102
103        // When using dynamic mode, ensure dynamicEl is an array
104        if (this.s.dynamic && this.s.dynamicEl !== 'undefined' && this.s.dynamicEl.constructor === Array && !this.s.dynamicEl.length) {
105            throw ('When using dynamic mode, you must also define dynamicEl as an Array.');
106        }
107
108        // lightGallery modules
109        this.modules = {};
110
111        // false when lightgallery complete first slide;
112        this.lGalleryOn = false;
113
114        this.lgBusy = false;
115
116        // Timeout function for hiding controls;
117        this.hideBartimeout = false;
118
119        // To determine browser supports for touch events;
120        this.isTouch = ('ontouchstart' in document.documentElement);
121
122        // Disable hideControlOnEnd if sildeEndAnimation is true
123        if (this.s.slideEndAnimatoin) {
124            this.s.hideControlOnEnd = false;
125        }
126
127        // Gallery items
128        if (this.s.dynamic) {
129            this.$items = this.s.dynamicEl;
130        } else {
131            if (this.s.selector === 'this') {
132                this.$items = this.$el;
133            } else if (this.s.selector !== '') {
134                if (this.s.selectWithin) {
135                    this.$items = $(this.s.selectWithin).find(this.s.selector);
136                } else {
137                    this.$items = this.$el.find($(this.s.selector));
138                }
139            } else {
140                this.$items = this.$el.children();
141            }
142        }
143
144        // .lg-item
145        this.$slide = '';
146
147        // .lg-outer
148        this.$outer = '';
149
150        this.init();
151
152        return this;
153    }
154
155    Plugin.prototype.init = function() {
156
157        var _this = this;
158
159        // s.preload should not be more than $item.length
160        if (_this.s.preload > _this.$items.length) {
161            _this.s.preload = _this.$items.length;
162        }
163
164        // if dynamic option is enabled execute immediately
165        var _hash = window.location.hash;
166        if (_hash.indexOf('lg=' + this.s.galleryId) > 0) {
167
168            _this.index = parseInt(_hash.split('&slide=')[1], 10);
169
170            $('body').addClass('lg-from-hash');
171            if (!$('body').hasClass('lg-on')) {
172                setTimeout(function() {
173                    _this.build(_this.index);
174                });
175
176                $('body').addClass('lg-on');
177            }
178        }
179
180        if (_this.s.dynamic) {
181
182            _this.$el.trigger('onBeforeOpen.lg');
183
184            _this.index = _this.s.index || 0;
185
186            // prevent accidental double execution
187            if (!$('body').hasClass('lg-on')) {
188                setTimeout(function() {
189                    _this.build(_this.index);
190                    $('body').addClass('lg-on');
191                });
192            }
193        } else {
194
195            // Using different namespace for click because click event should not unbind if selector is same object('this')
196            _this.$items.on('click.lgcustom', function(event) {
197
198                // For IE8
199                try {
200                    event.preventDefault();
201                    event.preventDefault();
202                } catch (er) {
203                    event.returnValue = false;
204                }
205
206                _this.$el.trigger('onBeforeOpen.lg');
207
208                _this.index = _this.s.index || _this.$items.index(this);
209
210                // prevent accidental double execution
211                if (!$('body').hasClass('lg-on')) {
212                    _this.build(_this.index);
213                    $('body').addClass('lg-on');
214                }
215            });
216        }
217
218    };
219
220    Plugin.prototype.build = function(index) {
221
222        var _this = this;
223
224        _this.structure();
225
226        // module constructor
227        $.each($.fn.lightGallery.modules, function(key) {
228            _this.modules[key] = new $.fn.lightGallery.modules[key](_this.el);
229        });
230
231        // initiate slide function
232        _this.slide(index, false, false, false);
233
234        if (_this.s.keyPress) {
235            _this.keyPress();
236        }
237
238        if (_this.$items.length > 1) {
239
240            _this.arrow();
241
242            setTimeout(function() {
243                _this.enableDrag();
244                _this.enableSwipe();
245            }, 50);
246
247            if (_this.s.mousewheel) {
248                _this.mousewheel();
249            }
250        } else {
251            _this.$slide.on('click.lg', function() {
252                _this.$el.trigger('onSlideClick.lg');
253            });
254        }
255
256        _this.counter();
257
258        _this.closeGallery();
259
260        _this.$el.trigger('onAfterOpen.lg');
261
262        // Hide controllers if mouse doesn't move for some period
263        _this.$outer.on('mousemove.lg click.lg touchstart.lg', function() {
264
265            _this.$outer.removeClass('lg-hide-items');
266
267            clearTimeout(_this.hideBartimeout);
268
269            // Timeout will be cleared on each slide movement also
270            _this.hideBartimeout = setTimeout(function() {
271                _this.$outer.addClass('lg-hide-items');
272            }, _this.s.hideBarsDelay);
273
274        });
275
276        _this.$outer.trigger('mousemove.lg');
277
278        //! focus prev arrow for testing
279        $('.lg-prev').focus();
280
281    };
282
283    Plugin.prototype.structure = function() {
284        var list = '';
285        var controls = '';
286        var i = 0;
287        var subHtmlCont = '';
288        var template;
289        var _this = this;
290
291        $('body').append('<div class="lg-backdrop"></div>');
292        $('.lg-backdrop').css('transition-duration', this.s.backdropDuration + 'ms');
293
294        // Create gallery items
295        for (i = 0; i < this.$items.length; i++) {
296            list += '<div class="lg-item"></div>';
297        }
298
299        // Create controlls
300        if (this.s.controls && this.$items.length > 1) {
301            //! add tabindex="#"
302            controls = '<div class="lg-actions">' +
303                '<button class="lg-prev lg-icon" tabindex="102">' + this.s.prevHtml + '</button>' +
304                '<button class="lg-next lg-icon" tabindex="104">' + this.s.nextHtml + '</button>' +
305                '</div>';
306        }
307
308        if (this.s.appendSubHtmlTo === '.lg-sub-html') {
309            subHtmlCont = '<div class="lg-sub-html"></div>';
310        }
311        //! add tabindex="#"
312        template = '<div class="lg-outer ' + this.s.addClass + ' ' + this.s.startClass + '">' +
313            '<div class="lg" style="width:' + this.s.width + '; height:' + this.s.height + '">' +
314            '<div class="lg-inner">' + list + '</div>' +
315            '<div class="lg-toolbar lg-group">' +
316            '<span class="lg-close lg-icon" tabindex="101"></span>' +
317            '</div>' +
318            controls +
319            subHtmlCont +
320            '</div>' +
321            '</div>';
322
323        $('body').append(template);
324        this.$outer = $('.lg-outer');
325        this.$slide = this.$outer.find('.lg-item');
326
327        if (this.s.useLeft) {
328            this.$outer.addClass('lg-use-left');
329
330            // Set mode lg-slide if use left is true;
331            this.s.mode = 'lg-slide';
332        } else {
333            this.$outer.addClass('lg-use-css3');
334        }
335
336        // For fixed height gallery
337        _this.setTop();
338        $(window).on('resize.lg orientationchange.lg', function() {
339            setTimeout(function() {
340                _this.setTop();
341            }, 100);
342        });
343
344        // add class lg-current to remove initial transition
345        this.$slide.eq(this.index).addClass('lg-current');
346
347        // add Class for css support and transition mode
348        if (this.doCss()) {
349            this.$outer.addClass('lg-css3');
350        } else {
351            this.$outer.addClass('lg-css');
352
353            // Set speed 0 because no animation will happen if browser doesn't support css3
354            this.s.speed = 0;
355        }
356
357        this.$outer.addClass(this.s.mode);
358
359        if (this.s.enableDrag && this.$items.length > 1) {
360            this.$outer.addClass('lg-grab');
361        }
362
363        if (this.s.showAfterLoad) {
364            this.$outer.addClass('lg-show-after-load');
365        }
366
367        if (this.doCss()) {
368            var $inner = this.$outer.find('.lg-inner');
369            $inner.css('transition-timing-function', this.s.cssEasing);
370            $inner.css('transition-duration', this.s.speed + 'ms');
371        }
372
373        setTimeout(function() {
374            $('.lg-backdrop').addClass('in');
375        });
376
377        setTimeout(function() {
378            _this.$outer.addClass('lg-visible');
379        }, this.s.backdropDuration);
380
381        if (this.s.download) {
382            this.$outer.find('.lg-toolbar').append('<a id="lg-download" target="_blank" download class="lg-download lg-icon"></a>');
383        }
384
385        // Store the current scroll top value to scroll back after closing the gallery..
386        this.prevScrollTop = $(window).scrollTop();
387
388    };
389
390    // For fixed height gallery
391    Plugin.prototype.setTop = function() {
392        if (this.s.height !== '100%') {
393            var wH = $(window).height();
394            var top = (wH - parseInt(this.s.height, 10)) / 2;
395            var $lGallery = this.$outer.find('.lg');
396            if (wH >= parseInt(this.s.height, 10)) {
397                $lGallery.css('top', top + 'px');
398            } else {
399                $lGallery.css('top', '0px');
400            }
401        }
402    };
403
404    // Find css3 support
405    Plugin.prototype.doCss = function() {
406        // check for css animation support
407        var support = function() {
408            var transition = ['transition', 'MozTransition', 'WebkitTransition', 'OTransition', 'msTransition', 'KhtmlTransition'];
409            var root = document.documentElement;
410            var i = 0;
411            for (i = 0; i < transition.length; i++) {
412                if (transition[i] in root.style) {
413                    return true;
414                }
415            }
416        };
417
418        if (support()) {
419            return true;
420        }
421
422        return false;
423    };
424
425    /**
426     *  @desc Check the given src is video
427     *  @param {String} src
428     *  @return {Object} video type
429     *  Ex:{ youtube  :  ["//www.youtube.com/watch?v=c0asJgSyxcY", "c0asJgSyxcY"] }
430     */
431    Plugin.prototype.isVideo = function(src, index) {
432
433        var html;
434        if (this.s.dynamic) {
435            html = this.s.dynamicEl[index].html;
436        } else {
437            html = this.$items.eq(index).attr('data-html');
438        }
439
440        if (!src) {
441            if(html) {
442                return {
443                    html5: true
444                };
445            } else {
446                console.error('lightGallery :- data-src is not pvovided on slide item ' + (index + 1) + '. Please make sure the selector property is properly configured. More info - http://sachinchoolur.github.io/lightGallery/demos/html-markup.html');
447                return false;
448            }
449        }
450
451        var youtube = src.match(/\/\/(?:www\.)?youtu(?:\.be|be\.com|be-nocookie\.com)\/(?:watch\?v=|embed\/)?([a-z0-9\-\_\%]+)/i);
452        var vimeo = src.match(/\/\/(?:www\.)?vimeo.com\/([0-9a-z\-_]+)/i);
453        var dailymotion = src.match(/\/\/(?:www\.)?dai.ly\/([0-9a-z\-_]+)/i);
454        var vk = src.match(/\/\/(?:www\.)?(?:vk\.com|vkontakte\.ru)\/(?:video_ext\.php\?)(.*)/i);
455
456        if (youtube) {
457            return {
458                youtube: youtube
459            };
460        } else if (vimeo) {
461            return {
462                vimeo: vimeo
463            };
464        } else if (dailymotion) {
465            return {
466                dailymotion: dailymotion
467            };
468        } else if (vk) {
469            return {
470                vk: vk
471            };
472        }
473    };
474
475    /**
476     *  @desc Create image counter
477     *  Ex: 1/10
478     */
479    Plugin.prototype.counter = function() {
480        if (this.s.counter) {
481            $(this.s.appendCounterTo).append('<div id="lg-counter"><span id="lg-counter-current">' + (parseInt(this.index, 10) + 1) + '</span> / <span id="lg-counter-all">' + this.$items.length + '</span></div>');
482        }
483    };
484
485    /**
486     *  @desc add sub-html into the slide
487     *  @param {Number} index - index of the slide
488     */
489    Plugin.prototype.addHtml = function(index) {
490        var subHtml = null;
491        var subHtmlUrl;
492        var $currentEle;
493        if (this.s.dynamic) {
494            if (this.s.dynamicEl[index].subHtmlUrl) {
495                subHtmlUrl = this.s.dynamicEl[index].subHtmlUrl;
496            } else {
497                subHtml = this.s.dynamicEl[index].subHtml;
498            }
499        } else {
500            $currentEle = this.$items.eq(index);
501            if ($currentEle.attr('data-sub-html-url')) {
502                subHtmlUrl = $currentEle.attr('data-sub-html-url');
503            } else {
504                subHtml = $currentEle.attr('data-sub-html');
505                if (this.s.getCaptionFromTitleOrAlt && !subHtml) {
506                    subHtml = $currentEle.attr('title') || $currentEle.find('img').first().attr('alt');
507                }
508            }
509        }
510
511        if (!subHtmlUrl) {
512            if (typeof subHtml !== 'undefined' && subHtml !== null) {
513
514                // get first letter of subhtml
515                // if first letter starts with . or # get the html form the jQuery object
516                var fL = subHtml.substring(0, 1);
517                if (fL === '.' || fL === '#') {
518                    if (this.s.subHtmlSelectorRelative && !this.s.dynamic) {
519                        subHtml = $currentEle.find(subHtml).html();
520                    } else {
521                        subHtml = $(subHtml).html();
522                    }
523                }
524            } else {
525                subHtml = '';
526            }
527        }
528
529        if (this.s.appendSubHtmlTo === '.lg-sub-html') {
530
531            if (subHtmlUrl) {
532                this.$outer.find(this.s.appendSubHtmlTo).load(subHtmlUrl);
533            } else {
534                this.$outer.find(this.s.appendSubHtmlTo).html(subHtml);
535            }
536
537        } else {
538
539            if (subHtmlUrl) {
540                this.$slide.eq(index).load(subHtmlUrl);
541            } else {
542                this.$slide.eq(index).append(subHtml);
543            }
544        }
545
546        // Add lg-empty-html class if title doesn't exist
547        if (typeof subHtml !== 'undefined' && subHtml !== null) {
548            if (subHtml === '') {
549                this.$outer.find(this.s.appendSubHtmlTo).addClass('lg-empty-html');
550            } else {
551                this.$outer.find(this.s.appendSubHtmlTo).removeClass('lg-empty-html');
552            }
553        }
554
555        this.$el.trigger('onAfterAppendSubHtml.lg', [index]);
556    };
557
558    /**
559     *  @desc Preload slides
560     *  @param {Number} index - index of the slide
561     */
562    Plugin.prototype.preload = function(index) {
563        var i = 1;
564        var j = 1;
565        for (i = 1; i <= this.s.preload; i++) {
566            if (i >= this.$items.length - index) {
567                break;
568            }
569
570            this.loadContent(index + i, false, 0);
571        }
572
573        for (j = 1; j <= this.s.preload; j++) {
574            if (index - j < 0) {
575                break;
576            }
577
578            this.loadContent(index - j, false, 0);
579        }
580    };
581
582    /**
583     *  @desc Load slide content into slide.
584     *  @param {Number} index - index of the slide.
585     *  @param {Boolean} rec - if true call loadcontent() function again.
586     *  @param {Boolean} delay - delay for adding complete class. it is 0 except first time.
587     */
588    Plugin.prototype.loadContent = function(index, rec, delay) {
589
590        var _this = this;
591        var _hasPoster = false;
592        var _$img;
593        //! added _alt to make sure we keep the alt when lightboxing
594        var _alt;
595        var _src;
596        var _poster;
597        var _srcset;
598        var _sizes;
599        var _html;
600        var getResponsiveSrc = function(srcItms) {
601            var rsWidth = [];
602            var rsSrc = [];
603            for (var i = 0; i < srcItms.length; i++) {
604                var __src = srcItms[i].split(' ');
605
606                // Manage empty space
607                if (__src[0] === '') {
608                    __src.splice(0, 1);
609                }
610
611                rsSrc.push(__src[0]);
612                rsWidth.push(__src[1]);
613            }
614
615            var wWidth = $(window).width();
616            for (var j = 0; j < rsWidth.length; j++) {
617                if (parseInt(rsWidth[j], 10) > wWidth) {
618                    _src = rsSrc[j];
619                    break;
620                }
621            }
622        };
623
624        if (_this.s.dynamic) {
625
626            if (_this.s.dynamicEl[index].poster) {
627                _hasPoster = true;
628                _poster = _this.s.dynamicEl[index].poster;
629            }
630
631            _html = _this.s.dynamicEl[index].html;
632            _src = _this.s.dynamicEl[index].src;
633
634            if (_this.s.dynamicEl[index].responsive) {
635                var srcDyItms = _this.s.dynamicEl[index].responsive.split(',');
636                getResponsiveSrc(srcDyItms);
637            }
638
639            _srcset = _this.s.dynamicEl[index].srcset;
640            _sizes = _this.s.dynamicEl[index].sizes;
641
642        } else {
643
644            if (_this.$items.eq(index).attr('data-poster')) {
645                _hasPoster = true;
646                _poster = _this.$items.eq(index).attr('data-poster');
647            }
648
649            _html = _this.$items.eq(index).attr('data-html');
650            _src = _this.$items.eq(index).attr('href') || _this.$items.eq(index).attr('data-src');
651            //! added _alt to make sure we keep the alt when lightboxing + using custom data-alt attribute for <a> tag
652            _alt = _this.$items.eq(index).attr('data-alt');
653
654            if (_this.$items.eq(index).attr('data-responsive')) {
655                var srcItms = _this.$items.eq(index).attr('data-responsive').split(',');
656                getResponsiveSrc(srcItms);
657            }
658
659            _srcset = _this.$items.eq(index).attr('data-srcset');
660            _sizes = _this.$items.eq(index).attr('data-sizes');
661
662        }
663
664        //if (_src || _srcset || _sizes || _poster) {
665
666        var iframe = false;
667        if (_this.s.dynamic) {
668            if (_this.s.dynamicEl[index].iframe) {
669                iframe = true;
670            }
671        } else {
672            if (_this.$items.eq(index).attr('data-iframe') === 'true') {
673                iframe = true;
674            }
675        }
676
677        var _isVideo = _this.isVideo(_src, index);
678        if (!_this.$slide.eq(index).hasClass('lg-loaded')) {
679            if (iframe) {
680                _this.$slide.eq(index).prepend('<div class="lg-video-cont lg-has-iframe" style="max-width:' + _this.s.iframeMaxWidth + '"><div class="lg-video"><iframe class="lg-object" frameborder="0" src="' + _src + '"  allowfullscreen="true"></iframe></div></div>');
681            } else if (_hasPoster) {
682                var videoClass = '';
683                if (_isVideo && _isVideo.youtube) {
684                    videoClass = 'lg-has-youtube';
685                } else if (_isVideo && _isVideo.vimeo) {
686                    videoClass = 'lg-has-vimeo';
687                } else {
688                    videoClass = 'lg-has-html5';
689                }
690                //! add tabindex="#"
691                _this.$slide.eq(index).prepend('<div class="lg-video-cont ' + videoClass + ' "><div class="lg-video"><span class="lg-video-play" tabindex="103"></span><img class="lg-object lg-has-poster" src="' + _poster + '" /></div></div>');
692
693            } else if (_isVideo) {
694                _this.$slide.eq(index).prepend('<div class="lg-video-cont "><div class="lg-video"></div></div>');
695                _this.$el.trigger('hasVideo.lg', [index, _src, _html]);
696            } else {
697                //! added _alt to make sure we keep the alt when lightboxing
698                _this.$slide.eq(index).prepend('<div class="lg-img-wrap"><img class="lg-object lg-image" src="' + _src + '" alt="' + _alt + '" /></div>');
699            }
700
701            _this.$el.trigger('onAferAppendSlide.lg', [index]);
702
703            _$img = _this.$slide.eq(index).find('.lg-object');
704            if (_sizes) {
705                _$img.attr('sizes', _sizes);
706            }
707
708            if (_srcset) {
709                _$img.attr('srcset', _srcset);
710                try {
711                    picturefill({
712                        elements: [_$img[0]]
713                    });
714                } catch (e) {
715                    console.warn('lightGallery :- If you want srcset to be supported for older browser please include picturefil version 2 javascript library in your document.');
716                }
717            }
718
719            if (this.s.appendSubHtmlTo !== '.lg-sub-html') {
720                _this.addHtml(index);
721            }
722
723            _this.$slide.eq(index).addClass('lg-loaded');
724        }
725
726        _this.$slide.eq(index).find('.lg-object').on('load.lg error.lg', function() {
727
728            // For first time add some delay for displaying the start animation.
729            var _speed = 0;
730
731            // Do not change the delay value because it is required for zoom plugin.
732            // If gallery opened from direct url (hash) speed value should be 0
733            if (delay && !$('body').hasClass('lg-from-hash')) {
734                _speed = delay;
735            }
736
737            setTimeout(function() {
738                _this.$slide.eq(index).addClass('lg-complete');
739                _this.$el.trigger('onSlideItemLoad.lg', [index, delay || 0]);
740            }, _speed);
741
742        });
743
744        // @todo check load state for html5 videos
745        if (_isVideo && _isVideo.html5 && !_hasPoster) {
746            _this.$slide.eq(index).addClass('lg-complete');
747        }
748
749        if (rec === true) {
750            if (!_this.$slide.eq(index).hasClass('lg-complete')) {
751                _this.$slide.eq(index).find('.lg-object').on('load.lg error.lg', function() {
752                    _this.preload(index);
753                });
754            } else {
755                _this.preload(index);
756            }
757        }
758
759        //}
760    };
761
762    /**
763    *   @desc slide function for lightgallery
764        ** Slide() gets call on start
765        ** ** Set lg.on true once slide() function gets called.
766        ** Call loadContent() on slide() function inside setTimeout
767        ** ** On first slide we do not want any animation like slide of fade
768        ** ** So on first slide( if lg.on if false that is first slide) loadContent() should start loading immediately
769        ** ** Else loadContent() should wait for the transition to complete.
770        ** ** So set timeout s.speed + 50
771    <=> ** loadContent() will load slide content in to the particular slide
772        ** ** It has recursion (rec) parameter. if rec === true loadContent() will call preload() function.
773        ** ** preload will execute only when the previous slide is fully loaded (images iframe)
774        ** ** avoid simultaneous image load
775    <=> ** Preload() will check for s.preload value and call loadContent() again accoring to preload value
776        ** loadContent()  <====> Preload();
777
778    *   @param {Number} index - index of the slide
779    *   @param {Boolean} fromTouch - true if slide function called via touch event or mouse drag
780    *   @param {Boolean} fromThumb - true if slide function called via thumbnail click
781    *   @param {String} direction - Direction of the slide(next/prev)
782    */
783    Plugin.prototype.slide = function(index, fromTouch, fromThumb, direction) {
784
785        var _prevIndex = this.$outer.find('.lg-current').index();
786        var _this = this;
787
788        // Prevent if multiple call
789        // Required for hsh plugin
790        if (_this.lGalleryOn && (_prevIndex === index)) {
791            return;
792        }
793
794        var _length = this.$slide.length;
795        var _time = _this.lGalleryOn ? this.s.speed : 0;
796
797        if (!_this.lgBusy) {
798
799            if (this.s.download) {
800                var _src;
801                if (_this.s.dynamic) {
802                    _src = _this.s.dynamicEl[index].downloadUrl !== false && (_this.s.dynamicEl[index].downloadUrl || _this.s.dynamicEl[index].src);
803                } else {
804                    _src = _this.$items.eq(index).attr('data-download-url') !== 'false' && (_this.$items.eq(index).attr('data-download-url') || _this.$items.eq(index).attr('href') || _this.$items.eq(index).attr('data-src'));
805
806                }
807
808                if (_src) {
809                    $('#lg-download').attr('href', _src);
810                    _this.$outer.removeClass('lg-hide-download');
811                } else {
812                    _this.$outer.addClass('lg-hide-download');
813                }
814            }
815
816            this.$el.trigger('onBeforeSlide.lg', [_prevIndex, index, fromTouch, fromThumb]);
817
818            _this.lgBusy = true;
819
820            clearTimeout(_this.hideBartimeout);
821
822            // Add title if this.s.appendSubHtmlTo === lg-sub-html
823            if (this.s.appendSubHtmlTo === '.lg-sub-html') {
824
825                // wait for slide animation to complete
826                setTimeout(function() {
827                    _this.addHtml(index);
828                }, _time);
829            }
830
831            this.arrowDisable(index);
832
833            if (!direction) {
834                if (index < _prevIndex) {
835                    direction = 'prev';
836                } else if (index > _prevIndex) {
837                    direction = 'next';
838                }
839            }
840
841            if (!fromTouch) {
842
843                // remove all transitions
844                _this.$outer.addClass('lg-no-trans');
845
846                this.$slide.removeClass('lg-prev-slide lg-next-slide');
847
848                if (direction === 'prev') {
849
850                    //prevslide
851                    this.$slide.eq(index).addClass('lg-prev-slide');
852                    this.$slide.eq(_prevIndex).addClass('lg-next-slide');
853                } else {
854
855                    // next slide
856                    this.$slide.eq(index).addClass('lg-next-slide');
857                    this.$slide.eq(_prevIndex).addClass('lg-prev-slide');
858                }
859
860                // give 50 ms for browser to add/remove class
861                setTimeout(function() {
862                    _this.$slide.removeClass('lg-current');
863
864                    //_this.$slide.eq(_prevIndex).removeClass('lg-current');
865                    _this.$slide.eq(index).addClass('lg-current');
866
867                    // reset all transitions
868                    _this.$outer.removeClass('lg-no-trans');
869                }, 50);
870            } else {
871
872                this.$slide.removeClass('lg-prev-slide lg-current lg-next-slide');
873                var touchPrev;
874                var touchNext;
875                if (_length > 2) {
876                    touchPrev = index - 1;
877                    touchNext = index + 1;
878
879                    if ((index === 0) && (_prevIndex === _length - 1)) {
880
881                        // next slide
882                        touchNext = 0;
883                        touchPrev = _length - 1;
884                    } else if ((index === _length - 1) && (_prevIndex === 0)) {
885
886                        // prev slide
887                        touchNext = 0;
888                        touchPrev = _length - 1;
889                    }
890
891                } else {
892                    touchPrev = 0;
893                    touchNext = 1;
894                }
895
896                if (direction === 'prev') {
897                    _this.$slide.eq(touchNext).addClass('lg-next-slide');
898                } else {
899                    _this.$slide.eq(touchPrev).addClass('lg-prev-slide');
900                }
901
902                _this.$slide.eq(index).addClass('lg-current');
903            }
904
905            if (_this.lGalleryOn) {
906                setTimeout(function() {
907                    _this.loadContent(index, true, 0);
908                }, this.s.speed + 50);
909
910                setTimeout(function() {
911                    _this.lgBusy = false;
912                    _this.$el.trigger('onAfterSlide.lg', [_prevIndex, index, fromTouch, fromThumb]);
913                }, this.s.speed);
914
915            } else {
916                _this.loadContent(index, true, _this.s.backdropDuration);
917
918                _this.lgBusy = false;
919                _this.$el.trigger('onAfterSlide.lg', [_prevIndex, index, fromTouch, fromThumb]);
920            }
921
922            _this.lGalleryOn = true;
923
924            if (this.s.counter) {
925                $('#lg-counter-current').text(index + 1);
926            }
927
928        }
929        _this.index = index;
930
931    };
932
933    /**
934     *  @desc Go to next slide
935     *  @param {Boolean} fromTouch - true if slide function called via touch event
936     */
937    Plugin.prototype.goToNextSlide = function(fromTouch) {
938        var _this = this;
939        var _loop = _this.s.loop;
940        if (fromTouch && _this.$slide.length < 3) {
941            _loop = false;
942        }
943
944        if (!_this.lgBusy) {
945            if ((_this.index + 1) < _this.$slide.length) {
946                _this.index++;
947                _this.$el.trigger('onBeforeNextSlide.lg', [_this.index]);
948                _this.slide(_this.index, fromTouch, false, 'next');
949            } else {
950                if (_loop) {
951                    _this.index = 0;
952                    _this.$el.trigger('onBeforeNextSlide.lg', [_this.index]);
953                    _this.slide(_this.index, fromTouch, false, 'next');
954                } else if (_this.s.slideEndAnimatoin && !fromTouch) {
955                    _this.$outer.addClass('lg-right-end');
956                    setTimeout(function() {
957                        _this.$outer.removeClass('lg-right-end');
958                    }, 400);
959                }
960            }
961        }
962    };
963
964    /**
965     *  @desc Go to previous slide
966     *  @param {Boolean} fromTouch - true if slide function called via touch event
967     */
968    Plugin.prototype.goToPrevSlide = function(fromTouch) {
969        var _this = this;
970        var _loop = _this.s.loop;
971        if (fromTouch && _this.$slide.length < 3) {
972            _loop = false;
973        }
974
975        if (!_this.lgBusy) {
976            if (_this.index > 0) {
977                _this.index--;
978                _this.$el.trigger('onBeforePrevSlide.lg', [_this.index, fromTouch]);
979                _this.slide(_this.index, fromTouch, false, 'prev');
980            } else {
981                if (_loop) {
982                    _this.index = _this.$items.length - 1;
983                    _this.$el.trigger('onBeforePrevSlide.lg', [_this.index, fromTouch]);
984                    _this.slide(_this.index, fromTouch, false, 'prev');
985                } else if (_this.s.slideEndAnimatoin && !fromTouch) {
986                    _this.$outer.addClass('lg-left-end');
987                    setTimeout(function() {
988                        _this.$outer.removeClass('lg-left-end');
989                    }, 400);
990                }
991            }
992        }
993    };
994
995    Plugin.prototype.keyPress = function() {
996        var _this = this;
997        if (this.$items.length > 1) {
998            $(window).on('keyup.lg', function(e) {
999                if (_this.$items.length > 1) {
1000                    if (e.keyCode === 37) {
1001                        e.preventDefault();
1002                        _this.goToPrevSlide();
1003                    }
1004
1005                    if (e.keyCode === 39) {
1006                        e.preventDefault();
1007                        _this.goToNextSlide();
1008                    }
1009                }
1010
1011                //! custom code to listen for 'enter' or 'space' keypresses to play video
1012                if ($(e.target).hasClass('lg-video-play') && e.keyCode === 13 || $(e.target).hasClass('lg-video-play') && e.keyCode === 32) {
1013                    e.preventDefault();
1014                    _this.$el.trigger('onSlideClick.lg');
1015                }
1016
1017                //! custom code to listen for 'enter' keypresses to close lightbox
1018                if ($(e.target).hasClass('lg-close') && e.keyCode === 13) {
1019                    e.preventDefault();
1020                    _this.destroy();
1021                }
1022
1023            });
1024        }
1025
1026        $(window).on('keydown.lg', function(e) {
1027            if (_this.s.escKey === true && e.keyCode === 27) {
1028                e.preventDefault();
1029                if (!_this.$outer.hasClass('lg-thumb-open')) {
1030                    _this.destroy();
1031                } else {
1032                    _this.$outer.removeClass('lg-thumb-open');
1033                }
1034            }
1035        });
1036    };
1037
1038    Plugin.prototype.arrow = function() {
1039        var _this = this;
1040        this.$outer.find('.lg-prev').on('click.lg', function() {
1041            _this.goToPrevSlide();
1042        });
1043
1044        this.$outer.find('.lg-next').on('click.lg', function() {
1045            _this.goToNextSlide();
1046        });
1047    };
1048
1049    Plugin.prototype.arrowDisable = function(index) {
1050
1051        // Disable arrows if s.hideControlOnEnd is true
1052        if (!this.s.loop && this.s.hideControlOnEnd) {
1053            if ((index + 1) < this.$slide.length) {
1054                this.$outer.find('.lg-next').removeAttr('disabled').removeClass('disabled');
1055            } else {
1056                this.$outer.find('.lg-next').attr('disabled', 'disabled').addClass('disabled');
1057            }
1058
1059            if (index > 0) {
1060                this.$outer.find('.lg-prev').removeAttr('disabled').removeClass('disabled');
1061            } else {
1062                this.$outer.find('.lg-prev').attr('disabled', 'disabled').addClass('disabled');
1063            }
1064        }
1065    };
1066
1067    Plugin.prototype.setTranslate = function($el, xValue, yValue) {
1068        // jQuery supports Automatic CSS prefixing since jQuery 1.8.0
1069        if (this.s.useLeft) {
1070            $el.css('left', xValue);
1071        } else {
1072            $el.css({
1073                transform: 'translate3d(' + (xValue) + 'px, ' + yValue + 'px, 0px)'
1074            });
1075        }
1076    };
1077
1078    Plugin.prototype.touchMove = function(startCoords, endCoords) {
1079
1080        var distance = endCoords - startCoords;
1081
1082        if (Math.abs(distance) > 15) {
1083            // reset opacity and transition duration
1084            this.$outer.addClass('lg-dragging');
1085
1086            // move current slide
1087            this.setTranslate(this.$slide.eq(this.index), distance, 0);
1088
1089            // move next and prev slide with current slide
1090            this.setTranslate($('.lg-prev-slide'), -this.$slide.eq(this.index).width() + distance, 0);
1091            this.setTranslate($('.lg-next-slide'), this.$slide.eq(this.index).width() + distance, 0);
1092        }
1093    };
1094
1095    Plugin.prototype.touchEnd = function(distance) {
1096        var _this = this;
1097
1098        // keep slide animation for any mode while dragg/swipe
1099        if (_this.s.mode !== 'lg-slide') {
1100            _this.$outer.addClass('lg-slide');
1101        }
1102
1103        this.$slide.not('.lg-current, .lg-prev-slide, .lg-next-slide').css('opacity', '0');
1104
1105        // set transition duration
1106        setTimeout(function() {
1107            _this.$outer.removeClass('lg-dragging');
1108            if ((distance < 0) && (Math.abs(distance) > _this.s.swipeThreshold)) {
1109                _this.goToNextSlide(true);
1110            } else if ((distance > 0) && (Math.abs(distance) > _this.s.swipeThreshold)) {
1111                _this.goToPrevSlide(true);
1112            } else if (Math.abs(distance) < 5) {
1113
1114                // Trigger click if distance is less than 5 pix
1115                _this.$el.trigger('onSlideClick.lg');
1116            }
1117
1118            _this.$slide.removeAttr('style');
1119        });
1120
1121        // remove slide class once drag/swipe is completed if mode is not slide
1122        setTimeout(function() {
1123            if (!_this.$outer.hasClass('lg-dragging') && _this.s.mode !== 'lg-slide') {
1124                _this.$outer.removeClass('lg-slide');
1125            }
1126        }, _this.s.speed + 100);
1127
1128    };
1129
1130    Plugin.prototype.enableSwipe = function() {
1131        var _this = this;
1132        var startCoords = 0;
1133        var endCoords = 0;
1134        var isMoved = false;
1135
1136        if (_this.s.enableSwipe && _this.doCss()) {
1137
1138            _this.$slide.on('touchstart.lg', function(e) {
1139                if (!_this.$outer.hasClass('lg-zoomed') && !_this.lgBusy) {
1140                    e.preventDefault();
1141                    _this.manageSwipeClass();
1142                    startCoords = e.originalEvent.targetTouches[0].pageX;
1143                }
1144            });
1145
1146            _this.$slide.on('touchmove.lg', function(e) {
1147                if (!_this.$outer.hasClass('lg-zoomed')) {
1148                    e.preventDefault();
1149                    endCoords = e.originalEvent.targetTouches[0].pageX;
1150                    _this.touchMove(startCoords, endCoords);
1151                    isMoved = true;
1152                }
1153            });
1154
1155            _this.$slide.on('touchend.lg', function() {
1156                if (!_this.$outer.hasClass('lg-zoomed')) {
1157                    if (isMoved) {
1158                        isMoved = false;
1159                        _this.touchEnd(endCoords - startCoords);
1160                    } else {
1161                        _this.$el.trigger('onSlideClick.lg');
1162                    }
1163                }
1164            });
1165        }
1166
1167    };
1168
1169    Plugin.prototype.enableDrag = function() {
1170        var _this = this;
1171        var startCoords = 0;
1172        var endCoords = 0;
1173        var isDraging = false;
1174        var isMoved = false;
1175        if (_this.s.enableDrag && _this.doCss()) {
1176            _this.$slide.on('mousedown.lg', function(e) {
1177                if (!_this.$outer.hasClass('lg-zoomed') && !_this.lgBusy && !$(e.target).text().trim()) {
1178                    e.preventDefault();
1179                    _this.manageSwipeClass();
1180                    startCoords = e.pageX;
1181                    isDraging = true;
1182
1183                    // ** Fix for webkit cursor issue https://code.google.com/p/chromium/issues/detail?id=26723
1184                    _this.$outer.scrollLeft += 1;
1185                    _this.$outer.scrollLeft -= 1;
1186
1187                    // *
1188
1189                    _this.$outer.removeClass('lg-grab').addClass('lg-grabbing');
1190
1191                    _this.$el.trigger('onDragstart.lg');
1192                }
1193            });
1194
1195            $(window).on('mousemove.lg', function(e) {
1196                if (isDraging) {
1197                    isMoved = true;
1198                    endCoords = e.pageX;
1199                    _this.touchMove(startCoords, endCoords);
1200                    _this.$el.trigger('onDragmove.lg');
1201                }
1202            });
1203
1204            $(window).on('mouseup.lg', function(e) {
1205                if (isMoved) {
1206                    isMoved = false;
1207                    _this.touchEnd(endCoords - startCoords);
1208                    _this.$el.trigger('onDragend.lg');
1209                } else if ($(e.target).hasClass('lg-object') || $(e.target).hasClass('lg-video-play')) {
1210                    _this.$el.trigger('onSlideClick.lg');
1211                }
1212
1213                // Prevent execution on click
1214                if (isDraging) {
1215                    isDraging = false;
1216                    _this.$outer.removeClass('lg-grabbing').addClass('lg-grab');
1217                }
1218            });
1219
1220        }
1221    };
1222
1223    Plugin.prototype.manageSwipeClass = function() {
1224        var _touchNext = this.index + 1;
1225        var _touchPrev = this.index - 1;
1226        if (this.s.loop && this.$slide.length > 2) {
1227            if (this.index === 0) {
1228                _touchPrev = this.$slide.length - 1;
1229            } else if (this.index === this.$slide.length - 1) {
1230                _touchNext = 0;
1231            }
1232        }
1233
1234        this.$slide.removeClass('lg-next-slide lg-prev-slide');
1235        if (_touchPrev > -1) {
1236            this.$slide.eq(_touchPrev).addClass('lg-prev-slide');
1237        }
1238
1239        this.$slide.eq(_touchNext).addClass('lg-next-slide');
1240    };
1241
1242    Plugin.prototype.mousewheel = function() {
1243        var _this = this;
1244        _this.$outer.on('mousewheel.lg', function(e) {
1245
1246            if (!e.deltaY) {
1247                return;
1248            }
1249
1250            if (e.deltaY > 0) {
1251                _this.goToPrevSlide();
1252            } else {
1253                _this.goToNextSlide();
1254            }
1255
1256            e.preventDefault();
1257        });
1258
1259    };
1260
1261    Plugin.prototype.closeGallery = function() {
1262
1263        var _this = this;
1264        var mousedown = false;
1265        this.$outer.find('.lg-close').on('click.lg', function() {
1266            _this.destroy();
1267        });
1268
1269        if (_this.s.closable) {
1270
1271            // If you drag the slide and release outside gallery gets close on chrome
1272            // for preventing this check mousedown and mouseup happened on .lg-item or lg-outer
1273            _this.$outer.on('mousedown.lg', function(e) {
1274
1275                if ($(e.target).is('.lg-outer') || $(e.target).is('.lg-item ') || $(e.target).is('.lg-img-wrap')) {
1276                    mousedown = true;
1277                } else {
1278                    mousedown = false;
1279                }
1280
1281            });
1282            
1283            _this.$outer.on('mousemove.lg', function() {
1284                mousedown = false;
1285            });
1286
1287            _this.$outer.on('mouseup.lg', function(e) {
1288
1289                if ($(e.target).is('.lg-outer') || $(e.target).is('.lg-item ') || $(e.target).is('.lg-img-wrap') && mousedown) {
1290                    if (!_this.$outer.hasClass('lg-dragging')) {
1291                        _this.destroy();
1292                    }
1293                }
1294
1295            });
1296
1297        }
1298
1299    };
1300
1301    Plugin.prototype.destroy = function(d) {
1302
1303        var _this = this;
1304
1305        if (!d) {
1306            _this.$el.trigger('onBeforeClose.lg');
1307            $(window).scrollTop(_this.prevScrollTop);
1308        }
1309
1310
1311        /**
1312         * if d is false or undefined destroy will only close the gallery
1313         * plugins instance remains with the element
1314         *
1315         * if d is true destroy will completely remove the plugin
1316         */
1317
1318        if (d) {
1319            if (!_this.s.dynamic) {
1320                // only when not using dynamic mode is $items a jquery collection
1321                this.$items.off('click.lg click.lgcustom');
1322            }
1323
1324            $.removeData(_this.el, 'lightGallery');
1325        }
1326
1327        // Unbind all events added by lightGallery
1328        this.$el.off('.lg.tm');
1329
1330        // Distroy all lightGallery modules
1331        $.each($.fn.lightGallery.modules, function(key) {
1332            if (_this.modules[key]) {
1333                _this.modules[key].destroy();
1334            }
1335        });
1336
1337        this.lGalleryOn = false;
1338
1339        clearTimeout(_this.hideBartimeout);
1340        this.hideBartimeout = false;
1341        $(window).off('.lg');
1342        $('body').removeClass('lg-on lg-from-hash');
1343
1344        if (_this.$outer) {
1345            _this.$outer.removeClass('lg-visible');
1346        }
1347
1348        $('.lg-backdrop').removeClass('in');
1349
1350        setTimeout(function() {
1351            if (_this.$outer) {
1352                _this.$outer.remove();
1353            }
1354
1355            $('.lg-backdrop').remove();
1356
1357            if (!d) {
1358                _this.$el.trigger('onCloseAfter.lg');
1359            }
1360
1361        }, _this.s.backdropDuration + 50);
1362    };
1363
1364    $.fn.lightGallery = function(options) {
1365        return this.each(function() {
1366            if (!$.data(this, 'lightGallery')) {
1367                $.data(this, 'lightGallery', new Plugin(this, options));
1368            } else {
1369                try {
1370                    $(this).data('lightGallery').init();
1371                } catch (err) {
1372                    console.error('lightGallery has not initiated properly');
1373                }
1374            }
1375        });
1376    };
1377
1378    $.fn.lightGallery.modules = {};
1379
1380})();
1381
1382
1383}));

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.