// ==UserScript== // @name mydealz Script // @namespace http://tampermonkey.net/ // @version 1.8.1 // @description mydealz Deal-Management: Deals filtern und ausblenden, alle Einstellungen per UI verwalten. // @author Moritz Baumeister (https://www.mydealz.de/profile/BobBaumeister), Flo (https://www.mydealz.de/profile/Basics0119) // @license MIT // @match https://www.mydealz.de/* // @icon https://www.google.com/s2/favicons?sz=64&domain=mydealz.de // @grant none // @downloadURL none // ==/UserScript== // Versions-Änderungen: // Fix: Touchscreen: UI lässt sich nun auch auf Geräten mit Touchscreen korrekt benutzen. UI schließt sich jetzt nicht mehr komplett, nachdem ein Wort aus der Liste gelöscht wurde. // Einbinden von Font Awesome für Icons const fontAwesomeLink = document.createElement('link'); fontAwesomeLink.rel = 'stylesheet'; fontAwesomeLink.href = 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css'; document.head.appendChild(fontAwesomeLink); // Add constant for touch detection const IS_TOUCH_DEVICE = ('ontouchstart' in window) || (navigator.maxTouchPoints > 0) || (navigator.msMaxTouchPoints > 0); // --- 1. Initial Setup --- const EXCLUDE_WORDS_KEY = 'excludeWords'; const EXCLUDE_MERCHANTS_KEY = 'excludeMerchantIDs'; const HIDDEN_DEALS_KEY = 'hiddenDeals'; const EXCLUDE_MERCHANTS_DATA_KEY = 'excludeMerchantsData'; const MERCHANT_PAGE_SELECTOR = '.merchant-banner'; // Load data immediately let excludeWords, excludeMerchantIDs, hiddenDeals; let dealThatOpenedSettings = null; // Add at top with other globals let settingsDiv = null; let isSettingsOpen = false; let merchantListDiv = null; let wordsListDiv = null; let uiClickOutsideHandler = null; // Add at top with other globals let activeSubUI = null; // Add at top with other globals try { excludeWords = JSON.parse(localStorage.getItem(EXCLUDE_WORDS_KEY)) || []; excludeMerchantIDs = JSON.parse(localStorage.getItem(EXCLUDE_MERCHANTS_KEY)) || []; hiddenDeals = JSON.parse(localStorage.getItem(HIDDEN_DEALS_KEY)) || []; } catch (error) { excludeWords = []; excludeMerchantIDs = []; hiddenDeals = []; } // --- 1. Core Functions --- function processArticles() { const deals = document.querySelectorAll('article.thread--deal, article.thread--voucher'); deals.forEach(deal => { const dealId = deal.getAttribute('id'); // Check if manually hidden if (hiddenDeals.includes(dealId)) { hideDeal(deal); return; } // Check if should be hidden by rules if (shouldExcludeArticle(deal)) { hideDeal(deal); return; } // Show deal if not excluded deal.style.display = 'block'; deal.style.opacity = '1'; }); } // Define observer const observer = new MutationObserver((mutations) => { mutations.forEach(mutation => { if (mutation.addedNodes.length) { processArticles(); addSettingsButton(); addHideButtons(); } }); }); // Initialize everything (function init() { processArticles(); addSettingsButton(); addHideButtons(); observer.observe(document.body, { childList: true, subtree: true }); })(); // --- 2. Hilfsfunktionen --- function shouldExcludeArticle(article) { const titleElement = article.querySelector('.thread-title'); const merchantLink = article.querySelector('a[href*="merchant-id="]'); if (titleElement && excludeWords.some(word => titleElement.textContent.toLowerCase().includes(word.toLowerCase()))) { return true; } if (merchantLink) { const merchantIDMatch = merchantLink.getAttribute('href').match(/merchant-id=(\d+)/); if (merchantIDMatch) { const merchantID = merchantIDMatch[1]; if (excludeMerchantIDs.includes(merchantID)) { return true; } } } return false; } function hideDeal(deal) { deal.style.display = 'none'; } // Funktion zum Speichern der ausgeblendeten Deals function saveHiddenDeals() { localStorage.setItem(HIDDEN_DEALS_KEY, JSON.stringify(hiddenDeals)); } // Speichern der `excludeWords` und `excludeMerchantIDs` function saveExcludeWords(words) { localStorage.setItem('excludeWords', JSON.stringify(words)); } function loadExcludeWords() { return JSON.parse(localStorage.getItem('excludeWords')) || []; } // Update save function to handle merchant data objects function saveExcludeMerchants(merchantsData) { // Filter out invalid entries const validMerchants = merchantsData.filter(m => m && typeof m.id !== 'undefined' && m.id !== null && typeof m.name !== 'undefined' && m.name !== null ); // Extract IDs for backwards compatibility const ids = validMerchants.map(m => m.id); localStorage.setItem(EXCLUDE_MERCHANTS_KEY, JSON.stringify(ids)); localStorage.setItem(EXCLUDE_MERCHANTS_DATA_KEY, JSON.stringify(validMerchants)); // Update global array excludeMerchantIDs = ids; } // Load function for merchant data function loadExcludeMerchants() { const merchantsData = JSON.parse(localStorage.getItem(EXCLUDE_MERCHANTS_DATA_KEY)) || []; const legacyIds = JSON.parse(localStorage.getItem(EXCLUDE_MERCHANTS_KEY)) || []; // Filter out invalid entries const validMerchants = merchantsData.filter(m => m && typeof m.id !== 'undefined' && m.id !== null && typeof m.name !== 'undefined' && m.name !== null ); // Convert legacy IDs if needed if (validMerchants.length === 0 && legacyIds.length > 0) { return legacyIds .filter(id => id && typeof id !== 'undefined') .map(id => ({ id, name: id })); } return validMerchants; } // Clean up existing data on script init (function cleanupMerchantData() { const merchants = loadExcludeMerchants(); saveExcludeMerchants(merchants); })(); // Fügt Event Listener hinzu, um Auto-Speichern zu ermöglichen function addAutoSaveListeners() { // Event Listener für Eingabefelder const excludeWordsInput = document.getElementById('excludeWordsInput'); excludeWordsInput.addEventListener('input', () => { const newWords = excludeWordsInput.value.split('\n').map(w => w.trim()).filter(Boolean); saveExcludeWords(newWords); excludeWords = newWords; processArticles(); }); const excludeMerchantIDsInput = document.getElementById('excludeMerchantIDsInput'); excludeMerchantIDsInput.addEventListener('input', () => { const newMerchantIDs = excludeMerchantIDsInput.value.split('\n').map(id => id.trim()).filter(Boolean); saveExcludeMerchants(newMerchantIDs); excludeMerchantIDs = newMerchantIDs; processArticles(); }); } // Remove highlighting-related event listeners // UI-Button zum Öffnen der Einstellungen wird nur einmal erstellt const settingsButton = document.createElement('button'); settingsButton.innerHTML = '⚙️'; settingsButton.style.padding = '10px'; settingsButton.style.background = 'transparent'; // Hintergrund transparent machen settingsButton.style.color = 'white'; settingsButton.style.border = 'none'; settingsButton.style.borderRadius = '5px'; settingsButton.style.cursor = 'pointer'; // UI-Button zum Verbergen der Deals wird nur einmal erstellt const hideButton = document.createElement('button'); hideButton.innerHTML = '❌'; hideButton.style.marginLeft = '10px'; hideButton.title = 'Deal verbergen'; // Tooltip hinzufügen hideButton.style.padding = '10px'; hideButton.style.background = 'transparent'; // Hintergrund transparent machen hideButton.style.color = 'white'; hideButton.style.border = 'none'; hideButton.style.borderRadius = '5px'; hideButton.style.cursor = 'pointer'; // Funktion, um das Verbergen der Deals zu ermöglichen hideButton.addEventListener('click', function(event) { const deal = event.target.closest('article'); if (deal) { const dealId = deal.getAttribute('id'); hiddenDeals.push(dealId); saveHiddenDeals(); hideDeal(deal); } }); // Add debug logging to settings button click handler function addSettingsButton() { const deals = document.querySelectorAll('article.thread--deal, article.thread--voucher'); deals.forEach(deal => { if (deal.hasAttribute('data-settings-added')) return; const settingsBtn = document.createElement('button'); settingsBtn.innerHTML = '⚙️'; settingsBtn.className = 'vote-button overflow--visible settings-button'; settingsBtn.title = 'Einstellungen'; settingsBtn.style.cssText = ` border: none; cursor: pointer; height: 32px; width: 32px; display: flex; align-items: center; justify-content: center; font-size: 16px; padding: 0; background: transparent; z-index: 1000; `; settingsBtn.onclick = (e) => { e.preventDefault(); e.stopPropagation(); dealThatOpenedSettings = deal; createSettingsUI(); return false; }; const settingsContainer = document.createElement('div'); settingsContainer.className = 'vote-box settings-container'; settingsContainer.style.cssText = ` display: flex; align-items: center; justify-content: center; margin-left: 8px; height: 32px; width: 32px; border-radius: 50%; background: #f2f2f2; border: 1px solid #e4e4e4; padding: 4px; z-index: 1000; `; settingsContainer.appendChild(settingsBtn); const voteBox = deal.querySelector('.vote-box'); if (voteBox && voteBox.parentNode) { voteBox.parentNode.insertBefore(settingsContainer, voteBox.nextSibling); deal.setAttribute('data-settings-added', 'true'); } }); } // Add to document ready handler document.addEventListener('DOMContentLoaded', () => { processArticles(); addSettingsButton(); }); function addHideButtons() { const deals = document.querySelectorAll('article:not([data-button-added])'); deals.forEach(deal => { if (deal.hasAttribute('data-button-added')) return; const voteTemp = deal.querySelector('.cept-vote-temp'); if (!voteTemp) return; // Remove popover const popover = voteTemp.querySelector('.popover-origin'); if (popover) popover.remove(); const hideButtonContainer = document.createElement('div'); hideButtonContainer.style.cssText = ` position: absolute; left: 0; top: 0; width: 100%; height: 100%; display: none; z-index: 10001; pointer-events: none; `; const hideButton = document.createElement('button'); hideButton.innerHTML = '❌'; hideButton.className = 'vote-button overflow--visible'; hideButton.title = 'Deal verbergen'; hideButton.style.cssText = ` position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); z-index: 10002; background: rgba(255, 255, 255, 0.9); border: none; border-radius: 50%; cursor: pointer; padding: 8px; width: 32px; height: 32px; display: flex; align-items: center; justify-content: center; pointer-events: all; `; // Touch device handling if ('ontouchstart' in window) { let buttonVisible = false; voteTemp.addEventListener('touchstart', (e) => { e.preventDefault(); e.stopPropagation(); if (!buttonVisible) { buttonVisible = true; hideButtonContainer.style.display = 'block'; } else { // Second touch on container: hide deal const dealId = deal.getAttribute('id'); hiddenDeals.push(dealId); saveHiddenDeals(); hideDeal(deal); } }, true); // Reset visibility when touch moves outside voteTemp.addEventListener('touchend', () => { if (!buttonVisible) { hideButtonContainer.style.display = 'none'; } }, true); } else { // Desktop hover behavior voteTemp.addEventListener('mouseenter', () => { hideButtonContainer.style.display = 'block'; }, true); voteTemp.addEventListener('mouseleave', () => { hideButtonContainer.style.display = 'none'; }, true); hideButton.onclick = (e) => { e.preventDefault(); e.stopPropagation(); const dealId = deal.getAttribute('id'); hiddenDeals.push(dealId); saveHiddenDeals(); hideDeal(deal); return false; }; } hideButtonContainer.appendChild(hideButton); voteTemp.appendChild(hideButtonContainer); deal.setAttribute('data-button-added', 'true'); }); } // HTML Decoder Funktion hinzufügen function decodeHtml(html) { const txt = document.createElement('textarea'); txt.innerHTML = html; return txt.value; } // --- 3. Backup- und Restore-Funktionen --- function backupData() { const backup = { excludeWords: excludeWords, excludeMerchantIDs: excludeMerchantIDs, merchantsData: loadExcludeMerchants() }; const now = new Date(); const timestamp = now.getFullYear() + '-' + String(now.getMonth() + 1).padStart(2, '0') + '-' + String(now.getDate()).padStart(2, '0') + '_' + String(now.getHours()).padStart(2, '0') + '.' + String(now.getMinutes()).padStart(2, '0'); const blob = new Blob([JSON.stringify(backup, null, 2)], { type: 'application/json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `mydealz_backup_${timestamp}.json`; a.click(); URL.revokeObjectURL(url); } // Restore-Funktion function restoreData(event) { const file = event.target.files[0]; if (file && file.type === 'application/json') { const reader = new FileReader(); reader.onload = function(e) { const restoredData = JSON.parse(e.target.result); if (restoredData.excludeWords && (restoredData.excludeMerchantIDs || restoredData.merchantsData)) { // Restore words saveExcludeWords(restoredData.excludeWords); excludeWords = restoredData.excludeWords; // Restore merchant data const merchantsData = restoredData.merchantsData || restoredData.excludeMerchantIDs.map(id => ({ id, name: id })); saveExcludeMerchants(merchantsData); // Update UI document.getElementById('excludeWordsInput').value = excludeWords.join('\n'); // Refresh deals processArticles(); } else { alert('Die Backup-Datei ist nicht im richtigen Format.'); } }; reader.readAsText(file); } else { alert('Bitte wählen Sie eine gültige JSON-Datei aus.'); } } // --- 4. Benutzeroberfläche (UI) --- function getSubUIPosition() { if (IS_TOUCH_DEVICE) { return ` position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); `; } return ` position: fixed; top: 50%; left: calc(50% + 310px); transform: translate(-50%, -50%); `; } function createMerchantListUI() { // Remove existing instance if it exists if (merchantListDiv && merchantListDiv.parentNode) { merchantListDiv.remove(); } merchantListDiv = document.createElement('div'); merchantListDiv.style.cssText = ` ${getSubUIPosition()} padding: 15px; background: #f9f9f9; border: 1px solid #ccc; border-radius: 5px; z-index: 1001; // Higher than settings UI width: 300px; `; const currentMerchants = loadExcludeMerchants(); const merchantListHTML = currentMerchants.map(merchant => `
${merchant.name} ID: ${merchant.id}
`).join(''); merchantListDiv.innerHTML = `

Ausgeblendete Händler

${merchantListHTML}
`; // Add the div to the document body document.body.appendChild(merchantListDiv); setupClickOutsideHandler(); // Add search functionality const searchInput = document.getElementById('merchantSearch'); searchInput.addEventListener('input', (e) => { const searchTerm = e.target.value.toLowerCase(); document.querySelectorAll('.merchant-item').forEach(item => { const merchantName = item.querySelector('span').textContent.toLowerCase(); const merchantId = item.querySelector('span:last-child').textContent.toLowerCase(); if (merchantName.includes(searchTerm) || merchantId.includes(searchTerm)) { item.style.display = 'flex'; } else { item.style.display = 'none'; } }); }); // Add clear all button handler document.getElementById('clearMerchantListButton').addEventListener('click', () => { if (confirm('Möchten Sie wirklich alle Händler aus der Liste entfernen?')) { saveExcludeMerchants([]); document.getElementById('merchantList').innerHTML = ''; processArticles(); } }); // Update delete button handlers document.querySelectorAll('.delete-merchant').forEach(button => { button.addEventListener('click', function(e) { // Prevent event bubbling e.preventDefault(); e.stopPropagation(); // Get merchant ID to delete const deleteButton = e.target.closest('.delete-merchant'); if (!deleteButton) return; const idToDelete = deleteButton.dataset.id; // Update merchant data const merchantsData = loadExcludeMerchants(); const updatedMerchants = merchantsData.filter(m => m.id !== idToDelete); // Save updated data saveExcludeMerchants(updatedMerchants); // Remove from UI deleteButton.closest('.merchant-item').remove(); // Refresh deals processArticles(); }); }); // Update close button handlers in createMerchantListUI document.getElementById('closeMerchantListButton').addEventListener('click', (e) => { e.stopPropagation(); // Prevent event bubbling closeActiveSubUI(); }); } function createExcludeWordsUI() { // Remove existing instance if it exists if (wordsListDiv && wordsListDiv.parentNode) { wordsListDiv.remove(); } wordsListDiv = document.createElement('div'); wordsListDiv.style.cssText = ` ${getSubUIPosition()} padding: 15px; background: #f9f9f9; border: 1px solid #ccc; border-radius: 5px; z-index: 1001; // Higher than settings UI width: 300px; `; const currentWords = loadExcludeWords(); const wordsListHTML = currentWords.map(word => `
${word}
`).join(''); wordsListDiv.innerHTML = `

Ausgeblendete Wörter

${wordsListHTML}
`; // Add the div to the document body document.body.appendChild(wordsListDiv); setupClickOutsideHandler(); // Add search functionality const searchInput = document.getElementById('wordSearch'); searchInput.addEventListener('input', (e) => { const searchTerm = e.target.value.toLowerCase(); document.querySelectorAll('.word-item').forEach(item => { const word = item.querySelector('span').textContent.toLowerCase(); item.style.display = word.includes(searchTerm) ? 'flex' : 'none'; }); }); // Add clear all button handler document.getElementById('clearWordsListButton').addEventListener('click', () => { if (confirm('Möchten Sie wirklich alle Wörter aus der Liste entfernen?')) { saveExcludeWords([]); document.getElementById('wordsList').innerHTML = ''; excludeWords = []; processArticles(); } }); // Add delete handlers document.querySelectorAll('.delete-word').forEach(button => { button.addEventListener('click', (e) => { // Prevent event bubbling e.preventDefault(); e.stopPropagation(); const deleteButton = e.target.closest('.delete-word'); if (!deleteButton) return; const wordToDelete = deleteButton.dataset.word; excludeWords = excludeWords.filter(word => word !== wordToDelete); saveExcludeWords(excludeWords); // Remove only the specific word item deleteButton.closest('.word-item').remove(); // Update deals without closing UI processArticles(); }); }); // Update close button handlers in createExcludeWordsUI document.getElementById('closeWordsListButton').addEventListener('click', (e) => { e.stopPropagation(); // Prevent event bubbling closeActiveSubUI(); }); } function getWordsFromTitle(dealElement) { const title = dealElement.querySelector('.thread-title').textContent; return title.split(/\s+/) .map(word => word.replace(/[^a-zA-Z0-9äöüÄÖÜß]/g, '')) .filter(word => word.length > 2); } // Add debug logging to settings UI creation function createSettingsUI() { if (isSettingsOpen) return; isSettingsOpen = true; settingsDiv = document.createElement('div'); settingsDiv.style.cssText = ` position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); padding: 15px; background: #f9f9f9; border: 1px solid #ccc; border-radius: 5px; z-index: 1000; max-width: 300px; overflow: auto; `; // Get merchant info from current deal let merchantName = null; let showMerchantButton = false; if (dealThatOpenedSettings) { const merchantLink = dealThatOpenedSettings.querySelector('a[data-t="merchantLink"]'); if (merchantLink) { merchantName = merchantLink.textContent.trim(); showMerchantButton = true; } } // Process articles when opening settings processArticles(); const currentExcludeWords = JSON.parse(localStorage.getItem(EXCLUDE_WORDS_KEY)) || []; const currentExcludeMerchantIDs = JSON.parse(localStorage.getItem(EXCLUDE_MERCHANTS_KEY)) || []; const dealWords = dealThatOpenedSettings ? getWordsFromTitle(dealThatOpenedSettings) : []; // Conditional merchant button HTML - only show if merchant exists const merchantButtonHtml = showMerchantButton ? ` ` : ''; settingsDiv.innerHTML = `

Einstellungen zum Ausblenden

${dealWords.map(word => `
${merchantButtonHtml}
`; // Explicitly add to DOM document.body.appendChild(settingsDiv); setupClickOutsideHandler(); // Add word input handler document.getElementById('addWordButton').addEventListener('click', () => { const newWord = document.getElementById('newWordInput').value.trim(); if (newWord && !excludeWords.includes(newWord)) { // Add new word at start of array excludeWords.unshift(newWord); saveExcludeWords(excludeWords); document.getElementById('newWordInput').value = ''; processArticles(); } }); // Add enter key handler for input document.getElementById('newWordInput').addEventListener('keypress', (e) => { if (e.key === 'Enter') { document.getElementById('addWordButton').click(); } }); // Only add merchant button listener if button exists const hideMerchantButton = document.getElementById('hideMerchantButton'); if (hideMerchantButton && showMerchantButton) { hideMerchantButton.addEventListener('click', () => { if (!dealThatOpenedSettings) return; const merchantLink = dealThatOpenedSettings.querySelector('a[href*="merchant-id="]'); if (!merchantLink) return; const merchantIDMatch = merchantLink.getAttribute('href').match(/merchant-id=(\d+)/); if (!merchantIDMatch) return; const merchantID = merchantIDMatch[1]; const merchantName = dealThatOpenedSettings.querySelector('a[data-t="merchantLink"]').textContent.trim(); // Load current data const merchantsData = loadExcludeMerchants(); // Check if ID already exists if (!merchantsData.some(m => m.id === merchantID)) { // Add new merchant at start of array merchantsData.unshift({ id: merchantID, name: merchantName }); saveExcludeMerchants(merchantsData); processArticles(); } }); } // Add merchant list button listener document.getElementById('showMerchantListButton').addEventListener('click', () => { closeActiveSubUI(); createMerchantListUI(); activeSubUI = 'merchant'; }); // Add words list button listener document.getElementById('showWordsListButton').addEventListener('click', () => { closeActiveSubUI(); createExcludeWordsUI(); activeSubUI = 'words'; }); // Always ensure close button works document.getElementById('closeSettingsButton').addEventListener('click', (e) => { e.stopPropagation(); // Prevent event bubbling if (settingsDiv?.parentNode) { settingsDiv.remove(); isSettingsOpen = false; } // Close merchant list if open if (merchantListDiv && merchantListDiv.parentNode) { merchantListDiv.remove(); } // Close words list if open if (wordsListDiv && wordsListDiv.parentNode) { wordsListDiv.remove(); } }); // Backup/Restore Event Listeners document.getElementById('createBackupButton').addEventListener('click', backupData); document.getElementById('restoreBackupButton').addEventListener('click', () => { document.getElementById('restoreFileInput').click(); }); document.getElementById('restoreFileInput').addEventListener('change', restoreData); } function initObserver() { observer.observe(document.body, { childList: true, subtree: true }); } // Call initial setup document.addEventListener('DOMContentLoaded', () => { processArticles(); initObserver(); }); // Update merchant list UI - add new item at top function addMerchantToList(merchant, merchantList) { const div = document.createElement('div'); div.className = 'merchant-item'; div.style.cssText = 'display: flex; justify-content: space-between; align-items: center; margin-bottom: 5px; padding: 5px; background: #f0f0f0; border-radius: 3px;'; div.innerHTML = `
${merchant.name} ID: ${merchant.id}
`; // Insert at beginning of list merchantList.insertBefore(div, merchantList.firstChild); } // Update word list UI - add new item at top function addWordToList(word, wordsList) { const div = document.createElement('div'); div.className = 'word-item'; div.style.cssText = 'display: flex; justify-content: space-between; align-items: center; margin-bottom: 5px; padding: 5px; background: #f0f0f0; border-radius: 3px;'; div.innerHTML = ` ${word} `; // Insert at beginning of list wordsList.insertBefore(div, wordsList.firstChild); } function setupClickOutsideHandler() { if (uiClickOutsideHandler) { document.removeEventListener('click', uiClickOutsideHandler); } uiClickOutsideHandler = (e) => { const settingsOpen = settingsDiv?.parentNode; const merchantsOpen = merchantListDiv?.parentNode; const wordsOpen = wordsListDiv?.parentNode; if (e.target.closest('.settings-button') || e.target.closest('#showMerchantListButton') || e.target.closest('#showWordsListButton')) { return; } const clickedOutside = (!settingsOpen || !settingsDiv.contains(e.target)) && (!merchantsOpen || !merchantListDiv.contains(e.target)) && (!wordsOpen || !wordsListDiv.contains(e.target)); if (clickedOutside) { if (settingsOpen) { settingsDiv.remove(); isSettingsOpen = false; } if (merchantsOpen) merchantListDiv.remove(); if (wordsOpen) wordsListDiv.remove(); document.removeEventListener('click', uiClickOutsideHandler); uiClickOutsideHandler = null; } }; setTimeout(() => document.addEventListener('click', uiClickOutsideHandler), 100); } // Add helper function to close sub-UIs function closeActiveSubUI() { if (activeSubUI === 'merchant' && merchantListDiv?.parentNode) { merchantListDiv.remove(); } else if (activeSubUI === 'words' && wordsListDiv?.parentNode) { wordsListDiv.remove(); } activeSubUI = null; } // Add new function to handle merchant pages function addMerchantPageHideButton() { // Check if we're on a merchant page const urlParams = new URLSearchParams(window.location.search); const merchantId = urlParams.get('merchant-id'); if (!merchantId) return; // Find merchant header const merchantBanner = document.querySelector(MERCHANT_PAGE_SELECTOR); if (!merchantBanner) return; // Get merchant name from page const merchantName = document.querySelector('.merchant-banner__title')?.textContent.trim(); if (!merchantName) return; // Create hide button container const hideButtonContainer = document.createElement('div'); hideButtonContainer.style.cssText = ` display: inline-flex; align-items: center; margin-left: 10px; `; // Create hide button const hideButton = document.createElement('button'); hideButton.innerHTML = ''; hideButton.title = `Alle Deals von ${merchantName} ausblenden`; hideButton.style.cssText = ` padding: 8px; background: #f0f0f0; border: 1px solid #ccc; border-radius: 3px; cursor: pointer; `; // Add click handler hideButton.addEventListener('click', () => { const merchantsData = loadExcludeMerchants(); // Check if ID already exists if (!merchantsData.some(m => m.id === merchantId)) { // Add new merchant at start of array merchantsData.unshift({ id: merchantId, name: merchantName }); saveExcludeMerchants(merchantsData); processArticles(); } }); // Add button to page hideButtonContainer.appendChild(hideButton); merchantBanner.appendChild(hideButtonContainer); } // Call function on page load document.addEventListener('DOMContentLoaded', () => { addMerchantPageHideButton(); });