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.