[TS] Citrus GFork

Alters the interface of Greasy Fork to become more friendly for authors and users alike. Stores sort order, provides text icon to distinguish between Library, Unlisted and Deleted script. Works on Sets also.

Fra 18.08.2014. Se den seneste versjonen.

// ==UserScript==
// @name                    [TS] Citrus GFork 
// @namespace               TimidScript
// @description             Alters the interface of Greasy Fork to become more friendly for authors and users alike. Stores sort order, provides text icon to distinguish between Library, Unlisted and Deleted script. Works on Sets also.

// @author                  TimidScript
// @homepageURL             https://openuserjs.org/users/TimidScript
// @copyright               © 2014 TimidScript, All Rights Reserved.
// @license                 https://github.com/TimidScript/GreasyMonkey/blob/master/LICENSE.md

// @version                 1.0.1
// @icon                    http://i.imgur.com/YKtX7ph.png

// @include                 https://greatest.deepsurf.us/*
// @exclude                 https://greatest.deepsurf.us/forum/*
// @require                 https://greatest.deepsurf.us/scripts/4334/code/4334.user.js

// @grant                   GM_getValue
// @grant                   GM_setValue
// @grant                   GM_deleteValue
// @grant                   GM_xmlhttpRequest
// ==/UserScript==

/* Information
********************************************************************************************
Copyright © 2014 TimidScript, All Rights Reserved.
Script's Homepage:              Check homepages below

TimidScript's Homepage:         https://openuserjs.org/users/TimidScript
                                https://greatest.deepsurf.us/users/1455-timidscript
                                https://monkeyguts.com/author.php?un=timidscript                                

                                http://userscripts.org/users/TimidScript
                                http://userscripts-mirror.org/users/100610/scripts

----------------------------------------------
    Version History
----------------------------------------------
1.0.1 (2014-08-18)
 - Initial release. Released as good enough. May contain bugs but good for general usage.   
 
**********************************************************************************************/

//#region TimidScript Library Functions
/* 
Copy and paste the commented out code underneath into your script for quick reference 
and auto-complete feature if available. 
*********************************************************************************/
var TSL = new Object();

//Remove node from document. Accepts id or node object
TSL.removeNode = function (node, doc) { TimidScriptLibrary.removeNode(node, doc); };

// Creates document element. Default doc value is the document.
TSL.createElement = function (tag, attributes, doc) { return TimidScriptLibrary.createElement(tag, attributes, doc) };

// Creates document element using html code. Default doc value is the document.
TSL.createElementHTML = function (html, doc) { return TimidScriptLibrary.createElementHTML(html, doc) };

//Add CSS styles to document header. Document can be left empty.
TSL.addStyle = function (id, CSS, doc) { TimidScriptLibrary.addSyle(id, CSS, doc); };

//General Functions
TSL.makeStruct = function (names) { return TimidScriptLibrary.makeStruct(names); };

// Checks if mouse event is within an elements client area
TSL.isMouseEventInClientArea = function (event, element) { return TimidScriptLibrary.isMouseEventInClientArea(event, element); };

//Returns the thickness of the scrollbar
TSL.getScrollBarThickness = function () { return TimidScriptLibrary.getScrollBarThickness(); };

//Array containing NTFS illegal characters alternatives
TSL.ALTNTFSChars = [["<", "〉"], [">", "〈"], [":", ":"], ['"', "‟"], ["/", "∕"], ["\\", ""], ["?", ""], ["*", "✳"], ];
TSL.replaceNTFSIllegals = function (str) { return TimidScriptLibrary.replaceNTFSIllegals(str); };

TSL.escapeRegExp = function (str) { return TimidScriptLibrary.escapeRegExp(str); };

//String Padding
String.prototype.lPad = function (chr, length) { return TimidScriptLibrary.paddingLeft(this, chr[0], length); };
String.prototype.rPad = function (chr, length) { return TimidScriptLibrary.paddingRight(this, chr[0], length); };
/*
*********************************************************************************/
//#endregion

(function ()
{
    OrangifyPage();

    var scripts = new Array();

    if (document.URL.match(/greasyfork\.org\/scripts\/\d+/)) //Script Page
    {
        TSL.addStyle("", "#script-content {background-color: #F9ECDB; margin: 0; padding-bottom: 5px;} #script-links > li:hover { background-color: yellow; } .current {background-color: #F9ECDB !important;}");
        TSL.addStyle("", ".install-link {background-color: #F7A207;} .install-help-link {background-color: #F9C565 !important;}");
        TSL.addStyle("", "#additional-info {border-radius: 5px;} #additional-info > div {background-color: white;");
        TSL.addStyle("", "header:first-child {background-color:white; padding: 5px 10px;}");
    }
    else if (document.URL.match(/greasyfork\.org\/scripts/)) //Script Listing
    {
        getScripts();
        createScriptTable();
        populateScriptTable();

        document.body.setAttribute("PageType", "ScriptPage");        
        document.body.insertBefore(document.getElementById("script-table"), document.getElementById("main-header").nextElementSibling);               

        var tag = GM_getValue("ScriptPage", "updated");
        var m = document.URL.match(/[\?&]sort=(\w+)/);
        m = (m) ? m[1] : "";
        if (m != tag) document.querySelector(("td[tag='" + tag + "']")).click();
        else document.querySelector(("td[tag='" + tag + "']")).setAttribute("class", "selectedHead");
                
        TSL.removeNode("browse-script-list");
    }
    else if (document.URL.match(/\/users\/(\w|-)+/)) //Authors Profile Page
    {
        getScripts();        
        OrangifyUserPage();        
        createScriptTable();        
        populateScriptTable();
        
        var pageType = (document.getElementById("#control-panel")) ? "PersonalProfile" : "UserProfile";
        document.body.setAttribute("PageType", pageType);

        var tag = GM_getValue(pageType, "updated");        
        var m = document.URL.match(/[\?&]sort=(\w+)/);
        m = (m) ? m[1] : "";
        
        if (m != tag) document.querySelector(("td[tag='" + tag + "']")).click();
        else document.querySelector(("td[tag='" + tag + "']")).setAttribute("class", "selectedHead");        
    }

    /*  
    ---------------------------------------------------------------------------*/
    function OrangifyPage()
    {
        var sname = document.getElementById("site-name");
        sname.innerHTML = "";

        var link = document.createElement("a");
        link.href = "/";
        link.innerHTML = '<img id="title-image" src="https://i.imgur.com/RqikjW1.jpg" /><span id="title-text">Greasy Fork</span>'
                        + '<span style="color: yellow; font-size: 12px; text-decoration: none; position: absolute; left: 90px; top: 70px;">100% Citrusy Goodness</span>';
        sname.appendChild(link);

        TSL.removeNode("script-list-option-groups");

        //#region Adding CSS Styles E3E2E2
        TSL.addStyle("CitrusGF_Main", "#main-header {background-color: orange;}"
                      + "#title-image {max-height: 60px; border-radius: 20px; margin-left: 5px;}"
                      + "#title-text {font-size: 50px; color:black; font-family:'Open Sans',sans-serif; margin: 0 10px;}");

        //#endregion
    }

    function OrangifyUserPage()
    {
        TSL.addStyle("CitrusGF_Shared", ".white-panel, #control-panel, #user-profile, #user-discussions-on-scripts-written {margin: 5px; border-radius: 8px; padding: 10px; }");
        TSL.addStyle("CitrusGF_Profile", ".white-panel, #user-discussions-on-scripts-written, #control-panel, #user-profile {background-color: white; }");
        TSL.addStyle("", "#user-control-panel, #control-panel h3 {margin: 0; padding: 0;}  #user-control-panel > li { display: inline-block; margin: 0 5px; padding: 2px 5px; border-radius: 5px; background-color: #F5F2F2; border: 1px solid #404040; box-shadow: 3px 3px 2px #888888;} #user-control-panel a {text-decoration: none;} #user-control-panel li:hover {background-color: #FBEACA;}");
        TSL.addStyle("", ".white-panel *, #user-discussions-on-scripts-written * {margin: 0;}");

        var author = document.createElement("h1");
        var name = document.getElementsByTagName("h2")[0];

        var up = document.getElementById("user-profile");
        if (!up)
        {
            up = document.createElement("section");
            up.id = "user-profile";
            up.textContent = "...";
            name.parentElement.insertBefore(up, name);
        }

        up.innerHTML = "<h1 style='margin: 0 0 5px 0; color: orange;'>" + name.textContent + "'s Profile</h1>" + up.innerHTML;
        TSL.removeNode(name);

        var el = document.getElementById("user-script-sets");
        el.parentElement.className = "white-panel";

        el = document.getElementById("user-script-list");        
        if (el) TSL.removeNode(el.parentElement);

        el = document.getElementById("user-deleted-script-list");
        if (el) TSL.removeNode(el.parentElement);
               
    }

    function getScripts(doc)
    {
        if (!doc) doc = document;
        var ids = ["user-script-list", "user-deleted-script-list", "browse-script-list"];
        scripts = new Array();

        for (var i = 0; i < ids.length; i++)
        {
            var el = doc.getElementById(ids[i]);
            if (!el) continue;

            var deleted = ids[i].indexOf("deleted") > 0;
            var list = el.children;
            for (var j = 0; j < list.length; j++)
            {
                var li = list[j];
                var script = new Object();
                script.name = li.getAttribute("data-script-name");
                script.id = li.getAttribute("data-script-id");
                script.author = li.getAttribute("data-script-author-name");
                script.authorID = li.getAttribute("data-script-author-id");
                script.description = li.getElementsByClassName("description")[0].textContent.trim();
                script.fans = li.getAttribute("data-script-fan-score");
                script.installsDaily = li.getAttribute("data-script-daily-installs");
                script.installsTotal = li.getAttribute("data-script-total-installs");
                script.dateCreated = li.getAttribute("data-script-created-date");
                script.dateUpdated = li.getAttribute("data-script-updated-date");
                script.type = li.getAttribute("data-script-type");
                script.deleted = deleted;

                scripts.push(script);
            }
        }
    }

    function createScriptTable()
    {
        var scriptTable = document.createElement("table");
        scriptTable.id = "script-table";
        var thead = scriptTable.createTHead();
        var row = thead.insertRow(-1);

        var headers = ["Name", "Fans", "Daily", "Total", "Created", "Updated"];
        var tags = ["name", "fans", "", "total_installs", "created", "updated"];

        for (var i = 0; i < headers.length; i++)
        {
            var cell = row.insertCell();
            cell.innerHTML = headers[i];
            cell.onclick = OnTableHeaderClick;
            cell.setAttribute("tag", tags[i]);
        }

        scriptTable.createTBody();
        document.body.appendChild(scriptTable);

        TSL.addStyle("CitrusGS_Table", "#script-table {display: block; margin: 5px;} body {background-color: #EFEFB1; margin: 0;}"
            + "#script-table thead td {background-color: orange; border-radius: 0 0 5px 5px; box-shadow: 3px 3px 2px #888888;}"
            + "#script-table thead td:hover {cursor:pointer; background-color: yellow;}"
            + "#script-table td {width: auto; padding: 2px 5px; text-align:center;}"
            + "#script-table tbody tr td:first-child {text-align:left;}"
            + "#script-table td:first-child{width: 99%;}"
            + "#script-table tbody td {background-color: #FFFBDB;}"
            + "#script-table tbody td:first-child{width: 99%; background-color: white;}"
            + "#script-table tbody tr:hover td {background-color: yellow;}"
            + ".selectedHead {background-color: yellow !important;}"
            + ".type-library, .type-unlisted, .type-deleted {font-size:small; display: inline-block; border-radius: 3px; padding: 0 5px; border: 1px solid black; box-shadow: 2px 2px 1px #888888; margin: 2px 0 3px 0;}"
            + ".type-library {background-color: #CEE7F3; }"
            + ".type-deleted {background-color: #F77A7A; margin-left: 5px;}"
            + ".type-unlisted {background-color: #CEFD8A; }"
            + ".type-library:before {content: 'Library';}"
            + ".type-deleted:before {content: 'Deleted';}"
            + ".type-unlisted:before {content: 'Unlisted';}"
            );
    }

    function populateScriptTable(clear)
    {
        var tbody = document.getElementById("script-table").getElementsByTagName("tbody")[0];
        if (clear) tbody.innerHTML = "";

        if (scripts.length == 0)
        {
            var row = tbody.insertRow(-1);
            cell = row.insertCell();
            cell.setAttribute("style", "text-align:center; font-weight: bold; font-style: oblique;");
            cell.textContent = "No Scripts"
            cell.setAttribute("colspan", 6);

        }

        for (var i = 0; i < scripts.length; i++)
        {
            var script = scripts[i];

            row = tbody.insertRow(-1);

            cell = row.insertCell();
            var el = document.createElement("div");
            el.style.marginBottom = "5px";
            el.innerHTML = "<a href='https://greatest.deepsurf.us/scripts/"
                            + script.id + "'><b>" + script.name + "</b></a>";
            cell.appendChild(el);

            el = document.createElement("div");
            el.textContent = script.description;
            cell.appendChild(el);

            if (script.type == "library")
            {
                el = document.createElement("span");
                el.className = "type-library";
                cell.appendChild(el);
            }
            else if (script.type == "unlisted")
            {
                el = document.createElement("span");
                el.className = "type-unlisted";
                cell.appendChild(el);
            }

            if (script.deleted)
            {
                el = document.createElement("span");
                el.className = "type-deleted";
                cell.appendChild(el);
            }

            row.insertCell().textContent = script.fans;
            row.insertCell().textContent = script.installsDaily;
            row.insertCell().textContent = script.installsTotal;
            row.insertCell().textContent = script.dateCreated;
            row.insertCell().textContent = script.dateUpdated;
        }


    }

    function OnTableHeaderClick(e)
    {
        if (this.className || this.parentElement.getAttribute("busy")) return;
        this.parentElement.setAttribute("busy", true);
        var header = this;

        //https://greatest.deepsurf.us/scripts?per_page=200&sort=updated
        //https://greatest.deepsurf.us/scripts?page=2&per_page=200&sort=updated
        //https://greatest.deepsurf.us/scripts/search?q=google
        //https://greatest.deepsurf.us/scripts/search?page=2&q=g

        var url = document.URL.replace(/(\?|&)sort=\w+/, "");
        var tag = this.getAttribute("tag");
        if (tag) url += ((url.indexOf("?") > 1) ? "&" : "?") + "sort=" + tag;

        console.log(url);

        GM_xmlhttpRequest({
            url: url,
            method: "GET",
            timeout: 15000,
            headers: {
                "User-agent": navigator.userAgent,
                "Host": "greatest.deepsurf.us",
                "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
                "Accept-Language": "en-US,en;q=0.5"
            },
            onload: function (xhr)
            {
                if (xhr.status == 200)
                {
                    GM_setValue(document.body.getAttribute("PageType"), tag);

                    var els = header.parentElement.getElementsByTagName("td");
                    for (var i = 0; i < els.length; i++) els[i].removeAttribute("class");
                    header.className = "selectedHead";
           
                    //stackoverflow.com/questions/19193335/change-the-url-in-browser-bar-without-reloading-page
                    window.history.pushState(null, "", xhr.finalUrl); //Change document URL

                    scripts = new Array();
                    //var doc = new DOMParser().parseFromString(xhr.responseText, 'text/xml');
                    dt = document.implementation.createDocumentType("html", "-//W3C//DTD HTML 4.01 Transitional//EN", "http://www.w3.org/TR/html4/loose.dtd"),
                    doc = document.implementation.createDocument("", "", dt),
                    documentElement = doc.createElement("html");
                    documentElement.innerHTML = xhr.responseText;
                    doc.appendChild(documentElement);

                    TSL.removeNode(document.getElementsByClassName("pagination")[0]);

                    var pager = doc.getElementsByClassName("pagination")[0];

                    if (pager)
                    {
                        document.body.insertBefore(pager, document.getElementById("script-table").nextElementSibling);
                    }

                    getScripts(doc);
                    populateScriptTable(true);
                }

                header.parentElement.removeAttribute("busy");
            }
        })();

    }
})();