// ==UserScript== // @name Tildes with "Newest reply" // @namespace blankie-scripts // @match https://tildes.net/* // @version 1.0.2 // @author blankie // @description A userscript that adds a "newest reply" to topics on Tildes // @inject-into content // @run-at document-end // ==/UserScript== "use strict"; function commentSortKey(li) { // Set `li` to the most nested reply while (true) { let reply = li.querySelector(".comment-tree-item"); if (!reply) { break; } li = reply; } return new Date(li.querySelector(".comment-header .comment-posted-time").dateTime); } function sortCommentsByNewestReply(ol = null, sortedCommentTrees = null) { ol = ol || document.querySelector("#comments"); sortedCommentTrees = sortedCommentTrees || new WeakSet(); let comments = []; for (let li of ol.children) { let commentTree = li.querySelector(".comment-tree"); if (!commentTree || sortedCommentTrees.has(commentTree)) { continue; } sortedCommentTrees.add(commentTree); sortCommentsByNewestReply(commentTree, sortedCommentTrees); comments.push(li); } comments.sort(function(lhs, rhs) { // `rhs - lhs` sorts by reverse chronological order, while `lhs - rhs` // sorts by chronological order return commentSortKey(rhs) - commentSortKey(lhs); }); for (let li of comments) { ol.append(li); } } function sortFormSubmitHook(event) { event.preventDefault(); let searchParams = new URLSearchParams(location.search); let sortMethod = event.target.querySelector("select").selectedOptions[0].value; if (sortMethod === "newest_reply") { searchParams.delete("comment_order"); searchParams.set("b_comment_order", "newest_reply"); history.pushState(null, "", `?${searchParams.toString()}`); sortCommentsByNewestReply(); } else { searchParams.delete("b_comment_order"); searchParams.set("comment_order", sortMethod); location.search = searchParams.toString(); } } function addNewestReply() { let form = document.querySelector(".topic-comments-header form"); if (!form) { return; } let searchParams = new URLSearchParams(location.search); let bCommentOrder = searchParams.get("b_comment_order"); let select = form.querySelector("select"); let newSelect = select.cloneNode(true); newSelect.removeAttribute("data-js-autosubmit-on-change"); newSelect.addEventListener("change", function() { // Auto-submit only if there is no "OK" button if (!form.querySelector("button[type=submit]")) { form.requestSubmit(); } }); let option = document.createElement("option"); option.value = "newest_reply"; option.innerText = "newest reply"; if (bCommentOrder === "newest_reply") { option.selected = true; } newSelect.append(option); select.replaceWith(newSelect); form.addEventListener("submit", sortFormSubmitHook); } addNewestReply(); if ((new URLSearchParams(location.search)).get("b_comment_order") === "newest_reply") { sortCommentsByNewestReply(); }