Skip to content

Instantly share code, notes, and snippets.

@foriequal0
Last active October 3, 2024 03:30
Show Gist options
  • Save foriequal0/1b4faa1e6c405c1bb2dac5031fba0a12 to your computer and use it in GitHub Desktop.
Save foriequal0/1b4faa1e6c405c1bb2dac5031fba0a12 to your computer and use it in GitHub Desktop.
Scroll to current file for GitHub
// ==UserScript==
// @name Scroll to current file for GitHub
// @match https://github.com/*
// @version 4
// ==/UserScript==
function check(callback) {
const result = callback();
if (!result) {
throw new Error("assertion Failed: "+ callback.toString());
}
return result;
}
function getRefName() {
const embeddedData = check(() => document.querySelector('script[data-target="react-app.embeddedData"]'));
const obj = JSON.parse(embeddedData.text);
const refName = check(() => obj?.payload?.refInfo?.name);
return refName;
}
function trimPrefix(str, prefix) {
check(() => str.startsWith(prefix));
return str.substring(prefix.length);
}
async function scrollToCurrentFile() {
const pathname = location.pathname;
const [_empty, _owner, _repo, type, ...rest] = pathname.split("/");
if (type != "blob" && type != "tree") {
return;
}
const restPath = rest.join("/");
const refName = getRefName();
const filePath = trimPrefix(restPath, refName);
if (!filePath) {
return;
}
const relativePath = trimPrefix(filePath, "/");
// item seems to be re-rendered right after `turbo:load` sometimes.
await new Promise(resolve => setTimeout(resolve, 0));
const item = document.getElementById(`${relativePath}-item`);
item?.scrollIntoView();
}
function debounce(func, ms) {
let handle;
return function () {
if (handle !== undefined) {
clearTimeout(handle);
}
handle = setTimeout(func, ms);
}
}
// After page load
window.addEventListener("turbo:load", scrollToCurrentFile);
// Window resize
window.addEventListener("resize", debounce(scrollToCurrentFile, 200));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment