Skip to content

Instantly share code, notes, and snippets.

@levibostian
Created September 9, 2025 14:15
Show Gist options
  • Save levibostian/b8b398ab3bcd7fd461ad6a38d1fdb68e to your computer and use it in GitHub Desktop.
Save levibostian/b8b398ab3bcd7fd461ad6a38d1fdb68e to your computer and use it in GitHub Desktop.
tampermonkey github pull request mark file as Viewed keyboard shortcut. Found it in https://github.com/orgs/community/discussions/10197, but modified it over time because I found some bugs.
// ==UserScript==
// @name GitHub PR review keyboard shortcut
// @version 0.3
// @description Mark file as "viewed" on GitHub PR UI when hovering and pressing 'Escape' key
// @match https://github.com/*
// @author dvdvdmt, nbolton
// @source https://github.com/orgs/community/discussions/10197
// ==/UserScript==
(function() {
'use strict';
if (window.disposeMarkAsViewedByEscape) {
window.disposeMarkAsViewedByEscape();
}
window.disposeMarkAsViewedByEscape = start();
function start() {
window.addEventListener('keydown', handleKeyDown);
return () => window.removeEventListener('keydown', handleKeyDown);
}
function isInEditableArea(el) {
if (!el) return false;
// If the target or any ancestor is input/textarea/select
if (el.closest && el.closest('input, textarea, select')) return true;
// If the target or ancestor has contentEditable=true (or is contentEditable)
const editable = el.closest && el.closest('[contenteditable]');
if (editable) {
const ce = editable.getAttribute('contenteditable');
// treat empty string or "true" as editable; also fallback to isContentEditable
if (ce === '' || ce === 'true' || editable.isContentEditable) return true;
}
// Some GitHub editors use role="textbox"
if (el.closest && el.closest('[role="textbox"]')) return true;
return false;
}
function markFileAsViewed() {
console.debug("Marking file as viewed");
const fileElement = document.querySelector(`[id^="diff-"]:hover`);
if (!fileElement){
console.debug("No file element under cursor");
return;
}
const buttons = [...fileElement.querySelectorAll('button')];
if (buttons.length === 0) {
console.debug("No buttons found in file element");
return;
}
// GitHub sometimes localizes the label; we attempt to match the visible label
const checkbox = buttons.find(btn => btn.textContent && btn.textContent.trim() === 'Viewed');
if (!checkbox) {
console.debug("No 'Viewed' checkbox/button in file element");
return;
}
checkbox.click();
}
function handleKeyDown(event) {
// Only act on plain Escape without modifiers
if (event.key !== 'Escape' || event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) {
return;
}
// If focus is inside any editable input/textarea/contentEditable, do nothing
if (isInEditableArea(event.target)) {
return;
}
markFileAsViewed();
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment