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