BỘ SƯU TẬP THE MAGNOLIA

ĐÓA MỘC LAN KIÊU HÃNH

Bộ sưu tập The Magnolia

CỔ ĐIỂN GIAO THOA

TỰ TIN TỎA SÁNG

Art decor
Trang Sức Thịnh Hành
`); win.document.close(); win.print();}/*CLick mở fancybox hướng dẫn hoặc mở panel hướng dẫn*/function openSizeGuide() { if (window.innerWidth >= 768) { /* Desktop → Fancybox*/ openFancybox('#sizeGuide', 'my-size-guide'); } else { /*Mobile → Slide panel*/ openSizeGuideMobile(); }}/*Mở panel hướng dẫn*/function openSizeGuideMobile() { const content = document.getElementById('sizeGuide'); const overlay = document.querySelector('.overlaybar'); const body = document.body; if (!content || !overlay) return; /* Tắt scroll body*/ body.classList.add('no-scroll'); /*frame 1*/ content.classList.add('sizeGuide-mobile'); content.classList.remove('active'); overlay.classList.add('active'); overlay.onclick = closeSizeGuideMobile; /*frame 2*/ requestAnimationFrame(() => { content.classList.add('active'); });}/*Đóng panel hướng dẫn*/function closeSizeGuideMobile() { const content = document.getElementById('sizeGuide'); const overlay = document.querySelector('.overlaybar'); const body = document.body; if (!content || !overlay) return; content.classList.remove('active'); overlay.classList.remove('active'); /* Mở lại scroll body*/ body.classList.remove('no-scroll'); setTimeout(() => { content.classList.remove('sizeGuide-mobile'); }, 300);}const fixedBar = document.querySelector('.div-fixed');const footer = document.querySelector('footer');/*Mở khi MKT cần button mua hàng kh che footerwindow.addEventListener('scroll', () => { const footerTop = footer.getBoundingClientRect().top; const windowHeight = window.innerHeight; if (footerTop <= windowHeight) { Khi footer chạm màn hình fixedBar.style.position = 'absolute'; fixedBar.style.bottom = `${windowHeight - footerTop}px`; } else { fixedBar.style.position = 'fixed'; fixedBar.style.bottom = '0'; }});*/document.addEventListener('DOMContentLoaded', () => { const filter = document.querySelector('.filter'); if (!filter) return; /*tạo 1 sentinel nằm ngay trước filter*/ const sentinel = document.createElement('div'); requestAnimationFrame(() => { sentinel.style.height = '1px'; }); filter.parentNode.insertBefore(sentinel, filter); const observer = new IntersectionObserver( ([entry]) => { /*khi sentinel ra khỏi viewport → filter đang sticky*/ filter.classList.toggle('is-stuck', !entry.isIntersecting); }, { root: null, threshold: 0 } ); observer.observe(sentinel);});/**JS tính chiều cao của tên sản phẩm *//*(function () { const grid = document.querySelector('.jewelry-list-product'); if (!grid) return; let scheduled = false; let resizeTimer = null; function alignNameByRow() { const items = grid.querySelectorAll('.product-jewelry'); if (!items.length) return; const columns = getComputedStyle(grid) .gridTemplateColumns.split(' ').length; const rows = []; for (let i = 0; i < items.length; i += columns) { rows.push(Array.from(items).slice(i, i + columns)); } requestAnimationFrame(() => { rows.forEach(row => { let maxHeight = 0; row.forEach(item => { const el = item.querySelector('.name-product'); if (!el) return; el.style.minHeight = ''; const h = el.getBoundingClientRect().height; if (h > maxHeight) maxHeight = h; }); row.forEach(item => { const el = item.querySelector('.name-product'); if (el) { el.style.minHeight = maxHeight + 'px'; } }); }); }); } function scheduleAlign() { if (scheduled) return; scheduled = true; (window.requestIdleCallback || function(cb){ return setTimeout(cb, 50); })(() => { alignNameByRow(); scheduled = false; }); } const observer = new MutationObserver((mutations) => { if (!mutations.some(m => m.addedNodes.length)) return; scheduleAlign(); }); observer.observe(grid, { childList: true, subtree: true }); window.addEventListener('resize', () => { clearTimeout(resizeTimer); resizeTimer = setTimeout(() => { scheduleAlign(); }, 200); }); window.addEventListener('load', scheduleAlign);})();*//**JS tính chiều cao của tên sản phẩm *//**Hàm đổi tên viết thường thành viết hoa chữ cái đầu khi gõ */function capitalizeWords(value) { return value .toLowerCase() .trim() .replace(/\s+/g, ' ') .split(' ') .map(word => { if (!word) return ''; return word.charAt(0).toUpperCase() + word.slice(1); }) .join(' ');}/**JS xử lý input viết hoa*/function attachCapitalizeOnSpace(input) { if (!input || input.dataset.formatInit) return; input.addEventListener('compositionstart', () => { input.dataset.typing = '1'; }); input.addEventListener('compositionend', () => { input.dataset.typing = '0'; }); const capitalizeWord = word => { if (!word) return ''; return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase(); }; /* ===== SPACE ===== */ input.addEventListener('keyup', (e) => { if (input.dataset.typing === '1') return; if (e.key === ' ') { const words = input.value.split(' '); if (words.length > 1) { const i = words.length - 2; words[i] = capitalizeWord(words[i]); input.value = words.join(' '); } } }); /* ===== BLUR===== */ input.addEventListener('blur', () => { if (input.dataset.typing === '1') return; const words = input.value.trim().split(/\s+/); input.value = words.map(capitalizeWord).join(' '); }); input.dataset.formatInit = '1';}/**Hàm đổi tên viết thường thành viết hoa chữ cái đầu khi gõ *//**Swiper ảnh phụ */(function () { /* ================= CONFIG ================= */ const MOBILE_BREAKPOINT = 768; let isMobile = window.innerWidth < MOBILE_BREAKPOINT; if(!isMobile) { return; } /* ================= INIT SWIPER ================= */ function initSwiper(el) { if (!el || el.swiper) return; const wrapper = el.querySelector('.swiper-wrapper'); const slides = el.querySelectorAll('.swiper-slide'); if (!wrapper || slides.length < 2) return; try { new Swiper(el, { slidesPerView: 1, spaceBetween: 0, roundLengths: false, observer: true, observeParents: true, watchSlidesProgress: true, scrollbar: { el: el.querySelector('.swiper-scrollbar'), draggable: true, hide: false } }); } catch (e) { console.warn('Swiper lỗi:', e); } } /* ================= DESTROY ================= */ function destroySwiper(el) { if (el && el.swiper) { el.swiper.destroy(true, true); } delete el.dataset.observed; delete el.dataset.prepared; delete el.dataset.touchBound; } /* ================= PREPARE (PRELOAD NHẸ) ================= */ function prepareSwiper(el) { if (!isMobile || el.dataset.prepared) return; el.dataset.prepared = "true"; /* delay để không block INP*/ const run = () => initSwiper(el); if ('requestIdleCallback' in window) { requestIdleCallback(run, { timeout: 300 }); } else { setTimeout(run, 80); } } /* ================= FALLBACK: INIT KHI USER CHẠM ================= */ function initOnTouch(el) { if (el.dataset.touchBound) return; el.dataset.touchBound = "true"; const handler = () => { if (!el.swiper) { initSwiper(el); } }; el.addEventListener('touchstart', handler, { once: true, passive: true }); el.addEventListener('mousedown', handler, { once: true }); } /* ================= INTERSECTION OBSERVER ================= */ const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (!entry.isIntersecting) return; const el = entry.target; prepareSwiper(el); /* preload trước*/ initOnTouch(el); /* fallback nếu chưa init kịp*/ observer.unobserve(el); }); }, { rootMargin: '250px 0px' /*preload trước khi user thấy*/ }); /* ================= OBSERVE ELEMENT ================= */ function observeEl(el) { if (!el || el.dataset.observed) return; el.dataset.observed = "true"; if (isMobile) { observer.observe(el); } } /* ================= INIT ALL ================= */ function initAllSwiper() { document.querySelectorAll('.swiper-mobile-product').forEach(observeEl); } /* ================= HANDLE AJAX ================= */ let moTimer; const mutationObserver = new MutationObserver((mutations) => { clearTimeout(moTimer); moTimer = setTimeout(() => { mutations.forEach(mutation => { mutation.addedNodes.forEach(node => { if (node.nodeType !== 1) return; if (node.classList?.contains('swiper-mobile-product')) { observeEl(node); } node.querySelectorAll?.('.swiper-mobile-product').forEach(observeEl); }); }); }, 120); }); const container = document.querySelector('#viewlist'); if (container) { mutationObserver.observe(container, { childList: true, subtree: true }); } /* ================= RESIZE ================= */ let resizeTimer; window.addEventListener('resize', () => { clearTimeout(resizeTimer); resizeTimer = setTimeout(() => { const nowMobile = window.innerWidth < MOBILE_BREAKPOINT; if (nowMobile === isMobile) return; isMobile = nowMobile; document.querySelectorAll('.swiper-mobile-product').forEach(el => { if (isMobile) { observeEl(el); } else { destroySwiper(el); } }); }, 200); }); /* ================= LOAD ================= */ window.addEventListener('load', () => { initAllSwiper(); });})();/*(function () { const container = document.querySelector('#viewlist'); if (!container) return; const isMobile = () => window.innerWidth < 768; let isActive = false; const imageCache = new Map(); function loadSubImages(el) { if (!el || el.dataset.loaded === "1" || el.dataset.loading === "1") return; const id = el.dataset.id; if (!id) return; const wrapper = el.querySelector('.swiper-wrapper'); if (!wrapper) return; if (imageCache.has(id)) { renderImages(el, imageCache.get(id)); return; } el.dataset.loading = "1"; fetch(path_url + `/ajax/get_related_images.php?idpr=${id}`) .then(res => res.json()) .then(data => { imageCache.set(id, data); renderImages(el, data); }) .catch(() => { el.dataset.loading = "0"; }); } function renderImages(el, data) { const wrapper = el.querySelector('.swiper-wrapper'); if (!wrapper) return; if (Array.isArray(data) && data.length) { const frag = document.createDocumentFragment(); data.forEach(img => { const slide = document.createElement('div'); slide.className = 'swiper-slide'; slide.innerHTML = img.img; frag.appendChild(slide); }); wrapper.appendChild(frag); } el.dataset.loaded = "1"; el.dataset.loading = "0"; if (el.swiper) el.swiper.update(); } function initSwiper(el) { if (!el || el.swiper) return; new Swiper(el, { slidesPerView: 1, spaceBetween: 0, resistanceRatio: 0.85, watchSlidesProgress: true, observer: true, observeParents: true, touchStartPreventDefault: false, touchMoveStopPropagation: false, scrollbar: { el: el.querySelector('.swiper-scrollbar'), draggable: true, hide: false } }); } function preloadFirstItems() { const items = container.querySelectorAll('.swiper-mobile-product'); requestIdleCallback(() => { for (let i = 0; i < Math.min(2, items.length); i++) { const el = items[i]; if (el.dataset.preloaded) continue; el.dataset.preloaded = "1"; initSwiper(el); loadSubImages(el); } }, { timeout: 300 }); } function bindSwipe(el) { if (el._swipeBound) return; el._swipeBound = true; const link = el.closest('a'); if (!link) return; let startX = 0; let startY = 0; let isSwipe = false; let prepared = false; const THRESHOLD = 8; const onPointerDown = (e) => { startX = e.clientX; startY = e.clientY; isSwipe = false; if (!prepared) { prepared = true; requestIdleCallback(() => { initSwiper(el); loadSubImages(el); }, { timeout: 150 }); } }; const onPointerMove = (e) => { const dx = e.clientX - startX; const dy = e.clientY - startY; if (Math.abs(dx) > THRESHOLD && Math.abs(dx) > Math.abs(dy)) { isSwipe = true; } }; const onClick = (e) => { if (isSwipe) e.preventDefault(); }; el.addEventListener('pointerdown', onPointerDown, { passive: true }); el.addEventListener('pointermove', onPointerMove, { passive: true }); link.addEventListener('click', onClick); el._swipeHandlers = { onPointerDown, onPointerMove, onClick, link }; } function unbindSwipe(el) { if (!el._swipeHandlers) return; const { onPointerDown, onPointerMove, onClick, link } = el._swipeHandlers; el.removeEventListener('pointerdown', onPointerDown); el.removeEventListener('pointermove', onPointerMove); link.removeEventListener('click', onClick); el._swipeHandlers = null; el._swipeBound = false; } function initEl(el) { if (!el || el.dataset.init) return; el.dataset.init = "1"; bindSwipe(el); } function initAll() { container.querySelectorAll('.swiper-mobile-product').forEach(initEl); } let observer = null; function startObserver() { if (observer) return; observer = new MutationObserver(mutations => { mutations.forEach(mutation => { mutation.addedNodes.forEach(node => { if (node.nodeType !== 1) return; if (node.classList?.contains('swiper-mobile-product')) { initEl(node); } node.querySelectorAll?.('.swiper-mobile-product').forEach(initEl); }); }); }); observer.observe(container, { childList: true, subtree: true }); } function stopObserver() { if (observer) { observer.disconnect(); observer = null; } } function enable() { if (isActive) return; isActive = true; initAll(); startObserver(); preloadFirstItems(); } function disable() { if (!isActive) return; isActive = false; stopObserver(); document.querySelectorAll('.swiper-mobile-product').forEach(el => { unbindSwipe(el); if (el.swiper) { el.swiper.destroy(true, true); } el.dataset.init = ""; }); } function check() { if (isMobile()) enable(); else disable(); } window.addEventListener('load', check); let resizeTimer; window.addEventListener('resize', () => { clearTimeout(resizeTimer); resizeTimer = setTimeout(check, 150); });})();*//**Swiper ảnh phụ */