[TS] Citrus GFork

Alters the interface of Greasy Fork to become more friendly for authors and users alike.

Від 18.08.2014. Дивіться остання версія.

// ==UserScript==
// @name                    [TS] Citrus GFork 
// @namespace               TimidScript
// @description             Alters the interface of Greasy Fork to become more friendly for authors and users alike. 

// @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");
            }
        })();

    }
})();