4

About

With Outdated Answers: accepted answer is now unpinned on Stack Overflow, I find that it would be nice to have an indicator. Some posts have multiple pages, and searching for the one post among many requires a little too much scrolling.

How it works

The script will check the timeline for an accept event. If it finds one, it will add a checkmark to the post title, as marked in red.

If this variable in the script is set to false:

const addToTitle = false;

the script will instead add a button next to the sorting filters, as marked in pink.

Clicking on the checkmark / button will take you directly to the accepted post.

Screenshot

Sites

Should work across the Stack Exchange network.
Note that the wording of the button isn't locale specific.

Platform

Should work with any user script manager & any browser running JavaScript.
Tested using Opera with Tampermonkey.

Code

Vanilla JavaScript:

// ==UserScript==
// @name         Stack Accepted Answer Button
// @description  Show a button that links to the accepted Answer.
// @version      0.3
// @namespace    scratte-fiddlings
// @author       Scratte (https://stackoverflow.com/users/12695027)
//
// @include      /^https://(?:[^/]+\.)?stackoverflow.com/questions/\d+/
// @include      /^https://(?:meta\.)?serverfault.com/questions/\d+/
// @include      /^https://(?:meta\.)?superuser.com/questions/\d+/
// @include      /^https://(?:meta\.)?askubuntu.com/questions/\d+/
// @include      /^https://(?:meta\.)?mathoverflow.net/questions/\d+/
// @include      /^https://stackapps.com/questions/\d+/
// @include      /^https://[^/]+\.stackexchange.com/questions/\d+/
//
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // Idea of adding the checkmark to the title came from double-beep (https://stackoverflow.com/users/10607772)
    // https://chat.stackoverflow.com/transcript/message/52991681#52991681
    const addToTitle = true;

    const answerFilters = document.querySelector("#answers #answers-header .js-filter-btn");
    if (!answerFilters)
        return;

    const isAnswerOnPage = (answerId) => {
        return !!document.querySelector(`#answer-${answerId}`);
    }

    const addButton = (answerId) => {
        const buttonLink = document.createElement("a");

        if (isAnswerOnPage(answerId)) {
            // https://chat.stackoverflow.com/transcript/message/52991704#52991704
            buttonLink.addEventListener("click", () => StackExchange.question.scrollToPost(answerId));
        } else {
            const link = `${window.location.origin}/a/${answerId}`;
            buttonLink.href = link;
        }

        if (addToTitle) {
            const title = document.querySelector("#question-header a");
            buttonLink.innerHTML = `<svg aria-hidden="true" class="svg-icon iconCheckmarkLg" width="36" height="36" viewBox="0 0 36 36">
                                        <path d="m6 14 8 8L30 6v8L14 30l-8-8v-8z"></path>
                                    </svg>`;
            buttonLink.style.color = "var(--green-500)";

            title?.before(buttonLink);
        } else {
            buttonLink.className = "mx6 flex--item s-btn s-btn__filled";
            buttonLink.title = "Links to the accepted Answer";
            buttonLink.style.backgroundColor = "var(--green-400)";
            buttonLink.style.border = "revert";
            buttonLink.style.color = "white";
            buttonLink.textContent = "Accepted";

            answerFilters.parentElement?.before(buttonLink);
        }
    }

    const fetchAnswer = async () => {
        const questionId = window.location.pathname.split('/')[2];

        const resp = await fetch(`/posts/${questionId}/timeline?filter=NoVoteDetail`);
        const text = await resp.text();
        const parsedHTML = new DOMParser().parseFromString(text, 'text/html');

        const events = parsedHTML.querySelector(".event-rows");
        for (const element of [...events.children]) {
            const eventType = element.dataset.eventtype;
            if (eventType === "answer") {
                const accepted = element.querySelector(".badge-earned-check");
                if (accepted) {
                    const answerId = element.dataset.eventid;
                    addButton(answerId);
                    return;
                }
            }
        }
    }

    fetchAnswer();

})();

Contact

For bugs, please post here. Comments are fine too.

5
  • wait... is that an actual question in the image? Sep 11 at 23:10
  • @Someone_who_likes_SE No, this is just like a mockup in order to show the userscript features. Sep 11 at 23:17
  • 1
    Oh. I thought someone's mouse wheel scrolled so slowly that it took 11 hours to scroll a question. Sep 11 at 23:19
  • @Someone_who_likes_SE There were 4 pages of Answers on the post. It takes a while to go through them all. Sep 11 at 23:22
  • 2
    Now the accepted answer is unpinned, so if there are pages and pages of answers above an accepted answer that scored this low, it would literally take hours. Thanks for this script! Sep 11 at 23:23

You must log in to answer this question.

Browse other questions tagged .