TamperMonkey KF QoL improvement scripts - including hide PM participant list, limit max participant display, etc.

  • 🐕 I am attempting to get the site runnning as fast as possible. If you are experiencing slow page load times, please report it.

Cold Root Beer

Refreshing
kiwifarms.net
Joined
Jul 8, 2020
Not sure if anyone else has already done this and shared, but I was getting annoyed by what a mess all the PMs that have everyone invited do to the UI and makes navigating the PM dropdown (and the PM pages themselves) hell. So I made some quick TamperMonkey scripts for myself to fix some of those things, and decided to share in case anyone else was annoyed too.

First one is a fix for the PM notification dropdown menu listing every single participant:

1649610977666.png

JavaScript:
// ==UserScript==
// @name         Shorten KF convo participants
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  shortens the list of convo participants when you open the PM dropdown
// @author       Cold Root Beer
// @match        https://kiwifarms.net/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=kiwifarms.net
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    let globalChangeLockout = false;

window.addEventListener('load', (event) => {
    let convoMenu = document.querySelector(`[data-href="/conversations/popup"]`);


    convoMenu.addEventListener('DOMSubtreeModified', CheckRunConvoShortener);
  });


function CheckRunConvoShortener() {
    if (!globalChangeLockout) {
        globalChangeLockout = true;
        ConvoShortener();

        globalChangeLockout = false;
    }
}

function ConvoShortener() {
    let listOfShit = document.getElementsByClassName("listInline listInline--selfInline listInline--comma");

    for (let index = 0; index < listOfShit.length; index++) {
        let giantList = listOfShit[index];

        let innerLength = giantList.childElementCount.valueOf();

        if (innerLength > 4) {
            let displayList = giantList.cloneNode(true);
            giantList.innerHTML = '';
            for (let j = 0; j < 4; j++) {
                giantList.appendChild(displayList.childNodes[0]);

            }
            let countNode = document.createElement("li");
            let countNodeText = document.createTextNode(`and ${innerLength - 3} more...`);

            countNode.appendChild(countNodeText);

            giantList.appendChild(countNode);

        }
    }
}

})();

The second one makes the actual conversation pages on the PMs with giant lists of people more usable/readable by hiding the bottom of the PM participant list by default, adding a button to toggle displaying the list, and turning the list into a fixed height scrollable element to make the page more usable even if you have it unhidden:

1649610314317.png
1649610297337.png
JavaScript:
// ==UserScript==
// @name         Hide toggle Convo Participants
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  By default hides the list of Convo Participants within DMs. Button to toggle if the list displays, and makes the list a fixed height scrollable element to make it easier to deal with
// @author       Cold Root Beer
// @match        https://kiwifarms.net/conversations/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=kiwifarms.net
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

  
    window.addEventListener('load', (event) => {
        let partipMenu = document.querySelector(`div.p-body-sidebar div.block div.block-container ol.block-body`);
        partipMenu.style.display = "none";
        partipMenu.style.overflowY = "scroll";
        partipMenu.style.maxHeight = "65vh";

        let toggleButton = document.createElement("button");
        toggleButton.innerHTML = 'Show/Hide participants';
        toggleButton.classList.add("button--primary", "button", "button--icon");

        toggleButton.addEventListener("click", () => {
            if (partipMenu.style.display === 'none') {
                partipMenu.style.display = 'block';
            } else {
                partipMenu.style.display = 'none';
            }
        });

        partipMenu.before(toggleButton);



  });
})();

To use these (if you don't already know), just install the tampermonkey extension, and create a new userscript for the one you want, and just control+A and control+V the code of the script, then save and it should be g2g. So, to use both of these, you'd have to create two new userscripts.

If I make any others in the future, I'll post them ITT. If anyone else has any KF improvement tampermonkey scripts they've made, feel free to share them ITT as well. If this isn't the right place to post this stuff, soz mods. If you have any questions, feel free to ask.
 
Wanted to get better at Javascript. I still feel like I didn't.
JavaScript:
// ==UserScript==
// @name        Tooltips for Kiwi Farms
// @include     https://kiwifarms.st/*
// @include     https://kiwifarms.st/chat/*
// @require     https://cdn.jsdelivr.net/gh/CoeJoder/waitForKeyElements.js@v1.2/waitForKeyElements.js
// @grant       none
// @unwrap
// ==/UserScript==

(function() {
    'use strict';
    /*
        I'm using a custom version of this library: https://github.com/CreativeTechGuy/Tooltips
        Things I added:
            Text and Border Color option
            Background Color option
    */
    class TooltipHelper{
        constructor(a){a=a||{},this.settings={tooltipWidth:a.tooltipWidth||300,tooltipHTMLTag:a.tooltipHTMLTag||"custom-tooltip",tooltipColor: a.tooltipColor||"rgb(255,255,255)",tooltipBGColor: a.tooltipBGColor||"rgba(17,17,17)"},
        this.tooltipData={cache:new WeakMap,maxDepth:0,currentElem:null},this._createTooltipElement(),document.body.addEventListener("mousemove",a=>{this._getEventPath(a)[0]!==this.tooltipData.currentElem&&(this.tooltipData.maxDepth=0,this.tooltipData.currentElem=null,this.tooltipElement.style.opacity="0")})}
        setTooltip(a,b){const c=this.tooltipData.cache.has(a);this.tooltipData.cache.set(a,{text:b,mousemove:b=>{this._getEventPath(b).length>this.tooltipData.maxDepth&&(this.tooltipData.maxDepth=this._getEventPath(b).length,this.tooltipData.currentElem=a,this._makeTooltipVisible(a))},mouseleave:()=>{this.tooltipData.currentElem===a&&(this.tooltipData.maxDepth=0,this.tooltipData.currentElem=null),this.tooltipElement.style.opacity="0"}});c||(a.style.setProperty("pointer-events","auto","important"),a.addEventListener("mouseenter",this.tooltipData.cache.get(a).mousemove),a.addEventListener("mousemove",this.tooltipData.cache.get(a).mousemove),a.addEventListener("mouseleave",this.tooltipData.cache.get(a).mouseleave))}
        _makeTooltipVisible(a){this._doesTooltipExist()||this._createTooltipElement(),this.tooltipElement.innerText=this.tooltipData.cache.get(a).text,window.requestAnimationFrame(()=>{this.tooltipElement.style.opacity="1";const b=this.tooltipElement.getBoundingClientRect(),c=this._getAbsoluteBoundingRect(a);this.tooltipElement.style.top=0<c.top-b.height-15?c.top-b.height-15+"px":c.bottom+15+"px";let d=Math.round(c.left+c.width/2);document.documentElement.scrollWidth>this.settings.tooltipWidth&&(d+this.settings.tooltipWidth/2>document.documentElement.scrollWidth&&(d+=document.documentElement.scrollWidth-(d+this.settings.tooltipWidth/2)),0>d-this.settings.tooltipWidth/2&&(d+=0-(d-this.settings.tooltipWidth/2))),this.tooltipElement.style.left=d-this.settings.tooltipWidth/2+"px"})}
        getTooltip(a){const b=this.tooltipData.cache.get(a);return b?b.text:null}
        removeTooltip(a){this.tooltipData.cache.get(a)&&(a.removeEventListener("mouseenter",this.tooltipData.cache.get(a).mousemove),a.removeEventListener("mousemove",this.tooltipData.cache.get(a).mousemove),a.removeEventListener("mouseleave",this.tooltipData.cache.get(a).mouseleave),this.tooltipData.cache.delete(a))}
        _getAbsoluteBoundingRect(a){const b=a.getBoundingClientRect(),c=window.pageXOffset||document.documentElement.scrollLeft,d=window.pageYOffset||document.documentElement.scrollTop;return{width:b.width,height:b.height,top:b.top+d,right:b.right+c,bottom:b.bottom+d,left:b.left+c}}
        _getEventPath(a){let b=a.path||a.composedPath&&a.composedPath();if(!b){b=[];for(let c=a.target;c;){let a=null;if(c.parentNode)a=c.parentNode;else if(c.host)a=c.host;else if(c.defaultView)a=c.defaultView;else break;b.push(a),c=a}}return b}
        _doesTooltipExist(){return null!==this.tooltipElement.parentElement}
        _createTooltipElement(){const a=document.createElement(this.settings.tooltipHTMLTag);a.style.cssText=`background-color:${this.settings.tooltipBGColor};border-radius:4px;color:${this.settings.tooltipColor};font-size:13px;font-weight:normal;padding:0.5em 1em;box-sizing:border-box;z-index:99999999;font-family:monospace;position:absolute;pointer-events:none;text-align:left;white-space:pre-wrap;width:${this.settings.tooltipWidth}px;transform:translate3d(0,0,0);-webkit-backface-visibility:hidden;backface-visibility:hidden;opacity:0;box-shadow:${this.settings.tooltipColor} 0px 0px 5px 0px inset;`,document.body.appendChild(a),this.tooltipElement=a}
    }

    const tooltipHelper = new TooltipHelper({
        tooltipWidth: 200,
        tooltipHTMLTag: "custom-tooltip",
        tooltipColor: "rgb(30,255,30)",
        tooltipBGColor: "rgba(10,10,10)"
    });

    tooltipHelper.setTooltip(document.getElementById("new-message-submit"), "Send message to chat.");

    waitForKeyElements(".author", addTooltipToChatAuthors, false, 200);
    waitForKeyElements(".activity", addLinksToChatUsers, false, 200);

    /*
        Adds tooltip to inform user that clicking on usernames in chat will add them to your message.
    */
    function addTooltipToChatAuthors() {
        var chatAuthors = document.getElementsByClassName("author"), i;
        for (i = 0; i < chatAuthors.length; i++) {
            var chatAuthorUsername = chatAuthors[i].innerHTML;
            tooltipHelper.setTooltip(chatAuthors[i], "Reply to @"+ chatAuthorUsername + " in your chat message.");
        }
    }

    /*
        Add link to profile of user in chat user list.
    */
    function addLinksToChatUsers() {
        var chatUsers = document.getElementsByClassName("activity"), i;
        for (i = 0; i < chatUsers.length; i++) {
            var chatUserActivityId = chatUsers[i].id;
            var chatUserId = chatUserActivityId.split("-")[2];
            var chatUserProfileURL = "/members/" + chatUserId + "/";
            try {
                var chatUserTextElm = chatUsers[i].children[1];
                chatUserTextElm.setAttribute("href", chatUserProfileURL);
                chatUserTextElm.style.color = "var(--link-color)";
            }catch {
            }
        }
    }

})();
 
Last edited:
Back