File: /home/confeduphaar/www/wp-content/themes/egovt/assets/libs/fancybox-master/src/js/guestures.js
// ==========================================================================
//
// Guestures
// Adds touch guestures, handles click and tap events
//
// ==========================================================================
(function (window, document, $) {
"use strict";
var requestAFrame = (function () {
return (
window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
// if all else fails, use setTimeout
function (callback) {
return window.setTimeout(callback, 1000 / 60);
}
);
})();
var cancelAFrame = (function () {
return (
window.cancelAnimationFrame ||
window.webkitCancelAnimationFrame ||
window.mozCancelAnimationFrame ||
window.oCancelAnimationFrame ||
function (id) {
window.clearTimeout(id);
}
);
})();
var getPointerXY = function (e) {
var result = [];
e = e.originalEvent || e || window.e;
e = e.touches && e.touches.length ? e.touches : e.changedTouches && e.changedTouches.length ? e.changedTouches : [e];
for (var key in e) {
if (e[key].pageX) {
result.push({
x: e[key].pageX,
y: e[key].pageY
});
} else if (e[key].clientX) {
result.push({
x: e[key].clientX,
y: e[key].clientY
});
}
}
return result;
};
var distance = function (point2, point1, what) {
if (!point1 || !point2) {
return 0;
}
if (what === "x") {
return point2.x - point1.x;
} else if (what === "y") {
return point2.y - point1.y;
}
return Math.sqrt(Math.pow(point2.x - point1.x, 2) + Math.pow(point2.y - point1.y, 2));
};
var isClickable = function ($el) {
if (
$el.is('a,area,button,[role="button"],input,label,select,summary,textarea,video,audio,iframe') ||
$.isFunction($el.get(0).onclick) ||
$el.data("selectable")
) {
return true;
}
// Check for attributes like data-fancybox-next or data-fancybox-close
for (var i = 0, atts = $el[0].attributes, n = atts.length; i < n; i++) {
if (atts[i].nodeName.substr(0, 14) === "data-fancybox-") {
return true;
}
}
return false;
};
var hasScrollbars = function (el) {
var overflowY = window.getComputedStyle(el)["overflow-y"],
overflowX = window.getComputedStyle(el)["overflow-x"],
vertical = (overflowY === "scroll" || overflowY === "auto") && el.scrollHeight > el.clientHeight,
horizontal = (overflowX === "scroll" || overflowX === "auto") && el.scrollWidth > el.clientWidth;
return vertical || horizontal;
};
var isScrollable = function ($el) {
var rez = false;
while (true) {
rez = hasScrollbars($el.get(0));
if (rez) {
break;
}
$el = $el.parent();
if (!$el.length || $el.hasClass("fancybox-stage") || $el.is("body")) {
break;
}
}
return rez;
};
var Guestures = function (instance) {
var self = this;
self.instance = instance;
self.$bg = instance.$refs.bg;
self.$stage = instance.$refs.stage;
self.$container = instance.$refs.container;
self.destroy();
self.$container.on("touchstart.fb.touch mousedown.fb.touch", $.proxy(self, "ontouchstart"));
};
Guestures.prototype.destroy = function () {
var self = this;
self.$container.off(".fb.touch");
$(document).off(".fb.touch");
if (self.requestId) {
cancelAFrame(self.requestId);
self.requestId = null;
}
if (self.tapped) {
clearTimeout(self.tapped);
self.tapped = null;
}
};
Guestures.prototype.ontouchstart = function (e) {
var self = this,
$target = $(e.target),
instance = self.instance,
current = instance.current,
$slide = current.$slide,
$content = current.$content,
isTouchDevice = e.type == "touchstart";
// Do not respond to both (touch and mouse) events
if (isTouchDevice) {
self.$container.off("mousedown.fb.touch");
}
// Ignore right click
if (e.originalEvent && e.originalEvent.button == 2) {
return;
}
// Ignore taping on links, buttons, input elements
if (!$slide.length || !$target.length || isClickable($target) || isClickable($target.parent())) {
return;
}
// Ignore clicks on the scrollbar
if (!$target.is("img") && e.originalEvent.clientX > $target[0].clientWidth + $target.offset().left) {
return;
}
// Ignore clicks while zooming or closing
if (!current || instance.isAnimating || current.$slide.hasClass("fancybox-animated")) {
e.stopPropagation();
e.preventDefault();
return;
}
self.realPoints = self.startPoints = getPointerXY(e);
if (!self.startPoints.length) {
return;
}
// Allow other scripts to catch touch event if "touch" is set to false
if (current.touch) {
e.stopPropagation();
}
self.startEvent = e;
self.canTap = true;
self.$target = $target;
self.$content = $content;
self.opts = current.opts.touch;
self.isPanning = false;
self.isSwiping = false;
self.isZooming = false;
self.isScrolling = false;
self.canPan = instance.canPan();
self.startTime = new Date().getTime();
self.distanceX = self.distanceY = self.distance = 0;
self.canvasWidth = Math.round($slide[0].clientWidth);
self.canvasHeight = Math.round($slide[0].clientHeight);
self.contentLastPos = null;
self.contentStartPos = $.fancybox.getTranslate(self.$content) || {
top: 0,
left: 0
};
self.sliderStartPos = $.fancybox.getTranslate($slide);
// Since position will be absolute, but we need to make it relative to the stage
self.stagePos = $.fancybox.getTranslate(instance.$refs.stage);
self.sliderStartPos.top -= self.stagePos.top;
self.sliderStartPos.left -= self.stagePos.left;
self.contentStartPos.top -= self.stagePos.top;
self.contentStartPos.left -= self.stagePos.left;
$(document)
.off(".fb.touch")
.on(isTouchDevice ? "touchend.fb.touch touchcancel.fb.touch" : "mouseup.fb.touch mouseleave.fb.touch", $.proxy(self, "ontouchend"))
.on(isTouchDevice ? "touchmove.fb.touch" : "mousemove.fb.touch", $.proxy(self, "ontouchmove"));
if ($.fancybox.isMobile) {
document.addEventListener("scroll", self.onscroll, true);
}
// Skip if clicked outside the sliding area
if (!(self.opts || self.canPan) || !($target.is(self.$stage) || self.$stage.find($target).length)) {
if ($target.is(".fancybox-image")) {
e.preventDefault();
}
if (!($.fancybox.isMobile && $target.parents(".fancybox-caption").length)) {
return;
}
}
self.isScrollable = isScrollable($target) || isScrollable($target.parent());
// Check if element is scrollable and try to prevent default behavior (scrolling)
if (!($.fancybox.isMobile && self.isScrollable)) {
e.preventDefault();
}
// One finger or mouse click - swipe or pan an image
if (self.startPoints.length === 1 || current.hasError) {
if (self.canPan) {
$.fancybox.stop(self.$content);
self.isPanning = true;
} else {
self.isSwiping = true;
}
self.$container.addClass("fancybox-is-grabbing");
}
// Two fingers - zoom image
if (self.startPoints.length === 2 && current.type === "image" && (current.isLoaded || current.$ghost)) {
self.canTap = false;
self.isSwiping = false;
self.isPanning = false;
self.isZooming = true;
$.fancybox.stop(self.$content);
self.centerPointStartX = (self.startPoints[0].x + self.startPoints[1].x) * 0.5 - $(window).scrollLeft();
self.centerPointStartY = (self.startPoints[0].y + self.startPoints[1].y) * 0.5 - $(window).scrollTop();
self.percentageOfImageAtPinchPointX = (self.centerPointStartX - self.contentStartPos.left) / self.contentStartPos.width;
self.percentageOfImageAtPinchPointY = (self.centerPointStartY - self.contentStartPos.top) / self.contentStartPos.height;
self.startDistanceBetweenFingers = distance(self.startPoints[0], self.startPoints[1]);
}
};
Guestures.prototype.onscroll = function (e) {
var self = this;
self.isScrolling = true;
document.removeEventListener("scroll", self.onscroll, true);
};
Guestures.prototype.ontouchmove = function (e) {
var self = this;
// Make sure user has not released over iframe or disabled element
if (e.originalEvent.buttons !== undefined && e.originalEvent.buttons === 0) {
self.ontouchend(e);
return;
}
if (self.isScrolling) {
self.canTap = false;
return;
}
self.newPoints = getPointerXY(e);
if (!(self.opts || self.canPan) || !self.newPoints.length || !self.newPoints.length) {
return;
}
if (!(self.isSwiping && self.isSwiping === true)) {
e.preventDefault();
}
self.distanceX = distance(self.newPoints[0], self.startPoints[0], "x");
self.distanceY = distance(self.newPoints[0], self.startPoints[0], "y");
self.distance = distance(self.newPoints[0], self.startPoints[0]);
// Skip false ontouchmove events (Chrome)
if (self.distance > 0) {
if (self.isSwiping) {
self.onSwipe(e);
} else if (self.isPanning) {
self.onPan();
} else if (self.isZooming) {
self.onZoom();
}
}
};
Guestures.prototype.onSwipe = function (e) {
var self = this,
instance = self.instance,
swiping = self.isSwiping,
left = self.sliderStartPos.left || 0,
angle;
// If direction is not yet determined
if (swiping === true) {
// We need at least 10px distance to correctly calculate an angle
if (Math.abs(self.distance) > 10) {
self.canTap = false;
if (instance.group.length < 2 && self.opts.vertical) {
self.isSwiping = "y";
} else if (instance.isDragging || self.opts.vertical === false || (self.opts.vertical === "auto" && $(window).width() > 800)) {
self.isSwiping = "x";
} else {
angle = Math.abs((Math.atan2(self.distanceY, self.distanceX) * 180) / Math.PI);
self.isSwiping = angle > 45 && angle < 135 ? "y" : "x";
}
if (self.isSwiping === "y" && $.fancybox.isMobile && self.isScrollable) {
self.isScrolling = true;
return;
}
instance.isDragging = self.isSwiping;
// Reset points to avoid jumping, because we dropped first swipes to calculate the angle
self.startPoints = self.newPoints;
$.each(instance.slides, function (index, slide) {
var slidePos, stagePos;
$.fancybox.stop(slide.$slide);
slidePos = $.fancybox.getTranslate(slide.$slide);
stagePos = $.fancybox.getTranslate(instance.$refs.stage);
slide.$slide
.css({
transform: "",
opacity: "",
"transition-duration": ""
})
.removeClass("fancybox-animated")
.removeClass(function (index, className) {
return (className.match(/(^|\s)fancybox-fx-\S+/g) || []).join(" ");
});
if (slide.pos === instance.current.pos) {
self.sliderStartPos.top = slidePos.top - stagePos.top;
self.sliderStartPos.left = slidePos.left - stagePos.left;
}
$.fancybox.setTranslate(slide.$slide, {
top: slidePos.top - stagePos.top,
left: slidePos.left - stagePos.left
});
});
// Stop slideshow
if (instance.SlideShow && instance.SlideShow.isActive) {
instance.SlideShow.stop();
}
}
return;
}
// Sticky edges
if (swiping == "x") {
if (
self.distanceX > 0 &&
(self.instance.group.length < 2 || (self.instance.current.index === 0 && !self.instance.current.opts.loop))
) {
left = left + Math.pow(self.distanceX, 0.8);
} else if (
self.distanceX < 0 &&
(self.instance.group.length < 2 ||
(self.instance.current.index === self.instance.group.length - 1 && !self.instance.current.opts.loop))
) {
left = left - Math.pow(-self.distanceX, 0.8);
} else {
left = left + self.distanceX;
}
}
self.sliderLastPos = {
top: swiping == "x" ? 0 : self.sliderStartPos.top + self.distanceY,
left: left
};
if (self.requestId) {
cancelAFrame(self.requestId);
self.requestId = null;
}
self.requestId = requestAFrame(function () {
if (self.sliderLastPos) {
$.each(self.instance.slides, function (index, slide) {
var pos = slide.pos - self.instance.currPos;
$.fancybox.setTranslate(slide.$slide, {
top: self.sliderLastPos.top,
left: self.sliderLastPos.left + pos * self.canvasWidth + pos * slide.opts.gutter
});
});
self.$container.addClass("fancybox-is-sliding");
}
});
};
Guestures.prototype.onPan = function () {
var self = this;
// Prevent accidental movement (sometimes, when tapping casually, finger can move a bit)
if (distance(self.newPoints[0], self.realPoints[0]) < ($.fancybox.isMobile ? 10 : 5)) {
self.startPoints = self.newPoints;
return;
}
self.canTap = false;
self.contentLastPos = self.limitMovement();
if (self.requestId) {
cancelAFrame(self.requestId);
}
self.requestId = requestAFrame(function () {
$.fancybox.setTranslate(self.$content, self.contentLastPos);
});
};
// Make panning sticky to the edges
Guestures.prototype.limitMovement = function () {
var self = this;
var canvasWidth = self.canvasWidth;
var canvasHeight = self.canvasHeight;
var distanceX = self.distanceX;
var distanceY = self.distanceY;
var contentStartPos = self.contentStartPos;
var currentOffsetX = contentStartPos.left;
var currentOffsetY = contentStartPos.top;
var currentWidth = contentStartPos.width;
var currentHeight = contentStartPos.height;
var minTranslateX, minTranslateY, maxTranslateX, maxTranslateY, newOffsetX, newOffsetY;
if (currentWidth > canvasWidth) {
newOffsetX = currentOffsetX + distanceX;
} else {
newOffsetX = currentOffsetX;
}
newOffsetY = currentOffsetY + distanceY;
// Slow down proportionally to traveled distance
minTranslateX = Math.max(0, canvasWidth * 0.5 - currentWidth * 0.5);
minTranslateY = Math.max(0, canvasHeight * 0.5 - currentHeight * 0.5);
maxTranslateX = Math.min(canvasWidth - currentWidth, canvasWidth * 0.5 - currentWidth * 0.5);
maxTranslateY = Math.min(canvasHeight - currentHeight, canvasHeight * 0.5 - currentHeight * 0.5);
// ->
if (distanceX > 0 && newOffsetX > minTranslateX) {
newOffsetX = minTranslateX - 1 + Math.pow(-minTranslateX + currentOffsetX + distanceX, 0.8) || 0;
}
// <-
if (distanceX < 0 && newOffsetX < maxTranslateX) {
newOffsetX = maxTranslateX + 1 - Math.pow(maxTranslateX - currentOffsetX - distanceX, 0.8) || 0;
}
// \/
if (distanceY > 0 && newOffsetY > minTranslateY) {
newOffsetY = minTranslateY - 1 + Math.pow(-minTranslateY + currentOffsetY + distanceY, 0.8) || 0;
}
// /\
if (distanceY < 0 && newOffsetY < maxTranslateY) {
newOffsetY = maxTranslateY + 1 - Math.pow(maxTranslateY - currentOffsetY - distanceY, 0.8) || 0;
}
return {
top: newOffsetY,
left: newOffsetX
};
};
Guestures.prototype.limitPosition = function (newOffsetX, newOffsetY, newWidth, newHeight) {
var self = this;
var canvasWidth = self.canvasWidth;
var canvasHeight = self.canvasHeight;
if (newWidth > canvasWidth) {
newOffsetX = newOffsetX > 0 ? 0 : newOffsetX;
newOffsetX = newOffsetX < canvasWidth - newWidth ? canvasWidth - newWidth : newOffsetX;
} else {
// Center horizontally
newOffsetX = Math.max(0, canvasWidth / 2 - newWidth / 2);
}
if (newHeight > canvasHeight) {
newOffsetY = newOffsetY > 0 ? 0 : newOffsetY;
newOffsetY = newOffsetY < canvasHeight - newHeight ? canvasHeight - newHeight : newOffsetY;
} else {
// Center vertically
newOffsetY = Math.max(0, canvasHeight / 2 - newHeight / 2);
}
return {
top: newOffsetY,
left: newOffsetX
};
};
Guestures.prototype.onZoom = function () {
var self = this;
// Calculate current distance between points to get pinch ratio and new width and height
var contentStartPos = self.contentStartPos;
var currentWidth = contentStartPos.width;
var currentHeight = contentStartPos.height;
var currentOffsetX = contentStartPos.left;
var currentOffsetY = contentStartPos.top;
var endDistanceBetweenFingers = distance(self.newPoints[0], self.newPoints[1]);
var pinchRatio = endDistanceBetweenFingers / self.startDistanceBetweenFingers;
var newWidth = Math.floor(currentWidth * pinchRatio);
var newHeight = Math.floor(currentHeight * pinchRatio);
// This is the translation due to pinch-zooming
var translateFromZoomingX = (currentWidth - newWidth) * self.percentageOfImageAtPinchPointX;
var translateFromZoomingY = (currentHeight - newHeight) * self.percentageOfImageAtPinchPointY;
// Point between the two touches
var centerPointEndX = (self.newPoints[0].x + self.newPoints[1].x) / 2 - $(window).scrollLeft();
var centerPointEndY = (self.newPoints[0].y + self.newPoints[1].y) / 2 - $(window).scrollTop();
// And this is the translation due to translation of the centerpoint
// between the two fingers
var translateFromTranslatingX = centerPointEndX - self.centerPointStartX;
var translateFromTranslatingY = centerPointEndY - self.centerPointStartY;
// The new offset is the old/current one plus the total translation
var newOffsetX = currentOffsetX + (translateFromZoomingX + translateFromTranslatingX);
var newOffsetY = currentOffsetY + (translateFromZoomingY + translateFromTranslatingY);
var newPos = {
top: newOffsetY,
left: newOffsetX,
scaleX: pinchRatio,
scaleY: pinchRatio
};
self.canTap = false;
self.newWidth = newWidth;
self.newHeight = newHeight;
self.contentLastPos = newPos;
if (self.requestId) {
cancelAFrame(self.requestId);
}
self.requestId = requestAFrame(function () {
$.fancybox.setTranslate(self.$content, self.contentLastPos);
});
};
Guestures.prototype.ontouchend = function (e) {
var self = this;
var swiping = self.isSwiping;
var panning = self.isPanning;
var zooming = self.isZooming;
var scrolling = self.isScrolling;
self.endPoints = getPointerXY(e);
self.dMs = Math.max(new Date().getTime() - self.startTime, 1);
self.$container.removeClass("fancybox-is-grabbing");
$(document).off(".fb.touch");
document.removeEventListener("scroll", self.onscroll, true);
if (self.requestId) {
cancelAFrame(self.requestId);
self.requestId = null;
}
self.isSwiping = false;
self.isPanning = false;
self.isZooming = false;
self.isScrolling = false;
self.instance.isDragging = false;
if (self.canTap) {
return self.onTap(e);
}
self.speed = 100;
// Speed in px/ms
self.velocityX = (self.distanceX / self.dMs) * 0.5;
self.velocityY = (self.distanceY / self.dMs) * 0.5;
if (panning) {
self.endPanning();
} else if (zooming) {
self.endZooming();
} else {
self.endSwiping(swiping, scrolling);
}
return;
};
Guestures.prototype.endSwiping = function (swiping, scrolling) {
var self = this,
ret = false,
len = self.instance.group.length,
distanceX = Math.abs(self.distanceX),
canAdvance = swiping == "x" && len > 1 && ((self.dMs > 130 && distanceX > 10) || distanceX > 50),
speedX = 300;
self.sliderLastPos = null;
// Close if swiped vertically / navigate if horizontally
if (swiping == "y" && !scrolling && Math.abs(self.distanceY) > 50) {
// Continue vertical movement
$.fancybox.animate(
self.instance.current.$slide, {
top: self.sliderStartPos.top + self.distanceY + self.velocityY * 150,
opacity: 0
},
200
);
ret = self.instance.close(true, 250);
} else if (canAdvance && self.distanceX > 0) {
ret = self.instance.previous(speedX);
} else if (canAdvance && self.distanceX < 0) {
ret = self.instance.next(speedX);
}
if (ret === false && (swiping == "x" || swiping == "y")) {
self.instance.centerSlide(200);
}
self.$container.removeClass("fancybox-is-sliding");
};
// Limit panning from edges
// ========================
Guestures.prototype.endPanning = function () {
var self = this,
newOffsetX,
newOffsetY,
newPos;
if (!self.contentLastPos) {
return;
}
if (self.opts.momentum === false || self.dMs > 350) {
newOffsetX = self.contentLastPos.left;
newOffsetY = self.contentLastPos.top;
} else {
// Continue movement
newOffsetX = self.contentLastPos.left + self.velocityX * 500;
newOffsetY = self.contentLastPos.top + self.velocityY * 500;
}
newPos = self.limitPosition(newOffsetX, newOffsetY, self.contentStartPos.width, self.contentStartPos.height);
newPos.width = self.contentStartPos.width;
newPos.height = self.contentStartPos.height;
$.fancybox.animate(self.$content, newPos, 366);
};
Guestures.prototype.endZooming = function () {
var self = this;
var current = self.instance.current;
var newOffsetX, newOffsetY, newPos, reset;
var newWidth = self.newWidth;
var newHeight = self.newHeight;
if (!self.contentLastPos) {
return;
}
newOffsetX = self.contentLastPos.left;
newOffsetY = self.contentLastPos.top;
reset = {
top: newOffsetY,
left: newOffsetX,
width: newWidth,
height: newHeight,
scaleX: 1,
scaleY: 1
};
// Reset scalex/scaleY values; this helps for perfomance and does not break animation
$.fancybox.setTranslate(self.$content, reset);
if (newWidth < self.canvasWidth && newHeight < self.canvasHeight) {
self.instance.scaleToFit(150);
} else if (newWidth > current.width || newHeight > current.height) {
self.instance.scaleToActual(self.centerPointStartX, self.centerPointStartY, 150);
} else {
newPos = self.limitPosition(newOffsetX, newOffsetY, newWidth, newHeight);
$.fancybox.animate(self.$content, newPos, 150);
}
};
Guestures.prototype.onTap = function (e) {
var self = this;
var $target = $(e.target);
var instance = self.instance;
var current = instance.current;
var endPoints = (e && getPointerXY(e)) || self.startPoints;
var tapX = endPoints[0] ? endPoints[0].x - $(window).scrollLeft() - self.stagePos.left : 0;
var tapY = endPoints[0] ? endPoints[0].y - $(window).scrollTop() - self.stagePos.top : 0;
var where;
var process = function (prefix) {
var action = current.opts[prefix];
if ($.isFunction(action)) {
action = action.apply(instance, [current, e]);
}
if (!action) {
return;
}
switch (action) {
case "close":
instance.close(self.startEvent);
break;
case "toggleControls":
instance.toggleControls();
break;
case "next":
instance.next();
break;
case "nextOrClose":
if (instance.group.length > 1) {
instance.next();
} else {
instance.close(self.startEvent);
}
break;
case "zoom":
if (current.type == "image" && (current.isLoaded || current.$ghost)) {
if (instance.canPan()) {
instance.scaleToFit();
} else if (instance.isScaledDown()) {
instance.scaleToActual(tapX, tapY);
} else if (instance.group.length < 2) {
instance.close(self.startEvent);
}
}
break;
}
};
// Ignore right click
if (e.originalEvent && e.originalEvent.button == 2) {
return;
}
// Skip if clicked on the scrollbar
if (!$target.is("img") && tapX > $target[0].clientWidth + $target.offset().left) {
return;
}
// Check where is clicked
if ($target.is(".fancybox-bg,.fancybox-inner,.fancybox-outer,.fancybox-container")) {
where = "Outside";
} else if ($target.is(".fancybox-slide")) {
where = "Slide";
} else if (
instance.current.$content &&
instance.current.$content
.find($target)
.addBack()
.filter($target).length
) {
where = "Content";
} else {
return;
}
// Check if this is a double tap
if (self.tapped) {
// Stop previously created single tap
clearTimeout(self.tapped);
self.tapped = null;
// Skip if distance between taps is too big
if (Math.abs(tapX - self.tapX) > 50 || Math.abs(tapY - self.tapY) > 50) {
return this;
}
// OK, now we assume that this is a double-tap
process("dblclick" + where);
} else {
// Single tap will be processed if user has not clicked second time within 300ms
// or there is no need to wait for double-tap
self.tapX = tapX;
self.tapY = tapY;
if (current.opts["dblclick" + where] && current.opts["dblclick" + where] !== current.opts["click" + where]) {
self.tapped = setTimeout(function () {
self.tapped = null;
if (!instance.isAnimating) {
process("click" + where);
}
}, 500);
} else {
process("click" + where);
}
}
return this;
};
$(document)
.on("onActivate.fb", function (e, instance) {
if (instance && !instance.Guestures) {
instance.Guestures = new Guestures(instance);
}
})
.on("beforeClose.fb", function (e, instance) {
if (instance && instance.Guestures) {
instance.Guestures.destroy();
}
});
})(window, document, jQuery);