<script>
document.addEventListener("DOMContentLoaded", function() {
(function () {
const sizeLabel = 'Ценовой диапазон';
// true = на все товары, false = только на товары с sizeLabel
const allProducts = false;
//шаг увеличения
const STEP_FOR_ONE = 10; // для товаров от 1шт
const STEP_FOR_MANY = 50; // для всех остальных товаров
const wholesaleTitle = "Диапазон цен: "; //Заголовок опции в в карточке товара
const wholesale = true;
function hasWholesaleOption(product) {
if (!product) return false;
return Array.from(product.querySelectorAll('.js-product-option-name'))
.some(el => el.textContent.trim() === sizeLabel);
}
function getFirstNumber(str) {
if (!str) return 0;
const m = String(str).match(/\d+/);
return m ? parseInt(m[0], 10) : 0;
}
function cacheQty(product, val) {
if (!product) return;
product.dataset._qty = val;
}
function setupWholesaleUI(product) {
if (!product || product.querySelector('.wholesale-wrapper')) return;
const optNames = product.querySelectorAll('.js-product-option-name');
const target = Array.from(optNames).find(el => el.textContent.trim() === sizeLabel);
if (!target) return;
const wrap = target.closest('.js-product-option');
if (!wrap) return;
wrap.classList.add('wholesale', 't-text');
const sel = wrap.querySelector('select');
if (sel) sel.disabled = true;
if (!wholesale) return;
let curr = '';
const currEl = product.querySelector('div[class*="_price-currency"]');
if (currEl && currEl.textContent.trim()) curr = currEl.textContent.trim();
if (sel && sel.options.length > 0) {
let html = '';
Array.from(sel.options).forEach(opt => {
const txt = opt.textContent.trim();
const pr = opt.getAttribute('data-product-variant-price') || '';
if (txt && pr) {
html += `<li data-threshold="${getFirstNumber(opt.value)}">${txt}</li>`;
}
});
wrap.insertAdjacentHTML('afterbegin', `
<div class="wholesale-wrapper">
<div class="wholesale-title">${wholesaleTitle}</div>
<ul class="wholesale-option">${html}</ul>
</div>`);
}
}
function getStepAndMin(product) {
const optNames = product.querySelectorAll('.js-product-option-name');
const target = Array.from(optNames).find(el => el.textContent.trim() === sizeLabel);
let min = 1;
if (target) {
const sel = target.closest('.js-product-option')?.querySelector('select');
if (sel?.options?.length) min = getFirstNumber(sel.options[0].value) || 1;
}
return { step: min === 1 ? STEP_FOR_ONE : STEP_FOR_MANY, min };
}
function selectBestOption(product, qty) {
const target = Array.from(product.querySelectorAll('.js-product-option-name'))
.find(el => el.textContent.trim() === sizeLabel);
if (!target) return;
const sel = target.closest('.js-product-option')?.querySelector('select');
if (!sel?.options.length) return;
const opts = Array.from(sel.options).map(o => ({el: o, v: getFirstNumber(o.value)})).sort((a,b)=>a.v-b.v);
let best = opts[0];
for (const o of opts) { if (o.v <= qty) best = o; else break; }
if (sel.value !== best.el.value) {
sel.value = best.el.value;
sel.dispatchEvent(new Event('change', { bubbles: true }));
setTimeout(() => { createTotalWrapper(product); updateActiveRule(product); }, 200);
} else {
updateActiveRule(product);
}
}
function updateActiveRule(product) {
const target = Array.from(product.querySelectorAll('.js-product-option-name'))
.find(el => el.textContent.trim() === sizeLabel);
if (!target) return;
const sel = target.closest('.js-product-option')?.querySelector('select');
if (!sel) return;
const cur = getFirstNumber(sel.value);
const w = product.querySelector('.wholesale-wrapper');
if (!w) return;
w.querySelectorAll('.wholesale-option li').forEach(li => {
li.classList.toggle('active-rule', parseInt(li.dataset.threshold) === cur);
});
}
function parsePrice(t) {
if (!t) return NaN;
return parseFloat(t.replace(/[^\d.,]/g, '').replace(',', '.'));
}
function createTotalWrapper(p) {
const inp = p.querySelector('.t-store__prod__quantity-input');
if (!inp) return;
const q = parseInt(inp.value);
if (isNaN(q) || q <= 0) return;
const pw = p.querySelector('.js-store-price-wrapper');
if (!pw) return;
const pe = pw.querySelector('.js-product-price');
if (!pe) return;
const pr = parsePrice(pe.textContent);
if (isNaN(pr) || pr <= 0) return;
let c = '';
const ce = p.querySelector('div[class*="_price-currency"]');
if (ce) c = ce.textContent.trim();
const tot = Math.round(pr * q * 100) / 100;
pw.setAttribute('data-total-label', `${pr} x ${q} = ${tot} ${c}`.trim());
pw.classList.add('t-text');
window.dispatchEvent(new Event('resize', { bubbles: true }));
}
function handleBlur(e) {
const inp = e.target;
const p = inp.closest('.js-product');
if (!p) return;
const { min } = getStepAndMin(p);
let v = parseInt(inp.value) || min;
if (v < min) v = min;
inp.value = v; cacheQty(p, v);
inp.dispatchEvent(new Event('change', { bubbles: true }));
createTotalWrapper(p); selectBestOption(p, v); updateActiveRule(p);
}
function initProduct(p) {
if (!p || p.dataset.qtyLocked) return;
const inp = p.querySelector('.t-store__prod__quantity-input');
const pe = p.querySelector('.js-product-price');
if (!inp || !pe) return;
p.dataset.qtyLocked = "true";
const { min, step } = getStepAndMin(p);
inp.value = min; cacheQty(p, min);
inp.dispatchEvent(new Event('input', { bubbles: true }));
inp.dispatchEvent(new Event('change', { bubbles: true }));
setTimeout(() => { createTotalWrapper(p); selectBestOption(p, min); updateActiveRule(p); }, 150);
setTimeout(() => {
if (parseInt(inp.value) < min) {
inp.value = min; cacheQty(p, min);
inp.dispatchEvent(new Event('change', { bubbles: true }));
createTotalWrapper(p); updateActiveRule(p);
}
}, 350);
if (!inp._blurAttached) {
inp.addEventListener('blur', handleBlur);
inp._blurAttached = true;
}
setupWholesaleUI(p);
}
function runInit() {
document.querySelectorAll('.js-product:not([data-qty-locked])').forEach(p => {
if (allProducts || hasWholesaleOption(p)) {
p.classList.add('wholesale-product');
initProduct(p);
}
});
}
runInit();
document.querySelectorAll('.js-store-grid-cont, .js-product-single, .t-store__relevants-grid-cont').forEach(el => {
['tStoreRendered', 'tStoreSingleProductsLoaded'].forEach(e => el.addEventListener(e, () => setTimeout(runInit, 150)));
});
document.addEventListener('click', e => { if(e.target.closest('a[href*="/tproduct/"], a[href^="#order"]')) setTimeout(runInit, 300); });
document.addEventListener('change', e => { if(e.target.closest('.js-product-controls-wrapper')) setTimeout(runInit, 150); });
document.addEventListener('input', e => {
if (e.target.matches('.t-store__prod__quantity-input')) {
const p = e.target.closest('.js-product');
if (p) cacheQty(p, e.target.value);
}
});
document.addEventListener('click', function(ev) {
const plus = ev.target.closest('.t-store__prod__quantity__plus-wrapper');
if (plus) {
const p = plus.closest('.js-product');
if (!allProducts && !hasWholesaleOption(p)) return;
ev.stopImmediatePropagation(); ev.preventDefault();
const { step, min } = getStepAndMin(p);
const inp = plus.closest('.t-store__prod__quantity')?.querySelector('.t-store__prod__quantity-input');
if (inp) {
let v = parseInt(inp.value) || min;
v = (min === 1 && v === 1) ? STEP_FOR_ONE : v + step;
inp.value = v; cacheQty(p, v);
inp.dispatchEvent(new Event('change', { bubbles: true }));
createTotalWrapper(p); selectBestOption(p, v); updateActiveRule(p);
}
return;
}
const minus = ev.target.closest('.t-store__prod__quantity__minus-wrapper');
if (minus) {
const p = minus.closest('.js-product');
if (!allProducts && !hasWholesaleOption(p)) return;
ev.stopImmediatePropagation(); ev.preventDefault();
const { step, min } = getStepAndMin(p);
const inp = minus.closest('.t-store__prod__quantity')?.querySelector('.t-store__prod__quantity-input');
if (inp) {
let v = parseInt(inp.value) || min;
v = Math.max(min, v - step);
inp.value = v; cacheQty(p, v);
inp.dispatchEvent(new Event('change', { bubbles: true }));
createTotalWrapper(p); selectBestOption(p, v); updateActiveRule(p);
}
}
}, true);
let _cartIdx = null;
document.addEventListener('focusin', e => {
const inp = e.target.closest('.t706__product-quantity-inp');
if (inp) _cartIdx = inp.closest('.t706__product')?.dataset.cartProductI;
});
if (typeof t_onReady === 'function') {
t_onReady(() => setTimeout(() => { if (typeof t_onFuncLoad === 'function') t_onFuncLoad('tcart__init', changeCart); }, 200));
}
function changeCart(){
function getCartStep(prod) {
if (!prod.wholesale_option) return 1;
const t = Object.keys(prod.wholesale_option).map(Number);
if (!t.length) return 1;
return Math.min(...t) === 1 ? STEP_FOR_ONE : STEP_FOR_MANY;
}
if (typeof tcart__product__plus === 'function') {
const orig = tcart__product__plus;
tcart__product__plus = function(btn) {
const el = btn.closest(".t706__product");
const i = el?.dataset.cartProductI;
if (!i || !window.tcart?.products?.[i]) return orig(btn);
const prod = window.tcart.products[i];
const step = getCartStep(prod);
const minT = prod.wholesale_option ? Math.min(...Object.keys(prod.wholesale_option).map(Number)) : 1;
if (prod.inv > 0 && prod.inv === prod.quantity) {
if (typeof tcart_dict === 'function') alert(tcart_dict("limitReached"));
return;
}
if (prod.wholesale_option && minT === 1 && prod.quantity === 1) prod.quantity = STEP_FOR_ONE;
else prod.quantity += step;
prod.amount = typeof tcart__roundPrice === 'function' ? tcart__roundPrice(prod.price * prod.quantity) : Math.round(prod.price * prod.quantity * 100) / 100;
const q = el.querySelector(".t706__product-quantity"); if(q) q.innerHTML = prod.quantity;
if(prod.single === "y" && prod.portion && typeof tcart__showWeight === 'function'){ const p = el.querySelector(".t706__product-portion"); if(p) p.innerHTML = tcart__showWeight(prod.quantity * prod.portion, prod.unit); }
if(prod.amount > 0 && typeof tcart__showPrice === 'function'){ const a = el.querySelector(".t706__product-amount"); if(a) a.innerHTML = tcart__showPrice(prod.amount); }
if(typeof tcart__updateTotalProductsinCartObj==='function') tcart__updateTotalProductsinCartObj();
if(typeof tcart__reDrawCartIcon==='function') tcart__reDrawCartIcon();
if(typeof tcart__reDrawTotal==='function') tcart__reDrawTotal();
if(typeof tcart__saveLocalObj==='function') tcart__saveLocalObj();
};
}
if (typeof tcart__product__minus === 'function') {
const orig = tcart__product__minus;
tcart__product__minus = function(btn) {
const el = btn.closest(".t706__product");
const i = el?.dataset.cartProductI;
if (!i || !window.tcart?.products?.[i]) return orig(btn);
const prod = window.tcart.products[i];
const step = getCartStep(prod);
const minT = prod.wholesale_option ? Math.min(...Object.keys(prod.wholesale_option).map(Number)) : 1;
prod.quantity = prod.wholesale_option ? Math.max(minT, prod.quantity - step) : Math.max(1, prod.quantity - step);
prod.amount = typeof tcart__roundPrice === 'function' ? tcart__roundPrice(prod.price * prod.quantity) : Math.round(prod.price * prod.quantity * 100) / 100;
if(prod.amount > 0 && typeof tcart__showPrice === 'function'){ const a = el.querySelector(".t706__product-amount"); if(a) a.innerHTML = tcart__showPrice(prod.amount); if(prod.single === "y" && prod.portion && typeof tcart__showWeight === 'function'){ const p = el.querySelector(".t706__product-portion"); if(p) p.innerHTML = tcart__showWeight(prod.quantity * prod.portion, prod.unit); } }
const q = el.querySelector(".t706__product-quantity"); if(q) q.innerHTML = prod.quantity;
if(prod.quantity <= 0 && typeof tcart__product__del === 'function') tcart__product__del(btn);
if(typeof tcart__updateTotalProductsinCartObj==='function') tcart__updateTotalProductsinCartObj();
if(typeof tcart__reDrawCartIcon==='function') tcart__reDrawCartIcon();
if(typeof tcart__reDrawTotal==='function') tcart__reDrawTotal();
if(typeof tcart__saveLocalObj==='function') tcart__saveLocalObj();
};
}
}
document.addEventListener('click', function(e) {
const link = e.target.closest('a[href^="#order"]');
if (!link) return;
const p = link.closest('.js-product');
if (!p) return;
const wb = p.querySelector('.wholesale');
if (!wb) return;
const uid = p.dataset.productGenUid;
if (!uid) return;
const sel = wb.querySelector('select');
if (!sel?.options.length) return;
const savedQty = parseInt(p.dataset._qty, 10) || 1;
const wOpt = {};
Array.from(sel.options).forEach(opt => {
const n = getFirstNumber(opt.value);
if (!n) return;
const pr = opt.getAttribute('data-product-variant-price');
if (!pr) return;
wOpt[n] = { option: sizeLabel, variant: opt.textContent.trim(), price: parseFloat(pr) };
});
setTimeout(() => {
if (!window.tcart?.products) return;
let upd = false;
for (const id in window.tcart.products) {
const prod = window.tcart.products[id];
if (prod.gen_uid === uid) {
prod.wholesale_option = wOpt;
upd = true;
checkWholesalePrice(id);
}
}
if (upd && typeof tcart__saveLocalObj === 'function') tcart__saveLocalObj();
if (savedQty > 1) {
setTimeout(() => {
const inp = p.querySelector('.t-store__prod__quantity-input');
if (inp && !inp.disabled) {
inp.value = savedQty; cacheQty(p, savedQty);
inp.dispatchEvent(new Event('input', { bubbles: true }));
inp.dispatchEvent(new Event('change', { bubbles: true }));
createTotalWrapper(p); selectBestOption(p, savedQty); updateActiveRule(p);
}
}, 200);
}
}, 300);
}, false);
function checkWholesalePrice(i) {
if (!window.tcart?.products?.[i]) return;
const prod = window.tcart.products[i];
if (!prod.wholesale_option) return;
const qty = prod.quantity;
const w = prod.wholesale_option;
const th = Object.keys(w).map(Number).sort((a,b)=>a-b);
let best = th[0];
for (const t of th) { if (t <= qty) best = t; else break; }
const b = w[best];
if (!b) return;
const idx = prod.options?.findIndex(o => o.option === sizeLabel);
if (idx === -1 || idx === undefined) return;
const cur = prod.options[idx];
if (cur.variant !== b.variant || cur.price !== b.price) {
prod.options[idx].variant = b.variant;
prod.options[idx].price = b.price;
prod.price = b.price;
prod.amount = typeof tcart__roundPrice === 'function' ? tcart__roundPrice(b.price * qty) : Math.round(b.price * qty * 100) / 100;
if (typeof tcart__reDrawProducts === 'function') tcart__reDrawProducts();
if (typeof tcart__updateTotalProductsinCartObj === 'function') tcart__updateTotalProductsinCartObj();
if (typeof tcart__reDrawTotal === 'function') tcart__reDrawTotal();
if (typeof tcart__saveLocalObj === 'function') tcart__saveLocalObj();
}
}
document.addEventListener('click', e => {
if (e.target.closest('.t706__product-plus, .t706__product-minus')) {
const p = e.target.closest('.t706__product');
if (p?.dataset.cartProductI) setTimeout(() => checkWholesalePrice(p.dataset.cartProductI), 100);
}
});
document.addEventListener('focusout', e => {
if (e.target.closest('.t706__product-quantity-inp') && _cartIdx != null) setTimeout(() => checkWholesalePrice(_cartIdx), 100);
});
document.addEventListener('change', e => {
if (e.target.closest('.t706__product-quantity-inp') && _cartIdx != null) setTimeout(() => checkWholesalePrice(_cartIdx), 150);
});
})();
});
</script>
<style>
.t706__cartwin-content {
max-width: 800px;
}
.wholesale-option li {
transition: all 0.2s ease;
padding: 4px 8px;
border-radius: 4px;
list-style: none;
}
.wholesale-option li.active-rule {
background: #f0f0f0;
font-weight: 600;
color: #000;
}
.js-product.wholesale-product .js-store-price-wrapper:after {
content: "Всего: " attr(data-total-label);
display: block;
font-size: 14px;
}
.wholesale-wrapper {
margin-bottom: 15px;
padding: 10px;
background: #f8f9fa;
border-radius: 6px;
font-size: 14px;
}
.wholesale-title {
font-weight: 600;
margin-bottom: 8px;
}
#allrecords .wholesale-option {
list-style: none;
padding: 0;
margin: 0;
}
.wholesale-option li {
padding: 4px 0;
border-bottom: 1px dashed #ddd;
font-size: 12px;
}
.wholesale-option li:last-child {
border-bottom: none;
}
.js-product-option.wholesale select[disabled] {
pointer-events: none;
opacity: 0.5;
}
.wholesale .js-product-option-name,
.wholesale .t-product__option-variants
{
display: none;
}
.js-product-controls-wrapper.t-store__card__prod-controls-wrapper {
padding-top: 10px;
}
</style>