20) return cb(); // не блокируем навсегда
setTimeout(() => waitSmartFilter(cb, tries + 1), 150);
}
// Удаляем ранее добавленные быстрые блоки (чтобы не дублировать)
function clearQuickFilters() {
const wrapper = q('.catalog-list__filtersort__filter');
if (!wrapper) return;
const items = wrapper.querySelectorAll('[data-quickfilter]');
items.forEach(i => i.remove());
}
// Создаёт html блока quickfilter на основе исходного контейнера $box
function buildQuickFilterFromBox($box) {
if (!$box) return null;
const $hintTitle = $box.querySelector('.bx-filter-parameters-box-hint .title');
const title = $hintTitle ? $hintTitle.textContent.trim() : ($box.getAttribute('data-title') || 'Фильтр');
const items = $box.querySelectorAll('.bx-filter-item');
if (!items.length) return null;
// Собираем элементы
let html = '
Все
';
items.forEach(it => {
const input = it.querySelector('input[type=checkbox]');
const id = input ? (input.id || input.getAttribute('name') || input.value) : null;
if (!id) return;
const textEl = it.querySelector('.bx-filter-param-text');
const titleText = textEl ? (textEl.getAttribute('title') || textEl.textContent) : it.textContent;
const safeTitle = (document.createElement('div')).appendChild(document.createTextNode(titleText.trim())).parentNode.textContent;
const activeClass = window._activeQuickFilters.has(id) ? ' active' : '';
html += `
${safeTitle}
`;
});
const block = document.createElement('div');
block.className = 'catalog-list__filtersort__filter-item dropdown';
block.setAttribute('data-quickfilter', title);
block.innerHTML = `
${title}
${html}
`;
return block;
}
// Универсальная функция добавления блока по селектору (jQuery-подобно)
function addQuickFilterBlock(selector) {
const $box = document.querySelector(selector);
if (!$box) return;
const wrapper = q('.catalog-list__filtersort__filter');
if (!wrapper) return;
const block = buildQuickFilterFromBox($box);
if (block) wrapper.appendChild(block);
}
window.addQuickFilterBlock = addQuickFilterBlock;
// Обработка клика по верхнему пункту
function onQuickFilterClick(ev) {
const item = ev.target.closest('.quickfilter-item');
if (!item) return;
ev.preventDefault();
// all
if (item.classList.contains('all')) {
const list = item.closest('.dropdown-list');
if (!list) return;
// снимаем все метки и реальное состояние
const items = list.querySelectorAll('.quickfilter-item');
items.forEach(el => {
el.querySelector('.checkbox')?.classList.remove('active');
const id = el.dataset.id;
if (id) {
window._activeQuickFilters.delete(id);
const input = findFilterInputById(id);
if (input && input.checked) triggerInputToggle(input, false);
}
});
// ставим "Все" активным
item.querySelector('.checkbox')?.classList.add('active');
return;
}
const id = item.dataset.id;
const chk = item.querySelector('.checkbox');
const willBeActive = !chk.classList.contains('active');
// переключаем визуально
chk.classList.toggle('active', willBeActive);
// сохраняем состояние
if (willBeActive) window._activeQuickFilters.add(id);
else window._activeQuickFilters.delete(id);
// находим реальный input и триггерим его
const input = findFilterInputById(id);
if (!input) {
console.warn('Не найден input для quickfilter id=', id);
return;
}
// Важно: ставим checked и диспатчим события, чтобы smartFilter подхватил
waitSmartFilter(() => {
triggerInputToggle(input, willBeActive);
});
}
// Построение блоков по URL (вставил ваши правила)
function buildQuickFiltersByUrl() {
clearQuickFilters();
const url = window.location.pathname.toLowerCase();
// Поиск
if (url.includes('/search.php')) {
addQuickFilterBlock('.MATERIAL');
addQuickFilterBlock('.TIP');
}
// Только главная страница каталога
if (url === '/catalog/' || url === '/catalog') {
addQuickFilterBlock('.SECTIONS');
addQuickFilterBlock('.MATERIAL');
}
if (url.includes('/chasy/') || url.includes('/sections-is-chasy/')) {
addQuickFilterBlock('.FOR_WHO');
addQuickFilterBlock('.WATCH_TYPE_MECH');
}
if (url.includes('/koltsa/') || url.includes('/sections-is-koltsa/')) {
addQuickFilterBlock('.SIZE');
addQuickFilterBlock('.MATERIAL');
}
if (url.includes('/sergi/') || url.includes('/sections-is-sergi-or-sergi/') || url.includes('/sections-is-sergi/')) {
addQuickFilterBlock('.TIP');
addQuickFilterBlock('.MATERIAL');
}
if (url.includes('/braslety/') || url.includes('/sections-is-braslety-or-braslety/') || url.includes('/sections-is-braslety/')) {
addQuickFilterBlock('.PLETENIE');
addQuickFilterBlock('.MATERIAL');
}
if (url.includes('/tsepi/') || url.includes('/sections-is-tsepi/')) {
addQuickFilterBlock('.PLETENIE');
addQuickFilterBlock('.MATERIAL');
}
if (url.includes('/collections/')) {
addQuickFilterBlock('.SECTIONS');
addQuickFilterBlock('.TIP');
}
if (url.includes('/obrazy/')) {
addQuickFilterBlock('.SECTIONS');
addQuickFilterBlock('.MATERIAL');
}
// === Специальное условие для крестиков ===
if (url.includes('/tip-is-krestik/')) {
addQuickFilterBlock('.STYLE');
}
}
window.buildQuickFiltersByUrl = buildQuickFiltersByUrl;
// Восстановить визуальное состояние quickfilter'ов из window._activeQuickFilters
function restoreQuickFilterVisuals() {
const items = qa('.quickfilter-item');
items.forEach(it => {
const id = it.dataset.id;
const checkbox = it.querySelector('.checkbox');
if (!id || !checkbox) return;
checkbox.classList.toggle('active', window._activeQuickFilters.has(id));
});
}
// Вставляет обработчик и собирает initial quickfilters
function initQuickFilter() {
buildQuickFiltersByUrl();
restoreQuickFilterVisuals();
const wrapper = q('.catalog-list__filtersort__filter');
if (wrapper) {
wrapper.removeEventListener('click', onQuickFilterClick);
wrapper.addEventListener('click', onQuickFilterClick);
}
}
// --- Реакция на AJAX / смену URL / ready ---
// Bitrix AJAX событие
if (typeof BX !== 'undefined' && BX.addCustomEvent) {
BX.addCustomEvent('onAjaxSuccess', function () {
// после перерисовки фильтра нужно восстановить верхние блоки
setTimeout(() => {
buildQuickFiltersByUrl();
restoreQuickFilterVisuals();
hideZeroFilterValues();
}, 120);
});
}
// Наблюдение за pushState (если Bitrix меняет URL)
(function observeUrlChanges() {
let last = location.href;
function tick() {
if (location.href !== last) {
last = location.href;
setTimeout(() => {
buildQuickFiltersByUrl();
restoreQuickFilterVisuals();
}, 120);
}
requestAnimationFrame(tick);
}
tick();
})();
// DOM ready
document.addEventListener('DOMContentLoaded', function () {
initQuickFilter();
setTimeout(hideZeroFilterValues, 200);
});
})();
// Работа с выводом фильтра для разных категории
document.addEventListener('DOMContentLoaded', function() {
// 🔧 Правила отображения фильтров
let filterRules = {
CHASY: ['WATCH_BRAND', 'WATCH_TYPE_MECH', 'WATCH_TYPE_MECH2', 'FOR_WHO', 'PRICES', 'WATCH_GLASS',
'WATCH_FUNCTION', 'WATCH_WATER', 'WATCH_DIAMETER', 'WATCH_BODY_MATERIAL', 'WATCH_CASE_SHAPE',
'WATCH_BODY_COLOR', 'WATCH_TYPE_FACE', 'WATCH_COLOR_FACE', 'WATCH_COLOR_STRAP', 'WATCH_TYPE_STRAP',
'WATCH_ROCK', 'SHOP', 'MATERIAL', 'METAL_PROBE', 'COLLECTION', 'DISCOUNTS', 'ZODIAC', 'SUBJECT',
'PRESENT', 'BESTSELLER',],
KOLTSA: ['FOR_WHO', 'PRICES', 'SIZE', 'LETTER', 'BESTSELLER',
'ROCK', 'ROCK_COLOR', 'ROCK_SHAPE',
'SHOP', 'MATERIAL', 'METAL_PROBE', 'COLLECTION',
'DISCOUNTS', 'ZODIAC', 'SUBJECT', 'PRESENT', 'TIP'],
SERGI: ['FOR_WHO', 'PRICES', 'PLETENIE', 'LETTER', 'BESTSELLER',
'ROCK', 'ROCK_COLOR', 'ROCK_SHAPE',
'SHOP', 'MATERIAL', 'METAL_PROBE', 'COLLECTION',
'DISCOUNTS', 'ZODIAC', 'SUBJECT', 'PRESENT', 'TIP'],
BRASLETY: ['FOR_WHO', 'PRICES', 'SIZE', 'PLETENIE', 'LETTER', 'BESTSELLER',
'ROCK', 'ROCK_COLOR', 'ROCK_SHAPE','ZASTEJKA', 'DIAMETR',
'SHOP', 'MATERIAL', 'METAL_PROBE', 'COLLECTION',
'DISCOUNTS', 'ZODIAC', 'SUBJECT', 'PRESENT', 'TIP'],
TSEPI: ['FOR_WHO', 'PRICES', 'SIZE', 'PLETENIE', 'LETTER', 'BESTSELLER','ZASTEJKA', 'DIAMETR',
'SHOP', 'MATERIAL', 'METAL_PROBE', 'COLLECTION',
'DISCOUNTS', 'ZODIAC', 'SUBJECT','PRESENT'],
KRESTIKI: ['FOR_WHO', 'PRICES', 'SIZE', 'LETTER', 'BESTSELLER',
'ROCK', 'ROCK_COLOR', 'ROCK_SHAPE',
'SHOP', 'MATERIAL', 'METAL_PROBE', 'COLLECTION',
'DISCOUNTS', 'ZODIAC', 'SUBJECT', 'PRESENT', 'TIP', 'STYLE'],
BIZHUTERIA: ['FOR_WHO', 'PRICES', 'SIZE', 'LETTER', 'BESTSELLER',
'ROCK', 'ROCK_COLOR', 'ROCK_SHAPE',
'SHOP', 'MATERIAL', 'METAL_PROBE', 'COLLECTION',
'DISCOUNTS', 'ZODIAC', 'SUBJECT', 'PRESENT', 'TIP'],
BUSY: ['FOR_WHO', 'PRICES', 'SIZE', 'LETTER', 'BESTSELLER',
'ROCK', 'ROCK_COLOR', 'ROCK_SHAPE',
'SHOP', 'MATERIAL', 'METAL_PROBE', 'COLLECTION',
'DISCOUNTS', 'ZODIAC', 'SUBJECT', 'PRESENT', 'TIP'],
DETSKOE: ['FOR_WHO', 'PRICES', 'SIZE', 'LETTER', 'BESTSELLER',
'ROCK', 'ROCK_COLOR', 'ROCK_SHAPE',
'SHOP', 'MATERIAL', 'METAL_PROBE', 'COLLECTION',
'DISCOUNTS', 'ZODIAC', 'SUBJECT', 'PRESENT', 'TIP'],
PIRSING: ['FOR_WHO', 'PRICES', 'SIZE', 'LETTER', 'BESTSELLER',
'ROCK', 'ROCK_COLOR', 'ROCK_SHAPE',
'SHOP', 'MATERIAL', 'METAL_PROBE', 'COLLECTION',
'DISCOUNTS', 'ZODIAC', 'SUBJECT', 'PRESENT', 'TIP'],
BROSHI: ['FOR_WHO', 'PRICES', 'SIZE', 'LETTER', 'BESTSELLER',
'ROCK', 'ROCK_COLOR', 'ROCK_SHAPE',
'SHOP', 'MATERIAL', 'METAL_PROBE', 'COLLECTION',
'DISCOUNTS', 'ZODIAC', 'SUBJECT', 'PRESENT', 'TIP'],
BULAVKI: ['FOR_WHO', 'PRICES', 'SIZE', 'LETTER', 'BESTSELLER',
'ROCK', 'ROCK_COLOR', 'ROCK_SHAPE',
'SHOP', 'MATERIAL', 'METAL_PROBE', 'COLLECTION',
'DISCOUNTS', 'ZODIAC', 'SUBJECT', 'PRESENT', 'TIP'],
KOLE: ['FOR_WHO', 'PRICES', 'SIZE', 'LETTER', 'BESTSELLER',
'ROCK', 'ROCK_COLOR', 'ROCK_SHAPE',
'SHOP', 'MATERIAL', 'METAL_PROBE', 'COLLECTION',
'DISCOUNTS', 'ZODIAC', 'SUBJECT', 'PRESENT', 'TIP'],
PODVESKI: ['FOR_WHO', 'PRICES', 'SIZE', 'LETTER', 'BESTSELLER',
'ROCK', 'ROCK_COLOR', 'ROCK_SHAPE',
'SHOP', 'MATERIAL', 'METAL_PROBE', 'COLLECTION',
'DISCOUNTS', 'ZODIAC', 'SUBJECT', 'PRESENT', 'TIP'],
};
const defaultHidden = [
'WATCH_BRAND', 'WATCH_TYPE_MECH', 'WATCH_TYPE_MECH2', 'WATCH_GLASS',
'WATCH_FUNCTION', 'WATCH_WATER', 'WATCH_DIAMETER', 'WATCH_BODY_MATERIAL', 'WATCH_CASE_SHAPE',
'WATCH_BODY_COLOR', 'WATCH_TYPE_FACE', 'WATCH_COLOR_FACE', 'WATCH_COLOR_STRAP', 'WATCH_TYPE_STRAP',
'WATCH_ROCK', 'SIZE', 'PLETENIE', 'WEIGHT_KRT', 'ZASTEJKA', 'DIAMETR',
'RING_HEIGHT', 'LETTER', 'BESTSELLER', 'ROCK_CUT', 'ROCK_CARAT', 'IMAGE','DESIGN','STYLE','TIP',
];
const productCheckboxes = {
CHASY: document.getElementById('section_chasy'),
KOLTSA: document.getElementById('section_koltsa'),
SERGI: document.getElementById('section_sergi'),
BRASLETY: document.getElementById('section_braslety'),
TSEPI: document.getElementById('section_tsepi'),
};
const otherFilterCheckboxes = document.querySelectorAll('.bx-filter-input-checkbox');
let lastType = null;
// Определяем тип каталога по URL
function detectTypeByUrl() {
const url = window.location.pathname.toLowerCase();
// поиск
if (url.includes('/search.php')) {
const params = new URLSearchParams(window.location.search);
const q = (params.get('q') || '').toLowerCase();
console.log('Search query:', q);
if (q.includes('кольц')) return 'KOLTSA';
if (q.includes('серьг')) return 'SERGI';
if (q.includes('брасл')) return 'BRASLETY';
if (q.includes('цеп')) return 'TSEPI';
if (q.includes('час')) return 'CHASY';
}
const urlRules = [
['collections-chasy', 'CHASY'],
// Спец. категории
['tip-is-krestik', 'KRESTIKI'],
['sections-is-bizhuteriya', 'BIZHUTERIA'],
['sections-is-busy', 'BUSY'],
['sections-is-detskoe-serebro', 'DETSKOE'],
['sections-is-pirsing', 'PIRSING'],
['sections-is-broshi-i-bulavki', 'BROSHI'],
['sections-is-bulavki', 'BULAVKI'],
['sections-is-kole', 'KOLE'],
['sections-is-podveski-i-kulony', 'PODVESKI'],
// Основные разделы каталога
['/chasy/', 'CHASY'],
['/koltsa/', 'KOLTSA'],
['/sergi/', 'SERGI'],
['/braslety/', 'BRASLETY'],
['/tsepi/', 'TSEPI'],
];
const match = urlRules.find(([pattern]) => url.includes(pattern));
return match ? match[1] : 'DEFAULT';
}
// Меняем правила по URL
function changeRulesByUrl(selectedType) {
const url = window.location.href.toLowerCase();
// Универсальный список свойств, которые всегда нужно очистить
const clearProps = ['ROCK_CARAT', 'ROCK_CUT'];
const typeRules = filterRules[selectedType];
if (!typeRules) return;
// Очистка базовых свойств для всех типов
filterRules[selectedType] = typeRules.filter(f => !clearProps.includes(f));
// === Общие условия для "бриллиантов" ===
if (url.includes('rock-is-brilliant')) {
filterRules[selectedType].push('ROCK_CARAT', 'ROCK_CUT');
console.log(`💎 Для ${selectedType}: добавлены ROCK_CARAT и ROCK_CUT`);
}
// === КРЕСТИКИ ===
if (url.includes('tip-is-krestik')) {
filterRules[selectedType].push('STYLE');
console.log(`💎 Для ${selectedType}: добавлен STYLE`);
}
// === Специфические правила ===
switch (selectedType) {
case 'KOLTSA':
filterRules.KOLTSA = filterRules.KOLTSA.filter(f => f !== 'RING_HEIGHT');
if (url.includes('tip-is-obruchalnye_koltsa')) {
filterRules.KOLTSA.push('RING_HEIGHT');
console.log('💍 Для KOLTSA добавлен RING_HEIGHT');
}
break;
case 'SERGI':
filterRules.SERGI = filterRules.SERGI.filter(f => f !== 'DIAMETR');
if (url.includes('tip-is-kongo')) {
filterRules.SERGI.push('DIAMETR');
console.log('✨ Для SERGI добавлен DIAMETR');
}
break;
case 'BRASLETY':
case 'TSEPI':
console.log(`🧿 Проверены правила для ${selectedType}`);
break;
}
}
// Основная функция обновления
function updateFiltersVisibility(force = false) {
const filterBoxes = document.querySelectorAll('.bx-filter-parameters-box');
let selectedType = detectTypeByUrl();
if (selectedType === 'DEFAULT') {
for (const [type, checkbox] of Object.entries(productCheckboxes)) {
if (checkbox && checkbox.checked) {
selectedType = type;
break;
}
}
}
changeRulesByUrl(selectedType);
if (!force && selectedType === lastType) return;
lastType = selectedType;
filterBoxes.forEach(box => {
const boxClasses = [...box.classList];
let shouldShow = true;
if (selectedType === 'DEFAULT') {
shouldShow = !defaultHidden.some(cls => boxClasses.includes(cls));
} else {
const visibleClasses = filterRules[selectedType] || [];
shouldShow = visibleClasses.some(cls => boxClasses.includes(cls));
}
box.style.transition = 'opacity 0.3s ease, max-height 0.3s ease';
box.style.overflow = 'hidden';
if (shouldShow) {
box.style.opacity = '1';
box.style.maxHeight = 'fit-content';
box.style.margin = '';
box.style.padding = '';
box.style.pointerEvents = 'auto';
} else {
box.style.opacity = '0';
box.style.maxHeight = '0';
box.style.margin = '0';
box.style.padding = '0';
box.style.pointerEvents = 'none';
}
});
console.log(`⚡ Фильтры обновлены (${selectedType})`);
function safeUpdateQFilter() {
// Проверяем, существует ли функция
if (typeof updateQFilter === 'function') {
if (!$('.catalog-list__filtersort__filter-item').length) {
updateQFilter();
}
} else {
// Если функция ещё не определена — подождать и проверить снова
setTimeout(safeUpdateQFilter, 200);
}
}
// Запускаем безопасную проверку
safeUpdateQFilter();
}
function bindFilterEvents() {
document.querySelectorAll('.bx-filter-input-checkbox').forEach(chk => {
if (chk.dataset.binded === 'Y') {
return;
}
chk.dataset.binded = 'Y';
chk.addEventListener('change', function () {
scrollTriggeredByFilter = true;
const selectedType = detectTypeByUrl();
changeRulesByUrl(selectedType);
setTimeout(() => updateFiltersVisibility(true), 100);
});
});
}
// === Прокрутка после выбора фильтра ===
function scrollToCatalogTop() {
const filterSortBlock = document.querySelector('.show-filter');
if (!filterSortBlock) {
// fallback если блока нет
window.scrollTo({ top: 0, behavior: 'smooth' });
return;
}
const offsetTop = filterSortBlock.getBoundingClientRect().top + window.pageYOffset;
window.scrollTo({
top: offsetTop,
behavior: 'smooth'
});
}
// === Флаг для предотвращения повторных скроллов ===
let scrollTriggeredByFilter = false;
// Следим за Bitrix AJAX — скроллим только если фильтр был выбран вручную
if (typeof BX !== 'undefined') {
BX.addCustomEvent('onAjaxSuccess', function() {
const selectedType = detectTypeByUrl();
changeRulesByUrl(selectedType);
setTimeout(() => {
updateFiltersVisibility(true);
// Скрываем фильтры с количеством 0
// На случай если Bitrix ещё что-то дорисовал
setTimeout(hideZeroFilterValues, 200);
bindFilterEvents(); // <-- добавить
if (scrollTriggeredByFilter) {
scrollToCatalogTop();
scrollTriggeredByFilter = false;
}
}, 100);
});
}
// Слушаем переключение чекбоксов фильтров
bindFilterEvents();
// Отслеживание изменения URL (Bitrix pushState)
let lastUrl = window.location.href;
const observeUrl = () => {
const current = window.location.href;
if (current !== lastUrl) {
lastUrl = current;
console.log('🔗 Обнаружено изменение URL:', current);
const selectedType = detectTypeByUrl();
changeRulesByUrl(selectedType);
setTimeout(() => updateFiltersVisibility(true), 100);
}
requestAnimationFrame(observeUrl);
};
observeUrl();
// Первый запуск
updateFiltersVisibility(true);
});