Tampering with Reddit
JavascriptUsing TamperMonkey for my recent post about messing with the Pepsi ROTY vote had me kind of on the lookout for other scripts to write.
JavaScript for Beginners
I often recommend new potential programmers who aren’t sure coding is for them try JavaScript (over Python) specifically because it allows you to immediately jump in, either via the Chrome Devtools console, or things like UserScripts, and mess with web pages for real. Silly things like removing elements of a page or changing how a button behaves can really give you that HackerMan™ feel, even if you’ve been coding for a while.
Automating Things for the Sake of Automating
Today I got around to thinking about a minor improvement to my life that 100% conforms to the “why do something mildly inconvenient in six seconds when I could spend 30 minutes automating” mindset.
I’m a fogie, by which I mean I still use old.reddit.com. I hate the new design for a lot of reasons, especially visually, but I specifically love the old design because it works with
Reddit Enhancement Suite (RES).
One thing I really love about RES is its keyboard shortcuts. I’m a big fan of Vimium but RES works way better, so I disable Vimium on Reddit. One of the best keyboard shortcuts is the one that lets you jump to a subreddit from r/all. However, 99.9% of the time when I use that keyboard shortcut it’s to go to a sub I just found and the first thing I have to do is use my mouse to the top of the page to select top of all time
. Can’t have that.
Back to UserScripts
So I decided to write a little script in Tampermonkey that makes it so that all the subreddit links link in a new page to the top of all time in a subreddit.
I started by trying to do it in jQuery. Or rather, thinking of trying to do it in jQuery. I remember almost 0% of the jQuery I learned 3 years ago when I was using JS and React regularly. $.ajax()
is still a thing, right?
Whatever. Vanilla JS is fine, honestly. I don’t get enough chances to write fat arrow functions (which are honestly one of my favorite. I way prefer them over Python’s Lambdas)
The first thing I tried was to add another link next to the subreddit links so I’d have the option to go to either top all time OR just the regular sub.
but I immediately encountered a goofy problem.
See, when you use document.getElementsByClass('subreddit');
to get all the subreddit links, that list doesn’t actually return a normal JavaScript Array
, it returns an HTMLCollection
. Which I assumed would behave close enough, but first of all forEach
is not defined on it so I have to use a for of
loop, and second, when I do loop over it for my first trip it hangs… and by adding a cap on the number of iterations I can see why.
See, it turns out that HTMLCollection
is live updated. So when I add a new anchor tag with the class subreddit
, it gets inserted into the HTMLCollection
and comes up on the next iteration, gets a new anchor tag added after it, and so on, infinitely.
The lazy workaround is to modify my goal and just change the links to point to the subreddit’s top all time, rather than adding an additional link.
and this does work
but it leaves something to be desired. Now if I actually just want to go to the subreddit, that’s a pain.
Back to Basics with querySelectors
With a quick search I was able to find other people encountering the same problem as I did with HTMLCollection
being dynamic. This blog post has a great explanation of a workaround, which is to use document.querySelectorAll
which returns a NodeList
instead, and NodeList
s are static.
It looks like nothing changed, but actually, it has! There’s two links there, smushed right next to each other. And by clicking on either of them, I can tell that one does indeed go to r/gaming
and the second goes to r/gaming/top
which is great.
Cleaning Up
By adding a 3px marginRight
to the style
of the original element I can split the two apart so that it looks a little nicer.
The one thing that’s missing is that on line 16 I added "/top"
to the end of the textContent
of the original element for the new element. So I expected it to be r/gaming/top
, not just /top
.
It turns out that HTMLElement.cloneNode()
has a parameter, deep
that defaults to true
, which means the textContent isn’t getting copied. So with one final change, here’s the final script
Cool! And as a final bonus, now that I’m working with a NodeList
I get NodeList.forEach()
.