您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Hides all listings without a "Call" option
// ==UserScript== // @name Hide Fake Dubizzle/Olx Listings // @namespace Violentmonkey Scripts // @match https://www.dubizzle.*/* // @grant none // @version 1.0 // @author swanknight // @description Hides all listings without a "Call" option // @icon https://www.google.com/s2/favicons?domain=www.dubizzle.com // @license GPLv3 // ==/UserScript== (function () { 'use strict'; const HIDE_CLASS = 'hide-listing-no-call-js'; // Insert minimal CSS to hide matched items const style = document.createElement('style'); style.textContent = `.${HIDE_CLASS} { display: none !important; }`; document.head.appendChild(style); function processListing(li) { if (!(li instanceof HTMLElement)) return; if (li.getAttribute('aria-label') !== 'Listing') return; // find any descendant div with aria-label="Call" const hasCallDiv = li.querySelector('div[aria-label="Call"]') !== null; if (!hasCallDiv) li.classList.add(HIDE_CLASS); else li.classList.remove(HIDE_CLASS); } function scanAll() { const listItems = document.querySelectorAll('li[aria-label="Listing"]'); listItems.forEach(processListing); } // Initial pass when DOM is ready if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', scanAll, { once: true }); } else { scanAll(); } // Observe for dynamically added/changed listings const observer = new MutationObserver(mutations => { const toCheck = new Set(); for (const m of mutations) { if (m.type === 'childList') { m.addedNodes.forEach(node => { if (node.nodeType !== 1) return; const el = node; if (el.matches && el.matches('li[aria-label="Listing"]')) toCheck.add(el); // also if an added subtree contains listing(s) el.querySelectorAll && el.querySelectorAll('li[aria-label="Listing"]').forEach(n => toCheck.add(n)); // if a descendant div with aria-label="Call" was added somewhere, re-scan ancestor listing(s) if (el.matches && el.matches('div[aria-label="Call"]')) { let ancestor = el.closest('li[aria-label="Listing"]'); if (ancestor) toCheck.add(ancestor); } el.querySelectorAll && el.querySelectorAll('div[aria-label="Call"]').forEach(div => { const ancestor = div.closest && div.closest('li[aria-label="Listing"]'); if (ancestor) toCheck.add(ancestor); }); }); m.removedNodes.forEach(node => { if (node.nodeType !== 1) return; const el = node; if (el.matches && el.matches('li[aria-label="Listing"]')) toCheck.add(el.parentElement); // parent may need re-check el.querySelectorAll && el.querySelectorAll('li[aria-label="Listing"]').forEach(n => toCheck.add(n.parentElement)); }); } else if (m.type === 'attributes') { const target = m.target; // If aria-label changed on a div or li, re-check the closest listing if (target instanceof Element) { const listing = target.closest && target.closest('li[aria-label="Listing"]'); if (listing) toCheck.add(listing); } } } // If nothing specific, do a lightweight rescan if (toCheck.size === 0) { scanAll(); } else { toCheck.forEach(item => item && processListing(item)); } }); observer.observe(document.documentElement || document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['aria-label'] }); })();