/home/bdqbpbxa/demo-subdomains/sendon.goodface.com.ua/layout/js/custom-solutions.js
// Prevent default function
function preventDefault(e) {
e.preventDefault();
}
// Scroll lock
function lockScroll() {
const html = document.documentElement;
const body = document.body;
const scrollTop = window.scrollY;
html.classList.add('-scroll-lock');
body.classList.add('-scroll-lock');
document.body.scrollTo(0, scrollTop);
html.setAttribute('data-scroll', scrollTop);
$('.--modal-scrollable-element').on('touchmove pointermove', preventDefault);
}
function unlockScroll() {
const html = document.documentElement;
const body = document.body;
const scrollPositionBeforeLock = html.getAttribute('data-scroll');
html.classList.remove('-scroll-lock');
body.classList.remove('-scroll-lock');
window.scrollTo(0, scrollPositionBeforeLock);
document.body.scrollTo(0, 0);
$('.--modal-scrollable-element').off('touchmove pointermove', preventDefault);
}
// Check device type
const isApple = navigator.userAgent.toLowerCase().indexOf('mac') !== -1;
const isAndroid = navigator.userAgent.toLowerCase().indexOf('android') !== -1;
if (isApple) {
document.body.classList.add('-apple');
}
if (isAndroid) {
document.body.classList.add('-android');
}
// Check device size
window.isPc = window.innerWidth > 1024;
window.isTablet = window.innerWidth > 759 && window.innerWidth <= 1024;
window.isMobile = window.innerWidth < 760;
function checkDeviceSize() {
window.isPc = window.innerWidth > 1024;
window.isTablet = window.innerWidth > 759 && window.innerWidth <= 1024;
window.isMobile = window.innerWidth < 760;
}
window.addEventListener('DOMContentLoaded', checkDeviceSize);
window.addEventListener('resize', checkDeviceSize);
// Set CSS variable with window.innerHeight
function setCssWindowInnerHeight() {
document.documentElement.style.setProperty(
"--window-inner-height",
`${window.innerHeight}px`
);
}
window.addEventListener("DOMContentLoaded", setCssWindowInnerHeight);
window.addEventListener("resize", setCssWindowInnerHeight);
// Set CSS variable with scrollbar width
function setScrollbarWidthInCSS() {
$('body').append(`
<div id="scrollbar-width-test" style="position: absolute;top: -999px;left: -999px;width: 50px;height: 50px;overflow: scroll;">
<div style="height: 100px;"></div>
</div>
`);
const scrollbarWidthTestEl = $('#scrollbar-width-test')[0];
const scrollbarWidth = scrollbarWidthTestEl.offsetWidth - scrollbarWidthTestEl.clientWidth;
document.documentElement.style.setProperty(
"--scrollbar-width",
`${scrollbarWidth}px`
);
window.scrollbarWidth = scrollbarWidth;
scrollbarWidthTestEl.remove();
}
window.addEventListener("DOMContentLoaded", setScrollbarWidthInCSS);
window.addEventListener("resize", setScrollbarWidthInCSS);
// anchors
function linkScroll(block, offset) {
const top = block.offset().top;
const scrollTop = $(window).scrollTop();
const windowHeight = $(window).outerHeight();
const documentBot = Math.max(
document.body.scrollHeight,
document.documentElement.scrollHeight,
document.body.offsetHeight,
document.documentElement.offsetHeight,
document.body.clientHeight,
document.documentElement.clientHeight
);
const isScrollToEnd = top + windowHeight > documentBot;
var scrollTo = isScrollToEnd ? documentBot - windowHeight : top;
if (offset) {
if (offset == 'center') {
scrollTo = top - (windowHeight / 2) + (block.innerHeight() / 2);
}
}
const distance = Math.abs(scrollTo - scrollTop);
const calcSpeed = distance * 0.02;
const speed = calcSpeed < 1000 ? 1000 : calcSpeed;
$("body,html").animate({
scrollTop: scrollTo,
},
speed
);
}
// Anchor link - params
const scrollLinkMinSpeed = 600;
const scrollLinkSpeedValue = 2;
const scrollLinkDefaultOffset = 40;
const scrollLinkCustomOffset = false;
const scrollLinkDefaultOffsetToTop = false;
const scrollLinkCustomOffsetToTop = false;
const scrollLinkDefaultOffsetToBottom = false;
const scrollLinkCustomOffsetToBottom = false;
// Anchor link - logic
$(document).on("click", "a", function (e) {
let el = $(this);
let href = el.attr("href");
let to = getElementByHref(href);
if (to) {
e.preventDefault()
if (!isPc) {
if (el.hasClass('-hover-swipe') || el.hasClass('solution-card')) {
setTimeout(function () {
clickOnAnchor(el, e);
}, 400);
} else {
clickOnAnchor(el, e);
}
} else {
clickOnAnchor(el, e);
}
}
});
function clickOnAnchor(el, e) {
let href = el.attr("href");
let to = getElementByHref(href);
const position = getScrollLinkFinalPosition(to);
if (position === window.scrollY) return;
// const speed = getScrollSpeedByPosition(position);
let speed = 0;
if (el.hasClass('cta-button')) {
speed = getScrollSpeedByPosition(position);;
}
$("html, body").animate({
scrollTop: position
}, speed);
}
// Anchor link - helpers
function getElementByHref(href) {
let hash = false;
if (href.indexOf("#") === 0) {
hash = href;
} else {
const url = new URL(href);
if (
url.host === window.location.host &&
url.pathname === window.location.pathname
) {
hash = url.hash ? url.hash : false;
}
}
if (hash === "#") {
hash = false;
} else {
hash = $(hash);
}
return hash.length ? hash : false;
}
function getScrollLinkDefaultValue(value, hasBg) {
if (value === false) return false;
let returnValue = false;
if (typeof value === "object") {
let objectKey;
if (hasBg && typeof value["hasBg"] !== "undefined") {
objectKey = value["hasBg"];
} else {
objectKey = value["default"];
}
if (typeof objectKey === "string" || typeof objectKey === "number") {
returnValue = objectKey;
} else if (typeof objectKey === "object") {
Object.keys(objectKey).forEach((key) => {
if (window.innerWidth > key) {
returnValue = objectKey[key];
return false;
}
});
}
} else {
returnValue = value;
}
return returnValue;
}
function getScrollLinkPositionByParams(to, offsetValue, customOffsetValue) {
const pageScrollHeight = Math.max(
document.body.scrollHeight,
document.documentElement.scrollHeight,
document.body.offsetHeight,
document.documentElement.offsetHeight,
document.body.clientHeight,
document.documentElement.clientHeight
);
const maxScrollHeight = pageScrollHeight - window.innerHeight;
const header = $(".header");
const marginTop = parseInt(to.css("margin-top"));
let offset = 0;
let position = to.offset().top;
if (offsetValue === "margin") {
offset += marginTop;
} else if (offsetValue === "half-margin") {
offset += marginTop / 2;
} else if (offsetValue === "header-height") {
offset += header.length ? header.outerHeight() : 0;
}
if (customOffsetValue) {
offset += customOffsetValue;
}
position -= offset;
if (position < 0) {
position = 0;
} else if (position > maxScrollHeight) {
position = maxScrollHeight;
}
return position;
}
function getScrollLinkFinalPosition(to) {
const hasBg = $(to).hasClass("--has-bg");
const offsetValue = getScrollLinkDefaultValue(scrollLinkDefaultOffset, hasBg);
const customOffsetValue = getScrollLinkDefaultValue(
scrollLinkCustomOffset,
hasBg
);
const offsetValueToTop = getScrollLinkDefaultValue(
scrollLinkDefaultOffsetToTop,
hasBg
);
const customOffsetValueToTop = getScrollLinkDefaultValue(
scrollLinkCustomOffsetToTop,
hasBg
);
const offsetValueToBottom = getScrollLinkDefaultValue(
scrollLinkDefaultOffsetToBottom,
hasBg
);
const customOffsetValueToBottom = getScrollLinkDefaultValue(
scrollLinkCustomOffsetToBottom,
hasBg
);
let position = getScrollLinkPositionByParams(
to,
offsetValue,
customOffsetValue
);
if (
position > window.scrollY &&
(offsetValueToBottom || customOffsetValueToBottom)
) {
if (offsetValueToBottom === false) {
position = getScrollLinkPositionByParams(
to,
offsetValue,
customOffsetValueToBottom
);
} else if (customOffsetValueToBottom === false) {
position = getScrollLinkPositionByParams(
to,
offsetValueToBottom,
customOffsetValue
);
} else {
position = getScrollLinkPositionByParams(
to,
offsetValueToBottom,
customOffsetValueToBottom
);
}
}
if (
position < window.scrollY &&
(offsetValueToTop || customOffsetValueToTop)
) {
if (offsetValueToTop === false) {
position = getScrollLinkPositionByParams(
to,
offsetValue,
customOffsetValueToTop
);
} else if (customOffsetValueToTop === false) {
position = getScrollLinkPositionByParams(
to,
offsetValueToTop,
customOffsetValue
);
} else {
position = getScrollLinkPositionByParams(
to,
offsetValueToTop,
customOffsetValueToTop
);
}
}
return position;
}
function getScrollSpeedByPosition(position) {
let speed = position * (0.001 * scrollLinkSpeedValue) * 100;
if (speed < scrollLinkMinSpeed) {
speed = scrollLinkMinSpeed;
}
return speed;
}
// Check in viewport
function checkElementsInViewport() {
$('[data-check-in-viewport]').each(function () {
const viewportTop = window.scrollY;
const viewportBottom = viewportTop + window.innerHeight;
const offsetTop = $(this).offset().top;
const offsetBottom = offsetTop + $(this).outerHeight();
const isInViewport = offsetTop > viewportTop && offsetTop < viewportBottom || offsetBottom > viewportTop &&
offsetBottom < viewportBottom;
const hasInViewportClass = $(this).hasClass('-in-viewport');
const hasNotInViewportClass = $(this).hasClass('-not-in-viewport');
if (isInViewport && !hasInViewportClass) {
$(this).removeClass('-not-in-viewport').addClass('-in-viewport');
}
if (!isInViewport && !hasNotInViewportClass) {
$(this).removeClass('-in-viewport').addClass('-not-in-viewport');
}
});
}
$(window).on('load resize scroll', checkElementsInViewport);
// Lazyload - params
// if you set DEFAULT_LAZYLOAD_OFFSET to 0 or false
// then all elements on the page will be loaded the first time the scroll event fires
const DEFAULT_LAZYLOAD_OFFSET = 700;
// Lazyload - loaders
function imgLazyload(customSelector, customLazyloadOffset) {
const isSelectorValid = typeof customSelector === 'string';
const selector = isSelectorValid ? `${customSelector} img.-lazyload` : 'img.-lazyload';
const notSelector = isSelectorValid ? '.-loaded' : '.-loaded, [data-custom-lazyload-trigger] .-lazyload';
$(selector).not(notSelector).each(function () {
if (!customSelector && !isElementAllowToLoad(this, customLazyloadOffset)) return;
$(this).on('load', lazyloadFullLoadedCallback);
$(this).removeAttr('srcset').addClass('-loaded');
});
}
function bgLazyload(customSelector, customLazyloadOffset) {
const isSelectorValid = typeof customSelector === 'string';
const selector = isSelectorValid ? `${customSelector} .-bg-lazyload` : '.-bg-lazyload';
const notSelector = isSelectorValid ? '.-loaded' : '.-loaded, [data-custom-lazyload-trigger] .-bg-lazyload';
$(selector).not(notSelector).each(function () {
if (!customSelector && !isElementAllowToLoad(this, customLazyloadOffset)) return;
const src = $(this).attr('data-src');
$(this).css('background-image', `url(${src})`).removeAttr('data-src').addClass('-loaded');
});
}
function videoLazyload(customSelector, customLazyloadOffset) {
const isSelectorValid = typeof customSelector === 'string';
const selector = isSelectorValid ? `${customSelector} video.-lazyload` : 'video.-lazyload';
const notSelector = isSelectorValid ? '.-loaded' : '.-loaded, [data-custom-lazyload-trigger] .-lazyload';
$(selector).not(notSelector).each(function () {
if (!customSelector && !isElementAllowToLoad(this, customLazyloadOffset)) return;
$(this).on('loadeddata', lazyloadFullLoadedCallback);
const src = $(this).attr('data-src');
const dataStart = $(this).attr('data-start-position');
const t = dataStart ? `#t=${dataStart}` : '';
const source = `<source type="video/mp4" src="${src}${t}" />`;
$(this).html(source).removeAttr('data-src').addClass('-loaded');
});
}
function iframeLazyload(customSelector, customLazyloadOffset) {
const isSelectorValid = typeof customSelector === 'string';
const selector = isSelectorValid ? `${customSelector} iframe.-lazyload` : 'iframe.-lazyload';
const notSelector = isSelectorValid ? '.-loaded' : '.-loaded, [data-custom-lazyload-trigger] iframe.-lazyload';
$(selector).not(notSelector).each(function () {
if (!customSelector && !isElementAllowToLoad(this, customLazyloadOffset)) return;
const src = $(this).attr('data-src');
$(this).on('load', lazyloadFullLoadedCallback);
$(this).attr('src', src).removeAttr('data-src').addClass('-loaded');
});
}
// Lazyload - helpers
function isElementAllowToLoad(el, customLazyloadOffset) {
const lazyloadOffset = customLazyloadOffset ? customLazyloadOffset : DEFAULT_LAZYLOAD_OFFSET;
if (!lazyloadOffset) return true;
const offsetTop = $(el).offset().top;
const offsetToLoad = window.scrollY + window.innerHeight + lazyloadOffset;
return offsetTop < offsetToLoad;
}
function lazyloadFullLoadedCallback(e) {
$(e.target).addClass('-full-loaded');
$(e.target).off('load', lazyloadFullLoadedCallback);
}
function lazyload(customSelector, customLazyloadOffset) {
imgLazyload(customSelector, customLazyloadOffset);
bgLazyload(customSelector, customLazyloadOffset);
videoLazyload(customSelector, customLazyloadOffset);
iframeLazyload(customSelector, customLazyloadOffset);
const notLoadedElementsCount = $('.-lazyload, .-bg-lazyload').not('.-loaded').length;
if (notLoadedElementsCount === 0) {
$(window).off('scroll', lazyloadOnScroll);
window.dispatchEvent(new Event('lazyload-final'));
}
}
function viewportLazyload() {
lazyload(false, 1);
}
function lazyloadOnScroll() {
if (window.scrollY > 0) {
lazyload();
}
}
$(window).on('load', viewportLazyload);
$(window).on('load scroll', lazyloadOnScroll);
// Callback after load all child images
function onLoadChildImages(el, callback) {
el.data("loaded-images", "0");
const images = el.find("img");
const imagesCount = images.length;
images.on("load", function () {
$(this).outerWidth();
if (!$(this).hasClass("-loaded")) {
let loadedImages = Number(el.data("loaded-images"));
loadedImages++;
if (loadedImages === imagesCount) {
setTimeout(() => {
if (callback) callback();
}, 100);
} else {
el.data("loaded-images", loadedImages);
}
} else {
setTimeout(() => {
if (callback) callback();
}, 100);
}
});
}
const phoneInput = $('.phone-mask');
phoneInput.inputmask({
mask: '+38 (999) 999 99 99',
showMaskOnHover: false
});
// Form validation
$(document).on('submit', '.form form', function (e) {
formValidation(e.target);
})
$(document).on('wpcf7mailsent', '.form form', function (e) {
let formWrapper = $(e.target).closest('.form__wrapper');
formWrapper.addClass('-sended');
if (!isPc) {
let currTabHeight = formWrapper.find('.form').innerHeight();
let nextTabHeight = formWrapper.find('.form__thank').innerHeight();
formWrapper.css({
height: `${currTabHeight}px`,
transition: 'unset'
});
formWrapper.outerWidth(); // Lifehack
formWrapper.css({
height: `${nextTabHeight}px`,
transition: ''
});
}
});
$(document).on('click', '.form__thank', function () {
let formWrapper = $(this).closest('.form__wrapper');
formWrapper.removeClass('-sended');
if (!isPc) {
let currTabHeight = formWrapper.find('.form').innerHeight();
let nextTabHeight = formWrapper.find('.form__thank').innerHeight();
formWrapper.css({
height: `${currTabHeight}px`,
transition: 'unset'
});
formWrapper.outerWidth(); // Lifehack
formWrapper.css({
height: `${nextTabHeight}px`,
transition: ''
});
}
})
function formValidation(form) {
$(form)
.find('[data-important]')
.removeClass('-valid -not-valid')
.each(function () {
const input = $(this).find('input, textarea');
const validationType = $(this).attr('data-important');
if (validationType === 'email') emailValidator(input);
if (validationType === 'count') countValidator(input);
if (validationType === 'length') lengthValidator(input);
if (validationType === 'checked') isCheckedValidator(input);
if (validationType === 'not-empty') notEmptyValidator(input);
if (validationType === 'inputmask') inputmaskValidator(input);
});
return $(form).find('[data-important].-not-valid').length === 0;
}
$(document).on('focus', '.form [data-important] input, .form [data-important] textarea', function () {
$(this).closest('[data-important]').removeClass('-valid -not-valid');
});
// Form validation - helper
function setInputValidation(input, status) {
if (status) {
input.closest('[data-important]').addClass('-valid');
} else {
input.closest('[data-important]').addClass('-not-valid');
}
}
// Form validation - validators
function notEmptyValidator(input) {
setInputValidation(input, input.val().trim().length > 0);
}
function inputmaskValidator(input) {
setInputValidation(input, input.inputmask('isComplete'));
}
function isCheckedValidator(input) {
setInputValidation(input, input.is(':checked'));
}
function emailValidator(input) {
const value = input.val().trim();
const reg =
/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{1,}))$/;
setInputValidation(input, reg.test(String(value).toLowerCase()));
}
function countValidator(input) {
let isValid = true;
const value = input.val().trim();
const min = input.data('min');
const max = input.data('max');
if (value.length === 0) isValid = false;
if (min && value < min) isValid = false;
if (max && value > max) isValid = false;
setInputValidation(input, isValid);
}
function lengthValidator(input) {
const value = input.val().trim();
const minLength = input.closest('[data-important]').attr('data-min-length');
const maxLength = input.closest('[data-important]').attr('data-max-length');
let isValid = false;
if (minLength && maxLength) {
isValid = value.length >= minLength && value.length <= maxLength;
}
if (minLength && !maxLength) {
isValid = value.length >= minLength;
}
if (!minLength && maxLength) {
isValid = value.length <= maxLength;
}
setInputValidation(input, isValid);
}
// Selector full transitionend callback
function fullTransitionendCallback(element, callback, customProperty = false) {
if ($(element).length === 0) return;
const transitionProperties = $(element).css('transition-property').split(',').map(property => {
return property.trim();
});
const transitionDurations = $(element).css('transition-duration').split(',').map(duration => {
return parseFloat(duration);
});
let longestProperty = false;
if (transitionProperties.length > 1 && customProperty === false) {
longestProperty = transitionProperties[transitionDurations.indexOf(Math.max(...transitionDurations))];
}
$(element).on('transitionstart', function () {
$(this).removeAttr('data-transitionend-triggered');
});
$(element).on('transitionend', function (e) {
const isTriggered = $(this).is('[data-transitionend-triggered]');
if (isTriggered) return;
const isCustomProperty = customProperty && e.originalEvent.propertyName === customProperty;
const isSingleCallback = customProperty === false && longestProperty === false && typeof callback ===
"function";
const isLongestPropertyCallback = longestProperty && e.originalEvent.propertyName === longestProperty &&
typeof callback === "function";
if (isCustomProperty || isSingleCallback || isLongestPropertyCallback) {
$(this).attr('data-transitionend-triggered', true);
callback(e);
}
});
}