Decreased Productivity Plus

Makes webpages more discreet

  1. // ==UserScript==
  2. // @name Decreased Productivity Plus
  3. // @icon http://i.imgur.com/ffgP58A.png
  4. // @namespace skoshy.com
  5. // @version 0.9.15
  6. // @description Makes webpages more discreet
  7. // @author Stefan Koshy
  8. // @match *://*/*
  9. // @match http*://*.messenger.com/*
  10. // @match http*://*.slack.com/messages/*
  11. // @match http*://mail.google.com/mail/*
  12. // @match http*://hangouts.google.com/webchat/*
  13. // @grant GM_getValue
  14. // @grant GM_setValue
  15. // ==/UserScript==
  16.  
  17. var DEBUG_MODE = false;
  18. var SCRIPT_ID = 'dpplus';
  19. var CURRENT_SITE = getCurrentSite();
  20.  
  21. // From https://gist.github.com/arantius/3123124
  22. // These are replacement functions for GreaseMonkey scripts, but the only work on a single domain instead of being cross domain
  23. // Todo: Implement solution that works cross domain
  24.  
  25. if (typeof GM_getValue == 'undefined') {
  26. function GM_getValue(aKey, aDefault) {
  27. 'use strict';
  28. let val = localStorage.getItem(SCRIPT_ID + aKey);
  29. if (null === val && 'undefined' != typeof aDefault) return aDefault;
  30. return val;
  31. }
  32. }
  33.  
  34. if (typeof GM_setValue == 'undefined') {
  35. function GM_setValue(aKey, aVal) {
  36. 'use strict';
  37. localStorage.setItem(SCRIPT_ID + aKey, aVal);
  38. }
  39. }
  40.  
  41. var css = {};
  42. css.defaults = {};
  43.  
  44. css.defaults.imageOpacity = '.05';
  45. css.defaults.imageOpacityHover = '.4';
  46.  
  47. css.defaults.imageOpacitySmall = '.2';
  48. css.defaults.imageOpacitySmallHover = '.55';
  49.  
  50. css.overrides = {};
  51. css.overrides.disableUnfocusedTransparency = [
  52. 'gmailhangouts'
  53. ];
  54.  
  55. css.common = {};
  56. css.common.css = `
  57. html {
  58. transition: opacity .1s ease-in-out;
  59. }
  60.  
  61. html.unfocused {
  62. opacity: .1;
  63. }
  64.  
  65. html, body, div, p, span, a, table, td {
  66. font-family: Arial, sans-serif !important;
  67. font-size: 13px !important;
  68. font-weight: 400 !important;
  69. color: #222 !important;
  70. background-color: rgba(255, 255, 255, .3) !important;
  71. }
  72.  
  73. img, figure, video
  74. {opacity: {{imageOpacity}};}
  75.  
  76. img:hover, figure:hover, video:hover
  77. {opacity: {{imageOpacityHover}};}
  78.  
  79. `;
  80. css.messenger = {};
  81. css.messenger.css = `
  82. ._1z8r img {font-size: 30px !important; opacity: .2;} /* Reaction images (emoji) in the react popup */
  83.  
  84. ._55lt img, /* Left hand avatars */
  85. ._4ld- div[style]:not([class]), /* Left hand avatars (group icons) */
  86. ._3xn1, /* Link Thumbnails */
  87. ._4tsk, /* Photo Messages */
  88. .img, /* Other images */
  89. [role="img"], /* more images */
  90. ._2pon /* Little blue messenger overlays */
  91. {opacity: {{imageOpacity}};}
  92.  
  93. ._2560, /* Small Emoji */
  94. ._1ifu /* Medium Emoji (32x32) */
  95. { opacity: .2; }
  96.  
  97. ._55lt img:hover,
  98. ._4ld- div[style]:not([class]):hover,
  99. ._3xn1:hover,
  100. ._4tsk:hover,
  101. .img:hover,
  102. [role="img"]:hover,
  103. ._2pon:hover
  104. {opacity: {{imageOpacityHover}};}
  105.  
  106. ._1a-, /* small fb emojis */
  107. .emoticon, /* embedded-in-messages emoji */
  108. ._5qi2 /* medium fb emojis standalone */
  109. {opacity: {{imageOpacitySmall}};}
  110.  
  111. ._1a-:hover,
  112. .emoticon:hover,
  113. ._5qi2:hover,
  114. {opacity: {{imageOpacitySmallHover}};}
  115.  
  116. /* Unread Messages override */
  117. ._1ht3 * { font-weight: bold !important; }
  118.  
  119. ._52mr /* Get rid of messages background */
  120. { background-color: transparent !important; }
  121.  
  122. ._hw2 ._53ij /* "Delete" Message Background Fix */
  123. ,.uiTooltipX .tooltipContent /* Various Tooltips */
  124. {background-color: rgba(0,0,0,.1) !important;}
  125. `;
  126.  
  127. css.slack = {};
  128. css.slack.css = `
  129. #col_channels_bg, #col_channels, #team_menu, #quick_switcher_btn, #team_menu_overlay, #col_channels_overlay {
  130. background: #f9f9f9 !important;
  131. } /* sidebar background */
  132.  
  133. #quick_switcher_btn #quick_switcher_label, #quick_switcher_btn .ts_icon, #quick_switcher_btn #quick_switcher_shortcut, body #team_menu_user_name {
  134. color: #222 !important;
  135. }
  136.  
  137. #team_header_user_name, /* username in sidebar */
  138. body .channels_list_holder ul li .primary_action.im_name > *:not(.unread_highlights) /* Items in sidebar */
  139. {color: black !important;}
  140.  
  141. body #channels_scroller.show_which_channel_is_active ul li.active .primary_action.im_name > *:not(.unread_highlights) /* Selected item in sidebar */
  142. {color: black !important;}
  143.  
  144. #col_channels h2 {
  145. color: black !important;
  146. } /* section headers in sidebar */
  147.  
  148. #channels_scroller.show_which_channel_is_active ul li.active a.channel_name, #channels_scroller.show_which_channel_is_active ul li.active a.group_name, #channels_scroller.show_which_channel_is_active ul li.active a.im_name, #channels_scroller.show_which_channel_is_active ul li.active a.mpim_name, #channels_nav ul li.unread_link.active a {
  149. background: #eee;
  150. } /* highlighted things in slack, like the current tab you're looking at */
  151.  
  152. body:not(.sorting_mode) .channels_list_holder ul li a:hover, #monkey_scroll_wrapper_for_channels_scroller .monkey_scroll_bar,
  153. body:not(.loading) #team_menu:hover, body:not(.loading) #team_menu.active, #quick_switcher_btn:hover, #quick_switcher_btn:active {
  154. background: #ddd;
  155. } /* highlighted things, hovering over them */
  156.  
  157. #channel_scroll_up /* the MORE UNREADS thing that shows up in the chat list when there's unread messages */
  158. {top: 10px;}
  159.  
  160. .ts_tip .ts_tip_multiline_inner, .ts_tip:not(.ts_tip_multiline) .ts_tip_tip /* tooltip, like when mousing over a message reaction */
  161. {background: rgba(0,0,0,.65) !important; border: 1px solid gray; color: white !important;}
  162.  
  163. #msgs_div img, #msgs_div figure, /* most images */
  164. #msgs_div .member_image /* avatars in message panel */
  165. {opacity: {{imageOpacity}};}
  166.  
  167. #msgs_div img:hover, #msgs_div figure:hover,
  168. #msgs_div .member_image:hover
  169. {opacity: {{imageOpacityHover}};}
  170. `;
  171.  
  172. css.gmail = {};
  173. css.gmail.css = `
  174. .wl /*Background color */
  175. { background: white !important; }
  176. .zE /* Unread Email rows */,
  177. .yO /* Read Email Rows */
  178. { background: transparent !important; }
  179. .TI .T-I-ax7, .z0 .T-I-ax7, .G-atb .T-I-ax7 /* Buttons, like the settings button, refresh, labels button, etc */
  180. { background: #ddd !important; }
  181. .ZY /* Header that shows up if you're forwarding any email to a new email address */
  182. {background-color: rgba(255,221,221,.2);}
  183. `;
  184. css.gmailhangouts = {};
  185. css.gmailhangouts.css = `
  186. .TsiDff /* Whole chat box */
  187. {opacity: .2; transition: opacity .1s ease-in-out;}
  188. .TsiDff:hover /* Hover over chat box */
  189. {opacity: 1;}
  190. .Ik /* Chat header */
  191. {background: rgba(0,0,0,.5) !important;}
  192. .uB /* Chat header, new message */
  193. {background: rgba(83, 169, 63,.6) !important; border-bottom-color: rgba(83, 169, 63,.6);}
  194. .GN * /* Chat header text */
  195. {color: white !important;}
  196. div.EV, /* Chat top button bar */
  197. .iN /* Chat background */
  198. {background: rgba(255, 255, 255, .9) !important;}
  199. .Ia .Bb /* Chat list contact */
  200. {transition: background .1s ease-in-out;}
  201. .Ia .Bb:hover, .Ia .Bb:focus /* Chat list contact, hovering */
  202. {background: rgba(35,35,35,.1);}
  203. .Ia .Bb>.R8jgRe>.ng /* Chat list, contact text */
  204. {text-shadow: none;}
  205. `;
  206. css.inbox = {};
  207. css.inbox.css = `
  208. .ss, .qG, .qG * /* Bolded Messages */
  209. { font-weight: bold !important; }
  210. `;
  211. css.none = {};
  212. css.none.css = ``;
  213.  
  214.  
  215. function addGlobalStyle(css, className, enabled, id) {
  216. var head, style;
  217. head = document.getElementsByTagName('head')[0];
  218. if (!head) { return; }
  219. style = document.createElement('style');
  220. style.type = 'text/css';
  221. style.innerHTML = css;
  222. style.id = id;
  223. style.className = className;
  224. head.appendChild(style);
  225. style.disabled = !enabled;
  226. }
  227.  
  228. function getCssStyleElements() {
  229. return document.getElementsByClassName(SCRIPT_ID+'-css');
  230. }
  231.  
  232. function getBgElements() {
  233. return document.querySelectorAll('[style*="url("]');
  234. }
  235.  
  236. function getGradientString() {
  237. return 'linear-gradient(rgba(255, 255, 255, 0.7) 0%, rgba(255, 255, 255, 0.7) 100%), ';
  238. }
  239.  
  240. function enableStyle() {
  241. var cssToInclude = '';
  242. var bgEls = getBgElements();
  243. var gradientString = getGradientString();
  244.  
  245. addGlobalStyle(parseCSS(
  246. css.common.css + css[CURRENT_SITE].css
  247. ), SCRIPT_ID+'-css', true, SCRIPT_ID+'-css');
  248.  
  249. // enable all background image manipulations
  250. for (var i = 0; i < bgEls.length; i++) {
  251. bgEls[i].attributes.origBackgroundImage = bgEls[i].style.backgroundImage;
  252. bgEls[i].style.backgroundImage = gradientString + bgEls[i].style.backgroundImage;
  253. }
  254. }
  255.  
  256. function disableStyle() {
  257. var cssEls = getCssStyleElements();
  258. var bgEls = getBgElements();
  259.  
  260. for (let i = 0; i < cssEls.length; i++) {
  261. cssEls[i].parentNode.removeChild(cssEls[i]); // remove the element
  262. }
  263.  
  264. // disable all background image manipulations
  265. for (var i = 0; i < bgEls.length; i++) {
  266. bgEls[i].style.backgroundImage = bgEls[i].attributes.origBackgroundImage;
  267. }
  268. }
  269.  
  270. function isStyleEnabled() {
  271. var cssEl = document.getElementById(SCRIPT_ID+'-css');
  272.  
  273. return isTruthy(cssEl);
  274. }
  275.  
  276. function parseCSS(parsed) {
  277. for (attribute in css.defaults) {
  278. exceptionToReplace = new RegExp('{{'+attribute+'}}', 'g');
  279. parsed = parsed.replace(exceptionToReplace, css['defaults'][attribute]);
  280. }
  281.  
  282. return parsed;
  283. }
  284.  
  285. document.addEventListener("keydown", function(e) {
  286. if (e.altKey === true && e.shiftKey === false && e.ctrlKey === false && e.metaKey === false && e.code == 'KeyI') {
  287. if (isStyleEnabled()) {
  288. disableStyle();
  289.  
  290. if (CURRENT_SITE != 'none') {GM_setValue( 'enabled_'+CURRENT_SITE , false );}
  291. } else {
  292. enableStyle();
  293.  
  294. if (CURRENT_SITE != 'none') {GM_setValue( 'enabled_'+CURRENT_SITE , true );}
  295. }
  296. }
  297. });
  298.  
  299. function getCurrentSite() {
  300. var url = document.documentURI;
  301. var toReturn = 'none';
  302.  
  303. if (url.indexOf('messenger.com') != -1) toReturn = 'messenger';
  304. if (url.indexOf('slack.com') != -1) toReturn = 'slack';
  305. if (url.indexOf('mail.google.com') != -1) toReturn = 'gmail';
  306. if (url.indexOf('hangouts.google.com/webchat') != -1) toReturn = 'gmailhangouts';
  307. if (url.indexOf('inbox.google.com') != -1) toReturn = 'inbox';
  308.  
  309. return toReturn;
  310. }
  311.  
  312. function init() {
  313. var styleEnabled = GM_getValue( 'enabled_'+CURRENT_SITE , true );
  314. if (CURRENT_SITE == 'none') styleEnabled = false; // don't automatically enable if the site isn't specifically tailored for the script
  315.  
  316. if (styleEnabled) {
  317. enableStyle();
  318. }
  319.  
  320. // unfocus / focus transparency effect
  321. if (css.overrides.disableUnfocusedTransparency.indexOf(CURRENT_SITE) == -1) {
  322. addEvent(window, "mouseout", function(e) {
  323. e = e ? e : window.event;
  324. var from = e.relatedTarget || e.toElement;
  325.  
  326. if (from == null) {
  327. // the cursor has left the building
  328. hideHtml();
  329. } else {
  330. showHtml();
  331. }
  332. });
  333. addEvent(window, "mouseover", function(e) {
  334. e = e ? e : window.event;
  335. var from = e.relatedTarget || e.toElement;
  336.  
  337. if (from != null) {
  338. showHtml();
  339. }
  340. });
  341. }
  342. }
  343.  
  344.  
  345. function hideHtml() {
  346. document.querySelector('html').classList.add('unfocused');
  347. }
  348.  
  349. function showHtml() {
  350. document.querySelector('html').classList.remove('unfocused');
  351. }
  352.  
  353. init();
  354.  
  355. /*
  356. * Utility functions
  357. */
  358.  
  359. function isTruthy(item) {
  360. return !isFalsy(item);
  361. }
  362.  
  363. // from https://gist.github.com/skoshy/69a7951b3070c2e2496d8257e16d7981
  364. function isFalsy(item) {
  365. if (
  366. !item
  367. || (typeof item == "object" && (
  368. Object.keys(item).length == 0 // for empty objects, like {}, []
  369. && !(typeof item.addEventListener == "function") // omit webpage elements
  370. ))
  371. )
  372. return true;
  373. else
  374. return false;
  375. }
  376.  
  377. function addEvent(obj, evt, fn) {
  378. if (obj.addEventListener) {
  379. obj.addEventListener(evt, fn, false);
  380. }
  381. else if (obj.attachEvent) {
  382. obj.attachEvent("on" + evt, fn);
  383. }
  384. }