Просмотр файла wu-static/js/lightgallery/js/lightgallery.js

Размер файла: 42.55Kb
  1. /*! lightgallery - v1.3.2 - 2016-09-23
  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 (jquery) {
  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. $('.lg-backdrop').addClass('in');
  365.  
  366. setTimeout(function() {
  367. _this.$outer.addClass('lg-visible');
  368. }, this.s.backdropDuration);
  369.  
  370. if (this.s.download) {
  371. this.$outer.find('.lg-toolbar').append('<a id="lg-download" target="_blank" download class="lg-download lg-icon"></a>');
  372. }
  373.  
  374. // Store the current scroll top value to scroll back after closing the gallery..
  375. this.prevScrollTop = $(window).scrollTop();
  376.  
  377. };
  378.  
  379. // For fixed height gallery
  380. Plugin.prototype.setTop = function() {
  381. if (this.s.height !== '100%') {
  382. var wH = $(window).height();
  383. var top = (wH - parseInt(this.s.height, 10)) / 2;
  384. var $lGallery = this.$outer.find('.lg');
  385. if (wH >= parseInt(this.s.height, 10)) {
  386. $lGallery.css('top', top + 'px');
  387. } else {
  388. $lGallery.css('top', '0px');
  389. }
  390. }
  391. };
  392.  
  393. // Find css3 support
  394. Plugin.prototype.doCss = function() {
  395. // check for css animation support
  396. var support = function() {
  397. var transition = ['transition', 'MozTransition', 'WebkitTransition', 'OTransition', 'msTransition', 'KhtmlTransition'];
  398. var root = document.documentElement;
  399. var i = 0;
  400. for (i = 0; i < transition.length; i++) {
  401. if (transition[i] in root.style) {
  402. return true;
  403. }
  404. }
  405. };
  406.  
  407. if (support()) {
  408. return true;
  409. }
  410.  
  411. return false;
  412. };
  413.  
  414. /**
  415. * @desc Check the given src is video
  416. * @param {String} src
  417. * @return {Object} video type
  418. * Ex:{ youtube : ["//www.youtube.com/watch?v=c0asJgSyxcY", "c0asJgSyxcY"] }
  419. */
  420. Plugin.prototype.isVideo = function(src, index) {
  421.  
  422. var html;
  423. if (this.s.dynamic) {
  424. html = this.s.dynamicEl[index].html;
  425. } else {
  426. html = this.$items.eq(index).attr('data-html');
  427. }
  428.  
  429. if (!src && html) {
  430. return {
  431. html5: true
  432. };
  433. }
  434.  
  435. var youtube = src.match(/\/\/(?:www\.)?youtu(?:\.be|be\.com)\/(?:watch\?v=|embed\/)?([a-z0-9\-\_\%]+)/i);
  436. var vimeo = src.match(/\/\/(?:www\.)?vimeo.com\/([0-9a-z\-_]+)/i);
  437. var dailymotion = src.match(/\/\/(?:www\.)?dai.ly\/([0-9a-z\-_]+)/i);
  438. var vk = src.match(/\/\/(?:www\.)?(?:vk\.com|vkontakte\.ru)\/(?:video_ext\.php\?)(.*)/i);
  439.  
  440. if (youtube) {
  441. return {
  442. youtube: youtube
  443. };
  444. } else if (vimeo) {
  445. return {
  446. vimeo: vimeo
  447. };
  448. } else if (dailymotion) {
  449. return {
  450. dailymotion: dailymotion
  451. };
  452. } else if (vk) {
  453. return {
  454. vk: vk
  455. };
  456. }
  457. };
  458.  
  459. /**
  460. * @desc Create image counter
  461. * Ex: 1/10
  462. */
  463. Plugin.prototype.counter = function() {
  464. if (this.s.counter) {
  465. $(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>');
  466. }
  467. };
  468.  
  469. /**
  470. * @desc add sub-html into the slide
  471. * @param {Number} index - index of the slide
  472. */
  473. Plugin.prototype.addHtml = function(index) {
  474. var subHtml = null;
  475. var subHtmlUrl;
  476. var $currentEle;
  477. if (this.s.dynamic) {
  478. if (this.s.dynamicEl[index].subHtmlUrl) {
  479. subHtmlUrl = this.s.dynamicEl[index].subHtmlUrl;
  480. } else {
  481. subHtml = this.s.dynamicEl[index].subHtml;
  482. }
  483. } else {
  484. $currentEle = this.$items.eq(index);
  485. if ($currentEle.attr('data-sub-html-url')) {
  486. subHtmlUrl = $currentEle.attr('data-sub-html-url');
  487. } else {
  488. subHtml = $currentEle.attr('data-sub-html');
  489. if (this.s.getCaptionFromTitleOrAlt && !subHtml) {
  490. subHtml = $currentEle.attr('title') || $currentEle.find('img').first().attr('alt');
  491. }
  492. }
  493. }
  494.  
  495. if (!subHtmlUrl) {
  496. if (typeof subHtml !== 'undefined' && subHtml !== null) {
  497.  
  498. // get first letter of subhtml
  499. // if first letter starts with . or # get the html form the jQuery object
  500. var fL = subHtml.substring(0, 1);
  501. if (fL === '.' || fL === '#') {
  502. if (this.s.subHtmlSelectorRelative && !this.s.dynamic) {
  503. subHtml = $currentEle.find(subHtml).html();
  504. } else {
  505. subHtml = $(subHtml).html();
  506. }
  507. }
  508. } else {
  509. subHtml = '';
  510. }
  511. }
  512.  
  513. if (this.s.appendSubHtmlTo === '.lg-sub-html') {
  514.  
  515. if (subHtmlUrl) {
  516. this.$outer.find(this.s.appendSubHtmlTo).load(subHtmlUrl);
  517. } else {
  518. this.$outer.find(this.s.appendSubHtmlTo).html(subHtml);
  519. }
  520.  
  521. } else {
  522.  
  523. if (subHtmlUrl) {
  524. this.$slide.eq(index).load(subHtmlUrl);
  525. } else {
  526. this.$slide.eq(index).append(subHtml);
  527. }
  528. }
  529.  
  530. // Add lg-empty-html class if title doesn't exist
  531. if (typeof subHtml !== 'undefined' && subHtml !== null) {
  532. if (subHtml === '') {
  533. this.$outer.find(this.s.appendSubHtmlTo).addClass('lg-empty-html');
  534. } else {
  535. this.$outer.find(this.s.appendSubHtmlTo).removeClass('lg-empty-html');
  536. }
  537. }
  538.  
  539. this.$el.trigger('onAfterAppendSubHtml.lg', [index]);
  540. };
  541.  
  542. /**
  543. * @desc Preload slides
  544. * @param {Number} index - index of the slide
  545. */
  546. Plugin.prototype.preload = function(index) {
  547. var i = 1;
  548. var j = 1;
  549. for (i = 1; i <= this.s.preload; i++) {
  550. if (i >= this.$items.length - index) {
  551. break;
  552. }
  553.  
  554. this.loadContent(index + i, false, 0);
  555. }
  556.  
  557. for (j = 1; j <= this.s.preload; j++) {
  558. if (index - j < 0) {
  559. break;
  560. }
  561.  
  562. this.loadContent(index - j, false, 0);
  563. }
  564. };
  565.  
  566. /**
  567. * @desc Load slide content into slide.
  568. * @param {Number} index - index of the slide.
  569. * @param {Boolean} rec - if true call loadcontent() function again.
  570. * @param {Boolean} delay - delay for adding complete class. it is 0 except first time.
  571. */
  572. Plugin.prototype.loadContent = function(index, rec, delay) {
  573.  
  574. var _this = this;
  575. var _hasPoster = false;
  576. var _$img;
  577. var _src;
  578. var _poster;
  579. var _srcset;
  580. var _sizes;
  581. var _html;
  582. var getResponsiveSrc = function(srcItms) {
  583. var rsWidth = [];
  584. var rsSrc = [];
  585. for (var i = 0; i < srcItms.length; i++) {
  586. var __src = srcItms[i].split(' ');
  587.  
  588. // Manage empty space
  589. if (__src[0] === '') {
  590. __src.splice(0, 1);
  591. }
  592.  
  593. rsSrc.push(__src[0]);
  594. rsWidth.push(__src[1]);
  595. }
  596.  
  597. var wWidth = $(window).width();
  598. for (var j = 0; j < rsWidth.length; j++) {
  599. if (parseInt(rsWidth[j], 10) > wWidth) {
  600. _src = rsSrc[j];
  601. break;
  602. }
  603. }
  604. };
  605.  
  606. if (_this.s.dynamic) {
  607.  
  608. if (_this.s.dynamicEl[index].poster) {
  609. _hasPoster = true;
  610. _poster = _this.s.dynamicEl[index].poster;
  611. }
  612.  
  613. _html = _this.s.dynamicEl[index].html;
  614. _src = _this.s.dynamicEl[index].src;
  615.  
  616. if (_this.s.dynamicEl[index].responsive) {
  617. var srcDyItms = _this.s.dynamicEl[index].responsive.split(',');
  618. getResponsiveSrc(srcDyItms);
  619. }
  620.  
  621. _srcset = _this.s.dynamicEl[index].srcset;
  622. _sizes = _this.s.dynamicEl[index].sizes;
  623.  
  624. } else {
  625.  
  626. if (_this.$items.eq(index).attr('data-poster')) {
  627. _hasPoster = true;
  628. _poster = _this.$items.eq(index).attr('data-poster');
  629. }
  630.  
  631. _html = _this.$items.eq(index).attr('data-html');
  632. _src = _this.$items.eq(index).attr('href') || _this.$items.eq(index).attr('data-src');
  633.  
  634. if (_this.$items.eq(index).attr('data-responsive')) {
  635. var srcItms = _this.$items.eq(index).attr('data-responsive').split(',');
  636. getResponsiveSrc(srcItms);
  637. }
  638.  
  639. _srcset = _this.$items.eq(index).attr('data-srcset');
  640. _sizes = _this.$items.eq(index).attr('data-sizes');
  641.  
  642. }
  643.  
  644. //if (_src || _srcset || _sizes || _poster) {
  645.  
  646. var iframe = false;
  647. if (_this.s.dynamic) {
  648. if (_this.s.dynamicEl[index].iframe) {
  649. iframe = true;
  650. }
  651. } else {
  652. if (_this.$items.eq(index).attr('data-iframe') === 'true') {
  653. iframe = true;
  654. }
  655. }
  656.  
  657. var _isVideo = _this.isVideo(_src, index);
  658. if (!_this.$slide.eq(index).hasClass('lg-loaded')) {
  659. if (iframe) {
  660. _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>');
  661. } else if (_hasPoster) {
  662. var videoClass = '';
  663. if (_isVideo && _isVideo.youtube) {
  664. videoClass = 'lg-has-youtube';
  665. } else if (_isVideo && _isVideo.vimeo) {
  666. videoClass = 'lg-has-vimeo';
  667. } else {
  668. videoClass = 'lg-has-html5';
  669. }
  670.  
  671. _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>');
  672.  
  673. } else if (_isVideo) {
  674. _this.$slide.eq(index).prepend('<div class="lg-video-cont "><div class="lg-video"></div></div>');
  675. _this.$el.trigger('hasVideo.lg', [index, _src, _html]);
  676. } else {
  677. _this.$slide.eq(index).prepend('<div class="lg-img-wrap"><img class="lg-object lg-image" src="' + _src + '" /></div>');
  678. }
  679.  
  680. _this.$el.trigger('onAferAppendSlide.lg', [index]);
  681.  
  682. _$img = _this.$slide.eq(index).find('.lg-object');
  683. if (_sizes) {
  684. _$img.attr('sizes', _sizes);
  685. }
  686.  
  687. if (_srcset) {
  688. _$img.attr('srcset', _srcset);
  689. try {
  690. picturefill({
  691. elements: [_$img[0]]
  692. });
  693. } catch (e) {
  694. console.error('Make sure you have included Picturefill version 2');
  695. }
  696. }
  697.  
  698. if (this.s.appendSubHtmlTo !== '.lg-sub-html') {
  699. _this.addHtml(index);
  700. }
  701.  
  702. _this.$slide.eq(index).addClass('lg-loaded');
  703. }
  704.  
  705. _this.$slide.eq(index).find('.lg-object').on('load.lg error.lg', function() {
  706.  
  707. // For first time add some delay for displaying the start animation.
  708. var _speed = 0;
  709.  
  710. // Do not change the delay value because it is required for zoom plugin.
  711. // If gallery opened from direct url (hash) speed value should be 0
  712. if (delay && !$('body').hasClass('lg-from-hash')) {
  713. _speed = delay;
  714. }
  715.  
  716. setTimeout(function() {
  717. _this.$slide.eq(index).addClass('lg-complete');
  718. _this.$el.trigger('onSlideItemLoad.lg', [index, delay || 0]);
  719. }, _speed);
  720.  
  721. });
  722.  
  723. // @todo check load state for html5 videos
  724. if (_isVideo && _isVideo.html5 && !_hasPoster) {
  725. _this.$slide.eq(index).addClass('lg-complete');
  726. }
  727.  
  728. if (rec === true) {
  729. if (!_this.$slide.eq(index).hasClass('lg-complete')) {
  730. _this.$slide.eq(index).find('.lg-object').on('load.lg error.lg', function() {
  731. _this.preload(index);
  732. });
  733. } else {
  734. _this.preload(index);
  735. }
  736. }
  737.  
  738. //}
  739. };
  740.  
  741. /**
  742. * @desc slide function for lightgallery
  743. ** Slide() gets call on start
  744. ** ** Set lg.on true once slide() function gets called.
  745. ** Call loadContent() on slide() function inside setTimeout
  746. ** ** On first slide we do not want any animation like slide of fade
  747. ** ** So on first slide( if lg.on if false that is first slide) loadContent() should start loading immediately
  748. ** ** Else loadContent() should wait for the transition to complete.
  749. ** ** So set timeout s.speed + 50
  750. <=> ** loadContent() will load slide content in to the particular slide
  751. ** ** It has recursion (rec) parameter. if rec === true loadContent() will call preload() function.
  752. ** ** preload will execute only when the previous slide is fully loaded (images iframe)
  753. ** ** avoid simultaneous image load
  754. <=> ** Preload() will check for s.preload value and call loadContent() again accoring to preload value
  755. ** loadContent() <====> Preload();
  756.  
  757. * @param {Number} index - index of the slide
  758. * @param {Boolean} fromTouch - true if slide function called via touch event or mouse drag
  759. * @param {Boolean} fromThumb - true if slide function called via thumbnail click
  760. */
  761. Plugin.prototype.slide = function(index, fromTouch, fromThumb) {
  762.  
  763. var _prevIndex = this.$outer.find('.lg-current').index();
  764. var _this = this;
  765.  
  766. // Prevent if multiple call
  767. // Required for hsh plugin
  768. if (_this.lGalleryOn && (_prevIndex === index)) {
  769. return;
  770. }
  771.  
  772. var _length = this.$slide.length;
  773. var _time = _this.lGalleryOn ? this.s.speed : 0;
  774. var _next = false;
  775. var _prev = false;
  776.  
  777. if (!_this.lgBusy) {
  778.  
  779. if (this.s.download) {
  780. var _src;
  781. if (_this.s.dynamic) {
  782. _src = _this.s.dynamicEl[index].downloadUrl !== false && (_this.s.dynamicEl[index].downloadUrl || _this.s.dynamicEl[index].src);
  783. } else {
  784. _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'));
  785.  
  786. }
  787.  
  788. if (_src) {
  789. $('#lg-download').attr('href', _src);
  790. _this.$outer.removeClass('lg-hide-download');
  791. } else {
  792. _this.$outer.addClass('lg-hide-download');
  793. }
  794. }
  795.  
  796. this.$el.trigger('onBeforeSlide.lg', [_prevIndex, index, fromTouch, fromThumb]);
  797.  
  798. _this.lgBusy = true;
  799.  
  800. clearTimeout(_this.hideBartimeout);
  801.  
  802. // Add title if this.s.appendSubHtmlTo === lg-sub-html
  803. if (this.s.appendSubHtmlTo === '.lg-sub-html') {
  804.  
  805. // wait for slide animation to complete
  806. setTimeout(function() {
  807. _this.addHtml(index);
  808. }, _time);
  809. }
  810.  
  811. this.arrowDisable(index);
  812.  
  813. if (!fromTouch) {
  814.  
  815. // remove all transitions
  816. _this.$outer.addClass('lg-no-trans');
  817.  
  818. this.$slide.removeClass('lg-prev-slide lg-next-slide');
  819.  
  820. if (index < _prevIndex) {
  821. _prev = true;
  822. if ((index === 0) && (_prevIndex === _length - 1) && !fromThumb) {
  823. _prev = false;
  824. _next = true;
  825. }
  826. } else if (index > _prevIndex) {
  827. _next = true;
  828. if ((index === _length - 1) && (_prevIndex === 0) && !fromThumb) {
  829. _prev = true;
  830. _next = false;
  831. }
  832. }
  833.  
  834. if (_prev) {
  835.  
  836. //prevslide
  837. this.$slide.eq(index).addClass('lg-prev-slide');
  838. this.$slide.eq(_prevIndex).addClass('lg-next-slide');
  839. } else if (_next) {
  840.  
  841. // next slide
  842. this.$slide.eq(index).addClass('lg-next-slide');
  843. this.$slide.eq(_prevIndex).addClass('lg-prev-slide');
  844. }
  845.  
  846. // give 50 ms for browser to add/remove class
  847. setTimeout(function() {
  848. _this.$slide.removeClass('lg-current');
  849.  
  850. //_this.$slide.eq(_prevIndex).removeClass('lg-current');
  851. _this.$slide.eq(index).addClass('lg-current');
  852.  
  853. // reset all transitions
  854. _this.$outer.removeClass('lg-no-trans');
  855. }, 50);
  856. } else {
  857.  
  858. var touchPrev = index - 1;
  859. var touchNext = index + 1;
  860.  
  861. if ((index === 0) && (_prevIndex === _length - 1)) {
  862.  
  863. // next slide
  864. touchNext = 0;
  865. touchPrev = _length - 1;
  866. } else if ((index === _length - 1) && (_prevIndex === 0)) {
  867.  
  868. // prev slide
  869. touchNext = 0;
  870. touchPrev = _length - 1;
  871. }
  872.  
  873. this.$slide.removeClass('lg-prev-slide lg-current lg-next-slide');
  874. _this.$slide.eq(touchPrev).addClass('lg-prev-slide');
  875. _this.$slide.eq(touchNext).addClass('lg-next-slide');
  876. _this.$slide.eq(index).addClass('lg-current');
  877. }
  878.  
  879. if (_this.lGalleryOn) {
  880. setTimeout(function() {
  881. _this.loadContent(index, true, 0);
  882. }, this.s.speed + 50);
  883.  
  884. setTimeout(function() {
  885. _this.lgBusy = false;
  886. _this.$el.trigger('onAfterSlide.lg', [_prevIndex, index, fromTouch, fromThumb]);
  887. }, this.s.speed);
  888.  
  889. } else {
  890. _this.loadContent(index, true, _this.s.backdropDuration);
  891.  
  892. _this.lgBusy = false;
  893. _this.$el.trigger('onAfterSlide.lg', [_prevIndex, index, fromTouch, fromThumb]);
  894. }
  895.  
  896. _this.lGalleryOn = true;
  897.  
  898. if (this.s.counter) {
  899. $('#lg-counter-current').text(index + 1);
  900. }
  901.  
  902. }
  903.  
  904. };
  905.  
  906. /**
  907. * @desc Go to next slide
  908. * @param {Boolean} fromTouch - true if slide function called via touch event
  909. */
  910. Plugin.prototype.goToNextSlide = function(fromTouch) {
  911. var _this = this;
  912. if (!_this.lgBusy) {
  913. if ((_this.index + 1) < _this.$slide.length) {
  914. _this.index++;
  915. _this.$el.trigger('onBeforeNextSlide.lg', [_this.index]);
  916. _this.slide(_this.index, fromTouch, false);
  917. } else {
  918. if (_this.s.loop) {
  919. _this.index = 0;
  920. _this.$el.trigger('onBeforeNextSlide.lg', [_this.index]);
  921. _this.slide(_this.index, fromTouch, false);
  922. } else if (_this.s.slideEndAnimatoin) {
  923. _this.$outer.addClass('lg-right-end');
  924. setTimeout(function() {
  925. _this.$outer.removeClass('lg-right-end');
  926. }, 400);
  927. }
  928. }
  929. }
  930. };
  931.  
  932. /**
  933. * @desc Go to previous slide
  934. * @param {Boolean} fromTouch - true if slide function called via touch event
  935. */
  936. Plugin.prototype.goToPrevSlide = function(fromTouch) {
  937. var _this = this;
  938. if (!_this.lgBusy) {
  939. if (_this.index > 0) {
  940. _this.index--;
  941. _this.$el.trigger('onBeforePrevSlide.lg', [_this.index, fromTouch]);
  942. _this.slide(_this.index, fromTouch, false);
  943. } else {
  944. if (_this.s.loop) {
  945. _this.index = _this.$items.length - 1;
  946. _this.$el.trigger('onBeforePrevSlide.lg', [_this.index, fromTouch]);
  947. _this.slide(_this.index, fromTouch, false);
  948. } else if (_this.s.slideEndAnimatoin) {
  949. _this.$outer.addClass('lg-left-end');
  950. setTimeout(function() {
  951. _this.$outer.removeClass('lg-left-end');
  952. }, 400);
  953. }
  954. }
  955. }
  956. };
  957.  
  958. Plugin.prototype.keyPress = function() {
  959. var _this = this;
  960. if (this.$items.length > 1) {
  961. $(window).on('keyup.lg', function(e) {
  962. if (_this.$items.length > 1) {
  963. if (e.keyCode === 37) {
  964. e.preventDefault();
  965. _this.goToPrevSlide();
  966. }
  967.  
  968. if (e.keyCode === 39) {
  969. e.preventDefault();
  970. _this.goToNextSlide();
  971. }
  972. }
  973. });
  974. }
  975.  
  976. $(window).on('keydown.lg', function(e) {
  977. if (_this.s.escKey === true && e.keyCode === 27) {
  978. e.preventDefault();
  979. if (!_this.$outer.hasClass('lg-thumb-open')) {
  980. _this.destroy();
  981. } else {
  982. _this.$outer.removeClass('lg-thumb-open');
  983. }
  984. }
  985. });
  986. };
  987.  
  988. Plugin.prototype.arrow = function() {
  989. var _this = this;
  990. this.$outer.find('.lg-prev').on('click.lg', function() {
  991. _this.goToPrevSlide();
  992. });
  993.  
  994. this.$outer.find('.lg-next').on('click.lg', function() {
  995. _this.goToNextSlide();
  996. });
  997. };
  998.  
  999. Plugin.prototype.arrowDisable = function(index) {
  1000.  
  1001. // Disable arrows if s.hideControlOnEnd is true
  1002. if (!this.s.loop && this.s.hideControlOnEnd) {
  1003. if ((index + 1) < this.$slide.length) {
  1004. this.$outer.find('.lg-next').removeAttr('disabled').removeClass('disabled');
  1005. } else {
  1006. this.$outer.find('.lg-next').attr('disabled', 'disabled').addClass('disabled');
  1007. }
  1008.  
  1009. if (index > 0) {
  1010. this.$outer.find('.lg-prev').removeAttr('disabled').removeClass('disabled');
  1011. } else {
  1012. this.$outer.find('.lg-prev').attr('disabled', 'disabled').addClass('disabled');
  1013. }
  1014. }
  1015. };
  1016.  
  1017. Plugin.prototype.setTranslate = function($el, xValue, yValue) {
  1018. // jQuery supports Automatic CSS prefixing since jQuery 1.8.0
  1019. if (this.s.useLeft) {
  1020. $el.css('left', xValue);
  1021. } else {
  1022. $el.css({
  1023. transform: 'translate3d(' + (xValue) + 'px, ' + yValue + 'px, 0px)'
  1024. });
  1025. }
  1026. };
  1027.  
  1028. Plugin.prototype.touchMove = function(startCoords, endCoords) {
  1029.  
  1030. var distance = endCoords - startCoords;
  1031.  
  1032. if (Math.abs(distance) > 15) {
  1033. // reset opacity and transition duration
  1034. this.$outer.addClass('lg-dragging');
  1035.  
  1036. // move current slide
  1037. this.setTranslate(this.$slide.eq(this.index), distance, 0);
  1038.  
  1039. // move next and prev slide with current slide
  1040. this.setTranslate($('.lg-prev-slide'), -this.$slide.eq(this.index).width() + distance, 0);
  1041. this.setTranslate($('.lg-next-slide'), this.$slide.eq(this.index).width() + distance, 0);
  1042. }
  1043. };
  1044.  
  1045. Plugin.prototype.touchEnd = function(distance) {
  1046. var _this = this;
  1047.  
  1048. // keep slide animation for any mode while dragg/swipe
  1049. if (_this.s.mode !== 'lg-slide') {
  1050. _this.$outer.addClass('lg-slide');
  1051. }
  1052.  
  1053. this.$slide.not('.lg-current, .lg-prev-slide, .lg-next-slide').css('opacity', '0');
  1054.  
  1055. // set transition duration
  1056. setTimeout(function() {
  1057. _this.$outer.removeClass('lg-dragging');
  1058. if ((distance < 0) && (Math.abs(distance) > _this.s.swipeThreshold)) {
  1059. _this.goToNextSlide(true);
  1060. } else if ((distance > 0) && (Math.abs(distance) > _this.s.swipeThreshold)) {
  1061. _this.goToPrevSlide(true);
  1062. } else if (Math.abs(distance) < 5) {
  1063.  
  1064. // Trigger click if distance is less than 5 pix
  1065. _this.$el.trigger('onSlideClick.lg');
  1066. }
  1067.  
  1068. _this.$slide.removeAttr('style');
  1069. });
  1070.  
  1071. // remove slide class once drag/swipe is completed if mode is not slide
  1072. setTimeout(function() {
  1073. if (!_this.$outer.hasClass('lg-dragging') && _this.s.mode !== 'lg-slide') {
  1074. _this.$outer.removeClass('lg-slide');
  1075. }
  1076. }, _this.s.speed + 100);
  1077.  
  1078. };
  1079.  
  1080. Plugin.prototype.enableSwipe = function() {
  1081. var _this = this;
  1082. var startCoords = 0;
  1083. var endCoords = 0;
  1084. var isMoved = false;
  1085.  
  1086. if (_this.s.enableSwipe && _this.isTouch && _this.doCss()) {
  1087.  
  1088. _this.$slide.on('touchstart.lg', function(e) {
  1089. if (!_this.$outer.hasClass('lg-zoomed') && !_this.lgBusy) {
  1090. e.preventDefault();
  1091. _this.manageSwipeClass();
  1092. startCoords = e.originalEvent.targetTouches[0].pageX;
  1093. }
  1094. });
  1095.  
  1096. _this.$slide.on('touchmove.lg', function(e) {
  1097. if (!_this.$outer.hasClass('lg-zoomed')) {
  1098. e.preventDefault();
  1099. endCoords = e.originalEvent.targetTouches[0].pageX;
  1100. _this.touchMove(startCoords, endCoords);
  1101. isMoved = true;
  1102. }
  1103. });
  1104.  
  1105. _this.$slide.on('touchend.lg', function() {
  1106. if (!_this.$outer.hasClass('lg-zoomed')) {
  1107. if (isMoved) {
  1108. isMoved = false;
  1109. _this.touchEnd(endCoords - startCoords);
  1110. } else {
  1111. _this.$el.trigger('onSlideClick.lg');
  1112. }
  1113. }
  1114. });
  1115. }
  1116.  
  1117. };
  1118.  
  1119. Plugin.prototype.enableDrag = function() {
  1120. var _this = this;
  1121. var startCoords = 0;
  1122. var endCoords = 0;
  1123. var isDraging = false;
  1124. var isMoved = false;
  1125. if (_this.s.enableDrag && !_this.isTouch && _this.doCss()) {
  1126. _this.$slide.on('mousedown.lg', function(e) {
  1127. // execute only on .lg-object
  1128. if (!_this.$outer.hasClass('lg-zoomed')) {
  1129. if ($(e.target).hasClass('lg-object') || $(e.target).hasClass('lg-video-play')) {
  1130. e.preventDefault();
  1131.  
  1132. if (!_this.lgBusy) {
  1133. _this.manageSwipeClass();
  1134. startCoords = e.pageX;
  1135. isDraging = true;
  1136.  
  1137. // ** Fix for webkit cursor issue https://code.google.com/p/chromium/issues/detail?id=26723
  1138. _this.$outer.scrollLeft += 1;
  1139. _this.$outer.scrollLeft -= 1;
  1140.  
  1141. // *
  1142.  
  1143. _this.$outer.removeClass('lg-grab').addClass('lg-grabbing');
  1144.  
  1145. _this.$el.trigger('onDragstart.lg');
  1146. }
  1147.  
  1148. }
  1149. }
  1150. });
  1151.  
  1152. $(window).on('mousemove.lg', function(e) {
  1153. if (isDraging) {
  1154. isMoved = true;
  1155. endCoords = e.pageX;
  1156. _this.touchMove(startCoords, endCoords);
  1157. _this.$el.trigger('onDragmove.lg');
  1158. }
  1159. });
  1160.  
  1161. $(window).on('mouseup.lg', function(e) {
  1162. if (isMoved) {
  1163. isMoved = false;
  1164. _this.touchEnd(endCoords - startCoords);
  1165. _this.$el.trigger('onDragend.lg');
  1166. } else if ($(e.target).hasClass('lg-object') || $(e.target).hasClass('lg-video-play')) {
  1167. _this.$el.trigger('onSlideClick.lg');
  1168. }
  1169.  
  1170. // Prevent execution on click
  1171. if (isDraging) {
  1172. isDraging = false;
  1173. _this.$outer.removeClass('lg-grabbing').addClass('lg-grab');
  1174. }
  1175. });
  1176.  
  1177. }
  1178. };
  1179.  
  1180. Plugin.prototype.manageSwipeClass = function() {
  1181. var touchNext = this.index + 1;
  1182. var touchPrev = this.index - 1;
  1183. var length = this.$slide.length;
  1184. if (this.s.loop) {
  1185. if (this.index === 0) {
  1186. touchPrev = length - 1;
  1187. } else if (this.index === length - 1) {
  1188. touchNext = 0;
  1189. }
  1190. }
  1191.  
  1192. this.$slide.removeClass('lg-next-slide lg-prev-slide');
  1193. if (touchPrev > -1) {
  1194. this.$slide.eq(touchPrev).addClass('lg-prev-slide');
  1195. }
  1196.  
  1197. this.$slide.eq(touchNext).addClass('lg-next-slide');
  1198. };
  1199.  
  1200. Plugin.prototype.mousewheel = function() {
  1201. var _this = this;
  1202. _this.$outer.on('mousewheel.lg', function(e) {
  1203.  
  1204. if (!e.deltaY) {
  1205. return;
  1206. }
  1207.  
  1208. if (e.deltaY > 0) {
  1209. _this.goToPrevSlide();
  1210. } else {
  1211. _this.goToNextSlide();
  1212. }
  1213.  
  1214. e.preventDefault();
  1215. });
  1216.  
  1217. };
  1218.  
  1219. Plugin.prototype.closeGallery = function() {
  1220.  
  1221. var _this = this;
  1222. var mousedown = false;
  1223. this.$outer.find('.lg-close').on('click.lg', function() {
  1224. _this.destroy();
  1225. });
  1226.  
  1227. if (_this.s.closable) {
  1228.  
  1229. // If you drag the slide and release outside gallery gets close on chrome
  1230. // for preventing this check mousedown and mouseup happened on .lg-item or lg-outer
  1231. _this.$outer.on('mousedown.lg', function(e) {
  1232.  
  1233. if ($(e.target).is('.lg-outer') || $(e.target).is('.lg-item ') || $(e.target).is('.lg-img-wrap')) {
  1234. mousedown = true;
  1235. } else {
  1236. mousedown = false;
  1237. }
  1238.  
  1239. });
  1240.  
  1241. _this.$outer.on('mouseup.lg', function(e) {
  1242.  
  1243. if ($(e.target).is('.lg-outer') || $(e.target).is('.lg-item ') || $(e.target).is('.lg-img-wrap') && mousedown) {
  1244. if (!_this.$outer.hasClass('lg-dragging')) {
  1245. _this.destroy();
  1246. }
  1247. }
  1248.  
  1249. });
  1250.  
  1251. }
  1252.  
  1253. };
  1254.  
  1255. Plugin.prototype.destroy = function(d) {
  1256.  
  1257. var _this = this;
  1258.  
  1259. if (!d) {
  1260. _this.$el.trigger('onBeforeClose.lg');
  1261. }
  1262.  
  1263. $(window).scrollTop(_this.prevScrollTop);
  1264.  
  1265. /**
  1266. * if d is false or undefined destroy will only close the gallery
  1267. * plugins instance remains with the element
  1268. *
  1269. * if d is true destroy will completely remove the plugin
  1270. */
  1271.  
  1272. if (d) {
  1273. if (!_this.s.dynamic) {
  1274. // only when not using dynamic mode is $items a jquery collection
  1275. this.$items.off('click.lg click.lgcustom');
  1276. }
  1277.  
  1278. $.removeData(_this.el, 'lightGallery');
  1279. }
  1280.  
  1281. // Unbind all events added by lightGallery
  1282. this.$el.off('.lg.tm');
  1283.  
  1284. // Distroy all lightGallery modules
  1285. $.each($.fn.lightGallery.modules, function(key) {
  1286. if (_this.modules[key]) {
  1287. _this.modules[key].destroy();
  1288. }
  1289. });
  1290.  
  1291. this.lGalleryOn = false;
  1292.  
  1293. clearTimeout(_this.hideBartimeout);
  1294. this.hideBartimeout = false;
  1295. $(window).off('.lg');
  1296. $('body').removeClass('lg-on lg-from-hash');
  1297.  
  1298. if (_this.$outer) {
  1299. _this.$outer.removeClass('lg-visible');
  1300. }
  1301.  
  1302. $('.lg-backdrop').removeClass('in');
  1303.  
  1304. setTimeout(function() {
  1305. if (_this.$outer) {
  1306. _this.$outer.remove();
  1307. }
  1308.  
  1309. $('.lg-backdrop').remove();
  1310.  
  1311. if (!d) {
  1312. _this.$el.trigger('onCloseAfter.lg');
  1313. }
  1314.  
  1315. }, _this.s.backdropDuration + 50);
  1316. };
  1317.  
  1318. $.fn.lightGallery = function(options) {
  1319. return this.each(function() {
  1320. if (!$.data(this, 'lightGallery')) {
  1321. $.data(this, 'lightGallery', new Plugin(this, options));
  1322. } else {
  1323. try {
  1324. $(this).data('lightGallery').init();
  1325. } catch (err) {
  1326. console.error('lightGallery has not initiated properly');
  1327. }
  1328. }
  1329. });
  1330. };
  1331.  
  1332. $.fn.lightGallery.modules = {};
  1333.  
  1334. })();
  1335.  
  1336.  
  1337. }));