`;
}
function animateValue(element, start, end, duration) {
return new Promise(resolve => {
let startTimestamp = null;
const step = (timestamp) => {
if (!startTimestamp) startTimestamp = timestamp;
const progress = Math.min((timestamp - startTimestamp) / duration, 1);
const current = (progress * (end - start) + start);
element.textContent = format(current);
if (progress < 1) {
window.requestAnimationFrame(step);
} else {
resolve();
}
};
window.requestAnimationFrame(step);
});
}
function initializeAdvancedPriceDisplays() {
const viewers = document.querySelectorAll(".price-range-container-v2");
viewers.forEach(async (viewer) => {
// جلوگیری از init دوباره
if (viewer.__priceRangeInited) return;
viewer.__priceRangeInited = true;
const productId = viewer.dataset.productId ? String(viewer.dataset.productId) : "";
const contentWrapper = viewer.querySelector(".price-range-content");
const columnsContainer = contentWrapper ? contentWrapper.querySelector(".price-range-columns-v2") : null;
if (!columnsContainer) return;
if (!productId) { setError(columnsContainer, "خطا: کلید محصول تعریف نشده."); return; }
let allPrices;
try {
allPrices = await getPricesForV2();
} catch (e) {
console.error("خطا در دریافت فایل قیمت:", e);
setError(columnsContainer, "خطا در ارتباط با سرور قیمت.", e && e.message ? e.message : withBust(PRICES_URL));
return;
}
const basePrice = getProductPriceToman(allPrices, productId);
if (!isFinite(basePrice)) {
setError(columnsContainer, `قیمت محصول با کلید "${productId}" یافت نشد.`);
return;
}
const priceFrom = basePrice - 10000000;
const priceTo = basePrice + 10000000;
// رندر اولیه DOM (ID یکتا بر اساس productId)
columnsContainer.innerHTML = `
`;
// بهتر: به جای document.getElementById از querySelector داخل خود viewer استفاده کنیم (ایمنتر برای چند ویجت)
const fromElement = viewer.querySelector(`#price-from-${CSS && CSS.escape ? CSS.escape(productId) : productId}`);
const toElement = viewer.querySelector(`#price-to-${CSS && CSS.escape ? CSS.escape(productId) : productId}`);
if (!fromElement || !toElement) {
setError(columnsContainer, "خطای داخلی: المانهای خروجی یافت نشد.");
return;
}
await new Promise(r => setTimeout(r, 100));
viewer.classList.add("loaded");
await Promise.all([
animateValue(fromElement, 0, priceFrom, 1500),
animateValue(toElement, 0, priceTo, 1700)
]);
// Shimmer هر ۵ ثانیه (یک بار برای هر viewer)
const priceWrappers = viewer.querySelectorAll(".price-value-wrapper");
setInterval(() => {
priceWrappers.forEach(wrapper => {
wrapper.classList.add("shimmer-effect-wrapper");
setTimeout(() => wrapper.classList.remove("shimmer-effect-wrapper"), 1200);
});
}, 5000);
// ژیروسکوپ (بهینه: یک listener برای هر viewer، فقط روی موبایل)
if (window.DeviceOrientationEvent && ("ontouchstart" in window)) {
window.addEventListener("deviceorientation", (event) => {
const beta = event.beta || 0;
const gamma = event.gamma || 0;
const rotateX = beta / 15;
const rotateY = gamma / -15;
const clampedRotateX = Math.max(-8, Math.min(8, rotateX));
const clampedRotateY = Math.max(-8, Math.min(8, rotateY));
requestAnimationFrame(() => {
viewer.style.transform =
`perspective(1000px) rotateX(${clampedRotateX}deg) rotateY(${clampedRotateY}deg)`;
});
}, { passive: true });
}
});
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", initializeAdvancedPriceDisplays);
} else {
initializeAdvancedPriceDisplays();
}
})();