Skip to content

Commit 4cf01d8

Browse files
authored
feat: Support for edited submissions on Redesign (#18)
* refactor: replace var with const/let * feat: Support for edited submissions on Redesign * feat: Edited submissions redesign in list view and popups * feat: Display when posts were edited on Redesign * fix: find edited submissions whenever url changes * feat: Support submission preview on profile [age * fix: show original appearing twice again * fix: add link in tagline for removed submissions old reddit * chore: bump version to 3.9.0 * docs: fix typos * refactor: better error handling
1 parent 4f5a4ef commit 4cf01d8

File tree

4 files changed

+177
-25
lines changed

4 files changed

+177
-25
lines changed

README.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
<a href="https://addons.mozilla.org/en-US/firefox/addon/unedit-for-reddit/">
1313
<img src="https://custom-icon-badges.herokuapp.com/amo/v/unedit-for-reddit?color=FF7139&label=firefox&logo=firefoxpng" alt="Firefox" /></a>
1414
<a href="https://greasyfork.org/en/scripts/407466-unedit-and-undelete-for-reddit">
15-
<img src="https://custom-icon-badges.herokuapp.com/github/v/release/DenverCoder1/Unedit-for-Reddit?color=000&label=greasyfork&logo=greasyforkpng" alt="Greasyfork" /></a>
15+
<img src="https://custom-icon-badges.herokuapp.com/github/v/release/DenverCoder1/Unedit-for-Reddit?color=000&label=greasy+fork&logo=greasyforkpng" alt="Greasy Fork" /></a>
1616
</p>
1717

1818
Creates a link next to edited and deleted Reddit comments and submissions to show the original post from before it was edited/removed.
@@ -35,7 +35,7 @@ The [Pushshift Reddit API](https://github.com/pushshift/api) is used for fetchin
3535

3636
### As a Userscript
3737

38-
This script can be installed to most browsers using userscript browser extensions such as [Violentmonkey](https://violentmonkey.github.io/), [Tampermonkey](https://www.tampermonkey.net/), among others using the green button on [Greasy Fork](https://greasyfork.org/en/scripts/407466-unedit-and-undelete-for-reddit).
38+
This script can be installed on most browsers using userscript browser extensions such as [Violentmonkey](https://violentmonkey.github.io/), [Tampermonkey](https://www.tampermonkey.net/), among others using the green button on [Greasy Fork](https://greasyfork.org/en/scripts/407466-unedit-and-undelete-for-reddit).
3939

4040
Alternatively, you may copy the contents of [`script.js`](https://github.com/DenverCoder1/Unedit-for-Reddit/blob/master/script.js) into a new script using any userscript browser extension.
4141

@@ -69,6 +69,12 @@ The following are known limitations that cannot be fixed:
6969

7070
## Changelog
7171

72+
## Changes in 3.9.0
73+
74+
- Support for edited submissions on Reddit Redesign on submission pages, list view, and popup view
75+
- Displays how long ago submissions were edited on Redesign since Reddit doesn't display this information
76+
- Minor code refactoring and added comments
77+
7278
### Changes in 3.8.0
7379

7480
- Added support for viewing deleted and moderator-removed submissions on Redesign and Old Reddit

manifest-v2.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"manifest_version": 2,
33
"name": "Unedit and Undelete for Reddit",
44
"description": "Creates links next to edited and deleted Reddit posts to show the original from before it was edited/removed.",
5-
"version": "3.8.0",
5+
"version": "3.9.0",
66
"content_scripts": [
77
{
88
"run_at": "document_idle",

manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"manifest_version": 3,
33
"name": "Unedit and Undelete for Reddit",
44
"description": "Creates links next to edited and deleted Reddit posts to show the original from before it was edited/removed.",
5-
"version": "3.8.0",
5+
"version": "3.9.0",
66
"content_scripts": [
77
{
88
"run_at": "document_idle",

script.js

Lines changed: 167 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// ==UserScript==
22
// @name Unedit and Undelete for Reddit
33
// @namespace http://tampermonkey.net/
4-
// @version 3.8.0
4+
// @version 3.9.0
55
// @description Creates the option next to edited and deleted Reddit comments/posts to show the original comment from before it was edited
66
// @author Jonah Lawrence (DenverCoder1)
77
// @match *://*reddit.com/*
@@ -37,6 +37,22 @@
3737
*/
3838
let currentLoading = null;
3939

40+
/**
41+
* List of submission ids of edited posts.
42+
* Used on Reddit redesign since the submissions are not marked as such.
43+
* This is set in the "load" event listener from the Reddit JSON API.
44+
* @type {Array<{id: string, edited: float}>}
45+
*/
46+
let editedSubmissions = [];
47+
48+
/**
49+
* The current URL that is being viewed.
50+
* On Redesign, this can change without the user leaving page,
51+
* so we want to look for new edited submissions if it changes.
52+
* @type {string}
53+
*/
54+
let currentURL = window.location.href;
55+
4056
/**
4157
* Showdown markdown converter
4258
* @type {showdown.Converter}
@@ -149,6 +165,9 @@
149165
// redesign
150166
if (!isOldReddit) {
151167
baseEl = document.querySelector(`#${postId}, .Comment.${postId}`);
168+
// in post preview popups, the id will appear again but in #overlayScrollContainer
169+
const popupEl = document.querySelector(`#overlayScrollContainer .Post.${postId}`);
170+
baseEl = popupEl ? popupEl : baseEl;
152171
if (baseEl) {
153172
if (baseEl.getElementsByClassName("RichTextJSON-root").length > 0) {
154173
bodyEl = baseEl.getElementsByClassName("RichTextJSON-root")[0];
@@ -238,8 +257,14 @@
238257
origBodyEl.scrollIntoView({ behavior: "smooth" });
239258
}
240259
}, 500);
241-
// on old reddit, if the comment is collapsed, expand it so the original comment is visible
242-
if (isOldReddit) {
260+
// Redesign
261+
if (!isOldReddit) {
262+
// Make sure collapsed submission previews are expanded to not hide the original comment.
263+
commentBodyElement.parentElement.style.maxHeight = "unset";
264+
}
265+
// Old reddit
266+
else {
267+
// If the comment is collapsed, expand it so the original comment is visible
243268
expandComment(commentBodyElement);
244269
}
245270
}
@@ -347,12 +372,14 @@
347372
showOriginalComment(commentBodyElement, "comment", post.body);
348373
// remove loading status from comment
349374
loading.innerHTML = "";
375+
logging.info("Successfully loaded comment.");
350376
} else if (post?.selftext) {
351377
// check if result has selftext instead of body (it is a submission post)
352378
// create new paragraph containing the selftext of the original submission
353379
showOriginalComment(commentBodyElement, "post", post.selftext);
354380
// remove loading status from post
355381
loading.innerHTML = "";
382+
logging.info("Successfully loaded post.");
356383
} else if (out?.data?.length === 0) {
357384
// data was returned empty
358385
loading.innerHTML = "not found";
@@ -379,6 +406,38 @@
379406
);
380407
}
381408

409+
/**
410+
* Convert unix timestamp in seconds to a relative time string (e.g. "2 hours ago").
411+
* @param {number} timestamp A unix timestamp in seconds.
412+
* @returns {string} A relative time string.
413+
*/
414+
function getRelativeTime(timestamp) {
415+
const time = new Date(timestamp * 1000);
416+
const now = new Date();
417+
const seconds = Math.round((now.getTime() - time.getTime()) / 1000);
418+
const minutes = Math.round(seconds / 60);
419+
const hours = Math.round(minutes / 60);
420+
const days = Math.round(hours / 24);
421+
const months = Math.round(days / 30.5);
422+
const years = Math.round(days / 365);
423+
if (years > 0 && months >= 12) {
424+
return `${years} ${years === 1 ? "year" : "years"} ago`;
425+
}
426+
if (months > 0 && days >= 30) {
427+
return `${months} ${months === 1 ? "month" : "months"} ago`;
428+
}
429+
if (days > 0 && hours >= 24) {
430+
return `${days} ${days === 1 ? "day" : "days"} ago`;
431+
}
432+
if (hours > 0 && minutes >= 60) {
433+
return `${hours} ${hours === 1 ? "hour" : "hours"} ago`;
434+
}
435+
if (minutes > 0 && seconds >= 60) {
436+
return `${minutes} ${minutes === 1 ? "minute" : "minutes"} ago`;
437+
}
438+
return "just now";
439+
}
440+
382441
/**
383442
* Locate comments and add links to each.
384443
*/
@@ -393,21 +452,51 @@
393452
editedComments = [];
394453
// redesign
395454
if (!isOldReddit) {
455+
// check for edited/deleted comments and deleted submissions
396456
selectors = [
397-
".Comment div:first-of-type span span:not(.found)", // Comments "edited..." or "Comment deleted/removed..."
457+
".Comment div:first-of-type span:not(.found)", // Comments "edited..." or "Comment deleted/removed..."
398458
".Post div div div:last-of-type div ~ div:last-of-type:not(.found)", // Submissions "It doesn't appear in any feeds..." message
399459
];
400460
elementsToCheck = Array.from(document.querySelectorAll(selectors.join(", ")));
401461
editedComments = elementsToCheck.filter(function (el) {
402462
el.classList.add("found");
403463
return (
404-
el.innerText.substring(0, 6) === "edited" || // include edited comments
405-
el.innerText.substring(0, 15) === "Comment deleted" || // include comments deleted by user
406-
el.innerText.substring(0, 15) === "Comment removed" || // include comments removed by moderator
407-
el.innerText.substring(0, 30) === "It doesn't appear in any feeds" || // include deleted submissions
408-
el.innerText.substring(0, 23) == "Moderators remove posts" // include submissions removed by moderators
464+
!el.children.length && // we only care about the element if it has no children
465+
(el.innerText.substring(0, 6) === "edited" || // include edited comments
466+
el.innerText.substring(0, 15) === "Comment deleted" || // include comments deleted by user
467+
el.innerText.substring(0, 15) === "Comment removed" || // include comments removed by moderator
468+
el.innerText.substring(0, 30) === "It doesn't appear in any feeds" || // include deleted submissions
469+
el.innerText.substring(0, 23) == "Moderators remove posts") // include submissions removed by moderators
409470
);
410471
});
472+
// Edited submissions found using the Reddit API
473+
editedSubmissions.forEach((submission) => {
474+
const postId = submission.id;
475+
const editedAt = submission.edited;
476+
selectors = [
477+
`#t3_${postId} > div:first-of-type > div:nth-of-type(2) > div:first-of-type > div:first-of-type > span:nth-of-type(3):not(.found)`, // Submission page
478+
`#t3_${postId} > div:last-of-type[data-click-id] > div:first-of-type > div:first-of-type > div:first-of-type:not(.found)`, // Subreddit listing view
479+
`.Post.t3_${postId} > div:last-of-type[data-click-id] > div:first-of-type > div:nth-of-type(2) > div:first-of-type:not(.found)`, // Profile/home listing view
480+
`.Post.t3_${postId}:not(.scrollerItem) > div:first-of-type > div:nth-of-type(2) > div:nth-of-type(2) > div:first-of-type > div:first-of-type:not(.found)`, // Preview popup
481+
];
482+
Array.from(document.querySelectorAll(selectors.join(", "))).forEach((el) => {
483+
el.classList.add("found");
484+
editedComments.push(el);
485+
// display when the post was edited
486+
const editedDateElement = document.createElement("span");
487+
editedDateElement.classList.add("edited-date");
488+
editedDateElement.style.fontStyle = "italic";
489+
editedDateElement.innerText = ` \u00b7 edited ${getRelativeTime(editedAt)}`; // middle-dot = \u00b7
490+
el.parentElement.appendChild(editedDateElement);
491+
});
492+
});
493+
// If the url has changed, check for edited submissions again
494+
// This is an async fetch that will check for edited submissions again when it is done
495+
if (currentURL !== window.location.href) {
496+
logging.info(`URL changed from ${currentURL} to ${window.location.href}`);
497+
currentURL = window.location.href;
498+
checkForEditedSubmissions();
499+
}
411500
}
412501
// old Reddit
413502
else {
@@ -428,32 +517,89 @@
428517
});
429518
}
430519
// create links
431-
editedComments.forEach(function (x) {
432-
createLink(x);
520+
editedComments.forEach(function (el) {
521+
// for removed submissions, add the link to an element in the tagline instead of the body
522+
if (el.closest(".usertext-body") && el.innerText === "[removed]") {
523+
el = el.closest(".entry")?.querySelector("p.tagline span:first-of-type") || el;
524+
}
525+
createLink(el);
433526
});
434527
}
435528

529+
/**
530+
* If the script timeout is not already set, set it and
531+
* run the findEditedComments in a second, otherwise do nothing.
532+
*/
533+
function waitAndFindEditedComments() {
534+
if (!scriptTimeout) {
535+
scriptTimeout = setTimeout(findEditedComments, 1000);
536+
}
537+
}
538+
539+
/**
540+
* Check for edited submissions using the Reddit JSON API.
541+
*
542+
* Since the Reddit Redesign website does not show if a submission was edited,
543+
* we will check the data in the Reddit JSON API for the information.
544+
*/
545+
function checkForEditedSubmissions() {
546+
// don't need to check if we're not on a submission page or list view
547+
if (!document.querySelector(".Post, .ListingLayout-backgroundContainer")) {
548+
return;
549+
}
550+
const pattern = new URLPattern(window.location.href);
551+
const jsonUrl = `https://www.reddit.com${pattern.pathname}.json?${pattern.search}`;
552+
logging.info(`Fetching additional info from ${jsonUrl}`);
553+
fetch(jsonUrl)
554+
.then(function (response) {
555+
if (!response.ok) {
556+
throw new Error(`${response.status} ${response.statusText}`);
557+
}
558+
return response.json();
559+
})
560+
.then(function (data) {
561+
logging.info("Response:", data);
562+
const out = data?.length ? data[0] : data;
563+
const children = out?.data?.children;
564+
if (children) {
565+
editedSubmissions = children
566+
.filter(function (post) {
567+
return post.kind === "t3" && post.data.edited;
568+
})
569+
.map(function (post) {
570+
return {
571+
id: post.data.id,
572+
edited: post.data.edited,
573+
};
574+
});
575+
logging.info("Edited submissions:", editedSubmissions);
576+
setTimeout(findEditedComments, 1000);
577+
}
578+
})
579+
.catch(function (error) {
580+
logging.error("Error fetching additional info:", error);
581+
});
582+
}
583+
436584
// check for new comments when you scroll
437-
window.addEventListener(
438-
"scroll",
439-
function () {
440-
if (!scriptTimeout) {
441-
scriptTimeout = setTimeout(findEditedComments, 1000);
442-
}
443-
},
444-
true
445-
);
585+
window.addEventListener("scroll", waitAndFindEditedComments, true);
586+
587+
// check for new comments when you click
588+
document.body.addEventListener("click", waitAndFindEditedComments, true);
446589

447590
// add additional styling, find edited comments, and set old reddit status on page load
448591
window.addEventListener("load", function () {
449592
// determine if reddit is old or redesign
450593
isOldReddit = /old\.reddit/.test(window.location.href) || !!document.querySelector("#header-img");
451-
// fix styling of created paragraphs in new reddit
594+
// Reddit redesign
452595
if (!isOldReddit) {
596+
// fix styling of created paragraphs in new reddit
453597
document.head.insertAdjacentHTML(
454598
"beforeend",
455599
"<style>p.og pre { font-family: monospace; background: #fff59d; padding: 6px; margin: 6px 0; color: black; } p.og h1 { font-size: 2em; } p.og h2 { font-size: 1.5em; } p.og > h3:first-child { font-weight: bold; margin-bottom: 0.5em; } p.og h3 { font-size: 1.17em; } p.og h4 { font-size: 1em; } p.og h5 { font-size: 0.83em; } p.og h6 { font-size: 0.67em; } p.og a { color: lightblue; text-decoration: underline; }</style>"
456600
);
601+
// check for edited submissions
602+
checkForEditedSubmissions();
457603
}
458604
// find edited comments
459605
findEditedComments();

0 commit comments

Comments
 (0)