您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Arrow or WASD through job cards; each move auto-opens the card so Indeed’s built-in highlight follows along. H = first • E = last.
// ==UserScript== // @name Indeed Joblist Arrow-Key Navigator // @namespace https://tampermonkey.net/ // @version 1.1.0 // @description Arrow or WASD through job cards; each move auto-opens the card so Indeed’s built-in highlight follows along. H = first • E = last. // @author NeonHD // @match https://*.indeed.com/* // @match https://*.indeed.ca/* // @match https://*.indeed.co.uk/* // @match https://*.indeed.*/* // @grant none // @license MIT // ==/UserScript== (() => { 'use strict'; /** * Utility: wait until a selector appears, then run a callback. * @param {string} selector * @param {(node: Element) => void} done */ const waitFor = (selector, done) => { const found = document.querySelector(selector); if (found) { done(found); return; } const observer = new MutationObserver(() => { const node = document.querySelector(selector); if (node) { observer.disconnect(); done(node); } }); observer.observe(document.body, { childList: true, subtree: true }); }; /** * True if an element is an editable field in which we should not intercept keys. * @param {Element} el * @returns {boolean} */ const isEditable = (el) => { const tag = el.tagName; return tag === 'INPUT' || tag === 'TEXTAREA' || el.isContentEditable; }; waitFor('#mosaic-provider-jobcards ul', (ul) => { const getCards = () => [...ul.querySelectorAll('.cardOutline')]; /** * Clicks / focuses / scrolls the ith card. * @param {number} i */ const activate = (i) => { const list = getCards(); if (!list.length) return; const idx = Math.max(0, Math.min(i, list.length - 1)); const target = list[idx]; const link = target.querySelector('a') || target; link.click(); // native highlight + pane link.focus({ preventScroll: true }); target.scrollIntoView({ block: 'center', behavior: 'smooth' }); currentIndex = idx; // eslint-disable-line no-use-before-define }; /* Determine initial index from Indeed’s own aria-pressed flag. */ let currentIndex = getCards().findIndex((c) => c.querySelector('[aria-pressed="true"]')); if (currentIndex < 0) currentIndex = 0; activate(currentIndex); /* Keep index valid when cards are lazily added/removed. */ const listObserver = new MutationObserver(() => { const len = getCards().length; if (!len) return; if (currentIndex >= len) currentIndex = len - 1; }); listObserver.observe(ul, { childList: true, subtree: true }); /* Key listener */ window.addEventListener( 'keydown', (event) => { if (isEditable(event.target)) return; const { key } = event; const listLen = getCards().length; let handled = false; if (['ArrowUp', 'ArrowLeft', 'w', 'a'].includes(key)) { activate(currentIndex - 1); handled = true; } else if (['ArrowDown', 'ArrowRight', 's', 'd'].includes(key)) { activate(currentIndex + 1); handled = true; } else if (key === 'h' || key === 'H') { activate(0); handled = true; } else if (key === 'e' || key === 'E') { activate(listLen - 1); handled = true; } if (handled) event.preventDefault(); }, true ); }); })();