Jump to content

User:TayIorRobinson/wikigender.js

From Wikipedia, the free encyclopedia
This is an old revision of this page, as edited by TayIorRobinson (talk | contribs) at 13:55, 13 August 2021 (add the thing). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.
(diff) ← Previous revision | Latest revision (diff) | Newer revision → (diff)
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
//<nowiki>
// ==UserScript==
// @name        WikiGender
// @author      Taylor Robinson
// @description a user script for showing statistics on Wikipedia articles about the gender of those linked in the article
// @match       *://*.wikipedia.org/wiki/*
// ==/UserScript==

/**
 * @typedef {HTMLDivElement} GenderBar
 * @typedef {'male' | 'female' | 'other' | 'none'} Gender
 * @typedef {{gender: string, title: string}} GenderedLink
 * @typedef {{gender: string, num_links: number, pct_links: number}} GenderSummary
 * @typedef {{article: string, details: GenderedLink[], num_outlinks: number, summary: GenderSummary[]}} GenderData
 */

(async() => {
    const GENDERDATA_API = "https://article-gender-data.wmcloud.org/api/v1/details";
    const GENDER_COLOURS = {
        male: "#517FC1",
        female: "#F19359",
        other: "#FAD965",
        none: "#EEEEEE"
    };

    /**
     * Requests the gender data for the current page.
     * @returns {Promise<GenderData>} The analysed gender data for the page.
     */
    async function fetchData() {
        let lang = location.host.split(".")[0];
        let article = location.pathname.split("/")[2];

        let response = await fetch(GENDERDATA_API + "?lang=" + lang + "&title=" + article);
        let data = await response.json();

        return data;
    }

    /**
     * Creates an instance of a gender bar on the current page.
     * @returns {GenderBar}
     */
    function createGenderBar() {
        let element = document.createElement("div");
        element.id = "genderbar";
        element.style.height = "5px";
        element.style.width = "100%";
        element.style.marginTop = "-0.5em";

        document.querySelector("#firstHeading").insertAdjacentElement("afterend", element);
        return element;
    }

    /**
     * There are many gender labels on Wikidata, however for ease of reading on the graph, we reduce it to 4 options.
     * @param {string} name
     * @returns {Gender}
     */
    function simplifyGender(name) {
        switch (name) {
        case "N/A":
            return "none";
        case "male":
        case "transgender male":
        case "transmasculine":
            return "male";
        case "female":
        case "transgender female":
        case "transfeminine":
            return "female";
        default:
            return "other";
        }
    }


    /**
     * Fills a genderbar with a gender summary.
     * @param {GenderBar} genderbar The gender bar to fill.
     * @param {GenderSummary[]} summaries The summary of the genders.
     */
    function fillGenderBar(genderbar, summaries) {
        genderbar.innerHTML = ""; // Clear the gender bar of any previous elements.
        let simpleSummaries = {
            male: { num_links: 0, pct_links: 0, gender: "male" },
            female: { num_links: 0, pct_links: 0, gender: "female" },
            other: { num_links: 0, pct_links: 0, gender: "other" },
            none: { num_links: 0, pct_links: 0, gender: "none" }
        };
        for (let summary of summaries) {
            simpleSummaries[simplifyGender(summary.gender)].num_links += summary.num_links;
            simpleSummaries[simplifyGender(summary.gender)].pct_links += summary.pct_links;
        }
        let x = 0;
        let gradientParts = [];
        for (let summary of Object.values(simpleSummaries)) {
            gradientParts.push(GENDER_COLOURS[summary.gender] + " " + x + "%");
            x += summary.pct_links * 100;
            gradientParts.push(GENDER_COLOURS[summary.gender] + " " + x + "%");
        }
        genderbar.style.backgroundImage = "linear-gradient(to right, " + gradientParts.join(", ") + ")";
    }

    /**
     * Applies colour to links on the page
     * @param {GenderedLink[]} links The links to colour.
     */
    function applyLinkColours(links) {
        let pageLinks = document.querySelector(".mw-parser-output").querySelectorAll("a[href^=\"/wiki/\"]");
        // Create an object of all the links on the page.
        let linksOnPage = {};
        for (let link of pageLinks) {
            linksOnPage[decodeURIComponent(link.href.split("/")[4].toLowerCase().replace(/_/g, " "))] = link;
        }
        // Colour the links.
        console.log(linksOnPage);
        for (let link of links) {
            let linkOnPage = linksOnPage[link.title];
            console.log(linkOnPage, link.title);
            if (!linkOnPage) continue;
            linkOnPage.style.backgroundColor = GENDER_COLOURS[simplifyGender(link.gender)] + "88";
        }
    }






    let mwIndicator = document.createElement("div");
    mwIndicator.className = "mw-indicator";
    mwIndicator.id = "mw-indicator-gender";
    document.querySelector(".mw-indicators").appendChild(mwIndicator);

    let link = document.createElement("a");
    link.href = "javascript:void";
    link.onclick = async() => {
        link.remove();
        let data = await fetchData();
        fillGenderBar(createGenderBar(), data.summary);
        applyLinkColours(data.details);
    };
    link.title = "Analyse the gender of the links on the page";
    mwIndicator.appendChild(link);

    let img = document.createElement("img");
    img.alt = "Gender equality icon";
    img.src = "/media/wikipedia/commons/thumb/d/d7/Gender_equality.png/20px-Gender_equality.png";
    img.srcset = "/media/wikipedia/commons/thumb/d/d7/Gender_equality.png/30px-Gender_equality.png 1.5x, /media/wikipedia/commons/thumb/d/d7/Gender_equality.png/40px-Gender_equality.png 2x";
    img.decoding = "async";
    img.height = 20;
    img.width = 20;
    link.appendChild(img);
})();

//</nowiki>