Always add docs.rs link

This script modifies crate overview pages on crates.io such that if the documentation link isn't to docs.rs, it inserts one that is next to it

Versión del día 08/09/2022. Echa un vistazo a la versión más reciente.

// ==UserScript==
// @name         Always add docs.rs link
// @namespace    https://alexanderschroeder.net/
// @version      0.2
// @description  This script modifies crate overview pages on crates.io such that if the documentation link isn't to docs.rs, it inserts one that is next to it
// @author       Alexander Krivács Schrøder
// @include      https://crates.io/crates/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=crates.io
// @grant        none
// @license      MIT OR Apache-2.0
// ==/UserScript==

(function() {
    'use strict';

    function injectDocsrsLink() {
        // Grab the existing documentation link
        const documentation_link_container = getDocumentationLinkContainer();
        if (!documentation_link_container) {
            return;
        }
        const docs_link = documentation_link_container.children[1];

        // If it's already a docs.rs link, we don't need to do anything else
        if (!docs_link.href.startsWith('https://docs.rs/')) {
            // Grab the crate name from the URL
            const crate_name = window.location.href.substring(window.location.href.lastIndexOf('/') + 1);

            // Create our own documentation link container, adding the class from the existing one for
            // proper styling
            const docsrs_documentation_link_container = document.createElement('div');
            docsrs_documentation_link_container.classList.add(documentation_link_container.classList[0]);

            // Insert the docs.rs icon
            docsrs_documentation_link_container.appendChild(DOCSRS_LINK_SVG_ELEMENT);

            // Create the docs.rs link
            const docsrs_link = document.createElement('a');
            docsrs_link.href = `https://docs.rs/${crate_name}/latest`;
            docsrs_link.innerHTML = `docs.rs/${crate_name}/latest`;
            docsrs_documentation_link_container.appendChild(docsrs_link);

            // Insert our custom docs.rs link into the document. We're done!
            documentation_link_container.insertAdjacentElement('afterend', docsrs_documentation_link_container);
        }
    }

    function waitForPageToBeReady() {
        if (document.querySelectorAll('h3').length) {
            console.debug(document.querySelectorAll('h3').length);
            setDocsrsLinkSvgElement();
            injectDocsrsLink();
        } else {
            window.setTimeout(waitForPageToBeReady, 250);
        }
    }

    // Because this is a SPA, there's no actual elements in the document when we start running.
    // Since what we do depends on the document being present, we'll wait in a loop until things
    // have settled down.
    waitForPageToBeReady();

    function getDocumentationLinkContainer() {
        const h3s = Array.from(document.querySelectorAll('h3'));
        const documentation_h3 = h3s.filter((v) => v.innerHTML === 'Documentation')[0];
        return documentation_h3 ? documentation_h3.nextElementSibling : null;
    }

    // Holds a ready-made docs.rs icon SVG element
    let DOCSRS_LINK_SVG_ELEMENT = null;

    function setDocsrsLinkSvgElement() {
        // Create SVG element based on SVG from crates.io
        const markup = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512" fill="currentColor"><path d="M488.6 250.2L392 214V105.5c0-15-9.3-28.4-23.4-33.7l-100-37.5c-8.1-3.1-17.1-3.1-25.3 0l-100 37.5c-14.1 5.3-23.4 18.7-23.4 33.7V214l-96.6 36.2C9.3 255.5 0 268.9 0 283.9V394c0 13.6 7.7 26.1 19.9 32.2l100 50c10.1 5.1 22.1 5.1 32.2 0l103.9-52 103.9 52c10.1 5.1 22.1 5.1 32.2 0l100-50c12.2-6.1 19.9-18.6 19.9-32.2V283.9c0-15-9.3-28.4-23.4-33.7zM358 214.8l-85 31.9v-68.2l85-37v73.3zM154 104.1l102-38.2 102 38.2v.6l-102 41.4-102-41.4v-.6zm84 291.1l-85 42.5v-79.1l85-38.8v75.4zm0-112l-102 41.4-102-41.4v-.6l102-38.2 102 38.2v.6zm240 112l-85 42.5v-79.1l85-38.8v75.4zm0-112l-102 41.4-102-41.4v-.6l102-38.2 102 38.2v.6z"></path></svg>`
        const template = document.createElement('template');
        template.innerHTML = markup;
        const element = template.content.firstChild;

        // Copy the class from the existing icon onto ours for proper styling
        const documentation_link_container = getDocumentationLinkContainer();
        if (!documentation_link_container) {
            return;
        }
        const docs_icon = documentation_link_container.children[0];
        element.classList.add(docs_icon.classList[0]);

        DOCSRS_LINK_SVG_ELEMENT = element;
    }
})();