PluginProbe
VikBooking Hotel Booking Engine & PMS / 1.8.14
VikBooking Hotel Booking Engine & PMS v1.8.14
1.8.16 1.8.15 1.8.14 1.8.13 1.8.12 1.8.11 1.8.10 1.8.9 1.8.6 1.8.7 1.8.8 trunk 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 All 37 releases
vikbooking / site / resources / vikfxgallery.js

vikfxgallery.js in VikBooking Hotel Booking Engine & PMS 1.8.14, at site/resources/vikfxgallery.js

863 lines 28.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * VikFXGallery jQuery plugin. Forked from
3 * the original project simplelightbox.
4 * v. 0.12
5 */
6 ;(function($, window, document, undefined)
7 {
8 'use strict';
9 $.fn.vikFxGallery = function(options)
10 {
11 var options = $.extend({
12 sourceAttr: 'href',
13 overlay: true,
14 spinner: true,
15 nav: true,
16 navText: ['‹', '›'],
17 captions: true,
18 captionDelay: 0,
19 captionSelector: 'img',
20 captionType: 'attr',
21 captionsData: 'title',
22 captionPosition: 'bottom',
23 captionClass: '',
24 close: true,
25 closeText: '×',
26 swipeClose: true,
27 showCounter: false,
28 fileExt: 'png|jpg|jpeg|gif|webp',
29 animationSlide: true,
30 animationSpeed: 250,
31 preloading: true,
32 enableKeyboard: true,
33 loop: true,
34 rel: false,
35 docClose: true,
36 swipeTolerance: 50,
37 widthRatio: 0.8,
38 heightRatio: 0.9,
39 scaleImageToRatio: false,
40 disableRightClick: false,
41 disableScroll: true,
42 alertError: false,
43 alertErrorMessage: 'Image not found',
44 additionalHtml: false,
45 history: true,
46 throttleInterval: 0,
47 doubleTapZoom: 2,
48 maxZoom: 10,
49 htmlClass: 'vikfxg-img-active'
50 }, options);
51
52 // global variables
53 var touchDevice = ('ontouchstart' in window),
54 pointerEnabled = window.navigator.pointerEnabled || window.navigator.msPointerEnabled,
55 touched = function(event) {
56 if (touchDevice) return true;
57 if (!pointerEnabled || typeof event === 'undefined' || typeof event.pointerType === 'undefined') return false;
58 if (typeof event.MSPOINTER_TYPE_MOUSE !== 'undefined') {
59 if (event.MSPOINTER_TYPE_MOUSE != event.pointerType) return true;
60 }
61 else {
62 if (event.pointerType != 'mouse') return true;
63 }
64 return false;
65 },
66 swipeDiff = 0,
67 swipeYDiff = 0,
68 curImg = $(),
69 transPrefix = function() {
70 var s = document.body || document.documentElement;
71 s = s.style;
72 if (s.WebkitTransition === '') return '-webkit-';
73 if (s.MozTransition === '') return '-moz-';
74 if (s.OTransition === '') return '-o-';
75 if (s.transition === '') return '';
76 return false;
77 },
78 opened = false,
79 loaded = [],
80 getRelated = function(rel, jqObj) {
81 var $related = jqObj.filter(function () {
82 return ($(this).attr('rel') === rel);
83 });
84 return $related;
85 },
86 objects = (options.rel && options.rel !== false) ? getRelated(options.rel, $(this)) : this,
87 tagname = (objects.get()[0] ? objects.get()[0].tagName : null),
88 transPrefix = transPrefix(),
89 globalScrollbarwidth = 0,
90 canTransisions = (transPrefix !== false) ? true : false,
91 supportsPushState = ('pushState' in history),
92 historyhasChanged = false,
93 historyUpdateTimeout,
94 winLoc = window.location,
95 getHash = function() {
96 return winLoc.hash.substring(1);
97 },
98 initialHash = getHash(),
99 updateHash = function() {
100 var hash = getHash(),
101 newHash = 'pid='+(index+1);
102 var newURL = winLoc.href.split('#')[0] + '#' + newHash;
103
104 if (supportsPushState) {
105 history[historyhasChanged ? 'replaceState' : 'pushState']('', document.title, newURL);
106 }else {
107 if (historyhasChanged) {
108 winLoc.replace(newURL);
109 } else {
110 winLoc.hash = newHash;
111 }
112 }
113 historyhasChanged = true;
114 },
115 resetHash = function() {
116 if (supportsPushState) {
117 history.pushState('', document.title, winLoc.pathname + winLoc.search);
118 } else {
119 winLoc.hash = '';
120 }
121 clearTimeout(historyUpdateTimeout);
122
123 },
124 updateURL = function() {
125 if (!historyhasChanged) {
126 updateHash(); // first time
127 } else {
128 historyUpdateTimeout = setTimeout(updateHash, 800);
129 }
130 },
131 throttle = function(func, limit) {
132 var inThrottle;
133 return function() {
134 var args = arguments;
135 var context = this;
136 if (!inThrottle) {
137 func.apply(context, args);
138 inThrottle = true;
139 setTimeout(function() {
140 return inThrottle = false;
141 }, limit);
142 }
143 };
144 },
145 prefix = 'vikfxgl',
146 overlay = $('<div>').addClass('vikfxg-overlay'),
147 closeBtn = $('<button>').addClass('vikfxg-close').html(options.closeText),
148 spinner = $('<div>').addClass('vikfxg-spinner').html('<div></div>'),
149 nav = $('<div>').addClass('vikfxg-navigation').html('<button class="vikfxg-prev">'+options.navText[0]+'</button><button class="vikfxg-next">'+options.navText[1]+'</button>'),
150 counter = $('<div>').addClass('vikfxg-counter').html('<span class="vikfxg-current"></span>/<span class="vikfxg-total"></span>'),
151 animating = false,
152 index = 0,
153 startIndex = 0,
154 caption = $('<div>').addClass('vikfxg-caption '+options.captionClass+' pos-'+options.captionPosition),
155 image = $('<div>').addClass('vikfxg-image'),
156 wrapper = $('<div>').addClass('vikfxg-wrapper').addClass('vikfx-gallery'),
157 isValidLink = function(element) {
158 if (!options.fileExt) return true;
159 var filEext = /\.([0-9a-z]+)(?=[?#])|(\.)(?:[\w]+)$/gmi;
160 var testExt = $(element).attr(options.sourceAttr).match(filEext);
161 return testExt && $(element).prop('tagName').toUpperCase() == tagname && (new RegExp('\.(' + options.fileExt + ')$', 'i')).test(testExt);
162 },
163 setup = function() {
164 if (options.close) closeBtn.appendTo(wrapper);
165 if (options.showCounter) {
166 if (objects.length > 1) {
167 counter.appendTo(wrapper);
168 counter.find('.vikfxg-total').text(objects.length);
169 }
170 }
171 if (options.nav) nav.appendTo(wrapper);
172 if (options.spinner) spinner.appendTo(wrapper);
173 },
174 openImage = function(elem) {
175 elem.trigger($.Event('show.vikfxgallery'));
176 if (options.disableScroll) globalScrollbarwidth = handleScrollbar('hide');
177 if (options.htmlClass && options.htmlClass != '') $('html').addClass(options.htmlClass);
178 wrapper.appendTo('body');
179 image.appendTo(wrapper);
180 if (options.overlay) overlay.appendTo($('body'));
181 animating = true;
182 index = objects.index(elem);
183 curImg = $('<img/>')
184 .hide()
185 .attr('src', elem.attr(options.sourceAttr))
186 .attr('data-scale', 1)
187 .attr('data-translate-x', 0)
188 .attr('data-translate-y', 0);
189 if (loaded.indexOf(elem.attr(options.sourceAttr)) == -1) {
190 loaded.push(elem.attr(options.sourceAttr));
191 }
192 image.html('').attr('style','');
193 curImg.appendTo(image);
194 addEvents();
195 overlay.fadeIn('fast');
196 $('.vikfxg-close').fadeIn('fast');
197 spinner.show();
198 nav.fadeIn('fast');
199 $('.vikfxg-wrapper .vikfxg-counter .vikfxg-current').text(index +1);
200 counter.fadeIn('fast');
201 adjustImage();
202 if (options.preloading) preload();
203 setTimeout(function() {
204 elem.trigger($.Event('shown.vikfxgallery'));
205 }, options.animationSpeed);
206 },
207 adjustImage = function(dir) {
208 if (!curImg.length) return;
209 var tmpImage = new Image(),
210 windowWidth = window.innerWidth * options.widthRatio,
211 windowHeight = window.innerHeight * options.heightRatio;
212 tmpImage.src = curImg.attr('src');
213 curImg.data('scale',1);
214 curImg.data('translate-x',0);
215 curImg.data('translate-y',0);
216 zoomPanElement(0,0,1);
217 $(tmpImage).on('error',function(ev) {
218 // image not found
219 objects.eq(index).trigger($.Event('error.vikfxgallery'));
220 animating = false;
221 opened = true;
222 spinner.hide();
223 var dirDefinined = (dir == 1 || dir == -1);
224 if (startIndex === index && dirDefinined) {
225 close();
226 return;
227 }
228 if (options.alertError) {
229 alert(options.alertErrorMessage);
230 } else {
231 console.error(options.alertErrorMessage);
232 }
233 if (dirDefinined) {
234 loadImage(dir);
235 } else {
236 loadImage(1);
237 }
238 return;
239 });
240
241 tmpImage.onload = function() {
242 if (typeof dir !== 'undefined') {
243 objects.eq(index)
244 .trigger($.Event('changed.vikfxgallery'))
245 .trigger($.Event((dir ===1 ? 'nextDone' : 'prevDone') + '.vikfxgallery'));
246 }
247
248 // history
249 if (options.history) {
250 updateURL();
251 }
252
253 if (loaded.indexOf(curImg.attr('src')) == -1) {
254 loaded.push(curImg.attr('src'));
255 }
256 var imageWidth = tmpImage.width,
257 imageHeight = tmpImage.height;
258
259 if (options.scaleImageToRatio || imageWidth > windowWidth || imageHeight > windowHeight) {
260 var ratio = imageWidth / imageHeight > windowWidth / windowHeight ? imageWidth / windowWidth : imageHeight / windowHeight;
261 imageWidth /= ratio;
262 imageHeight /= ratio;
263 }
264
265 $('.vikfxg-image').css({
266 'top': (window.innerHeight - imageHeight) / 2 + 'px',
267 'left': (window.innerWidth - imageWidth - globalScrollbarwidth)/ 2 + 'px',
268 'width': imageWidth + 'px',
269 'height': imageHeight + 'px'
270 });
271 spinner.hide();
272 curImg
273 .fadeIn('fast');
274 opened = true;
275 var cSel = (options.captionSelector == 'self') ? objects.eq(index) : objects.eq(index).find(options.captionSelector);
276 var captionText;
277 if (options.captionType == 'data') {
278 captionText = cSel.data(options.captionsData);
279 } else if (options.captionType == 'text') {
280 captionText = cSel.html();
281 } else {
282 captionText = cSel.prop(options.captionsData);
283 }
284
285 if (!options.loop) {
286 if (index === 0) { $('.vikfxg-prev').hide();}
287 if (index >= objects.length -1) {$('.vikfxg-next').hide();}
288 if (index > 0) { $('.vikfxg-prev').show(); }
289 if (index < objects.length -1) { $('.vikfxg-next').show(); }
290 }
291
292 if (objects.length == 1) $('.vikfxg-prev, .vikfxg-next').hide();
293
294 if (dir == 1 || dir == -1) {
295 var css = { 'opacity': 1.0 };
296 if (options.animationSlide) {
297 if (canTransisions) {
298 slide(0, 100 * dir + 'px');
299 setTimeout(function() {
300 slide(options.animationSpeed / 1000, 0 + 'px');
301 }, 50);
302 }
303 else {
304 css.left = parseInt($('.vikfxg-image').css('left')) + 100 * dir + 'px';
305 }
306 }
307
308 $('.vikfxg-image').animate(css, options.animationSpeed, function() {
309 animating = false;
310 setCaption(captionText, imageWidth);
311 });
312 } else {
313 animating = false;
314 setCaption(captionText, imageWidth);
315 }
316 if (options.additionalHtml && $('.vikfxg-additional-html').length === 0) {
317 $('<div>').html(options.additionalHtml).addClass('vikfxg-additional-html').appendTo($('.vikfxg-image'));
318 }
319 };
320 },
321 setCaption = function(captiontext, imageWidth) {
322 if (captiontext !== '' && typeof captiontext !== "undefined" && options.captions) {
323 caption.html(captiontext).css({'width': imageWidth + 'px'}).hide().appendTo($('.vikfxg-image')).delay(options.captionDelay).fadeIn('fast');
324 }
325 },
326 slide = function(speed, pos) {
327 var styles = {};
328 styles[transPrefix + 'transform'] = 'translateX(' + pos + ')';
329 styles[transPrefix + 'transition'] = transPrefix + 'transform ' + speed + 's linear';
330 $('.vikfxg-image').css(styles);
331 },
332 zoomPanElement = function(targetOffsetX, targetOffsetY, targetScale) {
333 var styles = {};
334 styles[transPrefix + 'transform'] = 'translate(' + targetOffsetX + ',' + targetOffsetY+ ') scale('+targetScale+')';
335 curImg.css(styles);
336 },
337 minMax = function(value, min, max) {
338 return (value < min) ? min : (value > max) ? max : value;
339 },
340 setZoomData = function(initialScale,targetOffsetX,targetOffsetY) {
341 curImg.data('scale',initialScale);
342 curImg.data('translate-x',targetOffsetX);
343 curImg.data('translate-y',targetOffsetY);
344 },
345 addEvents = function() {
346 // resize/responsive
347 $(window).on('resize.'+prefix, adjustImage);
348
349 // close lightbox on close btn
350 $(document).on('click.'+prefix+ ' touchstart.'+prefix, '.vikfxg-close', function(e) {
351 e.preventDefault();
352 if (opened) { close();}
353 });
354
355 if (options.history) {
356 setTimeout(function() {
357 $(window).on('hashchange.'+prefix,function() {
358 if (opened) {
359 if (getHash() === initialHash) {
360 close();
361 return;
362 }
363 }
364 });
365 }, 40);
366 }
367
368 // nav-buttons
369 nav.on('click.'+prefix, 'button', throttle(function(e) {
370 e.preventDefault();
371 swipeDiff = 0;
372 loadImage($(this).hasClass('vikfxg-next') ? 1 : -1);
373 }, options.throttleInterval));
374
375 // touch helpers
376 var swipeStart = 0,
377 swipeEnd = 0,
378 swipeYStart = 0,
379 swipeYEnd = 0,
380 zoomed = false,
381 mousedown = false,
382 imageLeft = 0,
383 containerHeight,
384 containerWidth,
385 containerOffsetX,
386 containerOffsetY,
387 imgHeight,
388 imgWidth,
389 capture = false,
390 initialOffsetX,
391 initialOffsetY,
392 initialPointerOffsetX,
393 initialPointerOffsetY,
394 initialPointerOffsetX2,
395 initialPointerOffsetY2,
396 initialScale = minMax(1, 1, options.maxZoom),
397 initialPinchDistance,
398 pointerOffsetX,
399 pointerOffsetY,
400 pointerOffsetX2,
401 pointerOffsetY2,
402 targetOffsetX,
403 targetOffsetY,
404 targetScale,
405 pinchOffsetX,
406 pinchOffsetY,
407 limitOffsetX,
408 limitOffsetY,
409 scaleDifference,
410 targetPinchDistance,
411 touchCount,
412 doubleTapped = false,
413 touchmoveCount = 0;
414
415 image
416 .on('touchstart.'+prefix+' mousedown.'+prefix, function(e)
417 {
418 if (e.target.tagName === 'A' && e.type == 'touchstart') {
419 return true;
420 }
421 e = e.originalEvent;
422 if (e.type == 'mousedown') {
423 initialPointerOffsetX = e.clientX;
424 initialPointerOffsetY = e.clientY;
425 containerHeight = image.height();
426 containerWidth = image.width();
427 imgHeight = curImg.height();
428 imgWidth = curImg.width();
429 containerOffsetX = image.position().left;
430 containerOffsetY = image.position().top;
431
432 initialOffsetX = parseFloat(curImg.data('translate-x'));
433 initialOffsetY = parseFloat(curImg.data('translate-y'));
434
435 capture = true;
436 } else {
437 touchCount = e.touches.length;
438 initialPointerOffsetX = e.touches[0].clientX;
439 initialPointerOffsetY = e.touches[0].clientY;
440 containerHeight = image.height();
441 containerWidth = image.width();
442 imgHeight = curImg.height();
443 imgWidth = curImg.width();
444 containerOffsetX = image.position().left;
445 containerOffsetY = image.position().top;
446
447 if (touchCount === 1) /* Single touch */ {
448 if (!doubleTapped) {
449 doubleTapped = true;
450 setTimeout(function() {
451 doubleTapped = false;
452 }, 300);
453 } else {
454 curImg.addClass('vikfxg-transition');
455 if (!zoomed) {
456 initialScale = options.doubleTapZoom;
457 setZoomData(0,0, initialScale);
458 zoomPanElement(0 + "px", 0 + "px", initialScale);
459 $('.vikfxg-caption').fadeOut(200);
460 zoomed = true;
461 } else {
462 initialScale = 1;
463 setZoomData(0,0,initialScale);
464 zoomPanElement(0 + "px", 0 + "px", initialScale);
465 zoomed = false;
466 }
467
468 setTimeout(function() {
469 curImg.removeClass('vikfxg-transition');
470 }, 200);
471 return false;
472 }
473
474 initialOffsetX = parseFloat(curImg.data('translate-x'));
475 initialOffsetY = parseFloat(curImg.data('translate-y'));
476 }
477 else if (touchCount === 2) /* Pinch */ {
478 initialPointerOffsetX2 = e.touches[1].clientX;
479 initialPointerOffsetY2 = e.touches[1].clientY;
480 initialOffsetX = parseFloat(curImg.data('translate-x'));
481 initialOffsetY = parseFloat(curImg.data('translate-y'));
482 pinchOffsetX = (initialPointerOffsetX + initialPointerOffsetX2) / 2;
483 pinchOffsetY = (initialPointerOffsetY + initialPointerOffsetY2) / 2;
484 initialPinchDistance = Math.sqrt(((initialPointerOffsetX - initialPointerOffsetX2) * (initialPointerOffsetX - initialPointerOffsetX2)) + ((initialPointerOffsetY - initialPointerOffsetY2) * (initialPointerOffsetY - initialPointerOffsetY2)));
485 }
486 capture = true;
487 }
488
489 if (mousedown) return true;
490 if (canTransisions) imageLeft = parseInt(image.css('left'));
491 mousedown = true;
492 swipeDiff = 0;
493 swipeYDiff = 0;
494 swipeStart = e.pageX || e.touches[ 0 ].pageX;
495 swipeYStart = e.pageY || e.touches[ 0 ].pageY;
496 return false;
497 })
498 .on('touchmove.'+prefix+' mousemove.'+prefix+' MSPointerMove', function(e)
499 {
500 if (!mousedown) return true;
501 e.preventDefault();
502 e = e.originalEvent;
503 /* Initialize helpers */
504 if (e.type == 'touchmove') {
505 if (capture === false) return false;
506 pointerOffsetX = e.touches[0].clientX;
507 pointerOffsetY = e.touches[0].clientY;
508 touchCount = e.touches.length;
509 touchmoveCount++;
510
511 if (touchCount > 1) /* Pinch */ {
512 pointerOffsetX2 = e.touches[1].clientX;
513 pointerOffsetY2 = e.touches[1].clientY;
514 targetPinchDistance = Math.sqrt(((pointerOffsetX - pointerOffsetX2) * (pointerOffsetX - pointerOffsetX2)) + ((pointerOffsetY - pointerOffsetY2) * (pointerOffsetY - pointerOffsetY2)));
515 if (initialPinchDistance === null) {
516 initialPinchDistance = targetPinchDistance;
517 }
518
519 if (Math.abs(initialPinchDistance - targetPinchDistance) >= 1) {
520 /* Initialize helpers */
521 targetScale = minMax(targetPinchDistance / initialPinchDistance * initialScale, 1, options.maxZoom);
522 limitOffsetX = ((imgWidth * targetScale) - containerWidth) / 2;
523 limitOffsetY = ((imgHeight * targetScale) - containerHeight) / 2;
524 scaleDifference = targetScale - initialScale;
525 targetOffsetX = (imgWidth * targetScale) <= containerWidth ? 0: minMax(initialOffsetX - ((((((pinchOffsetX - containerOffsetX) - (containerWidth / 2)) - initialOffsetX) / (targetScale - scaleDifference))) * scaleDifference), limitOffsetX * (-1), limitOffsetX);
526 targetOffsetY = (imgHeight * targetScale) <= containerHeight ? 0 : minMax(initialOffsetY - ((((((pinchOffsetY - containerOffsetY) - (containerHeight / 2)) - initialOffsetY) / (targetScale - scaleDifference))) * scaleDifference), limitOffsetY * (-1), limitOffsetY);
527
528 zoomPanElement(targetOffsetX + "px", targetOffsetY + "px", targetScale);
529
530 if (targetScale > 1) {
531 zoomed = true;
532 $('.vikfxg-caption').fadeOut(200);
533 }
534
535 initialPinchDistance = targetPinchDistance;
536 initialScale = targetScale;
537 initialOffsetX = targetOffsetX;
538 initialOffsetY = targetOffsetY;
539 }
540 } else {
541 targetScale = initialScale;
542 limitOffsetX = ((imgWidth * targetScale) - containerWidth) / 2;
543 limitOffsetY = ((imgHeight * targetScale) - containerHeight) / 2;
544 targetOffsetX = (imgWidth * targetScale) <= containerWidth ? 0 : minMax(pointerOffsetX - (initialPointerOffsetX - initialOffsetX), limitOffsetX * (-1), limitOffsetX);
545 targetOffsetY = (imgHeight * targetScale) <= containerHeight ? 0 : minMax(pointerOffsetY - (initialPointerOffsetY - initialOffsetY), limitOffsetY * (-1), limitOffsetY);
546
547 if (Math.abs(targetOffsetX) === Math.abs(limitOffsetX)) {
548 initialOffsetX = targetOffsetX;
549 initialPointerOffsetX = pointerOffsetX;
550 }
551
552 if (Math.abs(targetOffsetY) === Math.abs(limitOffsetY)) {
553 initialOffsetY = targetOffsetY;
554 initialPointerOffsetY = pointerOffsetY;
555 }
556
557 setZoomData(initialScale,targetOffsetX,targetOffsetY);
558 zoomPanElement(targetOffsetX + "px", targetOffsetY + "px", targetScale);
559 }
560 }
561 /* Mouse Move implementation */
562 if (e.type == 'mousemove' && mousedown) {
563 if (e.type == 'touchmove') return true;
564 if (capture === false) return false;
565 pointerOffsetX = e.clientX;
566 pointerOffsetY = e.clientY;
567 targetScale = initialScale;
568 limitOffsetX = ((imgWidth * targetScale) - containerWidth) / 2;
569 limitOffsetY = ((imgHeight * targetScale) - containerHeight) / 2;
570 targetOffsetX = (imgWidth * targetScale) <= containerWidth ? 0 : minMax(pointerOffsetX - (initialPointerOffsetX - initialOffsetX), limitOffsetX * (-1), limitOffsetX);
571 targetOffsetY = (imgHeight * targetScale) <= containerHeight ? 0 : minMax(pointerOffsetY - (initialPointerOffsetY - initialOffsetY), limitOffsetY * (-1), limitOffsetY);
572
573 if (Math.abs(targetOffsetX) === Math.abs(limitOffsetX)) {
574 initialOffsetX = targetOffsetX;
575 initialPointerOffsetX = pointerOffsetX;
576 }
577
578 if (Math.abs(targetOffsetY) === Math.abs(limitOffsetY)) {
579 initialOffsetY = targetOffsetY;
580 initialPointerOffsetY = pointerOffsetY;
581 }
582
583 setZoomData(initialScale,targetOffsetX,targetOffsetY);
584 zoomPanElement(targetOffsetX + "px", targetOffsetY + "px", targetScale);
585 }
586 if (!zoomed) {
587 swipeEnd = e.pageX || e.touches[ 0 ].pageX;
588 swipeYEnd = e.pageY || e.touches[ 0 ].pageY;
589 swipeDiff = swipeStart - swipeEnd;
590 swipeYDiff = swipeYStart - swipeYEnd;
591 if (options.animationSlide) {
592 if (canTransisions) slide(0, -swipeDiff + 'px');
593 else image.css('left', imageLeft - swipeDiff + 'px');
594 }
595 }
596 })
597 .on('touchend.'+prefix+' mouseup.'+prefix+' touchcancel.'+prefix+' mouseleave.'+prefix+' pointerup pointercancel MSPointerUp MSPointerCancel',function(e)
598 {
599 e = e.originalEvent;
600 if (touchDevice && e.type =='touchend') {
601 touchCount = e.touches.length;
602 if (touchCount === 0) /* No touch */ {
603 /* Set attributes */
604 setZoomData(initialScale,targetOffsetX,targetOffsetY);
605 if (initialScale == 1) {
606 zoomed = false;
607 $('.vikfxg-caption').fadeIn(200);
608 }
609 initialPinchDistance = null;
610 capture = false;
611 } else if (touchCount === 1) /* Single touch */ {
612 initialPointerOffsetX = e.touches[0].clientX;
613 initialPointerOffsetY = e.touches[0].clientY;
614 } else if (touchCount > 1) /* Pinch */ {
615 initialPinchDistance = null;
616 }
617 }
618
619 if (mousedown) {
620 mousedown = false;
621 var possibleDir = true;
622 if (!options.loop) {
623 if (index === 0 && swipeDiff < 0) { possibleDir = false; }
624 if (index >= objects.length -1 && swipeDiff > 0) { possibleDir = false; }
625 }
626 if (Math.abs(swipeDiff) > options.swipeTolerance && possibleDir) {
627 loadImage(swipeDiff > 0 ? 1 : -1);
628 }
629 else if (options.animationSlide)
630 {
631 if (canTransisions) slide(options.animationSpeed / 1000, 0 + 'px');
632 else image.animate({ 'left': imageLeft + 'px' }, options.animationSpeed / 2);
633 }
634
635 if (options.swipeClose && Math.abs(swipeYDiff) > 50 && Math.abs(swipeDiff) < options.swipeTolerance) {
636 close();
637 }
638 }
639 })
640 /** Detect Double click on image*/
641 .on('dblclick', function(e)
642 {
643 initialPointerOffsetX = e.clientX;
644 initialPointerOffsetY = e.clientY;
645 containerHeight = image.height();
646 containerWidth = image.width();
647 imgHeight = curImg.height();
648 imgWidth = curImg.width();
649 containerOffsetX = image.position().left;
650 containerOffsetY = image.position().top;
651
652 curImg.addClass('vikfxg-transition');
653 if (!zoomed) {
654 initialScale = options.doubleTapZoom;
655 setZoomData(0,0, initialScale);
656 zoomPanElement(0 + "px", 0 + "px", initialScale);
657 $('.vikfxg-caption').fadeOut(200);
658 zoomed = true;
659 } else {
660 initialScale = 1;
661 setZoomData(0,0,initialScale);
662 zoomPanElement(0 + "px", 0 + "px", initialScale);
663 zoomed = false;
664 }
665
666 setTimeout(function() {
667 curImg.removeClass('vikfxg-transition');
668 }, 200);
669 capture = true;
670 return false;
671 });
672 },
673 removeEvents = function() {
674 nav.off('click', 'button');
675 $(document).off('click.'+prefix, '.vikfxg-close');
676 $(window).off('resize.'+prefix);
677 $(window).off('hashchange.'+prefix);
678 },
679 preload = function() {
680 var next = (index+1 < 0) ? objects.length -1: (index+1 >= objects.length -1) ? 0 : index+1,
681 prev = (index-1 < 0) ? objects.length -1: (index-1 >= objects.length -1) ? 0 : index-1;
682 $('<img />').attr('src', objects.eq(next).attr(options.sourceAttr)).on('load', function() {
683 if (loaded.indexOf($(this).attr('src')) == -1) {
684 loaded.push($(this).attr('src'));
685 }
686 objects.eq(index).trigger($.Event('nextImageLoaded.vikfxgallery'));
687 });
688 $('<img />').attr('src', objects.eq(prev).attr(options.sourceAttr)).on('load', function() {
689 if (loaded.indexOf($(this).attr('src')) == -1) {
690 loaded.push($(this).attr('src'));
691 }
692 objects.eq(index).trigger($.Event('prevImageLoaded.vikfxgallery'));
693 });
694
695 },
696 loadImage = function(dir) {
697 objects.eq(index)
698 .trigger($.Event('change.vikfxgallery'))
699 .trigger($.Event((dir === 1 ? 'next' : 'prev') + '.vikfxgallery'));
700
701 var newIndex = index + dir;
702 if (animating || (newIndex < 0 || newIndex >= objects.length) && options.loop === false) return;
703 index = (newIndex < 0) ? objects.length -1: (newIndex > objects.length -1) ? 0 : newIndex;
704 $('.vikfxg-wrapper .vikfxg-counter .vikfxg-current').text(index +1);
705 var css = { 'opacity': 0 };
706 if (options.animationSlide) {
707 if (canTransisions) slide(options.animationSpeed / 1000, (-100 * dir) - swipeDiff + 'px');
708 else css.left = parseInt($('.vikfxg-image').css('left')) + -100 * dir + 'px';
709 }
710
711 $('.vikfxg-image').animate(css, options.animationSpeed, function() {
712 setTimeout(function() {
713 // fadeout old image
714 var elem = objects.eq(index);
715 curImg
716 .attr('src', elem.attr(options.sourceAttr));
717
718 if (loaded.indexOf(elem.attr(options.sourceAttr)) == -1) {
719 spinner.show();
720 }
721 $('.vikfxg-caption').remove();
722 adjustImage(dir);
723 if (options.preloading) preload();
724 }, 100);
725 });
726 },
727 close = function() {
728 if (animating) return;
729 var elem = objects.eq(index),
730 triggered = false;
731
732 elem.trigger($.Event('close.vikfxgallery'));
733 if (options.history) {
734 resetHash();
735 }
736 $('.vikfxg-image img, .vikfxg-overlay, .vikfxg-close, .vikfxg-navigation, .vikfxg-image .vikfxg-caption, .vikfxg-counter').fadeOut('fast', function() {
737 if (options.disableScroll) handleScrollbar('show');
738 if (options.htmlClass && options.htmlClass != '') $('html').removeClass(options.htmlClass);
739 $('.vikfxg-wrapper, .vikfxg-overlay').remove();
740 removeEvents();
741 if (!triggered) elem.trigger($.Event('closed.vikfxgallery'));
742 triggered = true;
743 });
744 curImg = $();
745 opened = false;
746 animating = false;
747 },
748 handleScrollbar = function(type) {
749 var scrollbarWidth = 0;
750 if (type == 'hide') {
751 var fullWindowWidth = window.innerWidth;
752 if (!fullWindowWidth) {
753 var documentElementRect = document.documentElement.getBoundingClientRect();
754 fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left);
755 }
756 if (document.body.clientWidth < fullWindowWidth) {
757 var scrollDiv = document.createElement('div'),
758 padding = parseInt($('body').css('padding-right'),10);
759 scrollDiv.className = 'vikfxg-scrollbar-measure';
760 $('body').append(scrollDiv);
761 scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth;
762 $(document.body)[0].removeChild(scrollDiv);
763 $('body').data('padding',padding);
764 if (scrollbarWidth > 0) {
765 $('body').addClass('hidden-scroll').css({'padding-right':padding+scrollbarWidth});
766 }
767 }
768 } else {
769 $('body').removeClass('hidden-scroll').css({'padding-right':$('body').data('padding')});
770 }
771 return scrollbarWidth;
772 };
773
774 // events
775 setup();
776
777 // open lightbox
778 objects.on('click.'+prefix, function(e) {
779 if (isValidLink(this)) {
780 e.preventDefault();
781 if (animating) return false;
782 var elem = $(this);
783 startIndex = objects.index(elem);
784 openImage(elem);
785 }
786 });
787
788 // close on click on doc
789 $(document).on('click.'+prefix+ ' touchstart.'+prefix, function(e) {
790 if (opened) {
791 if ((options.docClose && $(e.target).closest('.vikfxg-image').length === 0 && $(e.target).closest('.vikfxg-navigation').length === 0)) {
792 close();
793 }
794 }
795 });
796
797 // disable rightclick
798 if (options.disableRightClick) {
799 $(document).on('contextmenu', '.vikfxg-image img', function(e) {
800 return false;
801 });
802 }
803
804 // keyboard-control
805 if (options.enableKeyboard) {
806 $(document).on('keyup.'+prefix, throttle(function(e) {
807 swipeDiff = 0;
808 // keyboard control only if lightbox is open
809 var key = e.keyCode;
810 if (animating && key == 27) {
811 curImg.attr('src', '');
812 animating = false;
813 close();
814 }
815
816 if (opened) {
817 e.preventDefault();
818 if (key == 27) {
819 close();
820 }
821 if (key == 37 || e.keyCode == 39) {
822 loadImage(e.keyCode == 39 ? 1 : -1);
823 }
824 }
825 }, options.throttleInterval));
826 }
827
828 // Public methods
829 this.open = function(elem) {
830 elem = elem || $(this[0]);
831 startIndex = objects.index(elem);
832 openImage(elem);
833 };
834
835 this.close = function() {
836 close();
837 };
838
839 this.next = function() {
840 loadImage(1);
841 };
842
843 this.prev = function() {
844 loadImage(-1);
845 };
846
847 this.destroy = function() {
848 $(document).off('click.'+prefix).off('keyup.'+prefix);
849 close();
850 $('.vikfxg-overlay, .vikfxg-wrapper').remove();
851 this.off('click');
852 };
853
854 this.refresh = function() {
855 this.destroy();
856 $(this).vikFxGallery(options);
857 };
858
859 return this;
860
861 };
862 })(jQuery, window, document);
863