PageSourceSearch

https://fourthchurch.org/fancybox3/guestures.js

js fourthchurch.org collected 2026-09-24 21:53:19 UTC 27,483 bytes, 923 lines download raw bytes

vendor: 27,483 bytes, lines 1-923
1// ==========================================================================
2//
3// Guestures
4// Adds touch guestures, handles click and tap events
5//
6// ==========================================================================
7(function (window, document, $) {
8  "use strict";
9
10  var requestAFrame = (function () {
11    return (
12      window.requestAnimationFrame ||
13      window.webkitRequestAnimationFrame ||
14      window.mozRequestAnimationFrame ||
15      window.oRequestAnimationFrame ||
16      // if all else fails, use setTimeout
17      function (callback) {
18        return window.setTimeout(callback, 1000 / 60);
19      }
20    );
21  })();
22
23  var cancelAFrame = (function () {
24    return (
25      window.cancelAnimationFrame ||
26      window.webkitCancelAnimationFrame ||
27      window.mozCancelAnimationFrame ||
28      window.oCancelAnimationFrame ||
29      function (id) {
30        window.clearTimeout(id);
31      }
32    );
33  })();
34
35  var getPointerXY = function (e) {
36    var result = [];
37
38    e = e.originalEvent || e || window.e;
39    e = e.touches && e.touches.length ? e.touches : e.changedTouches && e.changedTouches.length ? e.changedTouches : [e];
40
41    for (var key in e) {
42      if (e[key].pageX) {
43        result.push({
44          x: e[key].pageX,
45          y: e[key].pageY
46        });
47      } else if (e[key].clientX) {
48        result.push({
49          x: e[key].clientX,
50          y: e[key].clientY
51        });
52      }
53    }
54
55    return result;
56  };
57
58  var distance = function (point2, point1, what) {
59    if (!point1 || !point2) {
60      return 0;
61    }
62
63    if (what === "x") {
64      return point2.x - point1.x;
65    } else if (what === "y") {
66      return point2.y - point1.y;
67    }
68
69    return Math.sqrt(Math.pow(point2.x - point1.x, 2) + Math.pow(point2.y - point1.y, 2));
70  };
71
72  var isClickable = function ($el) {
73    if (
74      $el.is('a,area,button,[role="button"],input,label,select,summary,textarea,video,audio,iframe') ||
75      $.isFunction($el.get(0).onclick) ||
76      $el.data("selectable")
77    ) {
78      return true;
79    }
80
81    // Check for attributes like data-fancybox-next or data-fancybox-close
82    for (var i = 0, atts = $el[0].attributes, n = atts.length; i < n; i++) {
83      if (atts[i].nodeName.substr(0, 14) === "data-fancybox-") {
84        return true;
85      }
86    }
87
88    return false;
89  };
90
91  var hasScrollbars = function (el) {
92    var overflowY = window.getComputedStyle(el)["overflow-y"],
93      overflowX = window.getComputedStyle(el)["overflow-x"],
94      vertical = (overflowY === "scroll" || overflowY === "auto") && el.scrollHeight > el.clientHeight,
95      horizontal = (overflowX === "scroll" || overflowX === "auto") && el.scrollWidth > el.clientWidth;
96
97    return vertical || horizontal;
98  };
99
100  var isScrollable = function ($el) {
101    var rez = false;
102
103    while (true) {
104      rez = hasScrollbars($el.get(0));
105
106      if (rez) {
107        break;
108      }
109
110      $el = $el.parent();
111
112      if (!$el.length || $el.hasClass("fancybox-stage") || $el.is("body")) {
113        break;
114      }
115    }
116
117    return rez;
118  };
119
120  var Guestures = function (instance) {
121    var self = this;
122
123    self.instance = instance;
124
125    self.$bg = instance.$refs.bg;
126    self.$stage = instance.$refs.stage;
127    self.$container = instance.$refs.container;
128
129    self.destroy();
130
131    self.$container.on("touchstart.fb.touch mousedown.fb.touch", $.proxy(self, "ontouchstart"));
132  };
133
134  Guestures.prototype.destroy = function () {
135    var self = this;
136
137    self.$container.off(".fb.touch");
138
139    $(document).off(".fb.touch");
140
141    if (self.requestId) {
142      cancelAFrame(self.requestId);
143      self.requestId = null;
144    }
145
146    if (self.tapped) {
147      clearTimeout(self.tapped);
148      self.tapped = null;
149    }
150  };
151
152  Guestures.prototype.ontouchstart = function (e) {
153    var self = this,
154      $target = $(e.target),
155      instance = self.instance,
156      current = instance.current,
157      $slide = current.$slide,
158      $content = current.$content,
159      isTouchDevice = e.type == "touchstart";
160
161    // Do not respond to both (touch and mouse) events
162    if (isTouchDevice) {
163      self.$container.off("mousedown.fb.touch");
164    }
165
166    // Ignore right click
167    if (e.originalEvent && e.originalEvent.button == 2) {
168      return;
169    }
170
171    // Ignore taping on links, buttons, input elements
172    if (!$slide.length || !$target.length || isClickable($target) || isClickable($target.parent())) {
173      return;
174    }
175    // Ignore clicks on the scrollbar
176    if (!$target.is("img") && e.originalEvent.clientX > $target[0].clientWidth + $target.offset().left) {
177      return;
178    }
179
180    // Ignore clicks while zooming or closing
181    if (!current || instance.isAnimating || current.$slide.hasClass("fancybox-animated")) {
182      e.stopPropagation();
183      e.preventDefault();
184
185      return;
186    }
187
188    self.realPoints = self.startPoints = getPointerXY(e);
189
190    if (!self.startPoints.length) {
191      return;
192    }
193
194    // Allow other scripts to catch touch event if "touch" is set to false
195    if (current.touch) {
196      e.stopPropagation();
197    }
198
199    self.startEvent = e;
200
201    self.canTap = true;
202    self.$target = $target;
203    self.$content = $content;
204    self.opts = current.opts.touch;
205
206    self.isPanning = false;
207    self.isSwiping = false;
208    self.isZooming = false;
209    self.isScrolling = false;
210    self.canPan = instance.canPan();
211
212    self.startTime = new Date().getTime();
213    self.distanceX = self.distanceY = self.distance = 0;
214
215    self.canvasWidth = Math.round($slide[0].clientWidth);
216    self.canvasHeight = Math.round($slide[0].clientHeight);
217
218    self.contentLastPos = null;
219    self.contentStartPos = $.fancybox.getTranslate(self.$content) || {
220      top: 0,
221      left: 0
222    };
223    self.sliderStartPos = $.fancybox.getTranslate($slide);
224
225    // Since position will be absolute, but we need to make it relative to the stage
226    self.stagePos = $.fancybox.getTranslate(instance.$refs.stage);
227
228    self.sliderStartPos.top -= self.stagePos.top;
229    self.sliderStartPos.left -= self.stagePos.left;
230
231    self.contentStartPos.top -= self.stagePos.top;
232    self.contentStartPos.left -= self.stagePos.left;
233
234    $(document)
235      .off(".fb.touch")
236      .on(isTouchDevice ? "touchend.fb.touch touchcancel.fb.touch" : "mouseup.fb.touch mouseleave.fb.touch", $.proxy(self, "ontouchend"))
237      .on(isTouchDevice ? "touchmove.fb.touch" : "mousemove.fb.touch", $.proxy(self, "ontouchmove"));
238
239    if ($.fancybox.isMobile) {
240      document.addEventListener("scroll", self.onscroll, true);
241    }
242
243    // Skip if clicked outside the sliding area
244    if (!(self.opts || self.canPan) || !($target.is(self.$stage) || self.$stage.find($target).length)) {
245      if ($target.is(".fancybox-image")) {
246        e.preventDefault();
247      }
248
249      if (!($.fancybox.isMobile && $target.parents(".fancybox-caption").length)) {
250        return;
251      }
252    }
253
254    self.isScrollable = isScrollable($target) || isScrollable($target.parent());
255
256    // Check if element is scrollable and try to prevent default behavior (scrolling)
257    if (!($.fancybox.isMobile && self.isScrollable)) {
258      e.preventDefault();
259    }
260
261    // One finger or mouse click - swipe or pan an image
262    if (self.startPoints.length === 1 || current.hasError) {
263      if (self.canPan) {
264        $.fancybox.stop(self.$content);
265
266        self.isPanning = true;
267      } else {
268        self.isSwiping = true;
269      }
270
271      self.$container.addClass("fancybox-is-grabbing");
272    }
273
274    // Two fingers - zoom image
275    if (self.startPoints.length === 2 && current.type === "image" && (current.isLoaded || current.$ghost)) {
276      self.canTap = false;
277      self.isSwiping = false;
278      self.isPanning = false;
279
280      self.isZooming = true;
281
282      $.fancybox.stop(self.$content);
283
284      self.centerPointStartX = (self.startPoints[0].x + self.startPoints[1].x) * 0.5 - $(window).scrollLeft();
285      self.centerPointStartY = (self.startPoints[0].y + self.startPoints[1].y) * 0.5 - $(window).scrollTop();
286
287      self.percentageOfImageAtPinchPointX = (self.centerPointStartX - self.contentStartPos.left) / self.contentStartPos.width;
288      self.percentageOfImageAtPinchPointY = (self.centerPointStartY - self.contentStartPos.top) / self.contentStartPos.height;
289
290      self.startDistanceBetweenFingers = distance(self.startPoints[0], self.startPoints[1]);
291    }
292  };
293
294  Guestures.prototype.onscroll = function (e) {
295    var self = this;
296
297    self.isScrolling = true;
298
299    document.removeEventListener("scroll", self.onscroll, true);
300  };
301
302  Guestures.prototype.ontouchmove = function (e) {
303    var self = this;
304
305    // Make sure user has not released over iframe or disabled element
306    if (e.originalEvent.buttons !== undefined && e.originalEvent.buttons === 0) {
307      self.ontouchend(e);
308      return;
309    }
310
311    if (self.isScrolling) {
312      self.canTap = false;
313      return;
314    }
315
316    self.newPoints = getPointerXY(e);
317
318    if (!(self.opts || self.canPan) || !self.newPoints.length || !self.newPoints.length) {
319      return;
320    }
321
322    if (!(self.isSwiping && self.isSwiping === true)) {
323      e.preventDefault();
324    }
325
326    self.distanceX = distance(self.newPoints[0], self.startPoints[0], "x");
327    self.distanceY = distance(self.newPoints[0], self.startPoints[0], "y");
328
329    self.distance = distance(self.newPoints[0], self.startPoints[0]);
330
331    // Skip false ontouchmove events (Chrome)
332    if (self.distance > 0) {
333      if (self.isSwiping) {
334        self.onSwipe(e);
335      } else if (self.isPanning) {
336        self.onPan();
337      } else if (self.isZooming) {
338        self.onZoom();
339      }
340    }
341  };
342
343  Guestures.prototype.onSwipe = function (e) {
344    var self = this,
345      instance = self.instance,
346      swiping = self.isSwiping,
347      left = self.sliderStartPos.left || 0,
348      angle;
349
350    // If direction is not yet determined
351    if (swiping === true) {
352      // We need at least 10px distance to correctly calculate an angle
353      if (Math.abs(self.distance) > 10) {
354        self.canTap = false;
355
356        if (instance.group.length < 2 && self.opts.vertical) {
357          self.isSwiping = "y";
358        } else if (instance.isDragging || self.opts.vertical === false || (self.opts.vertical === "auto" && $(window).width() > 800)) {
359          self.isSwiping = "x";
360        } else {
361          angle = Math.abs((Math.atan2(self.distanceY, self.distanceX) * 180) / Math.PI);
362
363          self.isSwiping = angle > 45 && angle < 135 ? "y" : "x";
364        }
365
366        if (self.isSwiping === "y" && $.fancybox.isMobile && self.isScrollable) {
367          self.isScrolling = true;
368
369          return;
370        }
371
372        instance.isDragging = self.isSwiping;
373
374        // Reset points to avoid jumping, because we dropped first swipes to calculate the angle
375        self.startPoints = self.newPoints;
376
377        $.each(instance.slides, function (index, slide) {
378          var slidePos, stagePos;
379
380          $.fancybox.stop(slide.$slide);
381
382          slidePos = $.fancybox.getTranslate(slide.$slide);
383          stagePos = $.fancybox.getTranslate(instance.$refs.stage);
384
385          slide.$slide
386            .css({
387              transform: "",
388              opacity: "",
389              "transition-duration": ""
390            })
391            .removeClass("fancybox-animated")
392            .removeClass(function (index, className) {
393              return (className.match(/(^|\s)fancybox-fx-\S+/g) || []).join(" ");
394            });
395
396          if (slide.pos === instance.current.pos) {
397            self.sliderStartPos.top = slidePos.top - stagePos.top;
398            self.sliderStartPos.left = slidePos.left - stagePos.left;
399          }
400
401          $.fancybox.setTranslate(slide.$slide, {
402            top: slidePos.top - stagePos.top,
403            left: slidePos.left - stagePos.left
404          });
405        });
406
407        // Stop slideshow
408        if (instance.SlideShow && instance.SlideShow.isActive) {
409          instance.SlideShow.stop();
410        }
411      }
412
413      return;
414    }
415
416    // Sticky edges
417    if (swiping == "x") {
418      if (
419        self.distanceX > 0 &&
420        (self.instance.group.length < 2 || (self.instance.current.index === 0 && !self.instance.current.opts.loop))
421      ) {
422        left = left + Math.pow(self.distanceX, 0.8);
423      } else if (
424        self.distanceX < 0 &&
425        (self.instance.group.length < 2 ||
426          (self.instance.current.index === self.instance.group.length - 1 && !self.instance.current.opts.loop))
427      ) {
428        left = left - Math.pow(-self.distanceX, 0.8);
429      } else {
430        left = left + self.distanceX;
431      }
432    }
433
434    self.sliderLastPos = {
435      top: swiping == "x" ? 0 : self.sliderStartPos.top + self.distanceY,
436      left: left
437    };
438
439    if (self.requestId) {
440      cancelAFrame(self.requestId);
441
442      self.requestId = null;
443    }
444
445    self.requestId = requestAFrame(function () {
446      if (self.sliderLastPos) {
447        $.each(self.instance.slides, function (index, slide) {
448          var pos = slide.pos - self.instance.currPos;
449
450          $.fancybox.setTranslate(slide.$slide, {
451            top: self.sliderLastPos.top,
452            left: self.sliderLastPos.left + pos * self.canvasWidth + pos * slide.opts.gutter
453          });
454        });
455
456        self.$container.addClass("fancybox-is-sliding");
457      }
458    });
459  };
460
461  Guestures.prototype.onPan = function () {
462    var self = this;
463
464    // Prevent accidental movement (sometimes, when tapping casually, finger can move a bit)
465    if (distance(self.newPoints[0], self.realPoints[0]) < ($.fancybox.isMobile ? 10 : 5)) {
466      self.startPoints = self.newPoints;
467      return;
468    }
469
470    self.canTap = false;
471
472    self.contentLastPos = self.limitMovement();
473
474    if (self.requestId) {
475      cancelAFrame(self.requestId);
476    }
477
478    self.requestId = requestAFrame(function () {
479      $.fancybox.setTranslate(self.$content, self.contentLastPos);
480    });
481  };
482
483  // Make panning sticky to the edges
484  Guestures.prototype.limitMovement = function () {
485    var self = this;
486
487    var canvasWidth = self.canvasWidth;
488    var canvasHeight = self.canvasHeight;
489
490    var distanceX = self.distanceX;
491    var distanceY = self.distanceY;
492
493    var contentStartPos = self.contentStartPos;
494
495    var currentOffsetX = contentStartPos.left;
496    var currentOffsetY = contentStartPos.top;
497
498    var currentWidth = contentStartPos.width;
499    var currentHeight = contentStartPos.height;
500
501    var minTranslateX, minTranslateY, maxTranslateX, maxTranslateY, newOffsetX, newOffsetY;
502
503    if (currentWidth > canvasWidth) {
504      newOffsetX = currentOffsetX + distanceX;
505    } else {
506      newOffsetX = currentOffsetX;
507    }
508
509    newOffsetY = currentOffsetY + distanceY;
510
511    // Slow down proportionally to traveled distance
512    minTranslateX = Math.max(0, canvasWidth * 0.5 - currentWidth * 0.5);
513    minTranslateY = Math.max(0, canvasHeight * 0.5 - currentHeight * 0.5);
514
515    maxTranslateX = Math.min(canvasWidth - currentWidth, canvasWidth * 0.5 - currentWidth * 0.5);
516    maxTranslateY = Math.min(canvasHeight - currentHeight, canvasHeight * 0.5 - currentHeight * 0.5);
517
518    //   ->
519    if (distanceX > 0 && newOffsetX > minTranslateX) {
520      newOffsetX = minTranslateX - 1 + Math.pow(-minTranslateX + currentOffsetX + distanceX, 0.8) || 0;
521    }
522
523    //    <-
524    if (distanceX < 0 && newOffsetX < maxTranslateX) {
525      newOffsetX = maxTranslateX + 1 - Math.pow(maxTranslateX - currentOffsetX - distanceX, 0.8) || 0;
526    }
527
528    //   \/
529    if (distanceY > 0 && newOffsetY > minTranslateY) {
530      newOffsetY = minTranslateY - 1 + Math.pow(-minTranslateY + currentOffsetY + distanceY, 0.8) || 0;
531    }
532
533    //   /\
534    if (distanceY < 0 && newOffsetY < maxTranslateY) {
535      newOffsetY = maxTranslateY + 1 - Math.pow(maxTranslateY - currentOffsetY - distanceY, 0.8) || 0;
536    }
537
538    return {
539      top: newOffsetY,
540      left: newOffsetX
541    };
542  };
543
544  Guestures.prototype.limitPosition = function (newOffsetX, newOffsetY, newWidth, newHeight) {
545    var self = this;
546
547    var canvasWidth = self.canvasWidth;
548    var canvasHeight = self.canvasHeight;
549
550    if (newWidth > canvasWidth) {
551      newOffsetX = newOffsetX > 0 ? 0 : newOffsetX;
552      newOffsetX = newOffsetX < canvasWidth - newWidth ? canvasWidth - newWidth : newOffsetX;
553    } else {
554      // Center horizontally
555      newOffsetX = Math.max(0, canvasWidth / 2 - newWidth / 2);
556    }
557
558    if (newHeight > canvasHeight) {
559      newOffsetY = newOffsetY > 0 ? 0 : newOffsetY;
560      newOffsetY = newOffsetY < canvasHeight - newHeight ? canvasHeight - newHeight : newOffsetY;
561    } else {
562      // Center vertically
563      newOffsetY = Math.max(0, canvasHeight / 2 - newHeight / 2);
564    }
565
566    return {
567      top: newOffsetY,
568      left: newOffsetX
569    };
570  };
571
572  Guestures.prototype.onZoom = function () {
573    var self = this;
574
575    // Calculate current distance between points to get pinch ratio and new width and height
576    var contentStartPos = self.contentStartPos;
577
578    var currentWidth = contentStartPos.width;
579    var currentHeight = contentStartPos.height;
580
581    var currentOffsetX = contentStartPos.left;
582    var currentOffsetY = contentStartPos.top;
583
584    var endDistanceBetweenFingers = distance(self.newPoints[0], self.newPoints[1]);
585
586    var pinchRatio = endDistanceBetweenFingers / self.startDistanceBetweenFingers;
587
588    var newWidth = Math.floor(currentWidth * pinchRatio);
589    var newHeight = Math.floor(currentHeight * pinchRatio);
590
591    // This is the translation due to pinch-zooming
592    var translateFromZoomingX = (currentWidth - newWidth) * self.percentageOfImageAtPinchPointX;
593    var translateFromZoomingY = (currentHeight - newHeight) * self.percentageOfImageAtPinchPointY;
594
595    // Point between the two touches
596    var centerPointEndX = (self.newPoints[0].x + self.newPoints[1].x) / 2 - $(window).scrollLeft();
597    var centerPointEndY = (self.newPoints[0].y + self.newPoints[1].y) / 2 - $(window).scrollTop();
598
599    // And this is the translation due to translation of the centerpoint
600    // between the two fingers
601    var translateFromTranslatingX = centerPointEndX - self.centerPointStartX;
602    var translateFromTranslatingY = centerPointEndY - self.centerPointStartY;
603
604    // The new offset is the old/current one plus the total translation
605    var newOffsetX = currentOffsetX + (translateFromZoomingX + translateFromTranslatingX);
606    var newOffsetY = currentOffsetY + (translateFromZoomingY + translateFromTranslatingY);
607
608    var newPos = {
609      top: newOffsetY,
610      left: newOffsetX,
611      scaleX: pinchRatio,
612      scaleY: pinchRatio
613    };
614
615    self.canTap = false;
616
617    self.newWidth = newWidth;
618    self.newHeight = newHeight;
619
620    self.contentLastPos = newPos;
621
622    if (self.requestId) {
623      cancelAFrame(self.requestId);
624    }
625
626    self.requestId = requestAFrame(function () {
627      $.fancybox.setTranslate(self.$content, self.contentLastPos);
628    });
629  };
630
631  Guestures.prototype.ontouchend = function (e) {
632    var self = this;
633
634    var swiping = self.isSwiping;
635    var panning = self.isPanning;
636    var zooming = self.isZooming;
637    var scrolling = self.isScrolling;
638
639    self.endPoints = getPointerXY(e);
640    self.dMs = Math.max(new Date().getTime() - self.startTime, 1);
641
642    self.$container.removeClass("fancybox-is-grabbing");
643
644    $(document).off(".fb.touch");
645
646    document.removeEventListener("scroll", self.onscroll, true);
647
648    if (self.requestId) {
649      cancelAFrame(self.requestId);
650
651      self.requestId = null;
652    }
653
654    self.isSwiping = false;
655    self.isPanning = false;
656    self.isZooming = false;
657    self.isScrolling = false;
658
659    self.instance.isDragging = false;
660
661    if (self.canTap) {
662      return self.onTap(e);
663    }
664
665    self.speed = 100;
666
667    // Speed in px/ms
668    self.velocityX = (self.distanceX / self.dMs) * 0.5;
669    self.velocityY = (self.distanceY / self.dMs) * 0.5;
670
671    if (panning) {
672      self.endPanning();
673    } else if (zooming) {
674      self.endZooming();
675    } else {
676      self.endSwiping(swiping, scrolling);
677    }
678
679    return;
680  };
681
682  Guestures.prototype.endSwiping = function (swiping, scrolling) {
683    var self = this,
684      ret = false,
685      len = self.instance.group.length,
686      distanceX = Math.abs(self.distanceX),
687      canAdvance = swiping == "x" && len > 1 && ((self.dMs > 130 && distanceX > 10) || distanceX > 50),
688      speedX = 300;
689
690    self.sliderLastPos = null;
691
692    // Close if swiped vertically / navigate if horizontally
693    if (swiping == "y" && !scrolling && Math.abs(self.distanceY) > 50) {
694      // Continue vertical movement
695      $.fancybox.animate(
696        self.instance.current.$slide, {
697          top: self.sliderStartPos.top + self.distanceY + self.velocityY * 150,
698          opacity: 0
699        },
700        200
701      );
702      ret = self.instance.close(true, 250);
703    } else if (canAdvance && self.distanceX > 0) {
704      ret = self.instance.previous(speedX);
705    } else if (canAdvance && self.distanceX < 0) {
706      ret = self.instance.next(speedX);
707    }
708
709    if (ret === false && (swiping == "x" || swiping == "y")) {
710      self.instance.centerSlide(200);
711    }
712
713    self.$container.removeClass("fancybox-is-sliding");
714  };
715
716  // Limit panning from edges
717  // ========================
718  Guestures.prototype.endPanning = function () {
719    var self = this,
720      newOffsetX,
721      newOffsetY,
722      newPos;
723
724    if (!self.contentLastPos) {
725      return;
726    }
727
728    if (self.opts.momentum === false || self.dMs > 350) {
729      newOffsetX = self.contentLastPos.left;
730      newOffsetY = self.contentLastPos.top;
731    } else {
732      // Continue movement
733      newOffsetX = self.contentLastPos.left + self.velocityX * 500;
734      newOffsetY = self.contentLastPos.top + self.velocityY * 500;
735    }
736
737    newPos = self.limitPosition(newOffsetX, newOffsetY, self.contentStartPos.width, self.contentStartPos.height);
738
739    newPos.width = self.contentStartPos.width;
740    newPos.height = self.contentStartPos.height;
741
742    $.fancybox.animate(self.$content, newPos, 366);
743  };
744
745  Guestures.prototype.endZooming = function () {
746    var self = this;
747
748    var current = self.instance.current;
749
750    var newOffsetX, newOffsetY, newPos, reset;
751
752    var newWidth = self.newWidth;
753    var newHeight = self.newHeight;
754
755    if (!self.contentLastPos) {
756      return;
757    }
758
759    newOffsetX = self.contentLastPos.left;
760    newOffsetY = self.contentLastPos.top;
761
762    reset = {
763      top: newOffsetY,
764      left: newOffsetX,
765      width: newWidth,
766      height: newHeight,
767      scaleX: 1,
768      scaleY: 1
769    };
770
771    // Reset scalex/scaleY values; this helps for perfomance and does not break animation
772    $.fancybox.setTranslate(self.$content, reset);
773
774    if (newWidth < self.canvasWidth && newHeight < self.canvasHeight) {
775      self.instance.scaleToFit(150);
776    } else if (newWidth > current.width || newHeight > current.height) {
777      self.instance.scaleToActual(self.centerPointStartX, self.centerPointStartY, 150);
778    } else {
779      newPos = self.limitPosition(newOffsetX, newOffsetY, newWidth, newHeight);
780
781      $.fancybox.animate(self.$content, newPos, 150);
782    }
783  };
784
785  Guestures.prototype.onTap = function (e) {
786    var self = this;
787    var $target = $(e.target);
788
789    var instance = self.instance;
790    var current = instance.current;
791
792    var endPoints = (e && getPointerXY(e)) || self.startPoints;
793
794    var tapX = endPoints[0] ? endPoints[0].x - $(window).scrollLeft() - self.stagePos.left : 0;
795    var tapY = endPoints[0] ? endPoints[0].y - $(window).scrollTop() - self.stagePos.top : 0;
796
797    var where;
798
799    var process = function (prefix) {
800      var action = current.opts[prefix];
801
802      if ($.isFunction(action)) {
803        action = action.apply(instance, [current, e]);
804      }
805
806      if (!action) {
807        return;
808      }
809
810      switch (action) {
811        case "close":
812          instance.close(self.startEvent);
813
814          break;
815
816        case "toggleControls":
817          instance.toggleControls();
818
819          break;
820
821        case "next":
822          instance.next();
823
824          break;
825
826        case "nextOrClose":
827          if (instance.group.length > 1) {
828            instance.next();
829          } else {
830            instance.close(self.startEvent);
831          }
832
833          break;
834
835        case "zoom":
836          if (current.type == "image" && (current.isLoaded || current.$ghost)) {
837            if (instance.canPan()) {
838              instance.scaleToFit();
839            } else if (instance.isScaledDown()) {
840              instance.scaleToActual(tapX, tapY);
841            } else if (instance.group.length < 2) {
842              instance.close(self.startEvent);
843            }
844          }
845
846          break;
847      }
848    };
849
850    // Ignore right click
851    if (e.originalEvent && e.originalEvent.button == 2) {
852      return;
853    }
854
855    // Skip if clicked on the scrollbar
856    if (!$target.is("img") && tapX > $target[0].clientWidth + $target.offset().left) {
857      return;
858    }
859
860    // Check where is clicked
861    if ($target.is(".fancybox-bg,.fancybox-inner,.fancybox-outer,.fancybox-container")) {
862      where = "Outside";
863    } else if ($target.is(".fancybox-slide")) {
864      where = "Slide";
865    } else if (
866      instance.current.$content &&
867      instance.current.$content
868      .find($target)
869      .addBack()
870      .filter($target).length
871    ) {
872      where = "Content";
873    } else {
874      return;
875    }
876
877    // Check if this is a double tap
878    if (self.tapped) {
879      // Stop previously created single tap
880      clearTimeout(self.tapped);
881      self.tapped = null;
882
883      // Skip if distance between taps is too big
884      if (Math.abs(tapX - self.tapX) > 50 || Math.abs(tapY - self.tapY) > 50) {
885        return this;
886      }
887
888      // OK, now we assume that this is a double-tap
889      process("dblclick" + where);
890    } else {
891      // Single tap will be processed if user has not clicked second time within 300ms
892      // or there is no need to wait for double-tap
893      self.tapX = tapX;
894      self.tapY = tapY;
895
896      if (current.opts["dblclick" + where] && current.opts["dblclick" + where] !== current.opts["click" + where]) {
897        self.tapped = setTimeout(function () {
898          self.tapped = null;
899
900          if (!instance.isAnimating) {
901            process("click" + where);
902          }
903        }, 500);
904      } else {
905        process("click" + where);
906      }
907    }
908
909    return this;
910  };
911
912  $(document)
913    .on("onActivate.fb", function (e, instance) {
914      if (instance && !instance.Guestures) {
915        instance.Guestures = new Guestures(instance);
916      }
917    })
918    .on("beforeClose.fb", function (e, instance) {
919      if (instance && instance.Guestures) {
920        instance.Guestures.destroy();
921      }
922    });
923})(window, document, jQuery);

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.