115 lines
3.4 KiB
JavaScript
115 lines
3.4 KiB
JavaScript
/**
|
|
* Mobile Touch Optimization
|
|
* Eliminates double-tap behavior and ensures immediate response on mobile devices
|
|
*/
|
|
|
|
(function () {
|
|
"use strict";
|
|
|
|
// Only apply on touch devices
|
|
if (!("ontouchstart" in window)) return;
|
|
|
|
// Disable 300ms click delay on mobile
|
|
let touchStartX, touchStartY;
|
|
|
|
// Add fastclick functionality for immediate response
|
|
document.addEventListener(
|
|
"touchstart",
|
|
function (e) {
|
|
touchStartX = e.touches[0].clientX;
|
|
touchStartY = e.touches[0].clientY;
|
|
},
|
|
{ passive: true },
|
|
);
|
|
|
|
document.addEventListener(
|
|
"touchend",
|
|
function (e) {
|
|
if (!touchStartX || !touchStartY) return;
|
|
|
|
const touchEndX = e.changedTouches[0].clientX;
|
|
const touchEndY = e.changedTouches[0].clientY;
|
|
|
|
// Check if it's a tap (not a swipe)
|
|
const diffX = Math.abs(touchEndX - touchStartX);
|
|
const diffY = Math.abs(touchEndY - touchStartY);
|
|
|
|
if (diffX < 10 && diffY < 10) {
|
|
// This is a tap, ensure immediate response
|
|
const target = e.target.closest(
|
|
"a, button, [data-bs-toggle], .product-card, .portfolio-card, .blog-card, .nav-link, .btn",
|
|
);
|
|
if (target && !target.disabled) {
|
|
// Add visual feedback
|
|
target.style.opacity = "0.7";
|
|
setTimeout(() => {
|
|
target.style.opacity = "";
|
|
}, 100);
|
|
}
|
|
}
|
|
|
|
touchStartX = null;
|
|
touchStartY = null;
|
|
},
|
|
{ passive: false },
|
|
);
|
|
|
|
// Remove hover states that cause double-tap on mobile
|
|
if (window.matchMedia("(hover: none)").matches) {
|
|
const style = document.createElement("style");
|
|
style.textContent = `
|
|
/* Override hover states for immediate touch response */
|
|
.product-card, .portfolio-card, .blog-card, .btn, .nav-link {
|
|
transition: transform 0.1s ease, opacity 0.1s ease !important;
|
|
}
|
|
`;
|
|
document.head.appendChild(style);
|
|
}
|
|
|
|
// Optimize click handlers for mobile
|
|
function optimizeClickHandler(selector) {
|
|
const elements = document.querySelectorAll(selector);
|
|
elements.forEach((el) => {
|
|
if (el.dataset.mobileOptimized) return;
|
|
el.dataset.mobileOptimized = "true";
|
|
|
|
// Remove any existing event listeners that might cause delays
|
|
el.style.pointerEvents = "auto";
|
|
el.style.touchAction = "manipulation";
|
|
|
|
// Ensure proper z-index for touch
|
|
const computedStyle = window.getComputedStyle(el);
|
|
if (computedStyle.position === "static") {
|
|
el.style.position = "relative";
|
|
}
|
|
});
|
|
}
|
|
|
|
// Apply optimizations when DOM is ready
|
|
document.addEventListener("DOMContentLoaded", function () {
|
|
optimizeClickHandler(
|
|
"a, button, .product-card, .portfolio-card, .blog-card, .btn, .nav-link, .filter-btn, .add-to-cart-btn",
|
|
);
|
|
});
|
|
|
|
// Apply optimizations to dynamically added content
|
|
const observer = new MutationObserver(function (mutations) {
|
|
mutations.forEach(function (mutation) {
|
|
if (mutation.type === "childList") {
|
|
mutation.addedNodes.forEach(function (node) {
|
|
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
optimizeClickHandler(
|
|
"a, button, .product-card, .portfolio-card, .blog-card, .btn, .nav-link, .filter-btn, .add-to-cart-btn",
|
|
);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
});
|
|
|
|
observer.observe(document.body, {
|
|
childList: true,
|
|
subtree: true,
|
|
});
|
|
})();
|