Better favourite button (no more refreshing page)

Toggle favorites via fetch without following href making double navigation a problem

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey, Greasemonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals {tampermonkey_link:Tampermonkey}.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Userscripts.

Voor het installeren van scripts heb je een extensie nodig, zoals {tampermonkey_link:Tampermonkey}.

Voor het installeren van scripts heb je een gebruikersscriptbeheerder nodig.

(Ik heb al een user script manager, laat me het downloaden!)

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

(Ik heb al een beheerder - laat me doorgaan met de installatie!)

// ==UserScript==
// @name        Better favourite button (no more refreshing page)
// @namespace   Violentmonkey Scripts
// @match       *://*.furaffinity.net/view/*
// @grant       none
// @version     1.0
// @license     MIT
// @author      crunchy2382
// @description Toggle favorites via fetch without following href making double navigation a problem
// @icon        https://www.furaffinity.net/themes/beta/img/banners/fa_logo.png
// ==/UserScript==

(function () {
    'use strict';

    function findFavButton() {
        return [...document.querySelectorAll('a')].find(a => {
            const text = a.textContent.trim();
            return text === '+Fav' || text === '-Fav';
        });
    }

    function extractFavButtonFromHTML(html) {
        const doc = new DOMParser().parseFromString(html, 'text/html');
        return [...doc.querySelectorAll('a')].find(a => {
            const t = a.textContent.trim();
            return t === '+Fav' || t === '-Fav';
        });
    }

    function bindButton(button) {
        if (button.dataset.favBound) return;
        button.dataset.favBound = 'true';

        const originalHref = button.href;
        if (!originalHref) return;

        button.dataset.favUrl = originalHref;
        button.removeAttribute('href');
        button.style.cursor = 'pointer';

        button.addEventListener('click', e => {
            e.preventDefault();
            e.stopPropagation();

            const url = button.dataset.favUrl;
            if (!url) return;

            button.style.pointerEvents = 'none';
            button.style.opacity = '0.6';

            fetch(url, {
                method: 'GET',
                credentials: 'same-origin'
            })
            .then(res => res.text())
            .then(html => {
                const newBtn = extractFavButtonFromHTML(html);
                if (!newBtn) return;

                button.textContent = newBtn.textContent.trim();
                button.dataset.favUrl = newBtn.href;
            })
            .finally(() => {
                button.style.pointerEvents = '';
                button.style.opacity = '';
            });
        });
    }

    function init() {
        const btn = findFavButton();
        if (btn) bindButton(btn);
    }

    init();

    new MutationObserver(init).observe(document.body, {
        childList: true,
        subtree: true
    });
})();