您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Highlight original poster comments on Hackers News and navigate them with the keyboard
// ==UserScript== // @name Hacker News - Highlight and navigate original poster's comments // @description Highlight original poster comments on Hackers News and navigate them with the keyboard // @namespace valacar // @author valacar // @include https://news.ycombinator.com/item?id=* // @version 0.3 // @grant none // @noframes // @license MIT // @compatible firefox Firefox // @compatible chrome Chrome // ==/UserScript== (function() { 'use strict'; const ENABLE_KEYBOARD_NAVIGATION = true; const VERTICAL_CENTER_PERCENT = 0.25; // percentage from the top function appendStyle(cssString) { const parent = document.head || document.documentElement; if (parent) { const style = document.createElement("style"); style.setAttribute("type", "text/css"); style.textContent = cssString; parent.appendChild(style); } } appendStyle( ` .originalPoster, .opPostCountInfo { background: #ffc; } .currentHighlight { background: linear-gradient(to right, #ffc 66%, transparent); } `); const posterUserName = document.querySelector('.subtext a').textContent; let opPostCount = 0; if (posterUserName) { const commentUserLinks = document.querySelectorAll('.comhead a'); if (commentUserLinks) { for (let i = 0; i < commentUserLinks.length; i++) { let commentUserName = commentUserLinks[i].textContent; if (posterUserName === commentUserName) { opPostCount++; commentUserLinks[i].classList.add('originalPoster'); commentUserLinks[i].id = 'op-post-' + opPostCount; } } } } if (opPostCount > 0) { const newSpan = document.createElement('span'); newSpan.textContent = ' (' + opPostCount + ' by original poster)'; newSpan.className = 'opPostCountInfo'; if (ENABLE_KEYBOARD_NAVIGATION) { newSpan.setAttribute('title', "Use the left/right arrow keys\n(or n/N, or n/p) to scroll to OP comments."); newSpan.setAttribute('style', "cursor: help;"); } const subText = document.querySelectorAll('.subtext a[href^="item?id="')[1]; subText.appendChild(newSpan); } // http://stackoverflow.com/questions/8922107/javascript-scrollintoview-middle-alignment Element.prototype.documentOffsetTop = function () { return this.offsetTop + (this.offsetParent ? this.offsetParent.documentOffsetTop() : 0); }; function ScrollToID(id) { const target = document.getElementById(id); const top = target.documentOffsetTop() - (window.innerHeight * VERTICAL_CENTER_PERCENT); window.scrollTo(0, top); const oldCurrent = document.querySelector(".currentHighlight"); if (oldCurrent) { oldCurrent.classList.remove("currentHighlight"); } // XXX: not the best idea to blindly go back two parents target.parentNode.parentNode.classList.add("currentHighlight"); } if (ENABLE_KEYBOARD_NAVIGATION) { let num = 0; window.addEventListener("keydown", function (event) { // Should do nothing if the key event was already consumed. if (event.defaultPrevented) { return; } // don't break alt-left and alt-right history navigation // and exit if textarea is in focus if (event.altKey || /(input|textarea)/i.test(document.activeElement.nodeName)) { return; } switch (event.key) { case "n": case "ArrowRight": case "Right": if (num < opPostCount) { num++; } break; case "N": case "p": case "ArrowLeft": case "Left": if (num > 1) { num--; } break; default: return; // Quit when this doesn't handle the key event. } // Consume the event for suppressing "double action". event.preventDefault(); //console.log('num = ' + num + ' focus = ' + document.activeElement.tagName); ScrollToID("op-post-" + num); }, true); } })();