// ==UserScript==
// @name MeFi Neater Bylines
// @namespace https://github.com/klipspringr/mefi-userscripts
// @version 2025-08-29-a
// @description MetaFilter: neaten up comment bylines
// @author Klipspringer
// @supportURL https://github.com/klipspringr/mefi-userscripts
// @license MIT
// @match *://*.metafilter.com/*
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_registerMenuCommand
// @downloadURL https://raw.githubusercontent.com/klipspringr/mefi-userscripts/main/mefi-replace-quote-label.user.js
// @updateURL https://raw.githubusercontent.com/klipspringr/mefi-userscripts/main/mefi-replace-quote-label.user.js
// ==/UserScript==
;(async () => {
"use strict"
if (
!/^\/(\d|comments\.mefi)/.test(window.location.pathname) ||
/rss$/.test(window.location.pathname)
)
return
const KEY_CUSTOM_LABEL = "custom-quote-button-label"
const SVG_REPLY = ``
const SVG_USE_REPLY = ``
const getSetting = async (key, def = "") => {
const value = await GM_getValue(key, def)
return String(value)
}
const handleEditLabel = async () => {
const existing = await GM_getValue(KEY_CUSTOM_LABEL, "")
const edited = prompt(
"Quote button label (leave blank for reply arrow):",
String(existing)
)
await GM_setValue(KEY_CUSTOM_LABEL, edited || "")
await modifyQuoteButtons()
}
GM_registerMenuCommand("Edit quote button", handleEditLabel)
const modifyQuoteButtons = async () => {
const start = performance.now()
const customLabel = await getSetting(KEY_CUSTOM_LABEL, "")
const label = customLabel || SVG_USE_REPLY
const nodes = document.querySelectorAll("a.quotebutton")
nodes.forEach((node) => {
// replace quote button content
node.innerHTML = label
if (node.hasAttribute("data-mrql-moved")) return
// move quote button to before flag button
node.parentNode.parentNode
.querySelector("span[id^='flag']")
?.before(node.parentNode)
// mark as done so we don't pick this up again
node.setAttribute("data-mrql-moved", "")
})
console.log(
"mefi-replace-quote-label",
nodes.length,
Math.round(performance.now() - start) + "ms"
)
}
document.body.insertAdjacentHTML("beforeend", SVG_REPLY)
// MefiQuote listens for the "mefi-comments" event, but:
// (a) my event listener wasn't picking that up for some reason; and
// (b) there could be timing issues as MefiQuote needs to complete its work first
// hence using MutationObserver instead.
const newCommentsElement = document.getElementById("newcomments")
if (newCommentsElement) {
const observer = new MutationObserver(() => modifyQuoteButtons())
observer.observe(newCommentsElement, { childList: true })
}
modifyQuoteButtons()
})()