Discussions » Development

Make "man2html" more readable

§
Posted: 23.3.2024

Hi,

I wrote a simple script to make "man2html" more readable.

If you're a Linux user (Debian / Ubuntu / Whatever) and it's hard for you to understand man pages in terminal, You might tried to view them with man2html. However, the design of these pages was a bit ugly to me, So I made the following JS code, that makes it more readable - With dark mode, proper font (monospaced), and the ability to remember your preferences with a dark-mode cookie (if set to 1, It will always be in dark mode. If set to 0, it will turn off).

I'll add two versions of the code, so you can see- One is the "original" (long, ugly code) and the second one is a minified version of the same code, so you can simply paste and use.

Have fun & feel free to give me your feedback. License: Public (you don't need to attribute me for the use, and you can use it for any purpose, including on commercial machines).

You can host your man2html on a virtual machine, or on your localhost, or on any other device, and when your browser will be searching for /cgi-bin/man/man*, It will treat it as man2html website and make it a bit prettier. As I mentioned, it saves one cookie - to remember your dark mode preferences. You can undo it by changing the code.

The long one:

// ==UserScript==
// @name         man2html Prettify
// @namespace    http://tampermonkey.net/
// @version      2024-03-15
// @description  Make man2html pages more pretty!
// @author       Public
// @match        *://*/cgi-bin/man/man*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=0.1
// @grant        none
// ==/UserScript==
(function(){
    "use strict";
    let a = null;
    let pos = 0;
    if (window.location.href.indexOf("cgi-bin/man/man2html") == -1 || document.title.indexOf("not found") > -1) {
        a = document.createElement("a");
        a.href = "/cgi-bin/man/man2html";
        a.innerHTML = "« Back to Home";
        a.style.marginRight = "10px";
        document.body.insertBefore(a, document.body.children[0]);
        pos = 1;
    }
    // Make a CSS styling syntax, and a <style> object
    a = [[],document.createElement("style")];
    // From here on, write the rules
    a[0].push("*{font-family:Red Hat Mono,Hack,monospace;box-sizing:border-box}");
    a[0].push(":root{--a:#14120c;--b:#fefefe;--c:#b30000;--d:#00ff95;--e:#492167}:focus{outline:2px solid;outline-offset:3px}");
    a[0].push("body ::selection,body::selection{background-color:var(--a);color:var(--b)}body ::-moz-selection,body::-moz-selection{background-color:var(--a);color:var(--b)}");
    a[0].push("body.m2h_dm ::selection,body.m2h_dm::selection{background-color:var(--b);color:var(--a)}body.m2h_dm ::-moz-selection,body.m2h_dm::-moz-selection{background-color:var(--b);color:var(--a)}");
    a[0].push("body{padding:20px 40px;background-color:var(--b);color:var(--a)}body.m2h_dm{background-color:var(--a);color:var(--b)}");
    a[0].push("body a{font-weight:bold}body a{color:var(--c)}body.m2h_dm a{color:var(--d)}");
    a[0].push("body a#m2h_tm::before{content:'Turn '}body a#m2h_tm::after{content:' dark mode'}");
    a[0].push("hr{border:1px solid rgba(0,0,0,0.15);margin:2.5px 0;display:block}body.m2h_dm hr{border-color:rgba(255,255,255,0.15)}");
    a[0].push("input{border:1px solid;background-color:rgba(0,0,0,0);color:var(--a);padding:7.5px 15px}body.m2h_dm input{color:var(--b)}");
    a[0].push("form{font-size:0;display:table;border-radius:50px;border:1px solid var(--e);overflow:hidden;position:relative}form input:last-child{cursor:pointer;font-weight:bold;text-transform:uppercase}");
    a[0].push("form input{border:0px solid rgba(0,0,0,0);display:table-cell}");
    a[0].push('form input[type="submit"],form input[type="reset"],form input[type="button"]{color:var(--b);background-color:var(--e)}');
    a[0].push("table{color:inherit;width:100%}table td{padding:2.5px}");
    a[0].push(".m2h_u{margin:0 10px;font-weight:normal;user-select:none;text-decoration:none;font-size:13px}.m2h_u::before,.m2h_u::after{text-decoration:none}.m2h_u::before{content:'[ '}.m2h_u::after{content:' ]'}");
    // Once we've done, Append it to the tag
    a[0] = a[0].join("");
    a[1].innerHTML = a[0];
    a = a[1];
    // Append the tag to the head, and override `a` for later use.
    document.head.appendChild(a);
    a = null;
    // Turn `a` into a 'toggle' button between dark and bright mode
    a = [document.createElement("a"),"m2h_tm"];
    a[0].href = "javascript:;";
    a[0].id = a[1];
    document.body.insertBefore(a[0], document.body.children[pos]);
    a = [document.getElementById(a.pop()),"m2h_dm"];
    // Make some useful functions
    function txt_update() {
        // 'Turn [on/off]' string
        a[0].innerHTML = document.body.classList.contains(a[1]) ? "off" : "on";
    }
    function chstate(e, m = null) {
        if (m === null) {
            if (document.body.classList.contains(a[1])) {
                document.body.classList.remove(a[1]);
            } else {
                document.body.classList.add(a[1]);
            }
        } else {
            // Add or remove manually by the script. Can be useful when having cookies...
            document.body.classList[(m == true ? "add" : "remove")](a[1]);
        }
        // update the shown text according to the new state
        txt_update(a[0]);
        // Update cookie
        cookie.set();
    }
    const cookie = { "name": "m2h_ck", "set": function() {
        // Set the cookie/update it
        document.cookie = cookie.name + "=" + (document.body.classList.contains(a[1]) ? 1 : 0) + "; Expires=" + (new Date(2147483647 * 1000).toUTCString()) + "; Path=/";
    }, "get": function() {
        // Get the cookie data
        if (document.cookie.indexOf(cookie.name + "=") > -1) {
            // Get the state
            let c = document.cookie.split("; ");
            for (let b = 0; b < c.length; b++) {
                if (c[b].indexOf(cookie.name + "=") > -1) {
                    c[b] = c[b].split(cookie.name + "=");
                    c[b] = c[b].pop();
                    c[b] = !isNaN(c[b]) ? Number(c[b]) : 0;
                    c = c[b];
                    b = null;
                    break;
                }
            }
            return c;
        }
        return null;
    }};
    a[0].addEventListener("click", chstate, false);
    if (cookie.get() == null) cookie.set();
    chstate(null, cookie.get());
    /*
    // If the page is 404, add a link to the homepage
    function pagestat() {
        return document.title.indexOf("not found") > -1 ? 404 : 200;
    }
    let pgst = pagestat();
    if (pgst == 404) {
        let b;
        b = document.createElement("br");
        document.body.appendChild(b);
        b = document.createElement("a");
        b.href = window.location.href.split("?")[0];
        b.innerHTML = "Back to Home";
        document.body.appendChild(b);
    }
    */
    // If the page is a manpage of something, add "Jump up" to each header section
    if (document.title.indexOf("Man page of") > -1) {
        let b = [];
        for (let i = 1; i <= 6; i++) b.push("h" + i);
        b = b.join(",");
        b = document.querySelectorAll(b);
        let is_index = false;
        for (let i = 1; i < b.length; i++) {
            // If is index, do only part:
            is_index = b[i].innerHTML.toLowerCase().trim() === "index";
            // Do with the rest
            let c;
            c = document.createElement("a");
            c.href = "#";
            c.classList.add("m2h_u");
            c.innerHTML = "Up";
            b[i].appendChild(c);
            if (!is_index) {
                c = document.createElement("a");
                c.href = "#index";
                c.classList.add("m2h_u");
                c.innerHTML = "Index";
                b[i].appendChild(c);
            }
        }
    }
})();

The short one (compressed):

// ==UserScript==
// @name         man2html Prettify (Min)
// @namespace    http://tampermonkey.net/
// @version      2024-03-15
// @description  Make man2html pages more pretty!
// @author       Public
// @match        *://*/cgi-bin/man/man*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=0.1
// @grant        none
// ==/UserScript==
!function(){"use strict";let n=null,o=0;function e(o,e=null){null===e?document.body.classList.contains(n[1])?document.body.classList.remove(n[1]):document.body.classList.add(n[1]):document.body.classList[1==e?"add":"remove"](n[1]),n[0],n[0].innerHTML=document.body.classList.contains(n[1])?"off":"on",t.set()}(-1==window.location.href.indexOf("cgi-bin/man/man2html")||-1<document.title.indexOf("not found"))&&(n=document.createElement("a"),n.href="/cgi-bin/man/man2html",n.innerHTML="&laquo; Back to Home",n.style.marginRight="10px",document.body.insertBefore(n,document.body.children[0]),o=1),n=[[],document.createElement("style")],n[0].push("*{font-family:Red Hat Mono,Hack,monospace;box-sizing:border-box}"),n[0].push(":root{--a:#14120c;--b:#fefefe;--c:#b30000;--d:#00ff95;--e:#492167}:focus{outline:2px solid;outline-offset:3px}"),n[0].push("body ::selection,body::selection{background-color:var(--a);color:var(--b)}body ::-moz-selection,body::-moz-selection{background-color:var(--a);color:var(--b)}"),n[0].push("body.m2h_dm ::selection,body.m2h_dm::selection{background-color:var(--b);color:var(--a)}body.m2h_dm ::-moz-selection,body.m2h_dm::-moz-selection{background-color:var(--b);color:var(--a)}"),n[0].push("body{padding:20px 40px;background-color:var(--b);color:var(--a)}body.m2h_dm{background-color:var(--a);color:var(--b)}"),n[0].push("body a{font-weight:bold}body a{color:var(--c)}body.m2h_dm a{color:var(--d)}"),n[0].push("body a#m2h_tm::before{content:'Turn '}body a#m2h_tm::after{content:' dark mode'}"),n[0].push("hr{border:1px solid rgba(0,0,0,0.15);margin:2.5px 0;display:block}body.m2h_dm hr{border-color:rgba(255,255,255,0.15)}"),n[0].push("input{border:1px solid;background-color:rgba(0,0,0,0);color:var(--a);padding:7.5px 15px}body.m2h_dm input{color:var(--b)}"),n[0].push("form{font-size:0;display:table;border-radius:50px;border:1px solid var(--e);overflow:hidden;position:relative}form input:last-child{cursor:pointer;font-weight:bold;text-transform:uppercase}"),n[0].push("form input{border:0px solid rgba(0,0,0,0);display:table-cell}"),n[0].push('form input[type="submit"],form input[type="reset"],form input[type="button"]{color:var(--b);background-color:var(--e)}'),n[0].push("table{color:inherit;width:100%}table td{padding:2.5px}"),n[0].push(".m2h_u{margin:0 10px;font-weight:normal;user-select:none;text-decoration:none;font-size:13px}.m2h_u::before,.m2h_u::after{text-decoration:none}.m2h_u::before{content:'[ '}.m2h_u::after{content:' ]'}"),n[0]=n[0].join(""),n[1].innerHTML=n[0],n=n[1],document.head.appendChild(n),n=null,n=[document.createElement("a"),"m2h_tm"],n[0].href="javascript:;",n[0].id=n[1],document.body.insertBefore(n[0],document.body.children[o]),n=[document.getElementById(n.pop()),"m2h_dm"];const t={name:"m2h_ck",set:function(){document.cookie=t.name+"="+(document.body.classList.contains(n[1])?1:0)+"; Expires="+new Date(2147483647e3).toUTCString()+"; Path=/"},get:function(){if(-1<document.cookie.indexOf(t.name+"=")){let e=document.cookie.split("; ");for(let o=0;o<e.length;o++)if(-1<e[o].indexOf(t.name+"=")){e[o]=e[o].split(t.name+"="),e[o]=e[o].pop(),e[o]=isNaN(e[o])?0:Number(e[o]),e=e[o],o=null;break}return e}return null}};if(n[0].addEventListener("click",e,!1),null==t.get()&&t.set(),e(0,t.get()),-1<document.title.indexOf("Man page of")){let n=[];for(let o=1;o<=6;o++)n.push("h"+o);n=n.join(","),n=document.querySelectorAll(n);var r;for(let e=1;e<n.length;e++){r="index"===n[e].innerHTML.toLowerCase().trim();let o;o=document.createElement("a"),o.href="#",o.classList.add("m2h_u"),o.innerHTML="Up",n[e].appendChild(o),r||(o=document.createElement("a"),o.href="#index",o.classList.add("m2h_u"),o.innerHTML="Index",n[e].appendChild(o))}}}();
§
Posted: 23.3.2024
Edited: 23.3.2024

I forgot to show some examples of how it looks. so here they are:

Main screen A man page

§
Posted: 23.3.2024

For comparison you can see here how the original design looks (to me it was really ugly): The original design

Post reply

Sign in to post a reply.