decembre

GM - [TS] Citrus GFork v.1.1.49 Fix by KONF (Marqued) + Decembre fix (+SleasyFork) - 2026.07

Jan 29th, 2022 (edited)
741
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ==UserScript==
  2. // @name                [TS] Citrus GFork v.1.1.49 Fix by KONF (Marqued)  + Decembre fix (+SleasyFork)
  3. // @namespace           TimidScript
  4. // @version             1.1.49
  5. // @date                2026-07-05
  6. // @description         NOW with version number in Listing!! Advance table view for Greasy Fork. Fixes display bugs. 100 scripts display at a time, favoured user count, remembers last sort order used on Script Listing, "My" Profile Listing, and third Party Listing. Able to distinguish between, Library, Unlisted and Deleted scripts using text icons. Beside FireFox, it now supports Opera and Chrome.
  7. // @author              TimidScript
  8. // @homepageURL         https://github.com/TimidScript
  9. // @copyright           © 2014+ TimidScript, Some Rights Reserved.
  10. // @license             https://github.com/TimidScript/UserScripts/blob/master/license.txt
  11. // @include             https://greasyfork.org/*
  12.  
  13. // @include             https://sleazyfork.org/*
  14.  
  15. // @require             https://greasyfork.org/scripts/19967/code/TSL - GM_update.js
  16. // @require             https://greasyfork.org/scripts/19968/code/TSLibrary - Generic.js
  17. // @resource MonkeyIcon https://i.imgur.com/RqikjW1.jpg
  18. // @resource FontAS     https://github.com/TimidScript/UserScripts/raw/master/resources/fonts/FontAwesome.css
  19. // @homeURL             https://greasyfork.org/en/scripts/4336
  20. // @grant               GM_getValue
  21. // @grant               GM_setValue
  22. // @grant               GM_deleteValue
  23. // @grant               GM_listValues
  24. // @grant               GM_xmlhttpRequest
  25. // @grant               GM_info
  26. // @grant               GM_getMetadata
  27. // @grant               GM_registerMenuCommand
  28. // @grant               GM_setClipboard
  29. // @grant               GM_getResourceURL
  30. // @grant               GM_getResourceText
  31. // @icon                data:image/png;base64,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
  32.  
  33. // ==/UserScript==
  34.  
  35.  
  36. /* License + Copyright Notice
  37. ********************************************************************************************
  38. License can be found at: https://github.com/TimidScript/UserScripts/blob/master/license.txt
  39. Below is a copy of the license the may not be up-to-date.
  40.  
  41. Copyright © TimidScript, Some Rights Reserved.
  42.  
  43. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
  44. following conditions are met:
  45.  
  46. 1) GPL-3 License is met that does not conflict with the rest of the license (http://www.gnu.org/licenses/gpl-3.0.en.html)
  47. 2) This notice must be included
  48. 3) Due credits and link to original author's homepage (included in this notice).
  49. 4) Notify the original author of redistribution
  50. 5) Clear clarification of the License and Notice to the end user
  51. 6) Do not upload on OpenUserJS.org or any other site that infringes on this license
  52.  
  53. TimidScript's Homepages:  GitHub:      https://github.com/TimidScript
  54.                           GreasyFork:  https://greasyfork.org/users/1455
  55. */
  56. /* Information
  57.  
  58.  
  59.  
  60. Suggestions
  61.  - Install record similar to OUJS-1
  62.  - Highlight your username in the forum
  63.  - Highlight your scripts in the forum
  64.  
  65. Unnecessary, unused Code:
  66.     getScriptHTML
  67.     getScriptJSON
  68.     makeStruct
  69.  
  70. TODO: Clean up the code
  71.  
  72. ********************************************************************************************
  73.     Version History
  74. ----------------------------------------------
  75. 1.1.49 2019-04-18
  76.  - Bugfix for Author data-script-author-name -->  data-script-authors.
  77.  - Bugfix in search
  78. 1.1.48 2017-03-18
  79.  - Bugfix: Fixed code that got broken due Changes in layout
  80.  - Add Code search support
  81. 1.1.47 2017-02-03
  82.  - Quickfix: Correctly handle libraries page
  83. 1.1.46 2017-02-02
  84.  - Changed the styling and layout
  85.  - Added library link
  86. 1.1.45.1 2017-01-07
  87.  - Quickfix in CSS
  88. 1.1.45 2017-01-07
  89.  - Change to the Header background-image
  90. 1.1.44 2016-12-16
  91.  - Table view added to feedback listing
  92.  - Sort to favourites added
  93. 1.1.43
  94.  - BugFix: Relevance when searching was not being supported. Now it is always the default in a search
  95.  - BugFix: Search bugs
  96.  - BugFix: Image size to fit parent element (script preview)
  97.  - BugFix: JSON structure has changed
  98.  - Monkey icon is now resource. Should have been years ago
  99.  - Changed the styling of the script preview
  100.  - Stores version numbers, so no longer does a JSON version call if version is up-to-date.
  101.  - Purge all stored script version details if older the 90 days
  102.  - Relative date in the discussion
  103. 1.1.42.1 (2016-10-22)
  104.  - Hotfix: Settings not being stored as I changed the stored name
  105. 1.1.42 (2016-10-22)
  106.  - Depreciated, Obsolete, Defunct and now Unsupported are checked first in description and then version. If it
  107.  is present the script is tagged with "No Longer Supported" orange tag to signify that it is no longer maintained.
  108.  It is recommended to use the keywords in the script description tag rather than version
  109.  - Removed filters and re-implemented the sorting algorithm
  110.  - Settings button added again. Can be found near the monkey icon. It toggles between relative date format and standard date format. Default is relative.
  111.  - Fixed the numbering of listing which must have gotten broken along the way
  112.  - The behaviour of script column sorting is now similar to default
  113.  - New script search button that automatically does partial word search to yield more results. Toggle through settings.
  114.  - Toggle between standard and relative date format is done through settings.
  115. 1.1.41 (2016-10-14)
  116.  - Relative date added
  117.  - Removed date format settings
  118. 1.1.40 (2016-10-14)
  119.  - Bugfix: When editting post the reply type is now stored
  120.  - Added a settings link to change the date format
  121. 1.1.39 (2016-09-03)
  122.  - Added Copy button to library page
  123. 1.1.38 (2016-05-27)
  124.  - Altered the license
  125. 1.1.37 (2016-05-25)
  126.  - Moving to GreasyFork and preparing to remove OUJS files
  127. 1.1.36 (2016-04-10)
  128.  - updateURL added
  129. 1.1.35 (2016-04-03)
  130.  - Changed license to GPL-3
  131. 1.1.34 (2016-02-27)
  132.  - Bug Fix: Displays version number in third party profiles
  133.  - Removed toggle For Deleted scripts
  134.  - Added discussion even when not logged in
  135. 1.1.33 (2015-10-05)
  136.  - Replaced base64 bmp icon with png version
  137. 1.1.32 (2015-07-04)
  138.  - Added overflow style to code tag
  139. 1.1.31 (2015-06-27)
  140.  - Using URI (base64) for script icon
  141. 1.1.30 (2015-06-08)
  142.  - Bug Fix: "Report Bug" and "Review" review button always visible even when there is no need.
  143. 1.1.29 (2015-06-08)
  144.  - Using json to populate the table. This allows the extraction of version number.
  145.  - Changed the feedback system rating interface. Review by default is hidden.
  146.  - Supporting of versions "Obselete", "Depreciated", and "Defunct" similar to the script "OUJS-1"
  147. 1.0.28b (2015-04-04)
  148.  - Bug fix to handle site searches
  149. 1.0.27 (2014-12-28)
  150.  - Bug fix to changes made in 1.0.25
  151.  - Changed the sets into a menu. CSS provided by decembre.
  152. 1.0.26 (2014-12-27)
  153.  - pre tag bug fix
  154. 1.0.25 (2014-12-27)
  155.  - decembre's request to show favourite sets to script listing
  156. script-list-set
  157.  - Bug Fix to support URL local syntax
  158. 1.0.24 (2014-12-06)
  159.  - Bug Fix in script paging
  160.  - Bug Fix due to changes in url flags. Change sort flag from "fans" to "ratings"
  161.  - Add total rating and provided total score also
  162.  - Added counter to the number of users that favoured the script, in feedback tab
  163. 1.0.23 (2014-11-29)
  164.  - Add styling for forum blockquote tag
  165.  - Changes to deal with new GF layout
  166. 1.0.22 (2014-11-07)
  167.  - Fix to handle changes in forum URL (localization added)
  168.  - Add more fonts colours to the forum to distinguish between different types of usernames/links.
  169. 1.0.21 (2014-10-31)
  170.  - Support for Opera now added. Dozen of browsers open causes confusion.
  171. 1.0.20 (2014-10-31)
  172.  - Change table header "Fans" to "Score"
  173.  - Slight changes to forum CSS
  174.  - Support for Opera and Chrome added.
  175. 1.0.19 (2014-10-23)
  176.  - Removed sign-out button as it has been added with today's site update
  177. 1.0.18 (2014-10-23)
  178.  - Bug fix to accommodate new site changes to the URL syntax (localization added)
  179. 1.0.17 (2014-10-18)
  180.  - Changed the framing of images to suite smaller images better
  181.  - Credit link now points to my GF profile rather than OUJS
  182.  - Added sign-out near the name
  183.  - Bug fix: add script table only when need
  184. 1.0.16 (2014-09-29)
  185.  - Got rid of the flashing timer
  186. 1.0.15 (2014-09-29)
  187.  - Fixed the issue that 1.0.14 supposedly had fixed
  188.  - Appreciation notice added
  189. 1.0.14 (2014-09-22)
  190.  - Re-fixed profile table sort :?
  191. 1.0.13 (2014-09-19)
  192.  - Fix in profile table sort
  193. 1.0.12 (2014-09-19)
  194.  - Bug fix in sorting of lists with search. Not using global flag when matching regex
  195. 1.0.11 (2014-09-16)
  196.  - Bug fix in search listing introduced in version 1.0.10
  197. 1.0.10 (2014-09-16)
  198.  - Bug Fix: Daily installs sort order
  199.  - Click on separator to toggle deleted script display
  200. 1.0.9 (2014-09-07)
  201.  - Added new CSS  for <code> and <pre> elements
  202. 1.0.8 (2014-08-03)
  203.  - Author name next to title
  204. 1.0.7 (2014-08-29)
  205.  - Added GM_update
  206.  - Added script numbers to table
  207. 1.0.6 (2014-08-21)
  208.  - Bug Fix for sorting
  209. 1.0.5 (2014-08-21)
  210.  - Small CSS fix provided by decembre (https://greasyfork.org/forum/discussion/comment/4182)
  211. 1.0.4 (2014-08-20)
  212.  - Bug Fix: Author not being displayed
  213.  - Bug Fix: Handle missing elements in user profile
  214. 1.0.3 (2014-08-20)
  215.  - Link to my homepage
  216.  - By default deleted scripts are hidden now
  217.  - Stole some CSS from OUJS ^_^
  218.  - Added a frame around images and max-width
  219.  - Few small bug fixes
  220. 1.0.2 (2014-08-19)
  221.  - Changes to CSS, including smaller font
  222.  - Changed the interface
  223.  - Added filter on user profile
  224.  - Changed the behaviour of column click. If clicked it goes to first page as oppose to remaining on the same page
  225.  - Increased number of scripts returned to 100
  226.  - Citrified, orangified and crucified the forum. ( ̄ _ゝ ̄)
  227.  - Small bug fixes
  228. 1.0.1 (2014-08-18)
  229.  - Initial release. Released as good enough. May contain bugs but good for general usage.
  230.  
  231. **********************************************************************************************/
  232.  
  233. (function ()
  234. {
  235.     var scripts = new Array(),
  236.         pathname = decodeURIComponent(document.location.pathname);
  237.  
  238.     TSL.addStyle("OverFlowCode", ".Comment .Message p {overflow-x:auto;}");
  239.     TSL.addStyle("FontAwesomeCSS", GM_getResourceText("FontAS"));
  240.  
  241.     OrangifyPage();
  242.     if (pathname.match(/(\w|-)+\/forum\/(post|discussion)\//) && document.getElementById("Form_Rating"))
  243.     {
  244.         TSL.addStyle("", ".choiceButtons {text-align:center; width: 80px;}");
  245.  
  246.         var po = document.querySelector(".PostOptions, .CommentOptions"),
  247.             lbl = po.querySelector("label"),
  248.             options = po.querySelectorAll(".RadioLabel"),
  249.             hld = document.createElement("div"),
  250.             btn1 = document.createElement("input"),
  251.             btn2 = document.createElement("input");
  252.  
  253.         btn1.className = btn2.className = "choiceButtons  Button";
  254.         btn1.value = "Report bug"; btn1.style.marginRight = "4px";
  255.         btn2.value = "Review";
  256.  
  257.         btn1.onclick = function (e)
  258.         {
  259.             btn1.style.color = "#2DCD05";
  260.             btn2.style.color = "";
  261.  
  262.             options[0].setAttribute("style", "margin-top: 5px !important;");
  263.             options[4].removeAttribute("style");
  264.  
  265.             options[1].setAttribute("style", "display: none !important;"); //options[1].style.display = "none !important";
  266.             options[2].setAttribute("style", "display: none !important;");
  267.             options[3].setAttribute("style", "display: none !important;");
  268.             lbl.setAttribute("style", "display: none !important;");
  269.  
  270.             if (e) options[0].click();
  271.         }
  272.  
  273.         btn2.onclick = function (e)
  274.         {
  275.             btn1.style.color = "";
  276.             btn2.style.color = "#2DCD05";
  277.  
  278.             options[0].setAttribute("style", "display: none !important;");
  279.             options[4].setAttribute("style", "display: none !important;");
  280.  
  281.             options[1].removeAttribute("style");
  282.             options[2].removeAttribute("style");
  283.             options[3].removeAttribute("style");
  284.             lbl.removeAttribute("style");
  285.  
  286.             if (e) options[3].click();
  287.         }
  288.  
  289.         hld.appendChild(btn1);
  290.         hld.appendChild(btn2);
  291.         po.insertBefore(hld, po.firstElementChild);
  292.  
  293.         //for (var i = 0; i < options.length; i++) console.log(options[i].firstElementChild.checked);
  294.         if (options[0].firstElementChild.checked || options[4].firstElementChild.checked) btn1.click(false);
  295.         else btn2.click(false);
  296.     }
  297.     else if (pathname.match(/\/[\w-]+\/scripts\/\d+/)) //Script Page
  298.     {
  299.         TSL.addStyle("", "#script-content {background-color: #F9ECDB; margin: 0; padding-bottom: 5px;} #script-links > li:hover { background-color: yellow; } .current {background-color: #F9ECDB !important;}");
  300.         TSL.addStyle("", ".install-link {background-color: #F7A207;} .install-help-link {background-color: #F9C565 !important;} #script-meta {padding-bottom:5px;} #script-feedback-suggestion, #script-meta {padding-left:5px;padding-right:5px;}");
  301.         TSL.addStyle("", "#additional-info {padding: 5px 0;} #additional-info, #additional-info > div {background-color: white;} #additional-info > h3 {padding: 5px 0; margin:0;} #additional-info > div.script-author-description {margin: 0 0;}");
  302.         TSL.addStyle("", "header:first-child {background-color:white; padding: 5px 10px;}");
  303.         TSL.addStyle("", ".fa-sort-alpha-asc[on] {color:blue; background-color: yellow;} .fa-sort-alpha-asc {margin-left: 5px;cursor:pointer; padding: 0 3px;} .fa-sort-alpha-asc:hover {background-color: brown; color: yellow;}");
  304.  
  305.         var notice = document.createElement("div");
  306.         notice.textContent = "Show your appreciation to the author by favouring the script and giving positive feedback";
  307.         notice.setAttribute("style", "padding: 3px 10px; border-radius: 4px; background-color: yellow; text-align: center;");
  308.  
  309.         if (pathname.match(/\/scripts\/[^\/]+\/feedback/i))
  310.         {
  311.             el = document.querySelector("#script-content");
  312.             if (el) el.insertBefore(notice, el.firstElementChild);
  313.  
  314.             el = document.querySelector(".inline-list");
  315.  
  316.             var count = el.querySelectorAll("li").length;
  317.  
  318.             var users = [];
  319.             var els = document.querySelectorAll(".inline-list li");
  320.             for (var i = 0; i < els.length; i++)
  321.             {
  322.                 els[i].setAttribute("position", i)
  323.                 users.push(els[i]);
  324.             }
  325.  
  326.             el = document.getElementById("feedback-favoriters");
  327.             el.innerHTML += " (<span style='color: #F00;'>" + count + "</span>";
  328.             el.innerHTML += '<i class="fa fa-sort-alpha-asc"></i>)';
  329.             el.lastElementChild.onclick = function (e)
  330.             {
  331.                 this.enabled = (this.enabled !== true);
  332.                 GM_setValue("Feedback Sorted", this.enabled);
  333.                 var il = document.querySelector(".inline-list");
  334.                 if (this.enabled)
  335.                 {
  336.  
  337.                     this.setAttribute("on", "");
  338.                     users.sort(function (a, b)
  339.                     {
  340.                         if (a.firstElementChild.textContent.toLowerCase() > b.firstElementChild.textContent.toLowerCase()) return 1;
  341.                         else return -1;
  342.                     });
  343.                     for (var i = 0; i < users.length; i++) il.appendChild(users[i]);
  344.                 }
  345.                 else
  346.                 {
  347.                     this.removeAttribute("on");
  348.                     users.sort(function (a, b)
  349.                     {
  350.                         if (parseInt(a.getAttribute("position")) > parseInt(b.getAttribute("position"))) return 1;
  351.                         else return -1;
  352.                     });
  353.                     for (var i = 0; i < users.length; i++) il.appendChild(users[i]);
  354.                 }
  355.             };
  356.             if (GM_getValue("Feedback Sorted", false)) document.querySelector(".fa-sort-alpha-asc").click();
  357.  
  358.             var els = document.querySelectorAll("#discussions > li");
  359.             if (GM_getValue("Feedback Table View", false) && els.length > 0)
  360.             {
  361.                 el = document.getElementById("discussions");
  362.                 var tab = document.createElement("table");
  363.                 tab.id = "DiscussionsTab";
  364.                 el.parentElement.insertBefore(tab, el);
  365.  
  366.                 TSL.addStyle("FeedbackTable", '#DiscussionsTab {width:100%; border-spacing: 0; border-collapse: collapse;}' //border:1px solid black;
  367.                     + '#DiscussionsTab tr {border-bottom: 1px solid gray;}'
  368.                     + '#DiscussionsTab div[class^=discussion] {height: 16px; width: 16px; margin: 0 5px; background-size: height: 16px; width: 16px;}'
  369.                     + '#DiscussionsTab .discussion-question {background-image: url(/images/circle-blue.png);}'
  370.                     + '#DiscussionsTab .discussion-alien {background-image: url(/images/circle-alien.png);}'
  371.                     + '#DiscussionsTab .discussion-good {background-image: url(/images/circle-green.png);}'
  372.                     + '#DiscussionsTab .discussion-ok {background-image: url(/images/circle-yellow.png);}'
  373.                     + '#DiscussionsTab .discussion-bad {background-image: url(/images/circle-red.png);}'
  374.                     + '#discussions {display:none;}'
  375.                     );
  376.  
  377.                 for (var i = 0, l, t, m, r, c, d; i < els.length; i++)
  378.                 {
  379.                     l = els[i].querySelectorAll("a"),
  380.                     t = els[i].querySelectorAll("time"),
  381.                     m = els[i].innerHTML.match(/<\/a>\s+([^<]+)\s+/g); //Too hard to extract the information for different languages one cannot speak
  382.  
  383.                     r = tab.insertRow(-1);
  384.  
  385.                     c = r.insertCell(-1);
  386.                     d = document.createElement("div");
  387.                     d.className = els[i].className;
  388.                     c.appendChild(d);
  389.  
  390.                     c = r.insertCell(-1);
  391.                     d = document.createElement("div");
  392.                     d.appendChild(l[0].cloneNode(true));
  393.                     c.appendChild(d);
  394.                     d = document.createElement("div");
  395.                     d.appendChild(l[1].cloneNode(true));
  396.                     d.innerHTML += "<span> >> </span>"
  397.                     d.appendChild(t[0]);
  398.                     c.appendChild(d);
  399.  
  400.                     if (l.length == 3)
  401.                     {
  402.                         c = r.insertCell(-1);
  403.  
  404.                         d = document.createElement("div");
  405.                         d.appendChild(l[2].cloneNode(true));
  406.                         c.appendChild(d);
  407.  
  408.                         d = document.createElement("div");
  409.                         d.appendChild(t[1]);
  410.                         c.appendChild(d);
  411.                     }
  412.                 }
  413.             }
  414.         }
  415.         else
  416.         {
  417.             var el = document.querySelector("#install-area");
  418.             if (el) el.appendChild(notice);
  419.         }
  420.     }
  421.     else if (!/\/scripts\/libraries/.test(location.pathname) && pathname.match(/\/[\w-]+\/scripts/)) //Script Listing
  422.     {
  423.         console.info("Script Listing");
  424.         document.body.setAttribute("PageType", "ListingPage");
  425.         getScripts();
  426.  
  427.         if (scripts.length > 0)
  428.         {
  429.             var isRelativeSearch = pathname.match(/scripts\/search/i) != null;
  430.             createScriptTable(pathname.match(/scripts\/search/i) != null);
  431.             populateScriptTable();
  432.  
  433.  
  434.             if (document.getElementById("script-table"))
  435.             {
  436.                 document.body.insertBefore(document.getElementById("script-table"), document.getElementById("main-header").nextElementSibling);
  437.                 //document.querySelector("#script-table tr td:nth-child(2)").appendChild(document.getElementById("UserSets"));
  438.  
  439.                 if (isRelativeSearch)
  440.                 {
  441.                     el = document.createElement("div");
  442.                     el.setAttribute("style", "text-align: right; padding: 1px 50px");
  443.                     el.appendChild(document.createElement("span"));
  444.                     document.body.insertBefore(el, document.getElementById("script-table"));
  445.  
  446.                     el = el.firstElementChild;
  447.                     el.id = "RelativeSearch";
  448.                     el.setAttribute("tag", "");
  449.                     el.textContent = "Relative Search";
  450.                     el.onclick = onTableHeaderClick;
  451.  
  452.                     TSL.addStyle("RelativeSearchCSS", '#RelativeSearch {display: inline-block; background-color:orange; border-radius: 3px; padding: 3px 20px; text-align: center; width: 300px;cursor:pointer;}');
  453.                 }
  454.  
  455.                 if (document.getElementById("UserSets"))
  456.                 {
  457.                     TSL.addStyle("TheBlackLagoon", "#UserSets {position: absolute !important;display: inline-table !important;float: none !important;left: 30px !important;top: 68px!important;padding: 2px 5px;background-color: yellow;border-radius: 5px;z-index: 200!important;visibility: hidden!important;opacity: 1!important;}"
  458.                                + "#UserSets:hover {visibility: visible!important;opacity: 1!important;}"
  459.                                + '#UserSets:before {content: "Sets ▼" !important; position: absolute !important;display: inline-block !important;left: 40px !important;top: -20px!important;margin: 2px 10px;padding: 1px 10px!important;background-color: yellow;border-radius: 5px;z-index: 200!important;visibility:visible!important;opacity: 1!important;}'
  460.                                + "#UserSets li {position: relative !important;display: inline !important;float: left!important;clear: both!important;min-width: 200px!important;margin-bottom: 2px!important;padding: 2px 8px;background-color: white;border-radius: 2px; text-align:left;}"
  461.                                );
  462.  
  463.                     TSL.addStyle("TheBlackLagoon", "#UserSets, #UserSets:before {position: absolute;top: 4px;float: left;background-color: #FFC763;border-radius: 5px;z-index: 200;opacity:1;}"
  464.                     + "#UserSets {display: inline-table;left:10px;padding: 2px 5px;visibility: hidden;}"
  465.                     + "#UserSets:hover {visibility: visible;opacity: 1;}"
  466.                     + '#UserSets:before {display: inline-block;left: 40px;top:-18px;content: "Sets ▼";padding: 1px 10px;visibility: visible;}'
  467.                     + "#UserSets li {position: relative;display: inline;float: left;clear: both;min-width: 200px;margin-bottom: 2px;padding: 2px 8px;background-color: white;border-radius: 2px; text-align:left;}"
  468.                     );
  469.  
  470.                     try
  471.                     {
  472.                         document.querySelector("[tag=name]").appendChild(document.getElementById("UserSets"));
  473.                     } catch(e) {};
  474.                 }
  475.  
  476.  
  477.  
  478.                 //TODO: Need to fix the Sets filter in listing search
  479.                 //var header = document.querySelectorAll("#script-table thead td")[1],
  480.                 //    sets = document.getElementById("UserSets");
  481.  
  482.                 //header.appendChild(sets);
  483.             }
  484.  
  485.             selectSortOrder("ListingPage", isRelativeSearch);
  486.  
  487.             TSL.removeNode("browse-script-list");
  488.         }
  489.     }
  490.     else if (document.URL.match(/\/users\/(\w|-)+/)) //Authors Profile Page
  491.     {
  492.         var pageType = (document.getElementById("control-panel")) ? "PersonalProfile" : "UserProfile";
  493.         document.body.setAttribute("PageType", pageType);
  494.         document.body.setAttribute("ProfilePage", "");
  495.  
  496.         getScripts();
  497.         OrangifyUserPage();
  498.  
  499.         if (scripts.length > 0)
  500.         {
  501.             createScriptTable();
  502.             populateScriptTable();
  503.  
  504.             selectSortOrder(pageType);
  505.         }
  506.     }
  507.  
  508.  
  509.     //Purge script details older than 90 days
  510.     var now = Date.now(), names = GM_listValues();
  511.     for (var i = 0; i < names.length; i++)
  512.     {
  513.         if (! /^Script:\d+/.test(names[i])) continue;
  514.  
  515.         //If greater than 30 days remove    1000*60*60*24=86400000
  516.         if ((now - JSON.parse(GM_getValue(names[i])).timestamp) / 86400000 > 90) GM_deleteValue(names[i]);
  517.     }
  518.  
  519.     /* Base CSS styling
  520.     ---------------------------------------------------------------------------*/
  521.     function OrangifyPage()
  522.     {
  523.         //#region Adding CSS Styles E3E2E2
  524.         TSL.addStyle("CitrusGF_Main", "body {font-size: 14px;} .pagination {text-align:center;}"
  525.                       + "#main-header, #Head {background-color: orange !important; background-image: none !important;} #Head a, #site-nav a {color: yellow !important;}"
  526.                       + ".current, .HomepageTitle, .Active a {border-color: orange !important;}"
  527.                       + "#site-name {text-decoration: underline; color: white;}"
  528.                       + "#title-image {height: 50px; border-radius: 20px; margin-left: 5px;}"
  529.                       + "#title-text {font-size: 40px; color:black; font-family:'Open Sans',sans-serif; font-weight: 400; margin: 0 10px; line-height: 48px;}"
  530.                       + "#title-subtext {color: yellow !important; font-size: 10px; text-decoration: none; position: absolute; left: 210px; top: 43px; font-weight: 400 !important;}"
  531.                       + "#settings-subtext {color: yellow !important; font-size: 10px; text-decoration: none; position: absolute; left: 70px; top: 43px; font-weight: 400 !important;}"
  532.                       + "#nav-user-info {top: 3px;}"
  533.                       + "pre {background-color: #FFFF99; padding: 5px; margin-left: 30px; padding: 5px 10px;}"
  534.                       + "code {padding: 2px 4px; font-size: 90%; color: #C7254E; background-color: #F9F2F4; white-space: nowrap; border-radius: 4px; font-family: Menlo,Monaco,Consolas,'Courier New',monospace;}"
  535.                       + "pre > code {white-space: pre; background-color: transparent;}"
  536.                       + "#CForkSettings {position: fixed; top: 150px; background:white; border: 5px groove orangered; width: 400px;}"
  537.                       + "#CForkSettings > div {margin: 5px 10px}"
  538.                       + "#CForkSettings > footer {background-color:orange; padding: 1px 5px;text-align:right;}"
  539.                       + "#CForkSettings label {cursor: default;}"
  540.                       + ".preview-result {background-color: white; border-top: 10px ridge black;}"
  541.                       + ".preview-result img {max-width: 98%;}"
  542.                       + "#script-table, [ProfilePage] > .width-constraint {display: block; margin: 5px auto; max-width:1000px;min-width:700px;border-radius: 0;box-shadow: 0 0 2px gray;}"
  543.                       + "#script-search > input[type=submit], .sidebar-search > input[type=submit] {cursor:pointer;}"
  544.                       );
  545.  
  546.         TSL.addStyle("CitrusGF_ScriptPage", "#additional-info img {max-width: 98%; border: 1px solid orange; box-shadow: 5px 5px 2px #888888; margin: 5px 0; padding: 2px; color: yellow; }");
  547.  
  548.         if (document.location.pathname.match(/[\w-]+\/forum\//i))
  549.         {
  550.             TSL.addStyle("CitrusGF_Forum", "body:not(.Settings) a:not(.Button) { color: #F19E06; }"
  551.                 + "body a.Username { color: #E17205 !important; }"
  552.                 + ".QuoteAuthor a[href*='forum/profile/'] { color: #FB4507 !important;}"
  553.                 + "a[href*='forum/profile/'] { color: #25C614 !important; font-weight: 600;}"
  554.                 + "code {padding: 1px 3px; border-radius: 3px; border: 1px solid; background-color: #F9EBD2; color: #EB5100; margin: 0;}"
  555.                 + "#title-subtext {top: 45px;}"
  556.                 + "blockquote {background-color: #FFFFA4; margin: 5px 0px 5px 30px; padding: 5px;}"
  557.                 );
  558.         }
  559.         //#endregion
  560.  
  561.  
  562.         var el = document.querySelector(".sidebar-search");
  563.         if (el)
  564.         {
  565.             TSL.addStyle("SSSearch", ".sidebar-search {display:inline-block;vertical-align: unset;} .sidebar-search input[name=q] {width:164px; margin:0 !important; width: 164px !important;}"
  566.                 + ".sidebar-search > input {line-height:16px;font-size:14px;} .sidebar-search [value='✱'] {right:20px !important;}");
  567.  
  568.             document.querySelector("#site-nav nav").appendChild(el);
  569.         }
  570.  
  571.         var sname = document.getElementById("site-name");
  572.         sname.innerHTML = "";
  573.  
  574.         var link = document.createElement("a");
  575.         link.href = "/";
  576.         link.innerHTML = '<img id="title-image" src="' + GM_getResourceURL("MonkeyIcon") + '" />'
  577.                         + '<span id="title-text">Greasy Fork&nbsp;</span>'
  578.                         + '<span id="settings-subtext">Settings</span>'
  579.                         + '<a id="title-subtext" href="/users/1455-timidscript">100% Citrusy Goodness by <b>TimidScript</b></span>';
  580.         sname.appendChild(link);
  581.  
  582.         var li = document.createElement("li");
  583.         link = document.createElement("a")
  584.         link.textContent = "Libraries";
  585.         link.href = "/scripts/libraries";
  586.         link.style.marginRight = "20px";
  587.         li.appendChild(link);
  588.         document.querySelector("nav").insertBefore(li, document.querySelector("nav").firstElementChild);
  589.  
  590.         var scriptsearch = document.querySelector("#script-search, .sidebar-search");
  591.         if (scriptsearch)
  592.         {
  593.             var el = document.createElement("input");
  594.             el.type = "submit";
  595.             el.value = "✱";
  596.             el.title = "Partial Search";
  597.             el.onclick = function (e)
  598.             {
  599.  
  600.                 e.stopImmediatePropagation();
  601.                 //var search = document.querySelector("#script-search [type=search], .sidebar-search [type=search]");
  602.                 var search = document.querySelector("[type=search]");
  603.                 search.value = "*" + search.value.trim() + "*";
  604.                 search.value = search.value.replace(/^\*\*|\*\*$/g, "*");
  605.             }
  606.  
  607.             if (GM_getValue("Use Original Search")) scriptsearch.appendChild(el);
  608.             else scriptsearch.insertBefore(el, scriptsearch.lastElementChild);
  609.         }
  610.  
  611.         document.getElementById("settings-subtext").onclick = function (e)
  612.         {
  613.             e.stopImmediatePropagation();
  614.             if (document.getElementById("CForkSettings")) return false;
  615.  
  616.             var settings = document.createElement("settings");
  617.             settings.id = "CForkSettings";
  618.             settings.innerHTML = '<div><input type="checkbox"><label> Use standard date format (e.g. 2016-01-30) rather than relative (e.g. 5 days ago)</label></div>'
  619.                         + '<div><input type="checkbox"><label> Disable partial search set as default search option</label></div>'
  620.                         + '<div><input type="checkbox"><label> Enable feedback table view</label></div>'
  621.                         + '<footer><button>Accept</button></footer>';
  622.  
  623.  
  624.             settings.style.left = ((document.body.clientWidth / 2) - 200) + "px";
  625.             document.body.appendChild(settings);
  626.             var lbls = settings.querySelectorAll("label");
  627.  
  628.             lbls[0].onclick = lbls[1].onclick = lbls[2].onclick = function (e) { this.previousElementSibling.click(); };
  629.  
  630.             var ipts = settings.querySelectorAll("input"), btn = settings.querySelector("button");
  631.  
  632.             if (GM_getValue("Use Standard Date Format", false)) ipts[0].checked = "checked";
  633.             if (GM_getValue("Use Original Search", false)) ipts[1].checked = "checked";
  634.             if (GM_getValue("Feedback Table View", false)) ipts[2].checked = "checked";
  635.  
  636.             btn.onclick = function (e)
  637.             {
  638.                 if (ipts[0].checked) GM_setValue("Use Standard Date Format", true); else GM_deleteValue("Use Standard Date Format");
  639.                 if (ipts[1].checked) GM_setValue("Use Original Search", true); else GM_deleteValue("Use Original Search");
  640.                 if (ipts[2].checked) GM_setValue("Feedback Table View", true); else GM_deleteValue("Feedback Table View");
  641.                 document.location.reload();
  642.                 TSL.removeNode(settings);
  643.             }
  644.  
  645.             return false;
  646.         };
  647.  
  648.         var require = document.querySelector("#script-content > p > code");
  649.         if (require && require.textContent.match("@require"))
  650.         {
  651.             var copyBar = document.createElement("div");
  652.             var copyBtn = document.createElement("button");
  653.             copyBtn.textContent = "Copy To Clipboard";
  654.             require.parentElement.insertBefore(copyBar, require.nextElementSibling);
  655.             require.setAttribute("style", "display:block;");
  656.             copyBtn.setAttribute("style", "margin-right:10px");
  657.  
  658.             copyBar.appendChild(copyBtn);
  659.             copyBar.appendChild(createRadio("Short URL"));
  660.             copyBar.appendChild(createRadio("Long URL"));
  661.             copyBar.appendChild(createRadio("Current Ver."));
  662.  
  663.             var scriptID = require.textContent.match(/\/scripts\/(\d+)/)[1];
  664.             var radios = copyBar.querySelectorAll("input");
  665.  
  666.             radios[0].setAttribute("requireURL", "// @require https://greasyfork.org/scripts/" + scriptID + "/code/" + scriptID + ".js");
  667.             radios[1].setAttribute("requireURL", require.textContent.replace(/\?\w+=\d+/, ""));
  668.             radios[2].setAttribute("requireURL", require.textContent);
  669.  
  670.             radios[0].onclick = radios[1].onclick = radios[2].onclick = function (e)
  671.             {
  672.                 for (var i = 0; i < radios.length; i++)
  673.                 {
  674.                     if (this != radios[i]) radios[i].checked = false;
  675.                 }
  676.  
  677.                 require.textContent = this.getAttribute("requireURL");
  678.             }
  679.  
  680.             copyBtn.onclick = function ()
  681.             {
  682.                 GM_setClipboard(require.textContent);
  683.             }
  684.  
  685.             radios[1].click();
  686.         }
  687.  
  688.  
  689.         if (pathname.match(/\/[\w-]+\/scripts/) && document.querySelector("#script-list-set ul")) //Script Listing
  690.         {
  691.             TSL.addStyle("TheBlackLagoon", "#UserSets {display: block; background-color: yellow; margin: 2px 10px; border-radius: 5px; padding: 2px 10px;}"
  692.                 + "#UserSets li {display: inline-block; padding: 2px 8px; background-color: white; border-radius: 2px;}"
  693.                 + "#UserSets li + li {margin-left: 1px}"
  694.                 );
  695.  
  696.             var sets = document.querySelector("#script-list-set ul");
  697.             var mh = document.getElementById("main-header");
  698.             sets.id = "UserSets";
  699.  
  700.             //document.body.insertBefore(sets, document.getElementById("main-header").nextElementSibling);
  701.             document.body.appendChild(sets);
  702.         }
  703. // decembre OK - TEST USER CSS - to SEE LANGUAGE PANEL
  704. //        TSL.removeNode("script-list-option-groups");
  705.  
  706.         function createRadio(text)
  707.         {
  708.             var option = document.createElement("div");
  709.             option.setAttribute("style", "display:inline-block; margin-right:10px;width:140px;")
  710.             var radio = document.createElement("input");
  711.             radio.type = "radio";
  712.             var lbl = document.createElement("label");
  713.             lbl.textContent = text;
  714.  
  715.             option.appendChild(radio);
  716.             option.appendChild(lbl);
  717.             return option;
  718.         }
  719.     }
  720.  
  721.     function disco(i)
  722.     {
  723.         notice.style.backgroundColor = (i % 2) ? "transparent" : "yellow";
  724.         if (i < 18) setTimeout(disco, 500, ++i);
  725.     }
  726.  
  727.     /* Styling for user page
  728.     ---------------------------------------------------------------------------*/
  729.     function OrangifyUserPage()
  730.     {
  731.         TSL.addStyle("CitrusGF_Shared", ".text-content {border: 0; box-shadow:0 0 0;padding:0;} #user-profile {background-color:#F9ECDB; margin: 0 15px}"
  732.             + "body > .width-constraint {background-color:white; margin: 5px auto;padding: 2px 10px;} #control-panel {margin-top: 15px;}"
  733.             );
  734.         TSL.addStyle("", "#user-control-panel, #control-panel h3 {margin: 0; padding: 0;}  #user-control-panel a {text-decoration: none;} #user-control-panel li:hover {background-color: #FBEACA;}"
  735.             + "#user-control-panel > li {background-color: #f5f2f2;border: 1px solid #404040;border-radius: 5px;box-shadow: 3px 3px 2px #888888;display: inline-block;margin: 2px 5px;min-width: 150px;padding: 2px 5px;text-align: center;}"
  736.             );
  737.         TSL.addStyle("CitrusGF_OUJS", 'code {padding: 2px 4px;font-size: 90%;color: #C7254E;background-color: #F9F2F4;white-space: nowrap;border-radius: 4px;font-family: Menlo,Monaco,Consolas,"Courier New",monospace; }');
  738.  
  739.  
  740.  
  741.         var el = document.getElementById("user-script-sets");
  742.         if (el) el.parentElement.className = "white-panel";
  743.  
  744.         el = document.getElementById("user-script-list");
  745.         if (el) TSL.removeNode(el.parentElement);
  746.  
  747.         el = document.getElementById("user-deleted-script-list");
  748.         if (el) TSL.removeNode(el.parentElement);
  749.  
  750.         //Get discussions
  751.         el = document.querySelector("#user-discussions-on-scripts-written");
  752.         if (el)
  753.         {
  754.             document.querySelector("body > .width-constraint").appendChild(el);
  755.             return;
  756.         }
  757.         //https://greasyfork.org/en/forum/discussions.json?script_author=1455
  758.         var userId = document.URL.match(/\/users\/(\d+)/)[1],
  759.             localURL = document.URL.replace(/\/users\/.+/, ""),
  760.             disURL = localURL + "/forum/discussions.json?script_author=" + userId;
  761.  
  762.         GM_xmlhttpRequest({
  763.             url: disURL,
  764.             method: "GET",
  765.             headers: { "User-agent": navigator.userAgent, "Accept": "text/xml" },
  766.             onload: function (xhr)
  767.             {
  768.                 if (xhr.status == 200)
  769.                 {
  770.                     var data = JSON.parse(xhr.responseText);
  771.                     if (typeof data !== "object" || data.CountDiscussions == 0) return;
  772.                     console.log(data);
  773.  
  774.                     var discussions = document.createElement("section");
  775.                     discussions.id = "user-discussions-on-scripts-written";
  776.                     discussions.innerHTML = '<h3>Discussions on scripts <a href="/en/forum/discussions/feed.rss?script_author="' + userId + '"><img src="/assets/feed-icon-14x14-ea341336588040dc7046d3423511d63d.png" alt="RSS Feed" rel="nofollow"></a></h3><ul class="discussion-list"></ul>';
  777.                     document.querySelector("body > .width-constraint").appendChild(discussions);
  778.  
  779.                     var list = discussions.querySelector("ul");
  780.  
  781.                     for (var i = 0, post, item; i < data.Discussions.length && i < 10; i++)
  782.                     {
  783.                         post = data.Discussions[i];
  784.  
  785.                         item = document.createElement("li");
  786.                         item.class = "discussion-question";
  787.                         item.innerHTML = '<a href="' + localURL + '/scripts/' + post.ScriptID + '">' + post.DiscussionAboutName + '</a> : '
  788.                             + '<a href="' + post.Url + '">' + post.Name + '</a> by '
  789.                             + '<a href="' + localURL + "/forum/profile/" + post.FirstUserID + "/" + post.FirstName + '">' + post.FirstName + '</a> '
  790.                             + '<time datetime="' + post.FirstDate + '">(' + getRelativeDate(post.FirstDate) + ')</time>, last comment by '
  791.                             + '<a href="' + localURL + "/forum/profile/" + post.LastUserID + "/" + post.LastName + '">' + post.LastName + '</a> '
  792.                             + '<time datetime="' + post.LastDate + '">(' + getRelativeDate(post.LastDate) + ')</time>';
  793.  
  794.  
  795.                         list.appendChild(item);
  796.                     }
  797.                 }
  798.                 else callback(xhr, null);
  799.  
  800.                 function getRelativeDate(date)
  801.                 {
  802.                     var ms = Date.now() - parseInt(new Date(date).getTime()),
  803.                         secs = Math.floor(ms / (1000)) % 60,
  804.                         mins = Math.floor(ms / (60 * 1000)) % 60,
  805.                         hrs = Math.floor(ms / (60 * 60 * 1000)) % 24,
  806.                         days = Math.floor(ms / (60 * 60 * 1000 * 24) % 7),
  807.                         weeks = Math.floor(ms / (60 * 60 * 1000 * 24) / 7);
  808.  
  809.                     if (weeks) return date.replace(/\s+.+/, "");
  810.                     if (days) return days + "day" + isPlural(days) + " and " + hrs + "hr" + isPlural(hrs);
  811.                     if (hrs) return hrs + "hr" + isPlural(hrs) + " and " + mins + "min" + isPlural(mins);
  812.                     if (mins) return mins + "min" + isPlural(mins) + " and " + secs + "sec" + isPlural(secs);
  813.                     return secs + "sec" + isPlural(secs);
  814.  
  815.                     function isPlural(val)
  816.                     {
  817.                         if (val == 1) return "";
  818.  
  819.                         return "s";
  820.                     }
  821.                 }
  822.             }
  823.         });
  824.     }
  825.  
  826.  
  827.     /* Gets the scripts from document
  828.     ---------------------------------------------------------------------------*/
  829.     function getScripts(doc)
  830.     {
  831.         if (!doc) doc = document;
  832.         var ids = ["user-script-list", "user-deleted-script-list", "browse-script-list"];
  833.         scripts = new Array();
  834.  
  835.         for (var i = 0, el, deleted, list; i < ids.length; i++)
  836.         {
  837.             el = doc.getElementById(ids[i]);
  838.             if (!el) continue;
  839.  
  840.             deleted = ids[i].indexOf("deleted") > 0;
  841.             list = el.children;
  842.             for (var j = 0, stamp; j < list.length; j++)
  843.             {
  844.                 var li = list[j];
  845.  
  846. // Fix by KONF
  847.                 if (li.classList.contains('ad-entry')) continue;
  848.  
  849.                 var script = new Object();
  850.                 script.name = li.getAttribute("data-script-name");
  851.                 script.id = li.getAttribute("data-script-id");
  852.                 script.author = li.getAttribute("data-script-authors");
  853.                 script.authorID = script.author.match(/"(\d+)":"(.+)"/)[1];
  854.                 script.author = script.author.match(/"(\d+)":"(.+)"/)[2];
  855.                 script.description = li.getElementsByClassName("description")[0].textContent.trim();
  856.                 script.rating = li.getAttribute("data-script-rating-score");
  857.                 script.ratings = (li.querySelector("dd.script-list-ratings")) ? li.querySelector("dd.script-list-ratings").innerHTML : "";
  858.                 script.installsDaily = li.getAttribute("data-script-daily-installs");
  859.                 script.installsTotal = li.getAttribute("data-script-total-installs");
  860. //Fix by KONF
  861. /*
  862.  OLD                 script.dateCreated = li.getAttribute("data-script-created-date") + "|" + li.querySelector(".script-list-created-date time").textContent;
  863.  
  864.     857
  865.  
  866.                 script.dateUpdated = li.getAttribute("data-script-updated-date") + "|" + li.querySelector("dd.script-list-updated-date span").textContent;
  867.  
  868.         854
  869.  
  870.                 script.dateUpdated = li.getAttribute("data-script-updated-date") + "|" + li.querySelector(".script-list-updated-date time").
  871. */
  872.                 script.dateCreated = li.getAttribute("data-script-created-date") + "|" + li.querySelector("dd.script-list-created-date span").textContent;
  873.                 script.dateUpdated = li.getAttribute("data-script-updated-date") + "|" + li.querySelector("dd.script-list-updated-date span").textContent;
  874.                 script.type = li.getAttribute("data-script-type");
  875.                 script.defunct = /defunct|depreciated|obselete|unsupported/i.test(script.description);
  876.                 script.deleted = deleted;
  877.                 scripts.push(script);
  878.  
  879.                 stamp = GM_getValue("Script:" + script.id, false);
  880. //Fix by KONF
  881. /* OLD
  882.                     if (li.querySelector(".script-list-updated-date time").getAttribute("datetime") != stamp.datetime) stamp.version = "";
  883.                     if (li.querySelector(".script-list-updated-date time").getAttribute("datetime") != stamp.datetime) stamp.version = "";
  884. */
  885.                 if (stamp)
  886.                 {
  887.                     stamp = JSON.parse(stamp);
  888.                     if (li.querySelector("dd.script-list-updated-date span").getAttribute("datetime") != stamp.datetime) stamp.version = "";
  889.                     else script.version = stamp.version;
  890.                 }
  891.                 else stamp = { datetime: li.querySelector("dd.script-list-updated-date span").getAttribute("datetime"), version: "", timestamp: "" };
  892.  
  893.                 stamp.timestamp = Date.now();
  894.                 GM_setValue("Script:" + script.id, JSON.stringify(stamp));
  895.             }
  896.         }
  897.     }
  898.  
  899.  
  900.     /* Creates scripts table (relative search)
  901.     ---------------------------------------------------------------------------*/
  902.     function createScriptTable(isRelativeSearch)
  903.     {
  904.         var scriptTable = document.createElement("table");
  905.         scriptTable.id = "script-table";
  906.         var thead = scriptTable.createTHead();
  907.         var row = thead.insertRow(-1);
  908.  
  909.         var headers = ["Name", "Ratings", "Daily", "Total", "Created", "Updated"];
  910.         var tags = ["name", "ratings", (isRelativeSearch ? "daily_installs" : ""), "total_installs", "created", "updated"];
  911.  
  912.         cell = row.insertCell(-1);
  913.         cell.textContent = "#";
  914.  
  915.         var cell;
  916.         for (var i = 0; i < headers.length; i++)
  917.         {
  918.             cell = row.insertCell(-1);
  919.             cell.innerHTML = headers[i];
  920.             cell.onclick = onTableHeaderClick;
  921.             cell.setAttribute("tag", tags[i]);
  922.         }
  923.  
  924.         cell = row.cells[1];
  925.  
  926.         //scriptTable.createTBody();
  927.         scriptTable.appendChild(document.createElement("tbody"));
  928.         document.body.appendChild(scriptTable);
  929.  
  930.         TSL.addStyle("CitrusGS_Table", "body {background-color: #EFEFB1; margin: 0;} body {background-color:whitesmoke;}"
  931.             //+ "#script-table {display: block; margin: 0 5px 5px 5px; }"
  932.             + "pagination {text-align:center;}"
  933.             + "#script-table thead td {background-color: orange; border-radius: 0 0 5px 5px; box-shadow: 3px 3px 2px #888888;position:relative;}"
  934.             + "#user-discussions-on-scripts-written > h3 {margin-bottom: 3px;}"
  935.             + "#script-table thead td:hover {cursor:pointer; background-color: yellow;}"
  936.             + "#script-table thead td:first-child:hover {cursor:default; background-color: orange;}"
  937.             + "#script-table td {white-space: nowrap;width: auto; padding: 2px 5px; text-align:center;}"
  938.             + "#script-table td:nth-child(0), #script-table td:nth-child(1), #script-table td:nth-child(2)  {white-space: normal;}"
  939.             //+ "#script-table thead tr td:nth-child(3) {width: 120px; display: block;}"
  940.             //+ ".total-rating-count {display: inline-block; min-width: 1em; text-align: center; padding: 0px 0.25em; border-radius: 10px;}"
  941.             + ".total-rating-count, .good-rating-count, .ok-rating-count, .bad-rating-count {display: inline-block; min-width: 1em; padding: 1px 3px; border-radius: 3px;}"
  942.             + ".total-rating-count {background-color: rgba(0, 0, 255, 0.1);}"
  943.             + "#script-table tbody td {background-color: #FFFBDB;}"
  944.             + "#script-table tbody td:first-child{background-color: #F9D5A6;}"
  945.             + "#script-table tbody td:nth-child(2){width: 99%; background-color: white;text-align:left;}"
  946.             + "#script-table tbody tr:hover td {background-color: yellow;}"
  947.             + ".loadingSort {background-color: #FDFDC3 !important;}"
  948.             + ".type-library, .type-unlisted, .type-deleted, .type-defunct {font-size:smaller; display: inline-block; border-radius: 3px; padding: 0 5px; border: 1px solid black;}"
  949.             + ".type-library, .type-unlisted, .type-deleted, .type-defunct {box-shadow: 2px 2px 1px #888888; margin: 2px 5px 3px 0;}"
  950.             + "#script-table tbody [library] td:nth-of-type(3) {background-color:lightgray;}"
  951.             + ".type-library {background-color: #CEFD8A;}"
  952.             + ".type-deleted {background-color: #F77A7A;}"
  953.             + ".type-defunct {background-color: #FF8600;}"
  954.             + ".type-unlisted, .filterU {background-color: #CEE7F3;}"
  955.             + ".type-library:before {content: 'Library';}"
  956.             + ".type-deleted:before {content: 'Deleted';}"
  957.             + ".type-unlisted:before {content: 'Unlisted';}"
  958.             + ".type-defunct:before {content: 'No Longer Supported';}"
  959.             + "#notice {margin:5px 5px 0 5px; background-color: #FDBB45;padding: 3px 5px; color: blue;}"
  960.             + "thetitle {margin-bottom: 3px;} .theauthor{font-size:small;}"
  961.         );
  962.  
  963.         TSL.addStyle("Al28dj21", ".thetitle a {margin-right: 2px !important;}");
  964.         TSL.addStyle("Al28dj23", ".theversion {font-size: xsmall; margin-right: 4px;}");
  965.         TSL.addStyle("Al28dj24", "tr[library] td:nth-child(2) {background-color: #F2FBEA !important;}");
  966.         TSL.addStyle("Al28dj25", "tr[unlisted] td:nth-child(2) {background-color: #F4FBFF !important;}");
  967.         TSL.addStyle("Al28dj27", "tr[deleted] td:nth-child(2) {background-color: #FDF7F7 !important;}");
  968.     }
  969.  
  970.     /* Populate the table with scripts
  971.     ---------------------------------------------------------------------------*/
  972.     function populateScriptTable(clear)
  973.     {
  974.         //populateScriptTable0(true); return;
  975.  
  976.         var tbody = document.getElementById("script-table").getElementsByTagName("tbody")[0];
  977.         if (clear) tbody.innerHTML = "";
  978.         if (scripts.length == 0) return;
  979.  
  980.         for (var i = 0; i < scripts.length; i++)
  981.         {
  982.             var script = getScriptHTML(i);
  983.  
  984.             row = tbody.insertRow(-1);
  985.             row.id = "s" + script.id;
  986.             cell = row.insertCell(-1);
  987.  
  988.             cell.textContent = "##";
  989.  
  990.             cell = row.insertCell(-1);
  991.             var el = document.createElement("div");
  992.             el.className = "thetitle";
  993.             el.innerHTML = "<a href='https://greasyfork.org/scripts/"
  994.                             + script.id + "' style='margin-right: 10px;'><b>" + script.name + "</b></a><span class='theversion'></span>";
  995.  
  996.             if (script.type == "library") AddScriptTag("library");
  997.             else if (script.type == "unlisted") AddScriptTag("unlisted");
  998.             else row.setAttribute("public", 0);
  999.  
  1000.             if (script.deleted) AddScriptTag("deleted");
  1001.             if (script.defunct) AddScriptTag("defunct");
  1002.  
  1003.  
  1004.             // If page listing add author detail
  1005.             if (document.body.getAttribute("PageType") == "ListingPage")
  1006.             {
  1007.                 el.innerHTML += '<span class="theauthor"><span>by </span><a href="https://greasyfork.org/users/' + script.authorID + '">' + script.author + '</a></span>';
  1008.             }
  1009.             cell.appendChild(el);
  1010.  
  1011.             el = document.createElement("div");
  1012.             el.textContent = script.description;
  1013.             cell.appendChild(el);
  1014.             cell = row.insertCell(-1);
  1015.             if (script.type != "library")
  1016.             {
  1017.                 cell.innerHTML = script.ratings + '<span class="total-rating-count">' + script.rating + '</span>';
  1018.                 cell.title = "Favoured plus Good Feedback, OK Feedback, Bad Feedback, Total Score (" + script.rating + ")";
  1019.             }
  1020.             row.insertCell(-1).textContent = script.installsDaily;
  1021.             row.insertCell(-1).textContent = script.installsTotal;
  1022.             row.insertCell(-1).textContent = GM_getValue("Use Standard Date Format", false) ? script.dateCreated.split("|")[0] : script.dateCreated.split("|")[1];
  1023.             row.insertCell(-1).textContent = GM_getValue("Use Standard Date Format", false) ? script.dateUpdated.split("|")[0] : script.dateUpdated.split("|")[1];
  1024.  
  1025.             function AddScriptTag(tag)
  1026.             {
  1027.                 el.innerHTML += '<span class="type-' + tag + '" />';
  1028.                 row.setAttribute(tag, "");
  1029.             }
  1030.  
  1031.             if (script.version) addScriptVersion(script);
  1032.         }
  1033.  
  1034.         OrganizeTableByCategory();
  1035.  
  1036.         function getScriptHTML(idx)
  1037.         {
  1038.             var properties = "name id author authorID description rating ratings installsDaily installsTotal dateCreated dateUpdated type deleted";
  1039.             return makeStruct(properties, scripts[idx]);
  1040.         }
  1041.     }
  1042.  
  1043.     function addScriptVersion(script)
  1044.     {
  1045.         var el = document.querySelector("#s" + script.id + " .thetitle .theversion");
  1046.  
  1047.         if (!el) return;
  1048.         el.innerHTML = "(<b>" + script.version + "</b>)";
  1049.  
  1050.         if (/defunct|depreciated|obselete|unsupported/i.test(script.version))
  1051.         {
  1052.             el.innerHTML += '<span class="type-defunct" />';
  1053.             el.parentElement.parentElement.setAttribute("defunct", "");
  1054.         }
  1055.  
  1056.         stamp = JSON.parse(GM_getValue("Script:" + script.id));
  1057.         stamp.version = script.version;
  1058.         GM_setValue("Script:" + script.id, JSON.stringify(stamp));
  1059.     }
  1060.  
  1061.     function numberScriptListing()
  1062.     {
  1063.         var rows = document.querySelectorAll("#script-table > tbody > tr");
  1064.  
  1065.         if (!rows) return;
  1066.  
  1067.         var offset = 1, len = rows.length.toString().length;
  1068.  
  1069.         if (document.body.getAttribute("PageType") == "ListingPage")
  1070.         {
  1071.             var page = 1, limit = 100, m = document.location.search.match(/(?:\?|&)page=(\d+)/);
  1072.             if (m) page = parseInt(m[1]);
  1073.  
  1074.             m = document.location.search.match(/per_page=(\d+)/);
  1075.             if (m) limit = parseInt(m[1]);
  1076.  
  1077.             console.log(page, limit);
  1078.             offset += limit * (page - 1);
  1079.         }
  1080.  
  1081.         for (var i = 0; i < rows.length; i++)
  1082.         {
  1083.             rows[i].firstElementChild.textContent = (i + offset).toString().lPad("0", len);
  1084.         }
  1085.     }
  1086.  
  1087.     function OrganizeTableByCategory()
  1088.     {
  1089.         if (document.body.getAttribute("PageType") == "ListingPage")
  1090.         {
  1091.             numberScriptListing();
  1092.             return;
  1093.         }
  1094.  
  1095.         var tbody = document.getElementById("script-table").getElementsByTagName("tbody")[0];
  1096.  
  1097.         var rows = tbody.children;
  1098.         for (var i = 0, n; i < rows.length - 1; i++)
  1099.         {
  1100.             n = i;
  1101.             for (var j = i + 1; j < rows.length; j++)
  1102.             {
  1103.                 if (getPosValue(rows[n]) > getPosValue(rows[j])) n = j;
  1104.             }
  1105.             if (n != i) tbody.insertBefore(rows[n], rows[i]);
  1106.         }
  1107.  
  1108.  
  1109.         numberScriptListing();
  1110.  
  1111.         function getPosValue(el)
  1112.         {
  1113.             var v = 0;
  1114.             if (el.hasAttribute("unlisted")) v += 4;
  1115.             if (el.hasAttribute("defunct")) v += 1;
  1116.             if (el.hasAttribute("library")) v += 2;
  1117.  
  1118.             if (el.hasAttribute("deleted")) v += 6;
  1119.  
  1120.             return v;
  1121.         }
  1122.     }
  1123.  
  1124.     /*
  1125.     ---------------------------------------------------------------------------*/
  1126.     function selectSortOrder(pageType, isRelativeSearch)
  1127.     {
  1128.         var tag = (isRelativeSearch) ? "" : GM_getValue(pageType, "updated");
  1129.  
  1130.         var m = document.URL.match(/[\?&]sort=(\w+)/);
  1131.         var tagURL = (m) ? m[1] : "";
  1132.  
  1133.         var page = document.URL.match(/[\?&]page=(\d+)/);
  1134.  
  1135.         TSL.addStyle("SelectedSortColumn", "[tag='" + tagURL + "'] {background-color: yellow !important;}");
  1136.  
  1137.         if (!isRelativeSearch && !page && (tagURL != tag || (document.URL.indexOf("per_page=100") < 0)))
  1138.         {
  1139.             document.querySelector(("[tag='" + tag + "']")).click();
  1140.             return;
  1141.         }
  1142.         getScriptVersionNumbers();
  1143.     }
  1144.  
  1145.     /*  Table header is clicked, get the correct script sorting
  1146.     ---------------------------------------------------------------------------*/
  1147.     function onTableHeaderClick(e)
  1148.     {
  1149.         if (document.querySelector("loadingSort")) return;
  1150.         this.className = "loadingSort";
  1151.  
  1152.         getScriptListing(this.getAttribute("tag"), true);
  1153.     }
  1154.  
  1155.     /*   Get script page
  1156.     ---------------------------------------------------------------------------*/
  1157.     function getScriptListing(tag, removePage)
  1158.     {
  1159.         var isListingPage = (document.body.getAttribute("PageType") == "ListingPage");
  1160.  
  1161.         if (/\/code-search\?/i.test(document.URL)) url = document.URL.match(/.+\/code-search\?/)[0] + "per_page=100";
  1162.         else if (isListingPage) url = document.URL.match(/https:\/\/greasyfork.org\/[\w-]+\/scripts(\/by-site\/[\w\.\-_]+|\/search)?/)[0] + "?per_page=100";
  1163.         else url = document.URL.replace(/\?.+/, "?");
  1164.  
  1165.         var m = document.URL.match(/[^=\?&]+=[^&]+/g);
  1166.         if (m)
  1167.             for (var i = 0; i < m.length; i++)
  1168.             {
  1169.                 //if (!m[i].match(/^(per_page|sort)/) && !(firstPage && m[i].match(/^page/))) url += "&" + m[i];
  1170.                 if (!m[i].match(/^(per_page|sort)/)) url += "&" + m[i];
  1171.             }
  1172.  
  1173.         if (tag) url += "&sort=" + tag;
  1174.         if (removePage) url = url.replace(/[\?&]page=\d+/, "");
  1175.  
  1176.         url = url.replace(/\?&/, "?");
  1177.         url = url.replace(/\?$/, "");
  1178.  
  1179.         if (url.indexOf("?") < 0) url = url.replace("&", "?");
  1180.  
  1181.         console.warn("getScriptListing IN: " + url)
  1182.         GM_xmlhttpRequest({
  1183.             url: url,
  1184.             method: "GET",
  1185.             timeout: 15000,
  1186.             headers: {
  1187.                 "User-agent": navigator.userAgent,
  1188.                 "Host": "greasyfork.org",
  1189.                 "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
  1190.                 "Accept-Language": "en-US,en;q=0.5"
  1191.             },
  1192.             onload: function (xhr)
  1193.             {
  1194.                 if (xhr.status == 200)
  1195.                 {
  1196.                     GM_setValue(document.body.getAttribute("PageType"), tag);
  1197.  
  1198.                     TSL.addStyle("SelectedSortColumn", "[tag='" + tag + "'] {background-color: yellow !important;}");
  1199.  
  1200.                     //stackoverflow.com/questions/19193335/change-the-url-in-browser-bar-without-reloading-page
  1201.                     window.history.pushState(null, "", xhr.finalUrl); //Change document URL
  1202.  
  1203.                     scripts = new Array();
  1204.                     //var doc = new DOMParser().parseFromString(xhr.responseText, 'text/xml');
  1205.  
  1206.                     var doc = document.implementation.createHTMLDocument('MPIV');
  1207.                     doc.documentElement.innerHTML = xhr.responseText;
  1208.  
  1209.                     TSL.removeNode(document.getElementsByClassName("pagination")[0]);
  1210.  
  1211.                     var pager = doc.getElementsByClassName("pagination")[0];
  1212.  
  1213.                     if (pager)
  1214.                     {
  1215.                         document.body.insertBefore(pager, document.getElementById("script-table").nextElementSibling);
  1216.                     }
  1217.  
  1218.                     getScripts(doc);
  1219.                     populateScriptTable(true);
  1220.                     getScriptVersionNumbers();
  1221.                 }
  1222.  
  1223.                 TSL.removeClass(document.querySelector(".loadingSort"), "loadingSort")
  1224.                 console.warn("getScriptListing OUT: " + url);
  1225.             }
  1226.         });
  1227.     }
  1228.  
  1229.     function getScriptVersionNumbers()
  1230.     {
  1231.         //No need to do a JSON call as the stored information is already up-to-date
  1232.         if (document.querySelectorAll(".theversion").length == document.querySelectorAll(".theversion b").length) return;
  1233.  
  1234.         var jsonURL = document.URL.replace(/(\?|$)/, ".json$1");
  1235.         console.log("JSON: " + jsonURL);
  1236.  
  1237.         //Get version number
  1238.         GM_xmlhttpRequest({
  1239.             url: jsonURL,
  1240.             method: "GET",
  1241.             timeout: 15000,
  1242.             headers: {
  1243.                 "User-agent": navigator.userAgent,
  1244.                 "Host": "greasyfork.org",
  1245.                 "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
  1246.                 "Accept-Language": "en-US,en;q=0.5"
  1247.             },
  1248.             onload: function (xhr)
  1249.             {
  1250.                 if (xhr.status == 200)
  1251.                 {
  1252.                     var data = JSON.parse(xhr.responseText), scripts;
  1253.                     //console.log(data);
  1254.                     if (typeof data !== "object") return;
  1255.                     scripts = data.all_listable_scripts || data;
  1256.  
  1257.                     for (var i = 0, script; i < scripts.length; i++)
  1258.                     {
  1259.                         script = scripts[i];
  1260.                         addScriptVersion(script);
  1261.                     }
  1262.  
  1263.                     OrganizeTableByCategory();
  1264.                 }
  1265.             }
  1266.         });
  1267.     }
  1268.  
  1269.     function getScriptJSON(obj)
  1270.     {
  1271.         var properties = "bad_ratings code_updated_at code_url contribution_amount contribution_url created_at daily_installs description fan_score good_ratings id license locale name namespace ok_ratings redistributable support_url total_installs url version";
  1272.         return makeStruct(properties, obj);
  1273.     }
  1274.  
  1275.     function makeStruct(keys, obj)
  1276.     {
  1277.         if (!obj) obj = {};
  1278.  
  1279.         var names = keys.split(" ").sort();
  1280.         for (var i = 0; i < names.length; i++)
  1281.         {
  1282.             obj[names[i]] = obj[names[i]];
  1283.         }
  1284.  
  1285.         return obj;
  1286.     }
  1287. })();
  1288.  
  1289.  
Add Comment
Please, Sign In to add comment