Reddit Enhancer

Extends Reddit and adds some useful Functions. (Requires frisch's UserScript Extender)

  1. // ==UserScript==
  2. // @name Reddit Enhancer
  3. // @namespace http://null.frisch-live.de/
  4. // @version 1.85
  5. // @description Extends Reddit and adds some useful Functions. (Requires frisch's UserScript Extender)
  6. // @author frisch
  7. // @include http://*.reddit.com/*
  8. // @include https://*.reddit.com/*
  9. // @exclude https://*.reddit.com/message/*
  10. // @exclude http://*.reddit.com/message/*
  11. // @exclude https://*.reddit.com/search?*
  12. // @grant GM_getValue
  13. // @grant GM_setValue
  14. // @grant GM_openInTab
  15. // ==/UserScript==
  16. console.log("Initializing Reddit Enhancer...");
  17.  
  18. var settings = {};
  19.  
  20. var enumKeys = {
  21. 'NONE': -1,
  22. 'BACKSPACE': 8,
  23. 'TAB': 9,
  24. 'ENTER': 13,
  25. 'SHIFT': 16,
  26. 'CTRL': 17,
  27. 'ALT': 18,
  28. 'PAUSE/BREAK': 19,
  29. 'CAPS LOCK': 20,
  30. 'ESCAPE': 27,
  31. 'SPACE': 32,
  32. 'PAGE UP': 33,
  33. 'PAGE DOWN': 34,
  34. 'END': 35,
  35. 'HOME': 36,
  36. 'LEFT ARROW': 37,
  37. 'UP ARROW': 38,
  38. 'RIGHT ARROW': 39,
  39. 'DOWN ARROW': 40,
  40. 'INSERT': 45,
  41. 'DELETE': 46,
  42. '0': 48,
  43. '1': 49,
  44. '2': 50,
  45. '3': 51,
  46. '4': 52,
  47. '5': 53,
  48. '6': 54,
  49. '7': 55,
  50. '8': 56,
  51. '9': 57,
  52. 'A': 65,
  53. 'B': 66,
  54. 'C': 67,
  55. 'D': 68,
  56. 'E': 69,
  57. 'F': 70,
  58. 'G': 71,
  59. 'H': 72,
  60. 'I': 73,
  61. 'J': 74,
  62. 'K': 75,
  63. 'L': 76,
  64. 'M': 77,
  65. 'N': 78,
  66. 'O': 79,
  67. 'P': 80,
  68. 'Q': 81,
  69. 'R': 82,
  70. 'S': 83,
  71. 'T': 84,
  72. 'U': 85,
  73. 'V': 86,
  74. 'W': 87,
  75. 'X': 88,
  76. 'Y': 89,
  77. 'Z': 90,
  78. 'LEFT WINDOW KEY': 91,
  79. 'RIGHT WINDOW KEY': 92,
  80. 'SELECT KEY': 93,
  81. 'NUMPAD 0': 96,
  82. 'NUMPAD 1': 97,
  83. 'NUMPAD 2': 98,
  84. 'NUMPAD 3': 99,
  85. 'NUMPAD 4': 100,
  86. 'NUMPAD 5': 101,
  87. 'NUMPAD 6': 102,
  88. 'NUMPAD 7': 103,
  89. 'NUMPAD 8': 104,
  90. 'NUMPAD 9': 105,
  91. 'MULTIPLY': 106,
  92. 'ADD': 107,
  93. 'SUBTRACT': 109,
  94. 'DECIMAL POINT': 110,
  95. 'DIVIDE': 111,
  96. 'F1': 112,
  97. 'F2': 113,
  98. 'F3': 114,
  99. 'F4': 115,
  100. 'F5': 116,
  101. 'F6': 117,
  102. 'F7': 118,
  103. 'F8': 119,
  104. 'F9': 120,
  105. 'F10': 121,
  106. 'F11': 122,
  107. 'F12': 123,
  108. 'NUM LOCK': 144,
  109. 'SCROLL LOCK': 145,
  110. 'SEMI-COLON': 186,
  111. 'EQUAL SIGN': 187,
  112. 'COMMA': 188,
  113. 'DASH': 189,
  114. 'PERIOD': 190,
  115. 'FORWARD SLASH': 191,
  116. 'GRAVE ACCENT': 192,
  117. 'OPEN BRACKET': 219,
  118. 'BACK SLASH': 220,
  119. 'CLOSE BRAKET': 221,
  120. 'SINGLE QUOTE': 222,
  121. };
  122. enumKeys.hasValue = function(val){
  123. for(var k in this)
  124. if(this[k] === val) {
  125. return true;
  126. }
  127.  
  128. return false;
  129. };
  130.  
  131. // User Script Enhancer Properties and Functions
  132. var jq = document.fExt.jq;
  133. var fExtCreateStyle = document.fExt.createStyle;
  134. var fExtAddSub = document.fExt.ctxMenu.addCtxSub;
  135. var fExtMessage = document.fExt.message;
  136. var fExtAddCtxItem = document.fExt.ctxMenu.addCtxItem;
  137. var fExtAddCtxSeparator = document.fExt.ctxMenu.addSeparator;
  138. var fExtClipboard = document.fExt.clipboard;
  139. var fExtGetSelection = document.fExt.getSelection;
  140. var fExtPopup = document.fExt.popup;
  141. var fExtSetLoading = document.fExt.setLoading;
  142.  
  143. var typeCheck = Object.prototype.toString;
  144. var numberOfSitesLoaded = 1;
  145. var isHiding = false;
  146.  
  147. var ctxItemUsrHdr, ctxItemUsrHdrPg, ctxItemUsrUnhdr, ctxItemSbHdr, ctxItemSbUnhdr, ctxItemKeywHdr, ctxItemKeywUnhdr, ctxUndo, ctxRedo, ctxItemCpyHtml, ctxItemSett;
  148. var upVoteLinks, downVoteLinks, rSubRedditLinks, rAuthorLinks, postList;
  149.  
  150. var loc = location.href;
  151. var isSinglePost = location.href.indexOf("/comments/") > 0 || location.href.indexOf("/submit$") > 0;
  152. var isUserPage = location.href.indexOf("/user/") > 0 || location.href.indexOf("/u/") > 0;
  153. var isUserSubmittedPage = isUserPage && location.href.indexOf("/submitted") > 0;
  154. var isMyMulti = location.href.indexOf("/me/m/") > 0;
  155. var isFriendsPage = location.href.indexOf("/r/friends") > 0;
  156. var isSubmitPage = location.href.indexOf("/submit?") > 0;
  157. var isMySavedPage = location.href.indexOf(settings.accountName + "/saved") > 0;
  158. var hiderElements;
  159. var headerHeight = jq("#header").outerHeight(true);
  160. var hideLinks = [];
  161. var userHideLinks = [];
  162. var subHideLinks = [];
  163. var duplicateLinks = [];
  164. var keywordsHideLinks = [];
  165. var rTitleLinks;
  166. var rEnhSub = fExtAddSub("Reddit Enhancer", undefined);
  167. var pstItems = [];
  168. pstItems.onlyVisible = function(){
  169. return this.filter(function(item){
  170. return jq("#" + item).is(":visible");
  171. });
  172. };
  173. pstItems.Next = function(steps){
  174. return GetFromArray(pstItems.onlyVisible(), pstItems.selected, steps ? steps : 1);
  175. };
  176. pstItems.Previous = function(steps){
  177. return GetFromArray(pstItems.onlyVisible(), pstItems.selected, steps ? steps * -1 : -1);
  178. };
  179. pstItems.First = function(){
  180. var visiblePosts = pstItems.onlyVisible();
  181. return visiblePosts.length > 0 ? visiblePosts[0] : undefined;
  182. };
  183. pstItems.Last = function(){
  184. var visiblePosts = pstItems.onlyVisible();
  185. return visiblePosts.length > 0 ? visiblePosts[visiblePosts.length - 1] : undefined;
  186. };
  187.  
  188. function GetFromArray(array, item, steps) {
  189. if(array.length === 0)
  190. return undefined;
  191. else if(item && jq.inArray(item, array) < 0)
  192. return undefined;
  193.  
  194. var ind = 0;
  195. if(item)
  196. ind = array.indexOf(item);
  197.  
  198. if(ind < 0)
  199. ind = 0;
  200.  
  201. var stepIndex = (steps < 0 ? steps * -1 : steps);
  202. var modifier = (steps < 0 ? -1 : 1);
  203.  
  204. ind += steps;
  205. while(ind >= array.length)
  206. ind -= array.length;
  207.  
  208. if(ind < 0)
  209. ind = array.length - 1;
  210.  
  211. return array[ind] === item ? undefined : array[ind];
  212. }
  213.  
  214. var reloadCancelled = true;
  215. var resourcesLinks = [];
  216. var subColors = {};
  217. var settingTranslation = [
  218. { key: "accountName", translation: "Your Profilename", hint: "Required to determine some pages (e.g. your saved pages)" },
  219.  
  220. { key: "markNSFW", translation: "Mark NSFW posts", hint: "Highlights NSFW posts" },
  221. { key: "replaceTopNew", translation: "Replace Top with New", hint: "Instead of landing on the Top-Page of a reddit, you'll be redirected to the New-Page instead" },
  222. { key: "sortByVotes", translation: "Sort by Votes", hint: "Sorts the posts by votes" },
  223. { key: "autoExpandSelectedPost", translation: "Autoexpand Posts", hint: "Causes selected Posts to automatically collapse/expand" },
  224. { key: "removeDuplicates", translation: "Remove Duplicates", hint: "Removes duplicate posts by checking the link/source of a post" },
  225. { key: "maximumNumberOfSitesToLoad", translation: "Autoload # of Pages", hint: "Let's you load more than one page at once. Currently buggy and will be worked on." },
  226.  
  227. { key: "animationItemTimeout", translation: "Animation Speed", hint: "" },
  228. { key: "hideItemTimeout", translation: "Posthiding Timeout", hint: "" },
  229. { key: "imagePreloadingTimeout", translation: "Preloading timeout", hint: "" },
  230.  
  231. { key: "hideUsers", translation: "Hide Users", hint: "If true, users in the 'Users to hide'-list will be hidden" },
  232. { key: "hideUsersNSFWonly", translation: "Hide Users NSFW posts only", hint: "Only hide NSFW posts by the users" },
  233. { key: "usersToHide", translation: "Users to hide", hint: "" },
  234.  
  235. { key: "hideSubs", translation: "Hide Subs", hint: "If true, subsreddits in the 'Subs to hide'-list will be hidden" },
  236. { key: "subsToHide", translation: "Subs to hide", hint: "" },
  237.  
  238. { key: "hideKeywords", translation: "Hide Keywords", hint: "If true, posts containing any keyword fromt he 'Keywords to hide'-list will be hidden" },
  239. { key: "keywordsToHide", translation: "Keywords to hide", hint: "" },
  240.  
  241. { key: "panelView", translation: "Panelview", hint: "Not yet implemented" },
  242.  
  243. { key: "shortcuts", translation: "Keyboard Shortcuts", hint: "" },
  244. { key: "voteUp", translation: "Upvote selected Post", hint: "" },
  245. { key: "previousPost", translation: "Select previous Post", hint: "" },
  246. { key: "voteDown", translation: "Downvote selected Post", hint: "" },
  247. { key: "toggleSelected", translation: "Expand/Collapse selected Post", hint: "" },
  248. { key: "hideSelected", translation: "Hide selected Post", hint: "" },
  249. { key: "nextPost", translation: "Select next Post", hint: "" },
  250. { key: "hideAll", translation: "Hide all Posts", hint: "Also reloads the page after hiding all posts (can be cancelled)" },
  251.  
  252. { key: "undoLast", translation: "Undo last action", hint: "Activates the latest element in the undo list" },
  253. { key: "redoLast", translation: "Redo last action", hint: "Activates the latest element in the redo list" },
  254.  
  255. { key: "previousImage", translation: "Display previous Image", hint: "Used for RES-Albums" },
  256. { key: "nextImage", translation: "Display next Image", hint: "Used for RES-Albums" },
  257.  
  258. { key: "zoomIn", translation: "Zoom in", hint: "Used for Images" },
  259. { key: "zoomOut", translation: "Zoom out", hint: "Used for Images" },
  260. { key: "rotateLeft", translation: "Rotate left", hint: "Used for Images" },
  261. { key: "rotateRight", translation: "Rotate right", hint: "Used for Images" }
  262. ];
  263.  
  264. // Images
  265. var imgBooks = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAYAAACpSkzOAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6RTMyQTVEQUUyQTIyMTFFMTlGMThGNDk3QjgyMTJCNjUiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6RTMyQTVEQUYyQTIyMTFFMTlGMThGNDk3QjgyMTJCNjUiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpFMzJBNURBQzJBMjIxMUUxOUYxOEY0OTdCODIxMkI2NSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpFMzJBNURBRDJBMjIxMUUxOUYxOEY0OTdCODIxMkI2NSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PgQa4kwAAAGQSURBVHjazFaBjYMwDIQXAzACI4BYoN2AblA2oBO0neD5CWADukG7QAUbPCNkA95+HZKVJyGlIL0lK62d+OLLEfCHYfDYfN/3pixN0x0NFbl6Pp+J96KN9QPTBAIIafgkPxryEY8E3rsAfhiKZDR8W0AuyLeunQUTu2SadgjxbnPyEPkY+VjkOX4EtbdZIBS5j0XJrrTwonXRiLVX8pLiHMsQ8106qgDSkR9G7ie66NBlBPpCw/lW+HvQgcZCewJRmFyQn/UuUCQTwJ6FGaPqzjTZQ6EIMcUbwOJWxHV6CyjVLgZYMRH7QvFGioRAHhpVmZPqLFaDjvH3iekVVDWiS/fnSDcIQ9L1e4ZQYjsH8kpH0hoCUBBPaJiTC9UtBootuR5yVouoczQWRiKUuQkQn9seir1PURqsBKRfRd5WQO0q8nawWXmvKYb/B1RuUD//A0TyPCHxEA9cv3ADvC6hmvUY8Oe+gsQrYHAEueFmV05fQQuNb/XyXTHUDlSVb6uOiuR4lfcTG2CQzrb+R4ABALaxlqMMGvrUAAAAAElFTkSuQmCC";
  266. var imgDuplicate = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAYAAACpSkzOAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6RDQxOEI0NzM3NDlBMTFFMTk1RDhCRjg3NzZFMkRGMjMiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6RDQxOEI0NzQ3NDlBMTFFMTk1RDhCRjg3NzZFMkRGMjMiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpENDE4QjQ3MTc0OUExMUUxOTVEOEJGODc3NkUyREYyMyIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpENDE4QjQ3Mjc0OUExMUUxOTVEOEJGODc3NkUyREYyMyIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Ph2iTEwAAAGJSURBVHjatFbBcYMwEBSEAsiXV0ogwydPpwPTgd0BVMCkAruDuAOnA7sBZsgvT//40oFzx6wyZwfQacA7cyMBkvZuTzoRGEKWZWtqdmQvZhp7so+6rjvjiQAkR485Ddm7L1mESOwC7O2XeQAiIdcoyRLSsnRX7tDHYIJktrSRYqJKWnKowNiU7ETPN2ThFAMNjjXSCkcsLFmsIpJwbRL6fr57dUMWOiZ3MzdbT+YVkRJDjqUU1S5akoUUeBb5XVHDVpEVoXkQkLO9z/Z2grxPsbVXkC9nIs4xfTOL5AgkJyTeRvDvgC8hHZ+zHNWgpPZAFg/VujmRHMWB3kKmDdl5ESIhV08Asli8K2cT3ZEc0F5ETWQJm9EcoUpr8LcgIvmEdWMkluiCfqUk4y18wIIlCNlex0isdCWS2ifX7vuJO4o934jEG83VHqIq5yIyF3K0hbjkGufPiSL5V0vg+z8hb2fNgfXNYX9hYmxl1wh8vJqB/Mk1om3bnyRJvqn7NlRaFGpsWfJfAQYApiSqoZCrNjYAAAAASUVORK5CYII=";
  267. var imgDelCat = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAYAAACpSkzOAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAG5SURBVEiJ3ZaxbhRBDIY/r45yOtImokVKc+N5gm0okiIFxUVpUiHlEWgipeENkNIkDQI6CiK60zZ0Z6p7ACQKmvAGic4UzMBmdTmSvRUI/mZ31rP+x/5tayTG+MDdD6qqOnJ3ZQCIiC0Wi5ci8srMrgBG7n4gImfuPgQHAO6uLZ/nAFVVVUeDMXTQ9l0Nla5laPselRczkyFJVPWGFtWQzlfh/yMaLftY8lt06+b7NqzS+e9G1D3ZEBX5T2n0GXgLfDCzj63vx8CzslgnoivgRQjhsZk975BgZichhK2ylhjjjdP3QUpp4u57QBk5JiLvZrPZm7JnaeruClV9yI/pvNMxPXL3p6q6Dxya2bc+Gn0NIWw1TXPdIvkEbAIbec8l8CXbzoHdPhGdNk1znVKatEjqTDTNe+pMNAV2UkqT3n2UNSETbJrZXFXrvH+uqtvZhrvvraNREX4DmKpqbWZzgEwy5Vcq9c9NbxExgBjjk3v+a/l5CdQlXaq6nSOrsw3AZDweH4rI2T0Ijs3sJPfOa35fDFFE9qXHdetneavqe1aXdwQuzGxX1rlmrWjYggtyw65FVHCXEfQdGszctvjNerkAAAAASUVORK5CYII=";
  268. var imgAbort = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAYAAACpSkzOAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDowNDZCQkYwMzM2Q0ExMUUyQjY5RUUwNzIwODVEMzBFMyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDowNDZCQkYwNDM2Q0ExMUUyQjY5RUUwNzIwODVEMzBFMyI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjA0NkJCRjAxMzZDQTExRTJCNjlFRTA3MjA4NUQzMEUzIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjA0NkJCRjAyMzZDQTExRTJCNjlFRTA3MjA4NUQzMEUzIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+Mya9PgAAAUlJREFUeNpi/P//PwM9ACPdLWJkZMSqwNjYWBJIxQKxOxAbALEQVOodEF8A4p1AvPjs2bPPsemHm4/LIqAFfECqGYgzgZiVgIN/A/F0IK4FWviJaIuAlmgBqc1ArERiCN0DYl+gZdcIWgS15CAQi5AZHW+A2B5mGVaLoMF1ngyfYPOZISgYYeYzoSlopoIlDFAzmrGmOhMTE1DqekhExBMLQAlE/syZM8/RfRRLRUsYoGbFwjjIFrnTIJ/CzWRBEjTAolABiD+SYPB7NL4BNouEsGj8CEw5H4i1BZhq0YWEsAUdTQGyRe9oYP47bEEHKiCd0MMcS3CQAi5g89FOGvhoJzaLFkMzGQMVM+xiDIug9cl0Klo0HbmOQk91tdACkVJwD2oW7hqWLtUELSs+rBkWqtAQiCcRmUB+Q9UaIlsysI2TYdOuAwgwAC/sonL067x5AAAAAElFTkSuQmCC";
  269. var imgDelUser = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAYAAACpSkzOAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAWhJREFUeNrEVottgzAQxVEGcDdwN4jEAA0bZAPMBFEmiDJB1AkKE2QEvAAqGzQjMELP1SOyELbPMlKfdLL4nN/5Pg9EEUBZlkdazmR2lWQTmSH7HIbBFAkQARJNy1fAtyGyNouISA60fDP8K+7Jdp77Z2agNfdEPqIT0/+USySZ/jKXaHP8O9HI9B9zibjDaHKJOqZ/t4UyPCLta2hYqy2a4QJtW4O932yidRG9e+kchLeG8CqyJ2rXufIUa28VCcQG0ZNp512F6x7Pg6I6R6k9aXsnu3ueL9HSyRqxQnBFGny4ITV9QomqPQgkasERyRbBpKAWILHRHRgOE6XhjXx+nJqMnu6Uzp5Pe6IHk8SVHLdJLmsfP5RhTq/aR+qxxCtCh+xOm06RT8jfiVIgaVOFZtAL8qAm7lIUGNApGjdroiWqUlQY/xMjuq9gzpERiz8fW68P5PcYE1RMvo4Na1TrOOBq3a8AAwDKrW/Ty1UcbgAAAABJRU5ErkJggg==";
  270. var imgTree = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAYAAACpSkzOAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6REIzNzg4NjJDMjdBMTFFMTgyQTdCNUFCM0MyNUJCMTYiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6REIzNzg4NjNDMjdBMTFFMTgyQTdCNUFCM0MyNUJCMTYiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo4REUwQTc2QkMyNzgxMUUxODJBN0I1QUIzQzI1QkIxNiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo4REUwQTc2Q0MyNzgxMUUxODJBN0I1QUIzQzI1QkIxNiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PqK2+9QAAAEGSURBVHjavJWNDYMgEIWFCewGHcHECRihG+gGdhLdQDdoN6ALkLpBR5AN2iM5EtI09fg5LyFEJH4+jnsnqgLRtu0GU/1ni5VVmaj33osCas4wvfb2iUyIU6JhNGygGIiLnByNCLGUzSJRzQxTh48KlZVVBJAhgPTGmAdBlRWUGoCPnRDiADOuX2F9ov6gpNQAQpoAssRAyEeHEB1A+tgjp+ZIo7LVHVnKBZIRFuMgCtRYTlB2UEEWi1Nzg5SHYbHygCAvLj/+pnUpMEmpaoTdv2BDDEgkWtAYWNBCcZcSpnqBcePsRx5mCTaW3WGfRzQ+f+1Xtsb3o6Vv7CCEvY/yut1a/AgwACqvUiICIj/gAAAAAElFTkSuQmCC";
  271.  
  272. // Variables - End
  273.  
  274. // Initialization - Start
  275. GMLoad();
  276.  
  277. // Initialization - Styles - Start
  278. jq("body").css("margin-bottom", "0");
  279. // Initialization - Styles - End
  280.  
  281. // Initialization - Controls - Start
  282. if (isSinglePost) {
  283. jq("div.media-preview").attr("style","");
  284. jq("#upvoter,#downvoter,#expander,#hideAll,#hideSelected,#toggleUserHidden,#toggleSubsHidden,#toggleKeywordsHidden,#toggleDuplicateHidden").addClass("disabled");
  285. }
  286.  
  287. // Initialization - Controls - Settings Dialog
  288. var settingsDialog = '<div style="display:none" id="rEnhSettings"><div class="tableContainer"><table cellspacing="0" cellpadding="0" border="0" width="700px"><colgroup><col width="200px" /><col width="auto" /></colgroup>';
  289. settingsDialog += '<thead><tr><th class="label">Setting</th><th class="setting">Value</th></tr></thead>';
  290.  
  291. function BuildSettings(settingsObject) {
  292. for (var key in settingsObject) {
  293. var varType = typeof settingsObject[key];
  294.  
  295. if (varType === "object") {
  296. if (typeCheck.call(settingsObject[key]) === '[object Array]')
  297. AddSettingToDialog(key, "list");
  298. else {
  299. settingsDialog += '<tr><td class="label" colspan="2"><b>' + key + '</b></td></tr>';
  300.  
  301. if (key === 'shortcuts') {
  302. for (var shortcut in settingsObject[key]) {
  303. AddSettingToDialog(shortcut, 'key');
  304. }
  305. } else BuildSettings(settingsObject[key]);
  306. }
  307. } else AddSettingToDialog(key, varType);
  308. }
  309. }
  310.  
  311. function getTranslationObject(key) {
  312. for (var i in settingTranslation) {
  313. if (settingTranslation[i].key === key) {
  314. return settingTranslation[i];
  315. }
  316. }
  317.  
  318. return { key: key, translation: key, hint: "" };
  319. }
  320.  
  321. function AddSettingToDialog(key, varType) {
  322. var transObject = getTranslationObject(key);
  323. settingsDialog += '<tr title="' + transObject.hint + '">';
  324. if (varType === "list") {
  325. settingsDialog += '<td class="label" colspan="2">' + transObject.translation + '</td>';
  326. settingsDialog += '</tr>';
  327. settingsDialog += '<tr title="' + transObject.hint + '">';
  328. settingsDialog += '<td class="setting" colspan="2"><textarea name="' + key + '" class="value" cols="80" rows="7" title="Separate entries by using comma"></textarea></td>';
  329. } else {
  330. settingsDialog += '<td class="label">' + transObject.translation + '</td>';
  331. if (varType === "key") {
  332. settingsDialog += '<td><select class="value" name="' + key + '">';
  333. for (var knownKey in enumKeys) {
  334. settingsDialog += '<option value="' + enumKeys[knownKey] + '">' + knownKey + '</option>';
  335. }
  336. settingsDialog += '</select><input type="Button" class="DetectShortcut" value="Assign" /></td>';
  337. } else {
  338. var inputType;
  339. switch (varType) {
  340. case "boolean":
  341. inputType = "checkbox";
  342. break;
  343. case "number":
  344. inputType = "number";
  345. break;
  346. case "string":
  347. inputType = "text";
  348. break;
  349. default:
  350. console.log("Cannot add setting " + key + " to settings dialog because unkown type " + varType);
  351. return;
  352. }
  353.  
  354. settingsDialog += '<td class="setting">' + '<input type="' + inputType + '" class="value" name="' + key + '"></td>';
  355. }
  356. }
  357. settingsDialog += '</tr>';
  358. }
  359.  
  360. jq(document).on("click", "input.DetectShortcut", function(e) {
  361. fExtMessage("Press the key to assign or press ESC to unassign.");
  362. jq(document).bind("keydown", { sender: this }, AssignShortcut);
  363. });
  364.  
  365. function AssignShortcut(e){
  366. var sender = e.data.sender;
  367. var jqSender = jq(sender);
  368.  
  369. e.preventDefault();
  370.  
  371. var kc = e.which;
  372.  
  373. if(kc != enumKeys.ESCAPE) {
  374. if(!enumKeys.hasValue(kc)){
  375. fExtMessage("Invalid Key! Choose a different key or press ESC to unassign.");
  376. return false;
  377. }
  378. else
  379. jqSender.parent().find("select").val(kc);
  380. }
  381. else
  382. jqSender.parent().find("select").val(enumKeys.NONE);
  383.  
  384.  
  385. fExtMessage(undefined);
  386.  
  387. jq(document).unbind("keydown", AssignShortcut);
  388. return false;
  389. }
  390.  
  391. BuildSettings(settings);
  392.  
  393. settingsDialog += '</table></div>';
  394. settingsDialog += '<div class="settingsButtons"><a href="#" id="renhSettingsClose">Close</a><a href="#" id="renhSettingsSave">Save</a></div>';
  395. settingsDialog += '</div>';
  396. jq("body").append(settingsDialog);
  397. // Initialization - Controls - End
  398.  
  399. // Moving the navigation buttons
  400. var jqNavButtons = jq("div.nav-buttons");
  401. if (jqNavButtons) {
  402. if (jqNavButtons.length === 1 && settings.maximumNumberOfSitesToLoad > 1) {
  403. GrabContent(jq("body").html());
  404. } else MainInitialization();
  405. } else MainInitialization();
  406.  
  407. function MainInitialization() {
  408. InitializeElements();
  409. InitializeStyles();
  410. InitializeEventHandlers();
  411.  
  412.  
  413. var fnHandleShortcut;
  414. if (!isSinglePost) {
  415. fnHandleShortcut = handleShortcutForOverview;
  416. postList = jq("#siteTable").find("div.thing");
  417.  
  418. postList.each(function(){
  419. jq(this).find("div.midcol").find("div.unvoted").each(function(index, item) {
  420. var jqItem = jq(item);
  421. var unvotedVal = jqItem.text();
  422. var multiplier = unvotedVal.indexOf("k") >= 0 ? 1000 : 1;
  423. var pts = parseFloat(unvotedVal.replace("k",""));
  424. if(isNaN(pts))
  425. pts = 0;
  426. else
  427. pts = pts * multiplier;
  428. if (pts > 100) jqItem.parent().css("background-color", "#99FF99");
  429. else if (pts > 0) jqItem.parent().css("background-color", "#CCFFCC");
  430. else if (pts < -10) jqItem.parent().css("background-color", "#FF9999");
  431. else if (pts < 0) jqItem.parent().css("background-color", "#FFCCCC");
  432. jqItem.parents("div.thing:first").data("VoteValue",pts);
  433. });
  434. });
  435.  
  436. if (!isUserPage) {
  437. if(settings.sortByVotes){
  438. // Marks Rating of Posts
  439. postList.sort(function(a, b) {
  440. var scoreA = parseInt(jq(a).data("VoteValue"));
  441. var scoreB = parseInt(jq(b).data("VoteValue"));
  442.  
  443. if (scoreA > scoreB)
  444. return -1;
  445. else if (scoreA < scoreB)
  446. return 1;
  447. else
  448. return 0;
  449. });
  450.  
  451. postList.detach();
  452. postList.appendTo(jq("#siteTable"));
  453. }
  454. }
  455.  
  456. for(var i = 0; i < postList.length; i++){
  457. var post = jq(postList[i]);
  458. if(!post.is(":visible"))
  459. continue;
  460.  
  461. var hideBtn = post.find("form.hide-button");
  462. var eventData = { thingID: post.attr("id") };
  463. hideBtn.bind("click", eventData, handleHideClick);
  464. }
  465. }
  466. else {
  467. jq("div.thing:first").find("img, video").each(function() {
  468. jq(this).attr("style","width: auto !important");
  469. });
  470. jq("div.thing:first").find("iframe").each(function() {
  471. jq(this).attr("style","width: 100% !important");
  472. });
  473. var pstID = jq("div.thing:first").attr("id");
  474.  
  475. fnHandleShortcut = handleShortcutForSinglePage;
  476. postList = jq(".sitetable").find("div.thing").not("#" + pstID);
  477.  
  478. postList.each(function(index, item) {
  479. pstItems.push(item.getAttribute("id"));
  480. });
  481. }
  482.  
  483. jq(document).bind("keydown", fnHandleShortcut);
  484.  
  485. jq(document).on("focusin", "input, textarea, select", function(e) {
  486. jq(document).unbind("keydown", fnHandleShortcut);
  487. });
  488. jq(document).on("focusout", "input, textarea, select", function(e) {
  489. jq(document).bind("keydown", fnHandleShortcut);
  490. });
  491.  
  492. // Removal of sponsor divs
  493. jq("[class^='sponsor'").remove();
  494.  
  495. upVoteLinks = jq(".up:not(.archived)");
  496. downVoteLinks = jq(".down:not(.archived)");
  497. rSubRedditLinks = jq("a.subreddit");
  498. rAuthorLinks = jq("a.author");
  499.  
  500. rAuthorLinks.each(function(index, item) {
  501. var href = item.getAttribute("href");
  502. if (href.indexOf("/submitted") === -1)
  503. item.setAttribute("href", href + "/submitted/");
  504. });
  505.  
  506. // Holy crap that new outbound url remapping is annoying af... here let's fix this shit
  507. jq("a[data-href-url]").each(function() {
  508. var jqThis = jq(this);
  509. var currentDataHref = this.getAttribute("data-href-url");
  510. this.setAttribute("data-outbound-url", currentDataHref);
  511. this.setAttribute("href", currentDataHref);
  512. });
  513.  
  514. if (settings.replaceTopNew) {
  515. jq("a.subreddit").each(function(index, item) {
  516. var hrefLink = item.getAttribute("href");
  517. if (!hrefLink.match(".*/$")) {
  518. hrefLink = hrefLink + "/";
  519. }
  520. hrefLink = hrefLink + "new";
  521. item.setAttribute("href", hrefLink);
  522. });
  523. }
  524.  
  525. jq("span.nsfw-stamp").each(function(index, item) {
  526. var jqItem = jq(item).parent("li");
  527. var parent = jqItem.parents("ul.flat-list.buttons");
  528. if (settings.markNSFW) {
  529. jqItem.parents("div.entry:first").addClass("NsfwItem");
  530. }
  531. jqItem.detach().appendTo(parent);
  532. jqItem.parents("div.thing:first").addClass("NsfwPost");
  533. });
  534.  
  535. jq("span.spoiler-stamp").each(function(index, item) {
  536. var jqItem = jq(item).parent("li");
  537. var parent = jqItem.parents("ul.flat-list.buttons");
  538. jqItem.detach().appendTo(parent);
  539. jqItem.parents("div.thing:first").addClass("SpoilerPost");
  540. });
  541.  
  542. // remove Gild and Share button
  543. jq("li.give-gold-button, li.share").remove();
  544. jq("li a:contains('promoted')").parent().remove();
  545. jq("li a:contains('gilded')").parent().remove();
  546. jq("li a:contains('rising')").parent().remove();
  547. jq("li a:contains('controversial')").parent().remove();
  548.  
  549. // highlight hide/unhide
  550. var hideSubsFromLocation = false;
  551. var hideUsersFromLocation = false;
  552.  
  553. if (!isMyMulti && !isMySavedPage && !isSinglePost && !isFriendsPage) {
  554. hideSubsFromLocation = true;
  555. hideUsersFromLocation = true;
  556. }
  557.  
  558. InitializeContextMenu();
  559.  
  560. if (!isSinglePost) {
  561. jq("a.comments.empty").each(function(index, item) {
  562. Mark(jq(item), "uncommented");
  563. });
  564.  
  565. jq("span.domain").each(function(index, span) {
  566. var item = jq(span).find("a");
  567. var jqItem = jq(item);
  568. var parentItem = jqItem.parents("div.entry");
  569. var txt = jqItem.text();
  570.  
  571. if (txt.indexOf("youtu") >= 0)
  572. Mark(parentItem, "video");
  573. else if (txt.indexOf("imgur") >= 0 || txt.indexOf("gfycat") >= 0)
  574. Mark(parentItem, "image");
  575. });
  576.  
  577. postList.find("a.title").each(function() {
  578. var text = this.text;
  579. if (text.length > 180) {
  580. var spacerInd = text.substring(0, 175).lastIndexOf(" ");
  581. this.setAttribute("title", "..." + text.substring(spacerInd));
  582. this.text = text.substring(0, spacerInd) + "... (more)";
  583. }
  584. });
  585.  
  586. postList.each(function(index, item) {
  587. pstItems.push(item.getAttribute("id"));
  588. });
  589.  
  590. for(var i = 0; i < pstItems.length; i++){
  591. var jqThing = jq("#" + pstItems[i]);
  592. var tagline = jqThing.find("p.tagline");
  593. tagline.detach();
  594. var subReddit = tagline.find("a.subreddit");
  595. subReddit.detach();
  596. var first = jqThing.find("div.entry p:first");
  597. var jqDiv = jq("<span class='thingUserSubInfo'></span>");
  598. jqDiv.insertBefore(first);
  599. var flatlistButtons = jqThing.find("ul.flat-list.buttons");
  600. flatlistButtons.detach();
  601.  
  602. tagline.appendTo(jqDiv);
  603. subReddit.appendTo(jqDiv);
  604. flatlistButtons.appendTo(jqDiv);
  605.  
  606.  
  607. if (settings.removeDuplicates) {
  608. var resource = jqThing.find("a.thumbnail").get(0);
  609. if(resource) {
  610. if (resourcesLinks.indexOf(resource.href) >= 0) {
  611. if (!jqThing.hasClass("duplicateHidden"))
  612. jqThing.addClass("duplicateHidden");
  613.  
  614. AddToHideLinks(jqThing);
  615. duplicateLinks.push(jqThing);
  616. } else
  617. resourcesLinks.push(resource.href);
  618. }
  619. }
  620. }
  621.  
  622. jq("div.thing.promotedlink").each(function() {
  623. AddToHideLinks(jq(this));
  624. });
  625.  
  626. if (!isFriendsPage && !isUserSubmittedPage) {
  627. rAuthorLinks.each(function(index, item) {
  628. var jqItem = jq(item);
  629. var userName = jqItem.text().replace("/r/", "").replace("r/","");
  630. var userIndex = jq.inArray(userName, settings.usersToHide);
  631. var itemThing = jqItem.parents("div.thing:first");
  632. if (userIndex >= 0) {
  633. var hideThisPost = settings.hideUsers &&
  634. !isUserPage &&
  635. (settings.hideUsersNSFWonly && jqItem.parents("div.entry").hasClass("NsfwItem") || !settings.hideUsersNSFWonly);
  636.  
  637. if (hideThisPost)
  638. AddToHideLinks(itemThing);
  639.  
  640. userHideLinks.push(itemThing);
  641. itemThing.addClass("userHidden");
  642. }
  643. });
  644. }
  645.  
  646. var hideThisPost = settings.hideKeywords && !isUserPage;
  647. for (var iKW = 0; iKW < settings.keywordsToHide.length; iKW++) {
  648. var kwItem = settings.keywordsToHide[iKW];
  649. if (kwItem) {
  650. jq("a.title:contains(" + kwItem + ")").each(function(jndex, jtem) {
  651. var thing = jq(jtem).parents("div.thing:first");
  652.  
  653. if (hideThisPost)
  654. AddToHideLinks(thing);
  655.  
  656. keywordsHideLinks.push(thing);
  657. if (!thing.hasClass("keywordsHidden"))
  658. thing.addClass("keywordsHidden");
  659. });
  660. }
  661. }
  662.  
  663. if (loc.indexOf("/r/all") >= 0 || loc.indexOf("/r/popular") >= 0) {
  664. rSubRedditLinks.each(function(index, item) {
  665. var subName = item.text.replace("/r/", "").replace("r/","");
  666. var subIndex = jq.inArray(subName, settings.subsToHide);
  667. if (subIndex >= 0) {
  668. var itemThing = jq(item).parents("div.thing:first");
  669. if (hideSubsFromLocation)
  670. AddToHideLinks(itemThing);
  671. subHideLinks.push(itemThing);
  672. itemThing.addClass("subsHidden");
  673. }
  674. });
  675. }
  676.  
  677. jq("#toggleSubsHidden").find("span").text(subHideLinks.length);
  678. jq("#toggleUserHidden").find("span").text(userHideLinks.length);
  679. jq("#toggleKeywordsHidden").find("span").text(keywordsHideLinks.length);
  680. jq("#toggleDuplicateHidden").find("span").text(duplicateLinks.length);
  681.  
  682. if(hideLinks.length > 0)
  683. HideAndAction(hideLinks, 0, null, "enhance");
  684. else
  685. InitializeHider();
  686.  
  687. var subs = jq("a.subreddit");
  688. if (subs.length > 0) {
  689. subs.each(function(index, item) {
  690. var jqItem = jq(item);
  691. var subText = jqItem.text().replace("/r/", "").replace("r/","");
  692. var subColor = subColors[subText];
  693.  
  694. if (!subColor) {
  695. subColor = getRandomColor();
  696. subColors[subText] = subColor;
  697. }
  698.  
  699. //jqItem.detach().prependTo(eleParent);
  700. jqItem.text(subText);
  701.  
  702. jqItem.parents("div.thing:first").css("background-color", subColor);
  703. });
  704. } else {
  705. jq("span.domain").each(function(index, span) {
  706. var item = jq(span).children("a");
  707.  
  708. if(item){
  709. var subText = item.text().replace("/r/", "").replace("r/","");
  710. var subColor = subColors[subText];
  711.  
  712. if (!subColor) {
  713. subColor = getRandomColor();
  714. subColors[subText] = subColor;
  715. }
  716.  
  717. item.parents("div.thing:first").css("background-color", subColor);
  718. }
  719. });
  720. }
  721.  
  722. jq(".last-clicked").removeClass("last-clicked");
  723. jq(".promotedlink").remove();
  724.  
  725. jq("span.author:contains('[deleted]')").parents("div.thing").each(function(){
  726. jq(this).find("a:contains('hide')").click();
  727. });
  728.  
  729. if (userHideLinks.length === 0) {
  730. jq("#toggleUserHidden").attr("style", "background-color: #808080 !important; color: #CFCFCF; border: 1px solid black;");
  731. } else {
  732. jq("#toggleUserHidden").click(function(e) {
  733. ToggleVisibility(e, this, ".userHidden");
  734. return false;
  735. });
  736. }
  737. if (subHideLinks.length === 0) {
  738. jq("#toggleSubsHidden").attr("style", "background-color: #808080 !important; color: #CFCFCF; border: 1px solid black;");
  739. } else {
  740. jq("#toggleSubsHidden").click(function(e) {
  741. ToggleVisibility(e, this, ".subsHidden");
  742. return false;
  743. });
  744. }
  745. if (duplicateLinks.length === 0) {
  746. jq("#toggleDuplicateHidden").attr("style", "background-color: #808080 !important; color: #CFCFCF; border: 1px solid black;");
  747. } else {
  748. jq("#toggleDuplicateHidden").click(function(e) {
  749. ToggleVisibility(e, this, ".duplicateHidden");
  750. return false;
  751. });
  752. }
  753. if (keywordsHideLinks.length === 0) {
  754. jq("#toggleKeywordsHidden").attr("style", "background-color: #808080 !important; color: #CFCFCF; border: 1px solid black;");
  755. } else {
  756. jq("#toggleKeywordsHidden").click(function(e) {
  757. ToggleVisibility(e, this, ".keywordsHidden");
  758. return false;
  759. });
  760. }
  761.  
  762. var navButton = jq("div.nav-buttons").find(".next-button").find("a:first");
  763. if (navButton.length === 1) {
  764. navButton.prepend().appendTo("#postNavigation");
  765. var navButtonPrev = jq("div.nav-buttons .prev-button a");
  766. if (navButtonPrev)
  767. navButtonPrev.prepend().appendTo("#postNavigation");
  768. }
  769. jq("div.nav-buttons").remove();
  770. }
  771.  
  772. fExtMessage(undefined);
  773. }
  774. // Initialization - End
  775.  
  776. // Events - Start
  777. function HideAllClick(e) {
  778. if(e)
  779. e.preventDefault();
  780.  
  781. if(jq("#hideAll").text().indexOf("?") >= 0)
  782. return;
  783.  
  784. isHiding = true;
  785.  
  786. var siteTable = jq("#siteTable");
  787. siteTable.css("display", "block");
  788. postList.css("display", "block");
  789. siteTable.css("height", siteTable.outerHeight(true) + "px");
  790.  
  791. siteTable.find("div.thing").each(function(index, thing) {
  792. var jqThing = jq(thing);
  793. var offs = jqThing.offset();
  794. var top = parseInt(offs.top);
  795. var width = jqThing.width();
  796. var height = jqThing.height();
  797.  
  798. setTimeout(function() {
  799. jqThing.css({
  800. top: top,
  801. left: 0,
  802. width: width,
  803. height: height,
  804. position: "absolute"
  805. });
  806. }, settings.animationItemTimeout);
  807. });
  808.  
  809.  
  810. reloadCancelled = false;
  811. setTimeout(function() {
  812. if(pstItems.selected)
  813. pstItems.jqSelected.animate({ scrollTop: pstItems.jqSelected.offset().top }, 0);
  814.  
  815. HideAndAction(hiderElements, 0, null, "reload");
  816. }, settings.hideItemTimeout);
  817. jq(this).hide();
  818.  
  819. return false;
  820. }
  821.  
  822. function HideSelectedClick(e) {
  823. if (pstItems.selected) {
  824. var selPst = pstItems.selected;
  825. jq("#nextPost").click();
  826. Hide(jq("#" + selPst), false, false);
  827. }
  828. else
  829. MakeActivePost(undefined, pstItems.Next());
  830.  
  831. if(e)
  832. e.preventDefault();
  833. return false;
  834. }
  835.  
  836. // Kontext-Menü
  837. jq("#fExtContextMenu").on("fExtContextMenuOpening", function(event, actor) {
  838. var txt = actor.text();
  839. var jqThing = getThingForCtxActor(actor);
  840. var usrTxt = 'Select a User';
  841. var subTxt = 'Select a Subreddit';
  842. var keywTxt = 'Select word(s)';
  843.  
  844. ctxItemUsrHdr.Toggle(false);
  845. ctxItemUsrHdrPg.Toggle(false);
  846. ctxItemUsrUnhdr.Toggle(false);
  847.  
  848. ctxItemSbHdr.Toggle(false);
  849. ctxItemSbUnhdr.Toggle(false);
  850. if(jqThing.length === 1) {
  851. var usrTxtFnd = jqThing.find(".author:first").text();
  852. var subTxtFnd = jqThing.find(".subreddit:first").text().replace("/r/","");
  853.  
  854. if(usrTxtFnd !== "") {
  855. usrTxt = usrTxtFnd;
  856. var usrIndex = jq.inArray(usrTxt, settings.usersToHide);
  857. ctxItemUsrHdr.Toggle(usrIndex < 0);
  858. ctxItemUsrHdrPg.Toggle(usrIndex < 0);
  859. ctxItemUsrUnhdr.Toggle(usrIndex >= 0);
  860. }
  861. if(subTxtFnd !== "") {
  862. subTxt = subTxtFnd;
  863. var subIndex = jq.inArray(subTxt, settings.subsToHide);
  864.  
  865. ctxItemSbHdr.Toggle(subIndex < 0);
  866. ctxItemSbUnhdr.Toggle(subIndex >= 0);
  867. }
  868. }
  869.  
  870. var selText = fExtGetSelection();
  871. var keywIndex = jq.inArray(selText, settings.keywordsToHide);
  872. bCanHide = selText !== "" && keywIndex < 0;
  873. bCanUnhide = selText !== "" && keywIndex >= 0;
  874.  
  875. ctxItemKeywHdr.Toggle(bCanHide);
  876. ctxItemKeywUnhdr.Toggle(bCanUnhide);
  877. ctxItemKeywHdr.ItemText("Hide Keywords - '" + (selText || keywTxt) + "'");
  878. ctxItemKeywUnhdr.ItemText("Unhide Keywords - '" + (selText || keywTxt) + "'");
  879.  
  880. ctxItemUsrHdr.ItemText("Hide User - " + usrTxt);
  881. ctxItemUsrHdrPg.ItemText("Hide User and open Page - " + usrTxt);
  882. ctxItemUsrUnhdr.ItemText("Unhide User - " + usrTxt);
  883.  
  884. ctxItemSbHdr.ItemText("Hide Sub - " + subTxt);
  885. ctxItemSbUnhdr.ItemText("Unhide Sub - " + subTxt);
  886.  
  887. ctxRedo.Toggle(ctxRedo.find("li.ctxItem").length > 0);
  888. ctxUndo.Toggle(ctxUndo.find("li.ctxItem").length > 0);
  889. });
  890.  
  891. if (!isSinglePost && !isSubmitPage) {
  892. jq(document).on("click", "div.thing, div.thing *", function(e) {
  893. if(e.target.nodeName === "A" || e.target.nodeName === "LI")
  894. return true;
  895.  
  896. var jqThing;
  897. if(e.target.nodeName === "DIV" && jq.inArray("thing", e.target.classList) >= 0)
  898. jqThing = jq(e.target);
  899. else if(jq(e.target).parents("div.thing:first").length === 1 && (e.target.nodeName === "SPAN" || (e.target.nodeName === "DIV" && jq.inArray("entry", e.target.classList) >= 0)))
  900. jqThing = jq(e.target).parents("div.thing:first");
  901.  
  902. if (jqThing && jqThing.is(":visible") && jqThing.attr("id") != pstItems.selected) {
  903. return MakeActivePost(pstItems.selected, jqThing.attr("id"));
  904. }
  905. else return true;
  906. });
  907. }
  908.  
  909. jq("#topPost").click(function() {
  910. MakeActivePost(pstItems.selected, pstItems.First());
  911. return false;
  912. });
  913.  
  914. jq("#botPost").click(function() {
  915. MakeActivePost(pstItems.selected, pstItems.Last());
  916. return false;
  917. });
  918.  
  919. jq("#prevPost").click(function() {
  920. MakeActivePost(pstItems.selected, pstItems.Previous());
  921. return false;
  922. });
  923.  
  924. jq("#nextPost").click(function() {
  925. MakeActivePost(pstItems.selected, pstItems.Next());
  926. return false;
  927. });
  928.  
  929. jq("#frPost").click(function() {
  930. var pst = pstItems.selected;
  931. var pstNew = pst;
  932. pstNew = pstItems.Previous(5);
  933.  
  934. MakeActivePost(pst, pstNew);
  935. return false;
  936. });
  937.  
  938. jq("#ffPost").click(function() {
  939. var pst = pstItems.selected;
  940. var pstNew = pst;
  941.  
  942. MakeActivePost(pstItems.selected, pstItems.Next(5));
  943. return false;
  944. });
  945.  
  946. // Events - Settings
  947. function SetSettingsValues(settingsObject) {
  948. for (var key in settingsObject) {
  949. var varType = typeof settingsObject[key];
  950.  
  951. SetSettingValue(key, varType, settingsObject[key]);
  952. }
  953. }
  954.  
  955. function SetSettingValue(key, varType, value) {
  956. var settingsElement = jq("#rEnhSettings").find("[name='" + key + "']");
  957.  
  958. switch (varType) {
  959. case "boolean":
  960. if (value)
  961. settingsElement.attr("checked", "true");
  962. else
  963. settingsElement.removeAttr("checked");
  964. break;
  965. case "number":
  966. settingsElement.val(value);
  967. break;
  968. case "string":
  969. settingsElement.val(value);
  970. break;
  971. case "object":
  972. if (typeCheck.call(value) === '[object Array]')
  973. settingsElement.val(value.toString());
  974. else
  975. SetSettingsValues(value);
  976. break;
  977. default:
  978. console.log("Cannot get setting " + key + " to settings dialog because unkown type " + varType);
  979. break;
  980. }
  981. }
  982.  
  983. function ShowSettings() {
  984. SetSettingsValues(settings);
  985.  
  986. jq("#rEnhSettings").show();
  987. return false;
  988. }
  989.  
  990. function SaveSettingsDialog(e) {
  991. e.preventDefault();
  992.  
  993. jq("#rEnhSettings").find("input, textarea, select").each(function() {
  994. var val;
  995. var key = this.name;
  996. var tag = this.tagName;
  997.  
  998. switch (tag) {
  999. case "INPUT":
  1000. var type = this.type;
  1001. switch (type) {
  1002. case "checkbox":
  1003. val = Boolean(this.checked);
  1004. break;
  1005. case "number":
  1006. val = parseFloat(this.value);
  1007. break;
  1008. case "text":
  1009. val = this.value;
  1010. break;
  1011. case "button":
  1012. break;
  1013. default:
  1014. console.log("unhandled input type " + type + " for key " + key);
  1015. break;
  1016. }
  1017. break;
  1018. case "TEXTAREA":
  1019. val = this.value.split(",");
  1020. break;
  1021. case "SELECT":
  1022. val = parseInt(this.value);
  1023. break;
  1024. default:
  1025. break;
  1026. }
  1027.  
  1028. if (val !== undefined) {
  1029. if (key in settings)
  1030. settings[key] = val;
  1031. else if (key in settings.shortcuts)
  1032. settings.shortcuts[key] = val;
  1033. }
  1034. });
  1035. GMSave();
  1036.  
  1037. fExtPopup("Settings saved!");
  1038.  
  1039. return false;
  1040. }
  1041. // Events - End
  1042.  
  1043. // Functions - Start
  1044. function handleShortcutForOverview(e) {
  1045. switch (e.which) {
  1046. case settings.shortcuts.voteUp:
  1047. Vote(pstItems.selected, "up");
  1048. break;
  1049. case settings.shortcuts.previousPost:
  1050. jq("#prevPost").click();
  1051. break;
  1052. case settings.shortcuts.voteDown:
  1053. Vote(pstItems.selected, "down");
  1054. break;
  1055. case settings.shortcuts.nextImage:
  1056. var imgActorNext = jq(".pstSelected").find("div.res-gallery-individual-controls").find("div.res-gallery-next");
  1057. if(imgActorNext.length > 0)
  1058. imgActorNext.get(0).click();
  1059. break;
  1060. case settings.shortcuts.toggleSelected:
  1061. if (pstItems.selected)
  1062. pstItems.jqSelected.find(".expando-button").get(0).click();
  1063. break;
  1064. case settings.shortcuts.previousImage:
  1065. var imgActorPrev = jq(".pstSelected").find("div.res-gallery-individual-controls").find("div.res-gallery-previous");
  1066. if(imgActorPrev.length > 0)
  1067. imgActorPrev.get(0).click();
  1068. break;
  1069. case settings.shortcuts.hideSelected:
  1070. HideSelectedClick();
  1071. break;
  1072. case settings.shortcuts.nextPost:
  1073. jq("#nextPost").click();
  1074. break;
  1075. case settings.shortcuts.hideAll:
  1076. if (reloadCancelled)
  1077. HideAllClick();
  1078. break;
  1079. case settings.shortcuts.zoomIn:
  1080. if (pstItems.selected)
  1081. pstItems.jqSelected.find("img, video, iframe").each(function() { document.fExt.zoomIn(this, 20); });
  1082. break;
  1083. case settings.shortcuts.zoomOut:
  1084. if (pstItems.selected)
  1085. pstItems.jqSelected.find("img, video, iframe").each(function() { document.fExt.zoomOut(this, 20); });
  1086. break;
  1087. case settings.shortcuts.rotateLeft:
  1088. if (pstItems.selected)
  1089. pstItems.jqSelected.find("img, video, iframe").each(function() { document.fExt.rotate(this, -90); });
  1090. break;
  1091. case settings.shortcuts.rotateRight:
  1092. if (pstItems.selected)
  1093. pstItems.jqSelected.find("img, video, iframe").each(function() { document.fExt.rotate(this, 90); });
  1094. break;
  1095. case settings.shortcuts.undoLast:
  1096. if(ctxUndo.Items.length > 0)
  1097. ctxUndo.Items[ctxUndo.Items.length - 1].Trigger();
  1098. break;
  1099. case settings.shortcuts.redoLast:
  1100. if(ctxRedo.Items.length > 0)
  1101. ctxRedo.Items[ctxRedo.Items.length - 1].Trigger();
  1102. break;
  1103. default:
  1104. return true;
  1105. }
  1106. return false;
  1107. }
  1108.  
  1109. var jqPost = jq("div.thing:first");
  1110. var jqPostID = jqPost.attr("id");
  1111. function handleShortcutForSinglePage(e) {
  1112. switch (e.which) {
  1113. case settings.shortcuts.voteUp:
  1114. Vote(jqPostID, "up");
  1115. break;
  1116. case settings.shortcuts.previousPost:
  1117. jq("#prevPost").click();
  1118. break;
  1119. case settings.shortcuts.voteDown:
  1120. Vote(jqPostID, "down");
  1121. break;
  1122. case settings.shortcuts.nextImage:
  1123. var imgActorNext = jqPost.find("div.res-gallery-individual-controls").find("div.res-gallery-next");
  1124. if(imgActorNext.length > 0)
  1125. imgActorNext.get(0).click();
  1126. break;
  1127. case settings.shortcuts.toggleSelected:
  1128. pstItems.jqSelected.find("a.expand:first").click();
  1129. break;
  1130. case settings.shortcuts.previousImage:
  1131. var imgActorPrev = jqPost.find("div.res-gallery-individual-controls").find("div.res-gallery-previous");
  1132. if(imgActorPrev.length > 0)
  1133. imgActorPrev.get(0).click();
  1134. break;
  1135. case settings.shortcuts.nextPost:
  1136. jq("#nextPost").click();
  1137. break;
  1138. case settings.shortcuts.zoomIn:
  1139. jqPost.find("img, video, iframe").each(function() { document.fExt.zoomIn(this, 20); });
  1140. break;
  1141. case settings.shortcuts.zoomOut:
  1142. jqPost.find("img, video, iframe").each(function() { document.fExt.zoomOut(this, 20); });
  1143. break;
  1144. case settings.shortcuts.rotateLeft:
  1145. jqPost.find("img, video, iframe").each(function() { document.fExt.rotate(this, -90); });
  1146. break;
  1147. case settings.shortcuts.rotateRight:
  1148. jqPost.find("img, video, iframe").each(function() { document.fExt.rotate(this, 90); });
  1149. break;
  1150. default:
  1151. return true;
  1152. }
  1153. return false;
  1154. }
  1155.  
  1156. function InitializeElements() {
  1157. var rPostNavigation = jq('<div id="postNavigation"><a href="#" id="topPost">Top</a><a href="#" id="frPost">&lt;&lt;</a><a href="#" id="prevPost">&lt;</a><a href="#" id="nextPost">&gt;</a><a href="#" id="ffPost">&gt;&gt;</a><a href="#" id="botPost">Bottom</a></div>');
  1158. rPostNavigation.appendTo("body");
  1159.  
  1160. var rTabMenu = jq("ul.tabmenu");
  1161. jq('<li class="spacerLi"></li>').appendTo(rTabMenu);
  1162.  
  1163. jq('<li><span class="">All Posts:</span></li>').appendTo(rTabMenu);
  1164. jq('<li><a href="#" class="choice tabButton" title="Updvotes all displayed posts" id="upvoter">Upvote</a></li>').appendTo(rTabMenu);
  1165. jq('<li><a href="#" class="choice tabButton" title="Downvotes all displayed posts" id="downvoter">Downvote</a></li>').appendTo(rTabMenu);
  1166.  
  1167. jq('<li><a href="#" class="choice tabButton collapsed" title="Expands all posts" id="expander">Expand</a></li>').appendTo(rTabMenu);
  1168.  
  1169. jq('<li class="spacerLi"></li>').appendTo(rTabMenu);
  1170. jq('<li><span class="">Hide:</span></li>').appendTo(rTabMenu);
  1171. jq('<li><a href="#" class="choice tabButton" style="background-color: rgb(255, 138, 138) !important;" title="Hides all displayed posts which prevents them from showing up again" id="hideAll">All (<span>?</span>)</a></li>').appendTo(rTabMenu);
  1172. jq('<li><a href="#" class="choice tabButton" style="display: none; background-color: rgb(255, 138, 138) !important;" title="Hides all displayed posts which prevents them from showing up again" id="hideSelected">Selected</a></li>').appendTo(rTabMenu);
  1173.  
  1174. jq('<li class="spacerLi"></li>').appendTo(rTabMenu);
  1175. jq('<li><span class="">Toggle hidden:</span></li>').appendTo(rTabMenu);
  1176. jq('<li><a href="#" class="choice tabButton" style="background-color: rgb(175, 255, 171) !important;" title="Toggles the hidden User posts" id="toggleUserHidden">Users (<span>?</span>)</a></li>').appendTo(rTabMenu);
  1177. jq('<li><a href="#" class="choice tabButton" style="background-color: rgb(175, 255, 171) !important;" title="Toggles the hidden Sub posts" id="toggleSubsHidden">Subs (<span>?</span>)</a></li>').appendTo(rTabMenu);
  1178. jq('<li><a href="#" class="choice tabButton" style="background-color: rgb(175, 255, 171) !important;" title="Toggles the hidden Keyword posts" id="toggleKeywordsHidden">Keywords (<span>?</span>)</a></li>').appendTo(rTabMenu);
  1179. jq('<li><a href="#" class="choice tabButton" style="background-color: rgb(175, 255, 171) !important;" title="Toggles the duplicate posts" id="toggleDuplicateHidden">Duplicates (<span>?</span>)</a></li>').appendTo(rTabMenu);
  1180.  
  1181. jq('<li class="spacerLi"></li>').appendTo(rTabMenu);
  1182. if (loc.indexOf("show=all") < 0) {
  1183. var parmChar = "?";
  1184. if(loc.indexOf("?") >= 0)
  1185. parmChar = "&";
  1186. jq('<li><a href="' + loc.replace('#', '') + parmChar + 'show=all" title="Show all posts of this sub, including previously hidden posts" class="choice tabButton" style="background-color: rgb(187, 187, 255) !important;" id="showAll">Show All</a></li>').appendTo(rTabMenu);
  1187. }
  1188. }
  1189.  
  1190. function InitializeStyles() {
  1191. fExtCreateStyle("#header { z-index: 107; }");
  1192. fExtCreateStyle("#siteTable { padding: 0 64px; }");
  1193. fExtCreateStyle("body.with-listing-chooser>.content, body.with-listing-chooser .footer-parent { margin-left: 0 !important; }");
  1194. fExtCreateStyle("div.listing-chooser { left: 0 !important; }");
  1195. fExtCreateStyle("div.side { right: 0; }");
  1196. fExtCreateStyle("div.side, div.listing-chooser { z-index: 106 !important; position: fixed !important; height: 90%; top: " + headerHeight + "px !important; margin: 0px; border: 1px solid black; width: 5px !important; overflow-y: hidden !important; padding: 8px !important; }");
  1197. fExtCreateStyle("div.side:hover { width: 500px !important; overflow-y: auto !important; max-height: 100vh; }");
  1198. fExtCreateStyle("div.listing-chooser:hover { width: 500px !important; overflow-y: auto !important; max-height: 100vh; }");
  1199. fExtCreateStyle("span.domain { font-weight: bold; }");
  1200.  
  1201. fExtCreateStyle("div.content { padding-top: 80px !important; }");
  1202. fExtCreateStyle(".tabButton { color: #333333 !important; background-color: rgb(252, 255, 215) !important; border: 1px solid black; }");
  1203. fExtCreateStyle(".spacerLi { width: 50px; }");
  1204. fExtCreateStyle("#postNavigation { position: fixed !important; top: 27px; width: 500px; margin: 0 auto; display: block; z-index: 108; /*font-size: 12px; font-weight: bold; */ left: 0; right: 0; } ");
  1205. fExtCreateStyle("#postNavigation a { background-color: #ffffff; border: 1px solid black; padding: 8px 14px; margin: 0 1px; }");
  1206. fExtCreateStyle("#postNavigation a:hover { background-color: #dfdfdf; }");
  1207. fExtCreateStyle(".pstSelected, .pstSelected * { z-index: 105; }");
  1208.  
  1209. fExtCreateStyle(".midcol { width: 32px !important; }");
  1210. fExtCreateStyle(".RES-keyNav-activeElement, .RES-keyNav-activeElement .md-container { background-color: transparent !important; }");
  1211. fExtCreateStyle("div.md { border: none !important; }");
  1212.  
  1213. if (isSinglePost) {
  1214. fExtCreateStyle(".livePreview { width: 1600px !important; }");
  1215. fExtCreateStyle(".livePreview p, .livePreview ol { width: 1500px !important; }");
  1216. fExtCreateStyle("div.usertext-edit { max-width: 50%; };");
  1217. fExtCreateStyle("div.usertext-edit div.md { width: 100%; max-width: 100%; }");
  1218. fExtCreateStyle("div.usertext-edit div.md textarea { width: 100%; }");
  1219. fExtCreateStyle(".pstSelected p.tagline { background-color: #DDDDFF; }");
  1220. } else {
  1221. fExtCreateStyle(".md { max-width: none !important; }");
  1222. fExtCreateStyle(".madeVisible *,div.expando * { z-index: 105; }");
  1223. fExtCreateStyle("a.madeVisible img, a.madeVisible video { max-height: 100vh !important; max-width: 95vw !important;}");
  1224. fExtCreateStyle("body { margin-bottom: 650px !important; }");
  1225. fExtCreateStyle("img.RESImage { border-bottom: #000 solid 3px !important; padding: 0 !important; }");
  1226. fExtCreateStyle("div.thing { min-height: 80px; padding: 5px 0; margin: 0 0 8px 0; border: 1px solid black; }");
  1227. fExtCreateStyle("div.thing.pstSelected div.entry>div:not(.expando-button) { background-color: #fff !important; padding: 10px 20px; border: 1px solid black; }");
  1228. fExtCreateStyle("div.thing div.entry img, div.thing div.entry video { display: none !important; }");
  1229. fExtCreateStyle("div.thing.pstSelected div.entry img, div.thing.pstSelected div.entry video { display: block !important; }");
  1230. if (settings.markNSFW) {
  1231. fExtCreateStyle(".NsfwPost { background-color: rgb(255, 81, 81) !important; }");
  1232. fExtCreateStyle(".NsfwItem .madeVisible { display: none; }");
  1233. fExtCreateStyle(".pstSelected .NsfwItem .madeVisible { display: initial !important; }");
  1234. fExtCreateStyle(".pstSelected .NsfwItem .madeVisible div { width: auto !important; }");
  1235. fExtCreateStyle(".pstSelected .NsfwItem * { z-index: 104 !important; }");
  1236. }
  1237. fExtCreateStyle(".entry .buttons li { line-height: inherit !important; width: 100px; }");
  1238. fExtCreateStyle(".thingUserSubInfo { padding: 4px 8px; height: 26px; display: block; }");
  1239. fExtCreateStyle(".thingUserSubInfo>* { float: left; clear: none; border: 1px solid black; margin: 0 2px; }");
  1240. fExtCreateStyle(".thingUserSubInfo * { font-size: 12px !important; }");
  1241. fExtCreateStyle(".thingUserSubInfo .nsfw-stamp { display: inline !important; }");
  1242. fExtCreateStyle(".thingUserSubInfo p.tagline { width: 450px; }");
  1243. fExtCreateStyle(".thingUserSubInfo a.subreddit { width: 160px; }");
  1244. fExtCreateStyle("ul.flat-list.buttons { float: left; clear: none; padding: 0; position: absolute; left: 870px; }");
  1245. fExtCreateStyle("ul.flat-list.buttons>li { cursor: pointer; }");
  1246. fExtCreateStyle("ul.flat-list.buttons>li, .thingUserSubInfo p.tagline, .thingUserSubInfo a.subreddit { padding: 6px !important; background-color: #eeeeee !important; text-align: center; }");
  1247. fExtCreateStyle("ul.flat-list.buttons>li:hover, .thingUserSubInfo p.tagline:hover, .thingUserSubInfo a.subreddit:hover { background-color: #cee3f8 !important; }");
  1248. //fExtCreateStyle("a.subreddit { float: left; background-color: white !important; color: #888; font-weight: bold; padding: 0 4px !important; }");
  1249. // fExtCreateStyle("p.tagline { float: left; position: relative; background-color: white; color: #888; font-weight: bold; padding: 0 1px; }");
  1250. fExtCreateStyle("p.title { color: #000000 !important; float: left; }");
  1251. fExtCreateStyle("p.title a { color: #000000 !important; }");
  1252. fExtCreateStyle("div.top-matter { height: 48px !important; }");
  1253. //fExtCreateStyle("ul.flat-list.buttons { padding-bottom: 40px; width: 800px; margin: 20px auto 0 auto; font-size: larger; text-align: center; left: 0; right: 0; clear: both; }");
  1254. //fExtCreateStyle("ul.flat-list.buttons li { padding: 4px; background-color: #fff; margin: 2px; border: 1px solid #999; }");
  1255. fExtCreateStyle(".usertext * { z-index: 1; }");
  1256. fExtCreateStyle("div.thing div.entry div.expando:not(.expando-uninitialized) { display: block !important; }");
  1257. fExtCreateStyle("div.thing div.entry div.expando span { display: none; }");
  1258. }
  1259. fExtCreateStyle(".toggleHidden, div.thing.hidden { background: repeating-linear-gradient(45deg, transparent, transparent 35px, rgba(255,255,255,.5) 35px, rgba(255,255,255,.5) 70px); }");
  1260.  
  1261. if(settings.hideUsers)
  1262. fExtCreateStyle(".userHidden .author { text-decoration: line-through; }");
  1263. if(settings.hideSubs)
  1264. fExtCreateStyle(".subsHidden .subreddit { text-decoration: line-through; }");
  1265.  
  1266. fExtCreateStyle(".userHidden a.title, .subsHidden a.title, .duplicateHidden a.title { background-position: 0 !important; background-repeat: no-repeat !important; padding: 8px 8px 8px 26px; }");
  1267. fExtCreateStyle(".userHidden a.title { background-image: url('" + imgDelUser + "') !important; }");
  1268. fExtCreateStyle(".subsHidden a.title { background-image: url('" + imgDelCat + "') !important; }");
  1269. fExtCreateStyle(".duplicateHidden a.title { background-image: url('" + imgDuplicate + "') !important; }");
  1270.  
  1271. fExtCreateStyle("ul.tabmenu .disabled { background-color: #dfdfdf !important; }");
  1272.  
  1273. fExtCreateStyle("#rEnhSettings { position: fixed; height: 750px; top: 50px; border: 1px solid black; width: 750px; padding: 12px; z-index: 1000; background-color: #FEFEFE; right: 0; left: 0; margin: 0 auto; }");
  1274. fExtCreateStyle("#rEnhSettings table { }");
  1275. fExtCreateStyle("#rEnhSettings table td.label, #rEnhSettings table td.value { }");
  1276. fExtCreateStyle("#rEnhSettings table td.label { float: left; clear: right; font-size: larger; }");
  1277. fExtCreateStyle("#rEnhSettings table td.value { float: right; clear: left; }");
  1278. fExtCreateStyle("#rEnhSettings table thead { font-size: large; }");
  1279. fExtCreateStyle("#rEnhSettings div.tableContainer { overflow-y: scroll; height: 700px; }");
  1280. fExtCreateStyle("#rEnhSettings div.settingsButtons { height: 50px; }");
  1281. fExtCreateStyle("#rEnhSettings * { z-index: 1000; margin: 4px; }");
  1282. fExtCreateStyle("#rEnhSettings td.label { }");
  1283. fExtCreateStyle("#rEnhSettings a { padding: 4px; border: 1px solid grey; float: right; }");
  1284. }
  1285.  
  1286. function InitializeHider() {
  1287. if(!hiderElements) {
  1288. hiderElements = [];
  1289. for(var i = 0; i < postList.length; i++){
  1290. var post = jq(postList[i]);
  1291. if(!post.is(":visible"))
  1292. continue;
  1293.  
  1294. hiderElements.push(post);
  1295. }
  1296.  
  1297. if (hiderElements.length === 0)
  1298. jq("#hideAll").attr("style", "background-color: #808080 !important; color: #CFCFCF; border: 1px solid black;");
  1299.  
  1300. var len = jq("form.hide-button").length;
  1301. if(len > 0)
  1302. jq("#hideAll").text("All (" + len + ")");
  1303. else
  1304. jq("#hideAll").text("None");
  1305.  
  1306. jq(".hide-button:contains(hidden)").click(function(e){
  1307. e.preventDefault();
  1308.  
  1309. jq(this).parents("div.thing:first").hide();
  1310.  
  1311. return false;
  1312. });
  1313. }
  1314. }
  1315.  
  1316. function VoteAndNext(sender, voteLinks, ind) {
  1317. var nextVoteItem = voteLinks[ind];
  1318. jq(nextVoteItem).click();
  1319.  
  1320. ind++;
  1321. if (voteLinks.length > ind) {
  1322. animateControl(sender);
  1323.  
  1324. setTimeout(function() {
  1325. VoteAndNext(sender, voteLinks, ind);
  1326. }, settings.animationItemTimeout);
  1327. } else {
  1328. jq("#downvoter").text("Downvote");
  1329. jq("#upvoter").text("Upvote");
  1330. }
  1331. }
  1332.  
  1333. function ExpandAndNext(expandLinks, ind) {
  1334. var jqExpander = jq("#expander");
  1335. var expandItem = expandLinks[ind];
  1336. jq(expandItem).click();
  1337.  
  1338. if (expandLinks.length > ind) {
  1339. animateControl(jqExpander);
  1340. setTimeout(function() {
  1341. ExpandAndNext(expandLinks, ind + 1);
  1342. }, settings.animationItemTimeout);
  1343. }
  1344. else {
  1345. if(jqExpander.hasClass("collapsed")) {
  1346. jqExpander.text("Collapse");
  1347. jqExpander.removeClass("collapsed");
  1348. jqExpander.addClass("expanded");
  1349. }
  1350. else {
  1351. jqExpander.text("Expand");
  1352. jqExpander.addClass("collapsed");
  1353. jqExpander.removeClass("expanded");
  1354. }
  1355. }
  1356. }
  1357.  
  1358. function animateControl(sender) {
  1359. var txt = jq(sender).text();
  1360. if (txt.length >= 3)
  1361. txt = ".";
  1362. else
  1363. txt = txt + ".";
  1364.  
  1365. jq(sender).text(txt);
  1366. }
  1367.  
  1368. function HideAndAction(hideLinks, index, previousLink, action) {
  1369. var jqLink = jq(previousLink);
  1370. var item = hideLinks[index];
  1371. if (jqLink.find("form.hide-button").length === 0) {
  1372. if (hideLinks.length > index) {
  1373. var perc = index * 100 / hideLinks.length;
  1374. fExtSetLoading(perc);
  1375. if (action !== "hideObject")
  1376. fExtMessage(action + " (" + index + "/" + hideLinks.length + ") ...");
  1377.  
  1378. Hide(item, action === "reload" || (action == "enhance" && jq(item).find("a.author.friend").length > 0 && duplicateLinks.indexOf(item) < 0));
  1379.  
  1380. var actArgs = [hideLinks, index + 1, previousLink, action];
  1381. ActionWhenElementIsInvisible(item, HideAndAction, actArgs);
  1382. } else {
  1383. isHiding = false;
  1384. fExtSetLoading(100);
  1385. fExtMessage(undefined);
  1386. switch (action) {
  1387. case "reload":
  1388. ReloadLooper(5);
  1389. break;
  1390. case "enhance":
  1391. if (pstItems.onlyVisible().length === 0)
  1392. ReloadLooper(5);
  1393. else
  1394. InitializeHider();
  1395. break;
  1396. case "nextPost":
  1397. if (pstItems.onlyVisible().length === 0)
  1398. ReloadLooper(5);
  1399. else
  1400. jq("#nextPost").click();
  1401. break;
  1402. default:
  1403. break;
  1404. }
  1405. }
  1406. } else setTimeout(function() { HideAndAction(hideLinks, index, previousLink, action); }, settings.hideItemTimeout);
  1407. }
  1408.  
  1409. function ReloadLooper(loops) {
  1410. if (reloadCancelled) {
  1411. fExtMessage();
  1412. return;
  1413. } else {
  1414. if (loops === 0) {
  1415. fExtMessage("Reloading...");
  1416. setTimeout(function() {
  1417. location.reload();
  1418. }, 1000);
  1419. } else {
  1420. var msg = "Reloading in " + loops + " seconds... (click here to cancel)";
  1421. fExtMessage(msg);
  1422. document.title = msg;
  1423. setTimeout(function() {
  1424. ReloadLooper(loops - 1);
  1425. }, 1000);
  1426. }
  1427. }
  1428. }
  1429.  
  1430. function Hide(item, displayAfter, handled) {
  1431. var jqHideButton = item.find("form.hide-button");
  1432.  
  1433. if (!isHiding && pstItems.selected === item.attr("id")) {
  1434. MakeActivePost(item.attr("id"), pstItems.Next());
  1435. }
  1436.  
  1437. if(!handled) {
  1438. jqHideButton.unbind("click", handleHideClick);
  1439.  
  1440. jqHideButton.find("a:first").click();
  1441.  
  1442. var args = [item, displayAfter, true];
  1443. AddUndo(Unhide, args, Hide, args, item.find("p.title").text());
  1444.  
  1445. jqHideButton.bind("click", handleHideClick);
  1446. }
  1447.  
  1448. item.hide(settings.animationItemTimeout);
  1449.  
  1450. if (displayAfter) {
  1451. ActionWhenElementIsInvisible(item, item.show, undefined);
  1452. }
  1453.  
  1454. if(pstItems.onlyVisible().length === 0) {
  1455. reloadCancelled = false;
  1456. ReloadLooper(5);
  1457. }
  1458.  
  1459. return true;
  1460. }
  1461.  
  1462. function Unhide(item, displayAfter, handled) {
  1463. jq(item).show();
  1464.  
  1465. if(!handled){
  1466. var args = [item, displayAfter, true];
  1467. AddUndo(Hide, args, Unhide, args, item.find("p.title").text());
  1468. }
  1469.  
  1470. return true;
  1471. }
  1472.  
  1473. function Mark(item, itemType) {
  1474. item.addClass("markedItem");
  1475. item.addClass(itemType);
  1476. }
  1477.  
  1478. function MakeActivePost(oldId, newId) {
  1479. if (oldId === undefined || newId === undefined || oldId !== newId) {
  1480. if (newId) {
  1481. if (newId !== pstItems.selected) {
  1482. pstItems.selected = newId;
  1483. pstItems.jqSelected = jq("#" + newId);
  1484. if (!pstItems.jqSelected.hasClass("pstSelected"))
  1485. pstItems.jqSelected.addClass("pstSelected");
  1486.  
  1487. if (settings.autoExpandSelectedPost) {
  1488. var jsExpander = pstItems.jqSelected.find(".expando-button.collapsed").get(0);
  1489. if (jsExpander)
  1490. jsExpander.click();
  1491. }
  1492. }
  1493. }
  1494. else {
  1495. pstItems.selected = undefined;
  1496. pstItems.jqSelected = undefined;
  1497. }
  1498.  
  1499. if (oldId) {
  1500. var jqOldPost = jq("#" + oldId);
  1501. jqOldPost.removeClass("pstSelected");
  1502.  
  1503. if (settings.autoExpandSelectedPost) {
  1504. var jsCollapser = jqOldPost.find(".expando-button.expanded").get(0);
  1505. if (jsCollapser)
  1506. jsCollapser.click();
  1507. }
  1508. }
  1509. }
  1510.  
  1511. if(pstItems.jqSelected)
  1512. scrollTo(pstItems.jqSelected);
  1513.  
  1514. return false;
  1515. }
  1516.  
  1517. // Image Preloading - Start
  1518. var preloadIndex = 0;
  1519. var preloadComplete = 0;
  1520. var preloadingImages = jq("a.title[href*='imgur'],a.title[href*='gfycat']").not(".thumbnail");
  1521. for(var i = 0; i < preloadingImages.length; i++){
  1522. var img = preloadingImages.get(i);
  1523.  
  1524. if (img.href.indexOf("https://") < 0) {
  1525. img.href = img.href.replace("http://", "https://");
  1526. }
  1527. }
  1528.  
  1529. function preloadSuccess(e){
  1530. console.log("Preloading image " + preloadIndex + " successful!");
  1531. preload();
  1532. }
  1533.  
  1534. function preloadError(e){
  1535. console.log("Error preloading image " + preloadIndex);
  1536. preload();
  1537. }
  1538.  
  1539. var preloadingImage = document.createElement('IMG');
  1540. preloadingImage.style.display = "block";
  1541. preloadingImage.style.position = "absolute";
  1542. preloadingImage.style.top = 0;
  1543. preloadingImage.style.left = 0;
  1544. preloadingImage.src= "about:blank";
  1545. preloadingImage.width=1;
  1546. preloadingImage.height=1;
  1547. preloadingImage.onerror = preloadError;
  1548. preloadingImage.onload = preloadSuccess;
  1549. document.body.appendChild(preloadingImage);
  1550.  
  1551. function preload() {
  1552. if(preloadIndex >= preloadingImages.length) {
  1553. preloadingImage.remove();
  1554. return;
  1555. }
  1556.  
  1557. var href = preloadingImages.get(preloadIndex).href;
  1558. preloadIndex++;
  1559.  
  1560. console.log("Preloading Image " + preloadIndex + " of " + preloadingImages.length + "(" + href + ")...");
  1561. preloadingImage.src = href;
  1562. }
  1563.  
  1564. setTimeout(function(){ preload(); }, 1000);
  1565. // Image preloading - End
  1566.  
  1567. function scrollTo(item) {
  1568. var jqItem = jq(item);
  1569. var offs = jqItem.offset();
  1570. var topPos = offs.top - headerHeight;
  1571.  
  1572. jq(document.body).scrollTop(topPos);
  1573. //jq(document.body).animate({ scrollTop: topPos }, settings.animationItemTimeout);
  1574. }
  1575.  
  1576. function AddToHideLinks(elm) {
  1577. if (!elm.hasClass("toggleHidden"))
  1578. elm.addClass("toggleHidden");
  1579.  
  1580. if (jq.inArray(elm, hideLinks) < 0)
  1581. hideLinks.push(elm);
  1582. }
  1583.  
  1584. function Vote(id, direction) {
  1585. if (id !== undefined) {
  1586. var element;
  1587.  
  1588. switch (direction) {
  1589. case "up":
  1590. element = jq("#" + id).find(".arrow.up, .arrow.upmod");
  1591. break;
  1592. case "down":
  1593. element = jq("#" + id).find(".arrow.down, .arrow.downmod");
  1594. break;
  1595. default:
  1596. break;
  1597. }
  1598.  
  1599. if (element.length > 0) {
  1600. element.click();
  1601. }
  1602. }
  1603. }
  1604.  
  1605. function AddUndo(fnUndo, argsUndo, fnRedo, argsRedo, suffix) {
  1606. if (ctxUndo.Items.length === 10) {
  1607. var removeThis = ctxUndo.Items[0];
  1608. ctxUndo.Items.splice(0, 1);
  1609. removeThis.remove();
  1610. }
  1611. if(!suffix)
  1612. suffix = "";
  1613. else if(suffix.length > 25)
  1614. suffix = suffix.substring(0, 25) + "...";
  1615.  
  1616. var ctxItem = fExtAddCtxItem(suffix && suffix.length > 0 ? fnRedo.name + " - " + suffix : fnRedo.name, ctxUndo);
  1617. ctxItem.ClickCloses = false;
  1618. ctxItem.fnUndo = fnUndo;
  1619. ctxItem.argsUndo = argsUndo;
  1620. ctxItem.fnRedo = fnRedo;
  1621. ctxItem.argsRedo = argsRedo;
  1622. ctxItem.Action = function(event, sender, actor) {
  1623. sender.fnUndo.apply(this, sender.argsUndo);
  1624. AddRedo(sender.fnUndo, sender.argsUndo, sender.fnRedo, sender.argsRedo, suffix);
  1625. sender.Remove();
  1626. };
  1627. }
  1628.  
  1629. function AddRedo(fnUndo, argsUndo, fnRedo, argsRedo, suffix) {
  1630. if (ctxRedo.Items.length === 10) {
  1631. ctxRedo.Items[0].remove();
  1632. ctxRedo.Items.splice(0, 1);
  1633. }
  1634. if(!suffix)
  1635. suffix = "";
  1636. else if(suffix.length > 25)
  1637. suffix = suffix.substring(0, 25) + "...";
  1638.  
  1639. var ctxItem = fExtAddCtxItem(suffix && suffix.length > 0 ? fnUndo.name + " - " + suffix : fnUndo.name, ctxRedo);
  1640. ctxItem.ClickCloses = false;
  1641. ctxItem.fnUndo = fnUndo;
  1642. ctxItem.argsUndo = argsUndo;
  1643. ctxItem.fnRedo = fnRedo;
  1644. ctxItem.argsRedo = argsRedo;
  1645. ctxItem.Action = function(event, sender, actor) {
  1646. sender.fnRedo.apply(this, sender.argsRedo);
  1647. AddUndo(sender.fnUndo, sender.argsUndo, sender.fnRedo, sender.argsRedo, suffix);
  1648. sender.remove();
  1649. };
  1650. }
  1651.  
  1652. function ToggleVisibility(event, sender, className) {
  1653. event.preventDefault();
  1654. if (jq(sender).data("state") === "shown") {
  1655. jq(sender).data("state","hidden");
  1656. jq(className).hide();
  1657. } else {
  1658. jq(sender).data("state","shown");
  1659. jq(className).show();
  1660. }
  1661. }
  1662.  
  1663. function HideObject(containingArray, arrayName, text, selector) {
  1664. if (jq.inArray(text, containingArray) < 0) {
  1665. fExtPopup("Adding '" + text + "' from '" + arrayName + "' to hide.");
  1666. containingArray.push(text);
  1667. GMSave();
  1668.  
  1669. var links = [];
  1670. var selectNext = false;
  1671.  
  1672. jq(selector).parents("div.thing").each(function(index, item) {
  1673. var jqItem = jq(item);
  1674. selectNext = selectNext || item.id === pstItems.selected;
  1675.  
  1676. if (jqItem.find("form.hide-button").length > 0)
  1677. links.push(jqItem);
  1678. });
  1679.  
  1680. HideAndAction(links, 0, null, "hideObject");
  1681.  
  1682. return true;
  1683. }
  1684. return false;
  1685. }
  1686.  
  1687. function UnhideObject(containingArray, arrayName, text, selector) {
  1688. var arrayIndex = jq.inArray(text, containingArray);
  1689. if (arrayIndex >= 0) {
  1690. fExtPopup("Removing '" + text + "' from '" + arrayName + "'.");
  1691. containingArray.splice(arrayIndex, 1);
  1692. GMSave();
  1693. return true;
  1694. }
  1695. return false;
  1696. }
  1697.  
  1698. function GrabContent(htmlContent) {
  1699. fExtMessage("Loading additional Pages (" + numberOfSitesLoaded + " of max " + settings.maximumNumberOfSitesToLoad + ")");
  1700.  
  1701. var navButtonNext = jq(htmlContent).find("div.nav-buttons").find(".next-button").find("a").get(0);
  1702. if (numberOfSitesLoaded < settings.maximumNumberOfSitesToLoad && navButtonNext) {
  1703. numberOfSitesLoaded += 1;
  1704. var srcUrl = navButtonNext.href;
  1705. //siteTable
  1706. jq.ajax({
  1707. url: srcUrl,
  1708. method: "get",
  1709. success: function(data) {
  1710. jq(data).find("div#siteTable").find("div.thing").each(function() {
  1711. jq(this).detach().appendTo("div#siteTable");
  1712. });
  1713.  
  1714. GrabContent(data);
  1715. },
  1716. error: function(data) {
  1717. console.log(data);
  1718. }
  1719. });
  1720. } else {
  1721. if (navButtonNext)
  1722. jq(navButtonNext).detach().appendTo("#postNavigation");
  1723.  
  1724. fExtMessage(numberOfSitesLoaded + " Pages loaded, starting initialization...");
  1725.  
  1726. MainInitialization();
  1727. }
  1728. }
  1729.  
  1730. function InitializeContextMenu() {
  1731. ctxItemUsrHdr = fExtAddCtxItem("Hide User", rEnhSub);
  1732. ctxItemUsrHdr.Action = function(event, sender, actor) {
  1733. var jqThing = getThingForCtxActor(actor);
  1734. var user = jqThing.find(".author:first").text();
  1735. var selector = "a.author:contains(" + user + ")";
  1736. var args = [settings.usersToHide, "Users", user, selector];
  1737. if (HideObject.apply(sender, args))
  1738. AddUndo(UnhideObject, args, HideObject, args, user);
  1739. };
  1740.  
  1741. ctxItemUsrHdrPg = fExtAddCtxItem("Hide User and open Userpage", rEnhSub);
  1742. ctxItemUsrHdrPg.Action = function(event, sender, actor) {
  1743. ctxItemUsrHdr.Action(event, sender, actor);
  1744. var jqThing = getThingForCtxActor(actor);
  1745. var user = jqThing.find(".author:first").text();
  1746. GM_openInTab("https://www.reddit.com/u/" + user + "/submitted/", true);
  1747. };
  1748.  
  1749. ctxItemUsrUnhdr = fExtAddCtxItem("Unhide User", rEnhSub);
  1750. ctxItemUsrUnhdr.Action = function(event, sender, actor) {
  1751. var jqThing = getThingForCtxActor(actor);
  1752. var user = jqThing.find(".author:first").text();
  1753. var selector = "a.author:contains(" + user + ")";
  1754. var args = [settings.usersToHide, "Users", user, selector];
  1755. if (UnhideObject.apply(sender, args)) {
  1756. jq("a.author:contains(" + user + ")").parents("div.thing").each(function(index, item) {
  1757. jq(item).show();
  1758. });
  1759. AddUndo(HideObject, args, UnhideObject, args, user);
  1760. }
  1761. };
  1762.  
  1763. fExtAddCtxSeparator(rEnhSub);
  1764.  
  1765. ctxItemSbHdr = fExtAddCtxItem("Hide Sub", rEnhSub);
  1766. ctxItemSbHdr.Action = function(event, sender, actor) {
  1767. var jqThing = getThingForCtxActor(actor);
  1768. var sub = jqThing.find(".subreddit:first").text().replace("/r/", "").replace("r/","");
  1769. var selector = "a.subreddit:contains(" + sub + ")";
  1770. var args = [settings.subsToHide, "Subs", sub, selector];
  1771. if (HideObject.apply(sender, args))
  1772. AddUndo(UnhideObject, args, HideObject, args, sub);
  1773. };
  1774.  
  1775. ctxItemSbUnhdr = fExtAddCtxItem("Unhide Sub", rEnhSub);
  1776. ctxItemSbUnhdr.Action = function(event, sender, actor) {
  1777. var jqThing = getThingForCtxActor(actor);
  1778. var sub = jqThing.find(".subreddit:first").text().replace("/r/", "").replace("r/","");
  1779. var selector = "a.subreddit:contains(" + sub + ")";
  1780. var args = [settings.subsToHide, "Subs", sub, selector];
  1781. if (UnhideObject.apply(sender, args)) {
  1782. jq(selector).parents("div.thing").each(function(index, item) {
  1783. jq(item).show();
  1784. });
  1785. AddUndo(HideObject, args, UnhideObject, args, sub);
  1786. }
  1787. };
  1788.  
  1789. fExtAddCtxSeparator(rEnhSub);
  1790.  
  1791. ctxItemKeywHdr = fExtAddCtxItem("Hide Keywords", rEnhSub);
  1792. ctxItemKeywHdr.Action = function(event, sender, actor) {
  1793. var keyword = fExtGetSelection().trim();
  1794. var selector = "a.title:contains(" + keyword + ")";
  1795. var args = [settings.keywordsToHide, "Keywords", keyword, selector];
  1796. if (HideObject.apply(sender, args))
  1797. AddUndo(UnhideObject, args, HideObject, args, keyword);
  1798. };
  1799.  
  1800. ctxItemKeywUnhdr = fExtAddCtxItem("Unhide Keywords", rEnhSub);
  1801. ctxItemKeywUnhdr.Action = function(event, sender, actor) {
  1802. var keyword = fExtGetSelection();
  1803. var selector = "a.title:contains(" + keyword + ")";
  1804. var args = [settings.keywordsToHide, "Keywords", keyword, selector];
  1805. if (UnhideObject.apply(sender, args)) {
  1806. jq(selector).parents("div.thing").each(function(index, item) {
  1807. jq(item).show();
  1808. });
  1809. AddUndo(HideObject, args, UnhideObject, args, keyword);
  1810. }
  1811. };
  1812.  
  1813. fExtAddCtxSeparator(rEnhSub);
  1814.  
  1815. // Undo/Redo
  1816. ctxUndo = fExtAddSub("Undo", rEnhSub);
  1817. ctxRedo = fExtAddSub("Redo", rEnhSub);
  1818.  
  1819. fExtAddCtxSeparator(rEnhSub);
  1820.  
  1821. ctxItemCpyHtml = fExtAddCtxItem("Copy HTML", rEnhSub);
  1822. ctxItemCpyHtml.Action = function(event, sender, actor) {
  1823. fExtClipboard("Copy", jq('div.content').html());
  1824. };
  1825.  
  1826. fExtAddCtxSeparator(rEnhSub);
  1827.  
  1828. ctxItemSett = fExtAddCtxItem("REnhancer Settings", rEnhSub);
  1829. ctxItemSett.Action = function() { ShowSettings(); };
  1830. }
  1831.  
  1832. function InitializeEventHandlers() {
  1833. jq("#fExtMessage").click(function() { reloadCancelled = true; });
  1834. jq("#hideAll").click(HideAllClick);
  1835. jq("#hideSelected").click(HideSelectedClick);
  1836. jq("#expander").click(function(e) {
  1837. e.preventDefault();
  1838. if(jq("#expander").hasClass("expanded"))
  1839. ExpandAndNext(jq("div.expando-button.expanded:visible"), 0);
  1840. else
  1841. ExpandAndNext(jq("div.expando-button.collapsed:visible"), 0);
  1842. return false;
  1843. });
  1844. jq("#renhSettingsSave").click(SaveSettingsDialog);
  1845. jq("#upvoter").click(function(e) {
  1846. e.preventDefault();
  1847. VoteAndNext(jq(this), upVoteLinks, 0);
  1848. return false;
  1849. });
  1850. jq("#downvoter").click(function(e) {
  1851. e.preventDefault();
  1852. VoteAndNext(jq(this), downVoteLinks, 0);
  1853. return false;
  1854. });
  1855. jq("#renhSettingsClose").click(function(e) {
  1856. jq("#rEnhSettings").hide();
  1857. return false;
  1858. });
  1859.  
  1860. jq("ul.flat-list.buttons>li:not(.report-button)").click(function(e){
  1861. if(e.target.tagName !== "A" && e.target.tagName !== "FORM") {
  1862. var targetItem = jq(e.target).find("a").first().get(0);
  1863. if(targetItem) targetItem.click(e);
  1864. else return true;
  1865. }
  1866. else return true;
  1867. });
  1868. }
  1869.  
  1870. function handleHideClick(e){
  1871. var jqThing;
  1872. if (e.data)
  1873. jqThing = jq("#" + e.data.thingID);
  1874. else
  1875. jqThing = jq(this).parents("div.thing:first");
  1876.  
  1877. var args = [jqThing, false, true];
  1878. AddUndo(Unhide, args, Hide, args, jqThing.find("p.title").text());
  1879.  
  1880. Hide(jqThing, undefined, true);
  1881. }
  1882.  
  1883. function ActionWhenElementIsInvisible(element, action, args, step) {
  1884. if (element.hasClass("hidden") || element.find("a[text=hidden]").length === 1 || step === 3)
  1885. action.apply(element, args);
  1886. else {
  1887. if(isNaN(step))
  1888. step = 0;
  1889.  
  1890. step++;
  1891.  
  1892. setTimeout(function() {
  1893. ActionWhenElementIsInvisible(element, action, args, step);
  1894. }, settings.hideItemTimeout);
  1895. }
  1896. }
  1897.  
  1898. // Functions - Load and Save
  1899. function GMLoadValue(valueName) {
  1900. var ret = GM_getValue(valueName);
  1901. if (ret !== undefined)
  1902. return ret.toString().split(",");
  1903.  
  1904. return [];
  1905. }
  1906.  
  1907. function GMSave() {
  1908. GM_setValue("settings", JSON.stringify(settings));
  1909. }
  1910.  
  1911. function GMLoad() {
  1912. settings = { // Defaults
  1913. accountName: "enter your account name here, e.g. throwaway001",
  1914. markNSFW: true,
  1915. replaceTopNew: false,
  1916. sortByVotes: false,
  1917. autoExpandSelectedPost: true,
  1918. removeDuplicates: true,
  1919. maximumNumberOfSitesToLoad: 1,
  1920.  
  1921. animationItemTimeout: 500,
  1922. imagePreloadingTimeout: 250,
  1923. hideItemTimeout: 750,
  1924.  
  1925. hideUsers: true,
  1926. hideUsersNSFWonly: true,
  1927. usersToHide: undefined,
  1928.  
  1929. hideSubs: true,
  1930. subsToHide: undefined,
  1931.  
  1932. hideKeywords: true,
  1933. keywordsToHide: undefined,
  1934.  
  1935. shortcuts: {
  1936. nextPost: 98,
  1937. previousPost: 104,
  1938. toggleSelected: 101,
  1939. hideSelected: 99,
  1940.  
  1941. hideAll: 97,
  1942.  
  1943. voteUp: 105,
  1944. voteDown: 103,
  1945.  
  1946. nextImage: 102,
  1947. previousImage: 100,
  1948. zoomIn: 107,
  1949. zoomOut: 109,
  1950. rotateLeft: 111,
  1951. rotateRight: 106,
  1952.  
  1953. undoLast: -1,
  1954. redoLast: -1,
  1955. },
  1956.  
  1957. panelView: false,
  1958. };
  1959.  
  1960. var lSettings = GM_getValue("settings");
  1961. if (lSettings !== undefined) {
  1962. settingsFromLoad(settings, JSON.parse(lSettings.toString()));
  1963. }
  1964.  
  1965. if (!settings.usersToHide)
  1966. settings.usersToHide = GMLoadValue("usersToHide");
  1967. if (!settings.subsToHide)
  1968. settings.subsToHide = GMLoadValue("subsToHide");
  1969. if (!settings.keywordsToHide)
  1970. settings.keywordsToHide = GMLoadValue("keywordsToHide");
  1971. }
  1972.  
  1973. function settingsFromLoad(setSettings, getSettings){
  1974. for (var k in getSettings) {
  1975. var varType = typeof getSettings[k];
  1976. var varTypeB = typeof setSettings[k];
  1977. switch (varType) {
  1978. case "boolean":
  1979. setSettings[k] = Boolean(getSettings[k]);
  1980. break;
  1981. case "number":
  1982. setSettings[k] = parseInt(getSettings[k]);
  1983. break;
  1984. case "object":
  1985. if(Array.isArray(getSettings[k]))
  1986. setSettings[k] = getSettings[k];
  1987. else
  1988. settingsFromLoad(setSettings[k], getSettings[k]);
  1989. break;
  1990. case "string":
  1991. default:
  1992. setSettings[k] = getSettings[k];
  1993. break;
  1994. }
  1995. }
  1996. }
  1997.  
  1998. // Functions - Misc
  1999. function getThingForCtxActor(actor){
  2000. return jq(actor).hasClass("thing") ? jq(actor) : jq(actor).parents("div.thing:first");
  2001. }
  2002.  
  2003. function grabExtension(src) {
  2004. var start, end;
  2005.  
  2006. start = src.lastIndexOf(".") + 1;
  2007. if (src.lastIndexOf("?") >= 0)
  2008. end = src.lastIndexOf("?");
  2009. else
  2010. end = src.length;
  2011.  
  2012. return src.substring(start, end);
  2013. }
  2014.  
  2015. function colorObject(r, g, b, a){
  2016. var rv = {
  2017. red: 0,
  2018. blue: 0,
  2019. green: 0,
  2020. alpha: 100
  2021. };
  2022.  
  2023. if(r)
  2024. rv.red = parseInt(r);
  2025. if(g)
  2026. rv.green = parseInt(g);
  2027. if(b)
  2028. rv.blue = parseInt(b);
  2029. if(a)
  2030. rv.alpha = parseInt(a);
  2031.  
  2032. rv.getRgba = function(){
  2033. return "rgba(" + this.red + "," + this.green + "," + this.blue + ", " + (this.alpha / 100) + ")";
  2034. };
  2035. rv.getHex = function(){
  2036. var strR = this.red.toString(16);
  2037. var strG = this.blue.toString(16);
  2038. var strB = this.green.toString(16);
  2039. if(strR.length === 1) strR = "0" + strR;
  2040. if(strG.length === 1) strG = "0" + strG;
  2041. if(strB.length === 1) strB = "0" + strB;
  2042.  
  2043. return "#" + strR + strG + strB;
  2044. };
  2045.  
  2046. return rv;
  2047. }
  2048.  
  2049. function getRandomColor() {
  2050. var color = '#';
  2051.  
  2052. // Neu rgb-style
  2053. var min = 155, max = 255;
  2054. var cO = colorObject(Math.random() * (max - min) + min, Math.random() * (max - min) + min, Math.random() * (max - min) + min);
  2055.  
  2056. if(cO.red > cO.green && cO.red > cO.blue)
  2057. color = getRandomColor();
  2058. else
  2059. color = cO.getHex();
  2060.  
  2061. return color;
  2062. }
  2063. // Functions - End