// ==UserScript== // @name מתמחים טופ - סינון נושאים לפי תגיות (גלובלי) // @namespace http://tampermonkey.net/ // @version 4.1 // @description סינון נושאים לפי תגיות בכל חלקי האתר, כולל טעינה דינמית וגלילה. // @match https://mitmachim.top/* // @match https://www.mitmachim.top/* // @grant none // ==/UserScript== (function () { 'use strict'; let currentRows = []; let currentTagInfos = []; let filterPanel = null; let debounceTimer = null; function getTagFromRow(row) { const link = row.querySelector('h3[component="topic/header"] a.text-reset, a.topic-title, .content a'); if (!link) return ''; const span = link.querySelector('span') || row.querySelector('.tag'); if (!span) return ''; const clone = span.cloneNode(true); clone.querySelectorAll('i, svg').forEach(el => el.remove()); return clone.textContent.replace(/\s+/g, ' ').trim(); } function slugifyTag(tag) { return tag .replace(/\s+/g, '-') .replace(/[^\w\u0590-\u05FF-]/g, ''); } function getSelectedSlugs() { if (!filterPanel) return []; return Array.from(filterPanel.querySelectorAll('input[type="checkbox"]:checked')) .map(chk => chk.value); } function addTagClasses(rows) { const tagSet = new Set(); rows.forEach(row => { const tag = getTagFromRow(row); if (!tag) return; const slug = slugifyTag(tag); row.classList.add('topic-tag-' + slug); tagSet.add(JSON.stringify({ tag, slug })); }); return Array.from(tagSet).map(str => JSON.parse(str)); } function ensureGlobalCSS() { if (document.getElementById('topics-tag-filter-css')) return; const css = ` li.category-item, li[component="category/topic"], tr.category-item { display: flex; } body.has-topic-filter li.category-item, body.has-topic-filter li[component="category/topic"], body.has-topic-filter tr.category-item { display: none !important; } body.has-topic-filter li.category-item.topic-tag-selected, body.has-topic-filter li[component="category/topic"].topic-tag-selected, body.has-topic-filter tr.category-item.topic-tag-selected { display: flex !important; } `; const style = document.createElement('style'); style.id = 'topics-tag-filter-css'; style.textContent = css; document.documentElement.appendChild(style); } function createOrUpdateFilterPanel(list, tagInfos) { ensureGlobalCSS(); if (filterPanel && !document.body.contains(filterPanel)) { filterPanel = null; currentTagInfos = []; } if (!filterPanel) { const panel = document.createElement('div'); panel.style.margin = '10px 0'; panel.style.padding = '10px'; panel.style.border = '1px solid #ccc'; panel.style.background = '#f9f9f9'; panel.style.display = 'flex'; panel.style.flexWrap = 'wrap'; panel.style.alignItems = 'center'; panel.style.gap = '8px'; panel.style.direction = 'rtl'; panel.style.borderRadius = '6px'; panel.style.zIndex = '999'; const title = document.createElement('span'); title.textContent = 'סינון לפי תגיות:'; title.style.fontWeight = 'bold'; panel.appendChild(title); const clearBtn = document.createElement('button'); clearBtn.type = 'button'; clearBtn.textContent = 'הכול'; clearBtn.style.marginInlineStart = '8px'; clearBtn.style.padding = '2px 6px'; clearBtn.style.fontSize = '12px'; clearBtn.style.cursor = 'pointer'; clearBtn.addEventListener('click', () => { panel.querySelectorAll('input[type="checkbox"]').forEach(chk => { chk.checked = false; }); applyFilter([]); }); panel.appendChild(clearBtn); const tagsContainer = document.createElement('div'); tagsContainer.className = 'tags-container'; tagsContainer.style.display = 'flex'; tagsContainer.style.flexWrap = 'wrap'; tagsContainer.style.gap = '6px'; tagsContainer.style.alignItems = 'center'; panel.appendChild(tagsContainer); const note = document.createElement('span'); note.textContent = ' (אפשר לבחור כמה תגיות; מוצגים נושאים שיש להם לפחות אחת מהן)'; note.style.fontSize = '11px'; note.style.color = '#666'; note.style.width = '100%'; panel.appendChild(note); if (list && list.parentElement) { list.parentElement.insertBefore(panel, list); } else { const contentArea = document.querySelector('#content, #ajaxify, main') || document.body; contentArea.prepend(panel); } panel.addEventListener('change', () => { const selected = getSelectedSlugs(); applyFilter(selected); }); filterPanel = panel; } const tagsContainer = filterPanel.querySelector('.tags-container'); if (!tagsContainer) return; const existingSlugs = new Set(Array.from(tagsContainer.querySelectorAll('input[type="checkbox"]')).map(chk => chk.value)); const selectedBefore = new Set(getSelectedSlugs()); tagInfos.forEach(info => { if (existingSlugs.has(info.slug)) return; const wrapper = document.createElement('label'); wrapper.style.display = 'flex'; wrapper.style.alignItems = 'center'; wrapper.style.gap = '4px'; wrapper.style.fontSize = '12px'; wrapper.style.cursor = 'pointer'; const chk = document.createElement('input'); chk.type = 'checkbox'; chk.value = info.slug; if (selectedBefore.has(info.slug)) chk.checked = true; const span = document.createElement('span'); span.textContent = info.tag; wrapper.appendChild(chk); wrapper.appendChild(span); tagsContainer.appendChild(wrapper); }); } function applyFilter(selectedSlugs) { const rows = currentRows; if (!rows.length) return; if (!selectedSlugs || !selectedSlugs.length) { document.body.classList.remove('has-topic-filter'); rows.forEach(row => { row.classList.remove('topic-tag-selected'); row.style.display = ''; }); return; } document.body.classList.add('has-topic-filter'); rows.forEach(row => { const hasAny = selectedSlugs.some(slug => row.classList.contains('topic-tag-' + slug)); if (hasAny) { row.classList.add('topic-tag-selected'); } else { row.classList.remove('topic-tag-selected'); } }); } function rescan() { const root = document.querySelector('#ajaxify') || document.querySelector('#content') || document.body; if (!root) return; const rows = Array.from(root.querySelectorAll('li.category-item, li[component="category/topic"], tr.category-item')); if (!rows.length) return; currentRows = rows; const tagInfos = addTagClasses(rows); currentTagInfos = mergeTagInfos(currentTagInfos, tagInfos); const list = rows[0].parentElement; createOrUpdateFilterPanel(list, currentTagInfos); const selected = getSelectedSlugs(); if (selected.length) { applyFilter(selected); } } function mergeTagInfos(oldInfos, newInfos) { const map = new Map(); [...oldInfos, ...newInfos].forEach(info => { map.set(info.slug, info); }); return Array.from(map.values()); } function start() { rescan(); const targetNode = document.querySelector('#ajaxify') || document.querySelector('#content') || document.body; if (!targetNode) return; const observer = new MutationObserver((mutations) => { const hasAddedNodes = mutations.some(m => m.type === 'childList' && m.addedNodes.length > 0); if (hasAddedNodes) { clearTimeout(debounceTimer); debounceTimer = setTimeout(() => { rescan(); }, 200); } }); observer.observe(targetNode, { childList: true, subtree: true }); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', start); } else { start(); } })();