Skip to content

Instantly share code, notes, and snippets.

@c6p
Last active April 29, 2024 23:58
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save c6p/463892bb243f611f2a3cfa4268c6435e to your computer and use it in GitHub Desktop.
Save c6p/463892bb243f611f2a3cfa4268c6435e to your computer and use it in GitHub Desktop.
Reddit Multi Column
// ==UserScript==
// @name Reddit Multi Column
// @namespace https://gist.github.com/c6p/463892bb243f611f2a3cfa4268c6435e
// @version 0.1.15
// @description Multi column layout for reddit redesign
// @author Can Altıparmak
// @homepageURL https://gist.github.com/c6p/463892bb243f611f2a3cfa4268c6435e
// @match https://www.reddit.com/*
// @grant none
// ==/UserScript==
/* jshint esversion: 6 */
(function() {
'use strict';
const MIN_WIDTH = 400;
const COLUMNS = 4;
let columns = COLUMNS;
let cleanup = null;
// https://codepen.io/jpkempf/pen/MbePGB
function debounce(fn, wait) {
var timeout;
return function() {
var context = this;
var args = arguments;
clearTimeout(timeout);
timeout = setTimeout(function() {
fn.apply(context, args);
}, wait);
};
}
const OUTER = '#SHORTCUT_FOCUSABLE_DIV > div > div > div > div > div:nth-child(2) > div:last-child'
const cardButton = () => document.querySelector('#layoutSwitch--card') // old
|| document.querySelector('#LayoutSwitch--picker > span:nth-child(2)') // new
const indexOfSmallest = function (a) {
let lowest = 0;
for (let i = 1; i<a.length; i++) {
if (a[i] < a[lowest]) lowest = i;
}
return lowest;
};
const select = function() {
let outer = document.querySelector(OUTER)
let inner = outer !== null ? outer.firstChild.firstChild : null
if (window.location.pathname === '/original/') // fix for OC
{
inner = outer.firstChild.firstChild.lastChild.previousSibling
}
else
{
while (inner.childElementCount <= 5) {
inner = inner.nextSibling
}
}
return { outer, inner };
}
const makeLayout = function(changes=[]) {
// TODO if changes not empty, update only changed
const { outer, inner } = select();
if (inner === null) return;
const c = cleanup;
if (c) {
outer.style = 'max-width: 100%'
outer.firstChild.removeAttribute("style");
inner.removeAttribute("style");
} else {
outer.style = 'width: 100%; max-width: 100%';
outer.firstChild.style = 'width: 100%; max-width: 100%';
inner.setAttribute("style", "width: 100%; position: relative;");
}
const cols = Math.floor(inner.offsetWidth / MIN_WIDTH);
//if (changes.length === 0 && cols === columns) return;
columns = cols;
const WIDTH = Math.floor((100-columns)/columns);
let posts = inner.children;
let heights = Array(columns).fill(0);
for (let i=0; i<posts.length; i++) {
const post = posts[i];
const col = indexOfSmallest(heights);
let s = post.style
s.position = c ? "" : "absolute";
s.width = c ? "" : `${WIDTH}%`;
s.left = c ? "" : `${col*(WIDTH+1)}%`;
s.top = c ? "" : `${heights[col]}px`;
s.zIndex = "10";
heights[col] += post.offsetHeight;
}
inner.style.height = c ? "" : `${Math.max(...heights)}px`;
};
const setLayout = function(changes, observer) {
const button = cardButton();
const c = button.nodeName === "BUTTON"
? button.getAttribute("aria-pressed") === "false" // old
: button.textContent !== "card" // new
console.warn(c)
if (c !== cleanup) {
cleanup = c;
window.requestAnimationFrame(makeLayout);
}
};
const pageChange = new MutationObserver(makeLayout);
window.addEventListener('resize', () => makeLayout());
const layoutSwitch = new MutationObserver(setLayout);
const watch = function(changes, observer) {
const { inner } = select();
if (inner === null) return;
pageChange.observe(inner, {childList: true});
layoutSwitch.observe(cardButton(), {attributes: true, subtree: true, characterData: true});
};
const apply = new MutationObserver(watch);
const page = document.querySelector('#SHORTCUT_FOCUSABLE_DIV');
apply.observe(page, {childList: true, subtree: true});
//watch();
setLayout();
window.requestAnimationFrame(makeLayout);
})();
@elmonteanalogo
Copy link

this broke today for me

@c6p
Copy link
Author

c6p commented Jun 25, 2021

It seems to be working for me. @elmonteanalogo could you share a subreddit that it does not work, so I can check?

@elmonteanalogo
Copy link

It seems to be working intermitently, it didn't work yesterday but it worked this morning. Not working right now though, in any subreddit or anywhere in the website. Been using it for about a year and its the first time it gives me issues. but I guess it could be on my end, I havent downloaded a different browser to test (I use yandex browser)

@c6p
Copy link
Author

c6p commented Jun 26, 2021

Maybe reddit is doing A/B testing with the layout, breaking the script. I can't reproduce for now.

@dmax511
Copy link

dmax511 commented Feb 2, 2022

could you do this for twitter?

@c6p
Copy link
Author

c6p commented Mar 13, 2022

@dmax511 I've looked into it, but Twitter is cycling element content with scroll position. It is possible, however very hard, with this approach. So I can't make any promises.

@dmax511
Copy link

dmax511 commented Mar 16, 2022

ok thanks for looking into it

@Krokette
Copy link

it doesn't seem to work anymore. Is there a fix for it ?

@drhouse
Copy link

drhouse commented Apr 29, 2024

it doesn't seem to work anymore. Is there a fix for it ?

I started using this userscript Reddit 2023 Ui Revert to forward www.reddit.com to new.reddit.com, then add:
// @match https://new.reddit.com/*
to the top of Reddit Multi Column script and it will work again

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment