11/13/2024, 5:53:40 PM
// ==UserScript== // @name LinkedIn Job Visibility Settings; year, job status highlight // @namespace Violentmonkey Scripts // @match https://www.linkedin.com/jobs/search/* // @match https://www.glassdoor.ca/Job/* // @match https://ca.indeed.com/* // @grant GM_getValue // @grant GM_setValue // @version 1.0 // @author LAMSTREAM // @description 11/13/2024, 5:53:40 PM // ==/UserScript== (function() { 'use strict'; // Define colors for each status const statusColors = { viewed: 'red', applied: 'green', promoted: 'purple', year: 'red' }; // Initialize settings with stored values or defaults const settings = { hideViewed: GM_getValue('hideViewed', true), hideApplied: GM_getValue('hideApplied', true), hidePromoted: GM_getValue('hidePromoted', true), panelPosition: GM_getValue('panelPosition', { x: 20, y: 20 }), isCollapsed: GM_getValue('isCollapsed', false) }; // Create and style the settings panel function createSettingsPanel() { const panel = document.createElement('div'); panel.style.cssText = ` position: fixed; top: ${settings.panelPosition.y}px; left: ${settings.panelPosition.x}px; background: white; padding: 15px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); z-index: 9999; font-family: system-ui, -apple-system, sans-serif; cursor: move; min-width: 200px; user-select: none; `; // Header container const header = document.createElement('div'); header.style.cssText = ` display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; cursor: move; `; const title = document.createElement('h3'); title.textContent = 'Job Visibility Settings'; title.style.margin = '0'; title.style.flex = '1'; // Collapse/Expand button const collapseBtn = document.createElement('button'); collapseBtn.style.cssText = ` background: none; border: none; cursor: pointer; font-size: 20px; padding: 0 5px; margin-left: 10px; `; collapseBtn.textContent = settings.isCollapsed ? '▼' : '▲'; collapseBtn.title = settings.isCollapsed ? 'Expand' : 'Collapse'; header.appendChild(title); header.appendChild(collapseBtn); panel.appendChild(header); // Content container const content = document.createElement('div'); content.style.display = settings.isCollapsed ? 'none' : 'block'; // Create toggle switches for each setting const options = [ { key: 'hideViewed', label: 'Hide Viewed', color: statusColors.viewed }, { key: 'hideApplied', label: 'Hide Applied', color: statusColors.applied }, { key: 'hidePromoted', label: 'Hide Promoted', color: statusColors.promoted } ]; options.forEach(({ key, label, color }) => { const container = document.createElement('div'); container.style.cssText = ` margin: 10px 0; padding: 8px; border-radius: 4px; background: ${color}15; border: 1px solid ${color}40; `; const toggle = document.createElement('input'); toggle.type = 'checkbox'; toggle.id = key; toggle.checked = settings[key]; toggle.style.marginRight = '8px'; const labelElement = document.createElement('label'); labelElement.htmlFor = key; labelElement.textContent = label; labelElement.style.color = color; labelElement.style.fontWeight = 'bold'; toggle.addEventListener('change', (e) => { settings[key] = e.target.checked; GM_setValue(key, e.target.checked); hideListItems(); }); container.appendChild(toggle); container.appendChild(labelElement); content.appendChild(container); }); panel.appendChild(content); // Make panel draggable let isDragging = false; let currentX; let currentY; let initialX; let initialY; header.addEventListener('mousedown', dragStart); document.addEventListener('mousemove', drag); document.addEventListener('mouseup', dragEnd); function dragStart(e) { initialX = e.clientX - settings.panelPosition.x; initialY = e.clientY - settings.panelPosition.y; isDragging = true; } function drag(e) { if (!isDragging) return; e.preventDefault(); currentX = e.clientX - initialX; currentY = e.clientY - initialY; // Update position settings.panelPosition = { x: currentX, y: currentY }; panel.style.left = `${currentX}px`; panel.style.top = `${currentY}px`; } function dragEnd() { if (!isDragging) return; isDragging = false; GM_setValue('panelPosition', settings.panelPosition); } // Handle collapse/expand collapseBtn.addEventListener('click', () => { settings.isCollapsed = !settings.isCollapsed; content.style.display = settings.isCollapsed ? 'none' : 'block'; collapseBtn.textContent = settings.isCollapsed ? '▼' : '▲'; collapseBtn.title = settings.isCollapsed ? 'Expand' : 'Collapse'; GM_setValue('isCollapsed', settings.isCollapsed); }); document.body.appendChild(panel); } // Function to hide li elements and color the status text const hideListItems = () => { const elements = document.querySelectorAll('.job-card-container__footer-item'); elements.forEach(element => { const text = element.innerText; // Color the status text based on type if (text.includes('Viewed')) { element.style.color = statusColors.viewed; if (settings.hideViewed) hideFromAncestor(element); } else if (text.includes('Applied')) { element.style.color = statusColors.applied; if (settings.hideApplied) hideFromAncestor(element); } else if (text.includes('Promoted')) { element.style.color = statusColors.promoted; if (settings.hidePromoted) hideFromAncestor(element); } }); }; // Function to hide the ancestor li element const hideFromAncestor = (element) => { let liElement = element.parentElement.closest('li'); if (liElement) { liElement.style.display = 'none'; } }; // Function to highlight the word "year" in text content const highlightYear = () => { const elements = [...document.querySelectorAll('.jobs-search__job-details--wrapper'), ...document.querySelectorAll('[class^="JobDetails_jobDescription"]'), ...document.querySelectorAll('#jobDescriptionText') ] observer.disconnect() elements.forEach(element => { // Get all text nodes within the element, including nested ones const walk = document.createTreeWalker( element, NodeFilter.SHOW_TEXT, null, false ); const textNodes = []; let node; while (node = walk.nextNode()) { textNodes.push(node); } // Process each text node textNodes.forEach(textNode => { const text = textNode.textContent; if (/(year|years)/i.test(text)) { const span = document.createElement('span'); span.innerHTML = text.replace(/(years|year)/gi, '<span style="color: red">$1</span>'); textNode.parentNode.replaceChild(span, textNode); } }); }); // Observe changes in the DOM observer.observe(document.body, { childList: true, subtree: true, characterData: true }); }; const highlightCurrentTab = () => { observer.disconnect(); // Temporarily stop observing mutations const items = document.querySelectorAll('[class*="JobsList_jobListItem"]'); // Get all job list items items.forEach(item => { const classList = item.className; // Get full class name as string if (classList.includes("JobsList_selected")) { item.classList.add("highlight"); // Add highlight if selected } else { item.classList.remove("highlight"); // Remove highlight if not selected } }); observer.observe(document.body, { childList: true, subtree: true }); // R###me observing }; // Observe changes in the DOM to apply the filtering dynamically const observer = new MutationObserver((mutations) => { hideListItems(); highlightYear(); highlightCurrentTab(); }); // Observe changes in the DOM observer.observe(document.body, { childList: true, subtree: true, characterData: true }); // Initial setup createSettingsPanel(); hideListItems(); highlightYear(); highlightCurrentTab() setTimeout(() => { const style = document.createElement("style"); style.textContent = ` body .highlight { position: relative !important; } body .highlight::before { content: ""; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(144, 238, 144, 0.5) !important; pointer-events: none; z-index: 1000; } `; document.head.appendChild(style); }, 100); })();