Elements Blocker

Long press to enter picker mode, click element to hide it forever

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name         Elements Blocker
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Long press to enter picker mode, click element to hide it forever
// @author       smoochie
// @match        *://*/*
// @run-at       document-end
// @grant        none
// @license      MIT
// ==/UserScript==



(function () {
  'use strict';



  const STORAGE_KEY = 'element-blocker';
  const LONG_PRESS_MS = 600;



  let pickerActive = false;
  let pressTimer = null;
  let highlighted = null;



  function getStored() {
    try {
      return JSON.parse(localStorage.getItem(STORAGE_KEY) || '{}');
    } catch { return {}; }
  }



  function applyStored() {
    const all = getStored();
    const host = location.hostname;
    const selectors = all[host] || [];
    selectors.forEach(sel => {
      try {
        document.querySelectorAll(sel).forEach(el => {
          el.style.cssText = 'display:none!important';
        });
      } catch {}
    });
  }



  function saveSelector(sel) {
    const all = getStored();
    const host = location.hostname;
    if (!all[host]) all[host] = [];
    if (!all[host].includes(sel)) {
      all[host].push(sel);
      localStorage.setItem(STORAGE_KEY, JSON.stringify(all));
    }
  }


  function getSelector(el) {
    if (el.id) return `#${CSS.escape(el.id)}`;


    const parts = [];
    let current = el;
    while (current && current !== document.body) {
      let part = current.tagName.toLowerCase();



      if (current.id) {
        part = `#${CSS.escape(current.id)}`;
        parts.unshift(part);
        break;
      }


      if (current.className && typeof current.className === 'string') {
        const classes = current.className.trim().split(/\s+/).slice(0, 2);
        part += '.' + classes.map(c => CSS.escape(c)).join('.');
      }


      const siblings = current.parentElement
        ? [...current.parentElement.children].filter(c => c.tagName === current.tagName)
        : [];
      if (siblings.length > 1) {
        const idx = siblings.indexOf(current) + 1;
        part += `:nth-of-type(${idx})`;
      }



      parts.unshift(part);
      current = current.parentElement;
    }



    return parts.join(' > ');
  }



  function showToast(msg, color = '#1a3a5c') {
    const old = document.getElementById('eb-toast');
    if (old) old.remove();


    const toast = document.createElement('div');
    toast.id = 'eb-toast';
    toast.textContent = msg;
    toast.style.cssText = `
      position: fixed;
      bottom: 30px;
      left: 50%;
      transform: translateX(-50%);
      background: ${color};
      color: #fff;
      padding: 10px 20px;
      font-size: 14px;
      font-family: sans-serif;
      z-index: 2147483647;
      pointer-events: none;
      white-space: nowrap;
    `;
    document.body.appendChild(toast);
    setTimeout(() => toast.remove(), 2500);
  }


  function highlight(el) {
    if (highlighted === el) return;
    clearHighlight();
    highlighted = el;
    el.dataset.ebOutline = el.style.outline || '';
    el.style.outline = '2px solid red';
    el.style.outlineOffset = '2px';
  }



  function clearHighlight() {
    if (highlighted) {
      highlighted.style.outline = highlighted.dataset.ebOutline || '';
      delete highlighted.dataset.ebOutline;
      highlighted = null;
    }
  }


  function enterPicker() {
    pickerActive = true;
    showToast('🔴 Selection mode - click on an item to hide it');
    document.body.style.cursor = 'crosshair';
  }


  function exitPicker() {
    pickerActive = false;
    clearHighlight();
    document.body.style.cursor = '';
  }


  document.addEventListener('touchstart', e => {
    pressTimer = setTimeout(() => {
      if (!pickerActive) enterPicker();
      else exitPicker();
    }, LONG_PRESS_MS);
  }, { passive: true });



  document.addEventListener('touchend', () => {
    clearTimeout(pressTimer);
  }, { passive: true });



  document.addEventListener('touchmove', () => {
    clearTimeout(pressTimer);
  }, { passive: true });



  document.addEventListener('mouseover', e => {
    if (!pickerActive) return;
    highlight(e.target);
  });



  document.addEventListener('click', e => {
    if (!pickerActive) return;
    e.preventDefault();
    e.stopPropagation();


    const el = e.target;
    const sel = getSelector(el);
    saveSelector(sel);
    el.style.cssText = 'display:none!important';
    showToast('✅ The element has been hidden and saved', '#1a6644');
    exitPicker();
  }, true);


  document.addEventListener('keydown', e => {
    if (e.key === 'Escape' && pickerActive) {
      exitPicker();
      showToast('❌ Selection mode has been canceled', '#888');
    }
  });

  applyStored();

  setTimeout(applyStored, 1500);
  setTimeout(applyStored, 4000);

  const observer = new MutationObserver(applyStored);
  observer.observe(document.body, { childList: true, subtree: true });

})();