Greasy Fork is available in English.

Trim Reddit

Trimmer for Reddit

// ==UserScript==
// @name          Trim Reddit
// @namespace     stgeorge
// @description   Trimmer for Reddit
// @require       http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js
// @match         *://old.reddit.com/*
// @match         *://www.reddit.com/*
// @grant         GM.xmlHttpRequest
// @grant         GM.getValue
// @grant         GM.setValue
// @grant         GM.deleteValue
// @version       3.14
// @license       MIT
// @run-at        document-end
// ==/UserScript==

(() => {
  let side = null;

  let DONT_MATCH = [
    /\/r\/\w+\/comments\//,
    /\/login/,
    /\/over18/,
  ];

  // Add a 'new' link to to the header.
  const OPT_NEW_LINKS = true;

  // Delete Automoderator comments.
  const OPT_NO_AUTOMODERATOR = true;

  const IMG_LINKS = $([
    'imgur.com',
    'i.imgur.com',
    'preview.redd.it',
    'youtube.com'
  ]);

  const CSS = 
    $(`<style id="trimreddit">
      .selected .choice {
        color: red !important;
      }
      .choice {
        color: black !important;
      }
      #search {
        text-align: center;
        padding: 5px;
        position: revert !important;
        margin-top: 0 !important;
        width: 80% !important;
        transform:none !important;
      }
      #search input {
        max-width: revert !important;
        min-width: revert !important;
        position: revert !important;
        margin: 0 !important;
      }
      #search input[type="submit"] {
        margin-left: 5px !important;
      }
      .tabmenu {
        margin: 10px 0 10px 0;
        position: revert !important;
        border: solid 1px black;
        padding: 5px;
      }
      .tabmenu li a {
        font-weight: normal !important;
        background-color: white !important;
        color: black !important;
      }
      #body-wrapper {
        display: flex;
        background: white;
        height: calc(100vh - 50px);
      }
      #sr-header-area {
        visibility: visible !important;
        top: 0 !important;
        position: revert !important;
        background-image: none !important;
      }
      #header {
        height: revert !important;
        min-height: 0 !important;
        position: sticky !important;
        font-size: 0.7rem;
        background: white !important;
        color: black !important;
        border-bottom: solid 1px black !important;
        padding: 0 !important;
        margin: 0 !important;
        z-index: 999 !important;
      }
      #header * {
        background-color: #fefefe !important;
        color: black !important;
      }
      #newr,#lgn {
        color: red !important;
      }
      #header::before {
        position: revert !important;
      }
      #header::after {
        position: revert !important;
        height: revert !important;
      }
      .thing {
        background-color:white !important;
        border: revert !important;
        border-bottom: solid 1px #ddd !important;
        border-radius: revert !important;
        box-shadow: revert !important;
      }
      .thing .title {
        color: revert !important;
        overflow: visible !important;
        padding-left: 0 !important;
      }
      .domain {
        display: table !important;
      }
      .link {
        margin: 0 !important;
        padding: 0px !important;
      }
      .link .thumbnail {
        margin-left: 5px !important;
        display: none !important;
      }
      .search-result-link .thumbnail {
        margin-left: 5px !important;
        display: none !important;
      }
      .link * {
        padding: 3px 2px 0px 5px !important;
        /* margin-right: revert !important; */
      }
      .link .rank,.title::before,.midcol {
        display: none !important;
      }
      .link.linkflair::after, .link.promoted::after {
        content: revert !important;
      }
      .linkflairlabel {
        cursor: pointer;
      }
      .title .linkflairlabel {
        display: none !important;
        position:revert !important;
      }
      .side * .thumbnail {
        display: none !important;
      }
      .entry {
        margin-left: 2px !important;
        overflow: visible !important;
      }
      body {
        padding-top: 0 !important;
        margin-left: 0 !important;
      }
      body div.content {
        margin: 5px !important;
      }
      .sitetable {
        border-bottom: 0 !important;
        border-left: 0 !important;
        border-right:solid 1px #eeeeff !important;
        margin-right: revert !important;
      }
      .linklisting.sitetable {
        margin-right: 0 !important;
      }
      .listing-page #siteTable {
        margin-right: 0;
      }
      #siteTable::before {
        padding: 0 !important;
        margin: 5px 0 5px 0 !important;
        content: '' !important;
        height: 0 !important;
        width: 0 important;
        border: none !important;
      }
      .thing .tagline .curuser {
        color: red !important;
        background-color: white !important;
        font-weight: bold !important;
      }
      .side {
        margin: 0 !important;
        z-index: 100 !important;
        background: url('') !important;
        background-color: transparent !important;
        box-shadow: revert !important;
        width:100% !important;
        overflow-y:auto !important;
        padding-top: 15px !important;
        border-left: solid 1px black !important;
      }
      .side::before {
        content: revert !important;
        background: revert !important;
      }
      .side:after {
        content: '';
      }
      .side * {
        font-size: 16px !important;
        text-align: left !important;
      }
      .side a {
        background-color: revert !important;
      }
      a.title {
        background: url('') !important;
      }
      .side .usertext p {
        background-color: revert !important;
        color: black !important;
        padding: 0 !important;
      }
      p:first-child,p:nth-child(2),p:nth-child(3) {
        border: none !important;
      }
      .side .md p {
        border-bottom: 0 !important;
      }
      .side .md h3, .side .md h2 {
        display: none !important;
      }
      .side .md p::before {
        border-right: 0 !important;
      }
      .side .md blockquote {
        position: relative !important;
      }
      .side .commentarea {
        margin-right: revert !important;
      }
      .awardings-bar {
        position: revert !important;
      }
      .sidemenu {
        padding:2px 2px 5px 5px;
        margin:2px;
        background-color:#eee;
        z-index:999;
      }
      .sidemenu-button {
        font-weight:bold;
        cursor:pointer;
      }
      .expando {
        position: revert !important;
      }
      .expando-button {
        display: none !important;
      }
      .md {
        background: white !important;
      }
      div.md>blockquote>p {
        position: inherit !important;
      }
      .md p::before {
        width:0 !important;
      }
      .content:before {
        background-color: revert !important;
        background-image: revert !important;
        height:0px !important;
      }
      .clicked {
        background-color: #f8fefe !important;
        border: solid 1px black !important;
        border-radius:10px;
      }
      .ui-resizable-e { 
        cursor: e-resize; 
        width: 2px; 
        right: -1px; 
        top: 0; 
        bottom: 0; 
        background-color: blue !important;
      }
      #popup {
        position: fixed;
        top: 0;
        left:0;
        background:rgba(0,0,0,0.75);
        width:100%;
        height:100%;
        display:none;
      }
      .searchpane,.search-result-group-header {
        display:none !important;
      }
      .search-result-listing {
        margin: revert !important;
      }
      .search-result-group {
        max-width: 100% !important;
        min-width: 100% !important;
        padding-left: 5px !important;
        padding-right: 5px !important;
      }
      .disabled {
        cursor:not-allowed;
      }
      .hide {
        display:none !important;
      }
      .menuarea,a[name="content"] {
        visibility:hidden;
        display:none;
      }
      .media-preview, .media-preview img.preview {
        display: block !important;
        visibility: visible !important;
      }
    </style>`);

  const CLASSIC_BUTTONS_CSS = 
    $(`<style>
      .classic-button {
        border:none !important;
        padding:8px !important;
        border-radius:9999px !important;
        color:white !important;
        background-color:#0045ac !important;
        font-weight:bold !important;
      }
    </style>`);

  function trim() {
    appendStyles();
    let tabmenu = $('.tabmenu').detach();
    $('.infobar').remove();
    $('.footer-parent').remove();
    $('#sr-header-area').siblings().remove();
    let content = $('.content[role="main"]');

    content.css({
      width:'35%',
      // height: '1000px',
      'overflow-y': 'auto',
      resize:'horizontal',
      margin: '0',
    });

    //
    // We make the right-hand side sidebar (.side) bigger and empty its
    // contents. Then, we make the main pane (.content) thinner and
    // use it show the list of articles. (We mark it as resizable horizontally
    // so that it can be widened.) When an article is clicked on in
    // the .content pane, we show its threaded comments in the .side pane.
    //
    // +----------------------------------------------------+
    // |                      #header                       |
    // +----------------------------------------------------+
    // |                #body-wrapper (new)                 |
    // | +-------------+----------------------------------+ |
    // | |  .content   |             .side                | |
    // | |+-----------+|                                  | |
    // | ||  tabmenu  ||                                  | |
    // | |+-----------+|                                  | |
    // | ||  #search  ||        Post and comments         | |
    // | |+-----------+|                                  | |
    // | || Post list ||                                  | |
    // | ||  ...      ||                                  | |
    // | |+-----------+|                                  | |
    // | +-------------+----------------------------------+ |
    // +----------------------------------------------------+
    //
    if (document.URL.indexOf('old.reddit.com') != -1) {
      $('body').css({'overflow-y':'hidden'});
    }
    let wrapper = $('<div id="body-wrapper"></div>');
    $('#header').after(wrapper);
    wrapper.append(content);
    let search = $('#search').detach();
    content.prepend(search);
    search.find('label').detach();
    let subs = /r\/(\w+)\//i.exec(top.location.href);
    if (subs && subs.length > 1) 
      $('#search').children('input[name="q"]').first().val('subreddit:'+subs[1]+' ');
    content.prepend(tabmenu);
    side = $('.side');
    side.empty();
    wrapper.append(side);

    $('.linkflairlabel').each(function(k,v) {
      let t = $(this);
      t.on('click', function(e) {
        let url = document.URL.replace('old','www');
        let m = url.match(/(.*\/r\/.*?)\//);
        let flair = t.children('span:first').text();
        if (flair) {
          top.location.href = m[1] +
            '?f=flair_name%3A%22'+encodeURIComponent(flair)+'%22';
        }
      });
    });

    let curbg = 'white';
    let first = null;
    retargetLinks($('.entry').add('.search-result'));
!!
    $('a.thumbnail').each(function(k,v) {
      let a = $(this);
      let href = a.attr('href');
      if (isImage(href)) {
        retarget(a);
      }
    });
    $('.entry a').add('.search-result a').add('a.title').each(function(k,v) {
      let t = $(this).closest('.thing');
      if (t.length == 0)
        t = $(this).closest('.search-result');
      let a = $(this);
      let title = a.text();
      let href = a.attr('href');
      if (href.indexOf('i.redd.it') != -1) {
        // Try to open inline images locally.
        href = t.find('a.comments').first().attr('href');
        if (href == null)
          href = t.find('a.bylink').first().attr('href');
      }
      if ((href != null) && (href.indexOf('/comments/') != -1)) {
        a.on('click', function(e) {
          e.preventDefault();
          e.stopPropagation();
          t.css({'background-color':'#ffeeee'});
          t.addClass('clicked');
          t.siblings().css({'background-color':curbg});
          t.siblings().removeClass('clicked');
          href = href.replace('www.reddit.com', 'old.reddit.com').
            replace('//reddit.com', '//www.reddit.com');
          (async () => {await GM.setValue('lastseen', href)})();
          loadComment(href+'?sort=new');
        });
        if (first === null && !t.hasClass('stickied')) {
          first = a;
        }
      }
    });
    (async() => {
      let last_seen = await GM.getValue('lastseen', null);
      GM.deleteValue('lastseen');
      let l = null;
      if (last_seen) {
        l = $('a[href="'+last_seen+'"]');
      }
      let to_show = (l && l.length > 0) ? l : first;
      if (to_show) {
        to_show.click();
      }
    })();
  }

  function appendStyles() {
    CSS.appendTo('head');
  }

  function appendClassicButtonStyles() {
    CLASSIC_BUTTONS_CSS.appendTo('head');
  }

  function isImage(href) {
    is_image = false;
    if (href) {
      IMG_LINKS.each(function(x,y) {
        if (href.indexOf('/'+y+'/') != -1) {
          is_image = true;
          return false;
        }
      });
    }
    return is_image;
  }

  function canRetarget(href) {
    do_retarget = false;
    if (href) {
      do_retarget =
        (href.startsWith('http://') || href.startsWith('https://'))
        && (
          (href.indexOf('.reddit.com/') == -1)
          || (
            (href.indexOf('/comments/') == -1)
            && ((href.indexOf('/user/') != -1) || (href.indexOf('/r/') != -1))
          )
        );
    }
    return do_retarget;
  }

  function retargetLinks(div) {
    div.find('a').each(function(k,v) {
      let anchor = $(this);
      let href = anchor.attr('href');
      let is_image = isImage(href);
      // Replace gallery link with the corr. comment link.
      if (href && (is_image || href.indexOf('.reddit.com/gallery/') != -1)) {
        let comment_anchor = anchor.closest('.top-matter').find('a.comments').first();
        href = comment_anchor.attr('href');
        anchor.attr('href', href);
      }
      if (is_image || canRetarget(href)) {
        retarget(anchor);
      }
    });
  }

  function retarget(link) {
    link.attr('rel','noopener');
    link.attr('target','_new');
  }

  function toggleComments(expand) {
    $('.commentarea').find('.comment').each(function(k,v) {
      let cur = $(v);
      let p = cur.parents('.comment');
      if (p.length == 0) {
        let children = cur.find('.comment');
        if (expand) {
          children.removeClass('collapsed').addClass('noncollapsed');
        } else {
          children.addClass('collapsed').removeClass('noncollapsed');
        }
        cur.removeClass('collapsed').addClass('noncollapsed');
      }
    });
  }
  
  function loadComment(u) {
    GM.xmlHttpRequest({
      method: "GET",
      url: u+'?sort=new',
      onload: function(response) {
        side.html($.parseHTML(response.responseText));
        let c = side.find('.content[role="main"]').detach();
        side.empty();
        side.append(`
          <div class="sidemenu">
            <span class="sidemenu-button" title="Expand/collapse lower levels" id="toggleall">[+/-]</span>
            <span style="margin-left:1em" title="Next entry by author" class="hide sidemenu-button" id="fnext">[&#9660;]</span>
            <span class="hide sidemenu-button" title="Previous entry by author" id="fprev">[&#9650;]</span>
            </div>
          </div>
        `);
        side.append(c);
        c.css({margin:'10px'});
        side.find('.infobar').detach();
        side.find('.top-matter').detach();
        // Remove Automoderator comments.
        if (OPT_NO_AUTOMODERATOR)
          side.find('.moderator').closest('.entry').detach();
        let toggle_expand = false;
        $('#toggleall').on('click', function(e) {
          e.preventDefault();
          e.stopPropagation();
          toggleComments(toggle_expand);
          toggle_expand = !toggle_expand;
        });
        retargetLinks(side);
        let all = [];
        let all_index = -1;
        let url = document.URL.replace(/\?.*/, '');
        side.find('a.author').each(function(k,v) {
          let a = $(this);
          if (a.attr('href') == top.location.href) {
            a.addClass('curuser');
            all.push(a);
          }
        });

        if (all.length > 0) {
          $('#fnext,#fprev').removeClass('hide');
          $('#fnext').on('click', function(e) {
            e.preventDefault();
            e.stopPropagation();
            if (++all_index >= all.length)
              all_index = 0;
            scrollTo(side, all[all_index]);
          });
          $('#fprev').on('click', function(e) {
            e.preventDefault();
            e.stopPropagation();
            if (--all_index < 0)
              all_index = all.length - 1;
            scrollTo(side, all[all_index]);
          });
        }
        setTimeout(function() {
          $(document).scrollTop(0);
          side.scrollTop(0);
          $('#toggleall').click();
        }, 500);
      }
    });
  }

  function enable(x, v) {
    if (v) {
      $(x).removeClass('disabled');
    } else {
      $(x).addClass('disabled');
    }
  }

  function scrollTo(p, el) {
    if (!el) return;
    setTimeout(function() {
      p.animate({
        scrollTop: el.offset().top - p.offset().top + p.scrollTop() - 50
      }, 1000);
    }, 500);
  }

  function fixHeader() {
    //
    // If OPT_NEW_LINKS is set, we add a 'new' link to to the header
    // to toggle between old and new reddits and a 'login' link.
    if (OPT_NEW_LINKS) {
      let bars = $('#sr-bar');
      let i = 0;
      bars.find('li').each(function(k,v) {
        if (i++ == 1) {
          let li = $(this);
          bars.prepend(addLink(li, 'newr', 'new',
            top.location.href.replace('old','www'), 'New Reddit'));
          bars.prepend(addLink(li, 'lgn', 'login',
            top.location.href.replace(/\.com\/.*/, '.com/login'), 'Login'));
          return false;
        }
      });
    }
  }

  function addLink(template, new_id, new_text, new_url, new_title) {
    let x = template.clone(true);
    let span = x.find('span').first();
    let a = x.find('a').first();
    a.text(new_text);
    a.attr('id', new_id);
    a.attr('href', new_url);
    a.attr('title', new_title);
    span.before(a);
    return x;
  }

  function trimClassicReddit() {
    addClassicButtons();
  }

  function toggleSidebars() {
    $('.sidebar-grid').toggleClass('grid');
    $('.left-sidebar-min').toggle();
    $('reddit-sidebar-nav').toggle();
    $('.right-sidebar').toggle();
  }

  function addClassicButtons() {
    //
    // Add a button to switch to old reddit.
    //
    appendClassicButtonStyles();
    let x = $('#get-app');

    // Ugh!
    x.before($('<button id="old-button" class="classic-button justify-center flex items-center button" type="button">Old</button>'));
    x.remove();
    let old_button = $('#old-button');
    old_button.closest('faceplate-tracker').next('span').text('Old (Classic) Reddit');

    let button_parent = old_button.closest('span.contents');
    let sidebar_toggle = button_parent.clone();
    sidebar_toggle.find('#old-button').replaceWith(
      $('<button id="sidebar-button" class="classic-button justify-center flex items-center button" type="button">Sidebars</button>')
    );
    button_parent.before(sidebar_toggle);
    $('#sidebar-button').closest('faceplate-tracker').next('span').text('Toggle sidebars');

    old_button.on('click', function() {
      top.location.hostname = 'old.reddit.com';
    });
    $('#sidebar-button').on('click', function(e) {
      e.preventDefault();
      e.stopPropagation();
      toggleSidebars();
    });
  }

  // Main.
  setTimeout(function() {
    if (document.URL.indexOf('www.reddit.com') != -1) {
      // NEW REDDIT.
      trimClassicReddit();
      $('div[data-adclicklocation="title"] a').each(function(k,v) {
        let a = $(this);
        a.on('click', function() {
          window.open(a.attr('href'), '_blank');
          return false;
        });
      });
    } else {
      // OLD REDDIT.
      let do_trim = true;
      $(DONT_MATCH).each(function(k,v) {
        if (document.URL.match(v)) {
          do_trim = false;
          return false;
        }
      });
      if (do_trim) {
        trim();
        fixHeader();
      }
    }
  }, 1000);

})();