NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name Reddit - Improve Saved Comments // @namespace https://openuserjs.org/users/zachhardesty7 // @author Zach Hardesty <zachhardesty7@users.noreply.github.com> (https://github.com/zachhardesty7) // @description reveals the save and report buttons and makes links right clickable // @copyright 2019, Zach Hardesty (https://zachhardesty.com/) // @license GPL-3.0-only; http://www.gnu.org/licenses/gpl-3.0.txt // @version 1.2.3 // @homepageURL https://github.com/zachhardesty7/tamper-monkey-scripts-collection/raw/master/reddit-improve-saved-comments.user.js // @homepage https://github.com/zachhardesty7/tamper-monkey-scripts-collection/raw/master/reddit-improve-saved-comments.user.js // @homepageURL https://openuserjs.org/scripts/zachhardesty7/Reddit_-_Improve_Saved_Comments // @homepage https://openuserjs.org/scripts/zachhardesty7/Reddit_-_Improve_Saved_Comments // @supportURL https://github.com/zachhardesty7/tamper-monkey-scripts-collection/issues // @updateURL https://openuserjs.org/meta/zachhardesty7/Reddit_-_Improve_Saved_Comments.meta.js // @downloadURL https://openuserjs.org/src/scripts/zachhardesty7/Reddit_-_Improve_Saved_Comments.user.js // @include https://www.reddit.com/user/*/saved/* // @require https://greasyfork.org/scripts/419640-onelementready/code/onElementReady.js?version=887637 // ==/UserScript== /* global onElementReady */ /** * sometimes you really need access to react internals to fix somebody * else's broken app and add no-brainer features * * @param {HTMLElement} DOMNode - arbitrary DOM node with a hidden react instance * @returns {object} react instance object */ const getReactInstance = (DOMNode) => DOMNode[Object.keys(DOMNode)[0]] /** * add features to comments * * @param {HTMLElement} button - triple dot more button under comments */ function improveComments(button) { const moreComponent = getReactInstance(button) const moreComponentProps = moreComponent.return.return.memoizedProps const genericButtonClass = button.parentElement.children[0].className const reportButton = document.createElement("button") reportButton.textContent = "Report" reportButton.className = genericButtonClass // navigate react obj reportButton.addEventListener( "click", moreComponentProps.children[0].props.onClick, ) // does not dynamically update text content const saveButton = document.createElement("button") saveButton.textContent = "Save / Unsave" saveButton.className = genericButtonClass saveButton.addEventListener( "click", moreComponentProps.children[1].props.onClick, ) // not defined in a separate function just because this is a quick // way to ensure that all of the important parts are loaded const comment = button.parentElement.parentElement.parentElement.parentElement.parentElement .parentElement.parentElement.parentElement // wrap the entirety of the comment in link el const container = comment.parentElement const wrapper = document.createElement("a") // link to comment page hidden in react instance wrapper.href = getReactInstance(comment).return.memoizedProps.comment.permalink wrapper.append(comment) // move all original DOM children wrapper.addEventListener("click", (e) => e.preventDefault()) // allow original click handler to take over container.append(wrapper) button.parentElement.append(reportButton) button.parentElement.append(saveButton) button.remove() } // gross, but Reddit uses styled-components / emotion and has almost no // constant selectors that don't change between renders, detail allows react to hydrate first window.addEventListener( "load", () => { onElementReady( "div.Comment > div > div > div:last-child > div > div:nth-child(2) > div:nth-child(2) > div:last-child > button:last-child[aria-haspopup][aria-expanded][aria-label]", { findOnce: false }, improveComments, ) }, false, )