اطلاعات تماس

اذربایجان شرقی تبریز- نصف راه برج ستاره باران طبقه ی 11 واحد 113

09029222528

شبکه های اجتماعی

Google
LinkedIn

با ما در تماس باشید

وب سایت ثقال مارکت

این فیلد را پر کنید
لطفاً یک نشانی ایمیل معتبر بنویسید.
این فیلد را پر کنید
بچسبان) ---------------------------------------------------------- کار: اگر عکس‌های محصول بیشتر از ۴ تا بود، فقط ۳ تای اول + یک کاشی «+N» نشان می‌دهد (بدون اسکرول). کلیک روی کاشی = باز شدن لایت‌باکس PhotoSwipe خود ووکامرس با همه عکس‌ها. برای تغییر تعداد: عدد VISIBLE را عوض کن. ========================================================== */ (function () { var VISIBLE = 4; // تعداد خانه‌های تامبنیل (آخرین خانه = کاشی +N) function openGallery(gal) { var trigger = gal.querySelector('.woocommerce-product-gallery__trigger'); if (trigger) { trigger.click(); return; } var link = gal.querySelector('.woocommerce-product-gallery__image a'); if (link) { link.click(); } } function upgrade(gal) { if (gal.dataset.sgDone) return; var list = gal.querySelector('.flex-control-thumbs'); if (!list) return; var items = Array.prototype.slice.call(list.querySelectorAll(':scope > li')); if (items.length <= VISIBLE) return; gal.dataset.sgDone = '1'; var keep = items.slice(0, VISIBLE - 1); var rest = items.slice(VISIBLE - 1); rest.forEach(function (li) { li.classList.add('sg-hidden'); }); var previewImg = rest[0].querySelector('img'); var tile = document.createElement('li'); tile.className = 'sg-more'; tile.setAttribute('data-more', '+' + rest.length); tile.title = 'مشاهده همه عکس‌ها'; if (previewImg) { var img = document.createElement('img'); img.src = previewImg.src; img.alt = 'مشاهده همه عکس‌ها'; tile.appendChild(img); } tile.addEventListener('click', function () { openGallery(gal); }); list.appendChild(tile); } function run() { document .querySelectorAll('.wpb_row.product .woocommerce-product-gallery') .forEach(upgrade); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', run); } else { run(); } // اگر گالری با تاخیر ساخته شد (کش/لیزی‌لود)، چند بار دیگر تلاش کن var tries = 0; var timer = setInterval(function () { run(); if (++tries > 10) clearInterval(timer); }, 800); // هوک عمومی: بعد از تعویض عکس‌ها با AJAX (مثلاً انتخاب واریشن در محصول // متغیردار که گالری را عوض می‌کند) صدا بزن: window.sgRefreshProductGallery() window.sgRefreshProductGallery = run; })(); /* ========================================================== بخش ۲: جمع‌کردن شناسه/دسته‌بندی/برچسب‌ها در یک خط کلیک روی دکمه «نمایش همه» همه موارد را باز می‌کند. ---------------------------------------------------------- نتیجه تحقیق سئو (انجام شد، مشکلی نیست): ۱) همه لینک‌ها در HTML سمت سرور می‌مانند؛ CSS/JS فقط ظاهر را جمع می‌کند. بدون جاوااسکریپت هم همه موارد دیده می‌شوند. ۲) گوگل صفحه را با رندر کامل (CSS+JS) بررسی و محتوای جمع‌شده/تبی را به‌طور کامل ایندکس می‌کند (تأیید رسمی گوگل از ۲۰۱۶ به بعد، چند بار تکرار شده). لینک‌های داخل بخش جمع‌شده هم کرال و دنبال می‌شوند. ۳) چون محتوا برای کاربر و ربات یکسان است، cloaking محسوب نمی‌شود. فقط لینک‌ها را nofollow نکن و URLها را عوض نکن. ========================================================== */ (function () { function setup(box) { if (!box || box.dataset.sgMetaDone) return; var links = Array.prototype.slice.call(box.querySelectorAll('a')); if (links.length < 4) return; // مورد کم است؛ جمع‌کردن لازم نیست box.dataset.sgMetaDone = '1'; box.classList.add('sg-meta', 'sg-collapsed'); var btn = document.createElement('button'); btn.type = 'button'; btn.className = 'sg-meta-toggle'; btn.title = 'نمایش همه'; function paint() { var open = box.classList.contains('sg-open'); btn.setAttribute('aria-expanded', open ? 'true' : 'false'); btn.textContent = open ? 'بستن ✕' : '+' + Math.max(hiddenCount, 1); } var hiddenCount = 0; function measure() { // قفل عرض: بدون آن، بازکردن موقت لینک‌ها max-content را بالا می‌برد، // فلکس ستون‌ها کش می‌آید و سنجش در عرض غیرواقعی انجام می‌شود // (نتیجه: خط دوم هرگز بریده نمی‌شد). var lockW = box.clientWidth; box.style.maxWidth = lockW + 'px'; box.querySelectorAll('.sg-cut').forEach(function (el) { el.classList.remove('sg-cut'); }); void box.offsetHeight; // رفرش چیدمان var baseTop = btn.offsetTop; hiddenCount = 0; var cutRest = false; links.forEach(function (a) { if (cutRest || a.offsetTop > baseTop + 4) { cutRest = true; a.classList.add('sg-cut'); hiddenCount++; } }); // لیبل گروهی که همه لینک‌هایش مخفی شد، مخفی شود box.querySelectorAll('.w-post-elm').forEach(function (g) { var gl = g.querySelectorAll('a'); var before = g.querySelector('.w-post-elm-before'); if (gl.length && before) { var allHidden = true; gl.forEach(function (a) { if (!a.classList.contains('sg-cut')) allHidden = false; }); before.classList.toggle('sg-cut', allHidden); } }); box.style.maxWidth = ''; // بازکردن قفل عرض } function recalc() { if (!box.classList.contains('sg-collapsed')) return; // دو پاس: متن دکمه بعد از paint عریض‌تر می‌شود و چیدمان را جابه‌جا // می‌کند؛ پاس دوم با عرض نهایی دکمه می‌سنجد تا همیشه تک‌خط بماند. // حداکثر ۳ پاس تا پایداری شمارش. var last = -1; for (var p = 0; p < 3; p++) { measure(); paint(); if (hiddenCount === last) break; last = hiddenCount; } } btn.addEventListener('click', function () { var open = box.classList.toggle('sg-open'); box.classList.toggle('sg-collapsed', !open); if (!open) recalc(); else box.querySelectorAll('.sg-cut').forEach(function (el) { el.classList.remove('sg-cut'); }); paint(); }); box.insertBefore(btn, box.firstChild); recalc(); var rT; window.addEventListener('resize', function () { clearTimeout(rT); rT = setTimeout(recalc, 200); }); if (document.fonts && document.fonts.ready) document.fonts.ready.then(recalc); window.addEventListener('load', recalc); // هر بازچیدمان داخلی (فونت، عکس، سایدبار، زوم) → سنجش دوباره تا تک‌خط بماند if ('ResizeObserver' in window) { var roT; try { new ResizeObserver(function () { clearTimeout(roT); roT = setTimeout(recalc, 150); }).observe(box); } catch (e) {} } } function run() { document.querySelectorAll('.wpb_row.product').forEach(function (scope) { var box = null; scope.querySelectorAll('.w-hwrapper').forEach(function (w) { if (w.querySelector('.post_taxonomy')) box = w; }); setup(box); }); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', run); } else { run(); } var tries = 0; var timer = setInterval(function () { run(); if (++tries > 10) clearInterval(timer); }, 800); })(); /* ========================================================== بخش ۳: تبدیل تب‌ها به آکاردئون در موبایل (تا ۷۶۸px) از دکمه‌ها و سکشن‌های خود قالب استفاده می‌کند، پس با منطق داخلی ایمپرزا/ووکامرس سازگار است. ========================================================== */ (function () { var mq = window.matchMedia('(max-width: 768px)'); function syncItems(tabs) { var secs = Array.prototype.slice.call(tabs.querySelectorAll('.w-tabs-section')); var items = tabs.querySelectorAll('.w-tabs-item'); var idx = 0; secs.forEach(function (s, i) { if (s.classList.contains('active')) idx = i; }); items.forEach(function (b, i) { b.classList.toggle('active', i === idx); b.setAttribute('aria-expanded', i === idx ? 'true' : 'false'); }); } function apply(scope) { var tabs = scope.querySelector('.w-tabs'); if (!tabs) return; if (mq.matches) { if (tabs.dataset.sgAcc === '1') return; tabs.dataset.sgAcc = '1'; tabs.classList.add('sg-acc'); var secs = tabs.querySelectorAll('.w-tabs-section'); var seen = false; secs.forEach(function (s) { var c = s.querySelector('.w-tabs-section-content'); if (c) c.removeAttribute('hidden'); var h = s.querySelector('.w-tabs-section-header'); if (s.classList.contains('active')) { if (!seen) { seen = true; if (h) h.setAttribute('aria-expanded', 'true'); } else s.classList.remove('active'); } else if (h) h.setAttribute('aria-expanded', 'false'); }); if (!seen && secs[0]) { secs[0].classList.add('active'); var h0 = secs[0].querySelector('.w-tabs-section-header'); if (h0) h0.setAttribute('aria-expanded', 'true'); } syncItems(tabs); } else { if (tabs.dataset.sgAcc !== '1') return; delete tabs.dataset.sgAcc; tabs.classList.remove('sg-acc'); var act = tabs.querySelector('.w-tabs-section.active'); if (!act) { var first = tabs.querySelector('.w-tabs-section'); if (first) first.classList.add('active'); } syncItems(tabs); } } document.addEventListener('click', function (e) { var h = e.target.closest && e.target.closest('.sg-acc .w-tabs-section-header'); if (!h) return; var tabs = h.closest('.w-tabs'); var sec = h.closest('.w-tabs-section'); var was = sec.classList.contains('active'); tabs.querySelectorAll('.w-tabs-section.active').forEach(function (s) { s.classList.remove('active'); var hh = s.querySelector('.w-tabs-section-header'); if (hh) hh.setAttribute('aria-expanded', 'false'); }); if (!was) { sec.classList.add('active'); h.setAttribute('aria-expanded', 'true'); } syncItems(tabs); }); function run() { document.querySelectorAll('.wpb_row.product').forEach(apply); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', run); } else { run(); } if (mq.addEventListener) mq.addEventListener('change', run); else if (mq.addListener) mq.addListener(run); })(); /* ========================================================== بخش ۴: نوار خرید ثابت پایین صفحه (موبایل و تبلت) تعداد + دکمه؛ دکمه، فرم اصلی را سابمیت می‌کند (سازگار با محصولات متغیردار). وقتی باکس خرید دیده می‌شود، نوار مخفی است. ========================================================== */ (function () { function setup(scope) { if (scope.dataset.sgBarDone) return; var form = scope.querySelector('form.cart'); var btn = scope.querySelector('.single_add_to_cart_button'); if (!form || !btn) return; scope.dataset.sgBarDone = '1'; var bar = document.createElement('div'); bar.className = 'sg-buybar sg-hidden-bar'; bar.innerHTML = '
'; var bbQty = bar.querySelector('.sg-bb-qty'); var bbBtn = bar.querySelector('.sg-buybar-btn'); bbBtn.textContent = (btn.textContent || '').trim() || 'افزودن به سبد خرید'; function origQty() { return scope.querySelector('form.cart .qty'); } function syncFromOrig() { var o = origQty(); if (o && document.activeElement !== bbQty) bbQty.value = o.value; } syncFromOrig(); function push(v) { var o = origQty(); if (!o) return; var min = parseFloat(o.getAttribute('min')) || 1; v = Math.max(min, Math.floor(v) || min); var max = parseFloat(o.getAttribute('max')); if (max) v = Math.min(max, v); o.value = v; o.dispatchEvent(new Event('input', { bubbles: true })); o.dispatchEvent(new Event('change', { bubbles: true })); bbQty.value = v; } bar.querySelector('.sg-bb-minus').addEventListener('click', function () { push(parseFloat(bbQty.value || '1') - 1); }); bar.querySelector('.sg-bb-plus').addEventListener('click', function () { push(parseFloat(bbQty.value || '1') + 1); }); bbQty.addEventListener('change', function () { push(parseFloat(bbQty.value || '1')); }); document.addEventListener('input', function (e) { if (e.target === origQty()) syncFromOrig(); }); bbBtn.addEventListener('click', function () { btn.click(); }); document.body.appendChild(bar); var box = scope.querySelector('.w-post-elm.add_to_cart') || form; var ioFired = false; function rectVisible() { var r = box.getBoundingClientRect(); var vh = window.innerHeight || document.documentElement.clientHeight; return r.bottom > vh * 0.05 && r.top < vh * 0.45; } function applyVisible(boxSeen) { bar.classList.toggle('sg-hidden-bar', boxSeen); } if ('IntersectionObserver' in window) { try { new IntersectionObserver(function (entries) { ioFired = true; entries.forEach(function (en) { bar.classList.toggle('sg-hidden-bar', en.isIntersecting); }); }, { rootMargin: '-5% 0px -55% 0px' }).observe(box); } catch (e) { ioFired = true; bar.classList.remove('sg-hidden-bar'); } } else { ioFired = true; bar.classList.remove('sg-hidden-bar'); } // فالبک: اگر IO دیر کرد یا اصلاً فایر نشد (برخی وب‌ویوها/پیش‌نمایش‌ها)، // با getBoundingClientRect همگام شو — همان منطق، بدون تداخل با IO. var fbT; function fallback() { if (ioFired) return; applyVisible(rectVisible()); // دیده شدن باکس = مخفی شدن نوار (مثل IO) } window.addEventListener('scroll', function () { clearTimeout(fbT); fbT = setTimeout(fallback, 100); }, { passive: true }); if ('onscrollend' in window) window.addEventListener('scrollend', fallback); window.addEventListener('resize', function () { clearTimeout(fbT); fbT = setTimeout(fallback, 100); }); setTimeout(fallback, 600); } function run() { if (!window.matchMedia('(max-width: 1024px)').matches) return; document.querySelectorAll('.wpb_row.product').forEach(setup); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', run); } else { run(); } var tries = 0; var timer = setInterval(function () { run(); if (++tries > 10) clearInterval(timer); }, 800); })(); /* ========================================================== بخش ۵: لیبل «تعداد:» کنار انتخاب‌گر تعداد فرم خرید (المان بیلدر لیبل ندارد؛ اسنیپت آن را می‌سازد تا در همه حالت‌ها — ساده/متغیر، دسکتاپ/موبایل — کنار استپر باشد) ========================================================== */ (function () { function run() { document.querySelectorAll('.wpb_row.product form.cart').forEach(function (form) { if (form.querySelector(':scope > .sg-qty-label, .variations_button > .sg-qty-label')) return; var q = form.querySelector('.plus-minus-button') || form.querySelector('.quantity'); if (!q || !q.parentNode) return; var s = document.createElement('span'); s.className = 'sg-qty-label'; s.textContent = 'تعداد:'; q.parentNode.insertBefore(s, q); }); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', run); } else { run(); } var tries = 0; var timer = setInterval(function () { run(); if (++tries > 10) clearInterval(timer); }, 800); })(); /* ========================================================== بخش ۶: دایره درصد تخفیف کنار قیمت (متن سفید) درصد را از روی قیمت خط‌خورده و قیمت جدید حساب می‌کند، پس با عوض شدن واریشن هم به‌روز می‌شود. اگر تخفیفی نباشد، دایره ساخته/نشان داده نمی‌شود. ========================================================== */ (function () { var FA = '۰۱۲۳۴۵۶۷۸۹'; function num(txt) { var t = String(txt || '').replace(/[۰-۹]/g, function (d) { return FA.indexOf(d); }).replace(/[^0-9]/g, ''); return parseInt(t, 10) || 0; } function fa(txt) { return String(txt).replace(/[0-9]/g, function (d) { return FA[d]; }); } function paint(scope) { var panel = scope.querySelector('p.price'); if (!panel) return; var wrap = panel.querySelector(':scope > .sg-off-wrap'); var del = panel.querySelector('del'); var ins = panel.querySelector('ins'); var oldV = del ? num(del.textContent) : 0; var curV = num(ins ? ins.textContent : panel.textContent); if (!oldV || !curV || curV >= oldV) { // بدون تخفیف: دایره را بردار و del را از بسته‌بندی خارج کن var oldEl = panel.querySelector('.sg-off-circle'); if (oldEl) oldEl.remove(); if (wrap && del && del.parentNode === wrap) { panel.insertBefore(del, wrap); wrap.remove(); } else if (wrap && !del) wrap.remove(); return; } var txt = fa(Math.round((oldV - curV) / oldV * 100)) + '٪'; if (!wrap) { wrap = document.createElement('span'); wrap.className = 'sg-off-wrap'; wrap.setAttribute('aria-hidden', 'true'); if (ins) panel.insertBefore(wrap, ins); else panel.appendChild(wrap); } var el = wrap.querySelector(':scope > .sg-off-circle'); if (!el) { el = document.createElement('span'); el.className = 'sg-off-circle'; el.setAttribute('dir', 'rtl'); wrap.insertBefore(el, wrap.firstChild); } else if (wrap.firstChild !== el) { wrap.insertBefore(el, wrap.firstChild); // دایره همیشه بالای عدد } if (del && del.parentNode !== wrap) wrap.appendChild(del); if (el.textContent !== txt) el.textContent = txt; // فقط وقتی فرق کرد بنویس (جلوگیری از حلقه آبزرور) } function run() { document.querySelectorAll('.wpb_row.product').forEach(paint); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', run); } else { run(); } var tries = 0; var timer = setInterval(function () { run(); if (++tries > 10) clearInterval(timer); }, 800); // قیمت با انتخاب واریشن عوض می‌شود (ووکامرس) — دایره را همگام نگه دار if ('MutationObserver' in window) { try { var obs = new MutationObserver(function () { run(); }); document.querySelectorAll('.wpb_row.product p.price').forEach(function (p) { obs.observe(p, { childList: true, characterData: true, subtree: true }); }); } catch (e) { /* بدون آبزرور هم با تاخیرهای بالا پوشش داده می‌شود */ } } })(); /* ========================================================== بخش ۷: نوار اعتماد بین کارت خرید و باکس تب‌ها ۵ ویژگی (آیکون + متن) در یک خط؛ در همه عرض‌ها تک‌خط می‌ماند و با سوایپ اسکرول می‌شود — بدون نوار اسکرول و بدون فلش. متن‌ها را از آرایه ITEMS عوض کن. ========================================================== */ (function () { var ITEMS = [ { t: 'ضمانت اصلی بودن کالا', i: 'shield' }, { t: 'هفت روز ضمانت بازگشت کالا', i: 'box' }, { t: 'امکان پرداخت در محل', i: 'pin' }, { t: '۲۴ ساعته، ۷ روز هفته', i: 'head' }, { t: 'امکان تحویل سریع', i: 'truck' } ]; function svg(inner) { return ''; } var ICONS = { shield: '', box: '', pin: '', head: '', truck: '' }; function run() { var tabs = document.querySelector('.w-tabs'); if (!tabs || !tabs.parentNode) return; if (tabs.dataset.sgPTrustDone) return; tabs.dataset.sgPTrustDone = '1'; var bar = document.createElement('div'); bar.className = 'sg-p-trust'; bar.setAttribute('role', 'list'); bar.setAttribute('aria-label', 'مزیت‌های خرید'); var h = ''; ITEMS.forEach(function (o) { h += '
' + svg(ICONS[o.i] || ICONS.shield) + '' + o.t + '
'; }); bar.innerHTML = h; tabs.parentNode.insertBefore(bar, tabs); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', run); } else { run(); } var tries = 0; var timer = setInterval(function () { run(); if (++tries > 10) clearInterval(timer); }, 800); })(); /* ========================================================== بخش ۸: باکس بزرگ خلاصه خرید (قیمت + توضیح کوتاه + کارت خرید) هر سه را داخل یک کارت برجسته می‌گذارد. جداکننده‌های بین‌شان با CSS مخفی می‌شوند. جابه‌جایی گره‌هاست (شنونده‌ها حفظ می‌شود) و با به‌روزرسانی قیمت واریشن هم سازگار است. ========================================================== */ (function () { function run() { document.querySelectorAll('.wpb_row.product').forEach(function (scope) { if (scope.dataset.sgBoxDone) return; var price = scope.querySelector('p.price'); var desc = scope.querySelector('.post_content'); var buy = scope.querySelector('.add_to_cart'); if (!price || !desc || !buy) return; if (price.parentNode !== desc.parentNode || desc.parentNode !== buy.parentNode) return; scope.dataset.sgBoxDone = '1'; var parent = price.parentNode; var box = document.createElement('div'); box.className = 'sg-summary-box'; parent.insertBefore(box, price); // همه گره‌های بین قیمت تا کارت خرید (شامل جداکننده‌ها) به داخل باکس var n = price; while (n) { var nx = n.nextSibling; box.appendChild(n); if (n === buy) break; n = nx; } // امتیاز محصول زیر باکس قیمت var rating = scope.querySelector('.product_field.rating'); var pp = box.querySelector('p.price'); if (rating && pp && (rating.parentNode !== box || rating.previousElementSibling !== pp)) { box.insertBefore(rating, pp.nextSibling); } }); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', run); } else { run(); } var tries = 0; var timer = setInterval(function () { run(); if (++tries > 10) clearInterval(timer); }, 800); })(); } /* end once-guard */