Skip to content

Instantly share code, notes, and snippets.

@v3rm0n
Last active April 18, 2022 08:02
Show Gist options
  • Save v3rm0n/f96d98fdf4d24aca86ea10700808553d to your computer and use it in GitHub Desktop.
Save v3rm0n/f96d98fdf4d24aca86ea10700808553d to your computer and use it in GitHub Desktop.
// ==UserScript==
// @name OnVoteMoveDownReddit
// @description Simple script that allows using a/z for voting and on vote will move to next element and expand it in Reddit. x will expand the thing if it is not already expanded. When at the end of the page, new content is loaded automatically
// @exclude https://old.reddit.com/r/*/comments/*
// @match https://old.reddit.com/r/*
// @match https://old.reddit.com/
// ==/UserScript==
// CSS for the active thing
const style = document.createElement("style");
style.type = "text/css";
style.innerHTML =
".thing.active { border-style: dotted; border-color: cornflowerblue; }";
document.getElementsByTagName("head")[0].appendChild(style);
// Things are content
const things = document.getElementsByClassName("thing");
const makeActive = (element) => element.classList.add("active");
const makeInactive = (element) => element.classList.remove("active");
const clearPreviousActive = () => {
for (let thing of things) {
makeInactive(thing);
}
};
// Event listeners for activating a thing by clicking on it
for (let thing of things) {
thing.addEventListener("click", (event) => {
clearPreviousActive();
makeActive(event.currentTarget);
});
}
// Activate first thing by default
makeActive(things[0]);
// Loads next page of 100 things and parses out the list of them
const loadNext = async (lastThing) => {
const id = lastThing.getAttribute("data-fullname");
const response = await fetch(
`${window.location.href.split("?")[0]}?count=100&after=${id}`
);
const allContent = await response.text();
const parser = new DOMParser();
const htmlDocument = parser.parseFromString(allContent, "text/html");
const siteTable = htmlDocument.documentElement.querySelector("#siteTable");
return siteTable.children;
};
// Removes nav buttons and appends new things to the content. New content has its own nav buttons.
const addContentToPage = (lastThing, content) => {
document.querySelector(".nav-buttons").remove();
for (let thing of content) {
lastThing.parentElement.append(thing);
}
};
const getLastThing = () => {
const allThings = document.querySelectorAll(".thing");
return allThings[allThings.length - 1];
};
const loadMoreContent = async () => {
const lastThing = getLastThing();
const content = await loadNext(lastThing);
addContentToPage(lastThing, content);
};
const expand = (thing) => {
const expandButton = thing.querySelector("div.expando-button.collapsed");
if (expandButton) {
expandButton.click();
}
};
const collapse = (thing) => {
const collapseButton = thing.querySelector("div.expando-button.expanded");
if (collapseButton) {
collapseButton.click();
}
};
const getNextSibling = (elem, selector) => {
// Get the next sibling element
let sibling = elem.nextElementSibling;
// If the sibling matches our selector, use it
// If not, jump to the next sibling and continue the loop
while (sibling) {
if (sibling.matches(selector)) return sibling;
sibling = sibling.nextElementSibling;
}
};
let autoExpand = false;
const moveToNext = (current) => {
collapse(current);
// Get next thing that is not an ad
const nextThing = getNextSibling(current, ".thing:not(.promoted)");
clearPreviousActive();
makeActive(nextThing);
if (autoExpand) {
expand(nextThing);
}
nextThing.scrollIntoView(true);
if (window.innerHeight + window.scrollY >= document.body.offsetHeight) {
// you're at the bottom of the page
loadMoreContent();
}
};
document.addEventListener(
"keydown",
(event) => {
const keyName = event.key;
const currentActive = document.querySelector(".thing.active");
if (currentActive) {
switch (keyName) {
case "a":
const upArrow = currentActive.querySelector(".arrow.up");
upArrow.click();
moveToNext(currentActive);
break;
case "z":
const downArrow = currentActive.querySelector(".arrow.down");
downArrow.click();
moveToNext(currentActive);
break;
case "x":
autoExpand = !autoExpand;
if (autoExpand) {
expand(currentActive);
} else {
collapse(currentActive);
}
break;
}
}
},
false
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment