[UPDATED] Reddit - Top Comments Preview (old & new design)

Preview to the top comments on Reddit (+ optional auto-load comments and images, auto-hide sidebar)

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください。
// ==UserScript==
// @name           [UPDATED] Reddit - Top Comments Preview (old & new design)
// @namespace      https://greasyfork.org/users/1007060-humzakh
// @author         jesuis-parapluie > humzakh
// @version        3.03
// @description    Preview to the top comments on Reddit (+ optional auto-load comments and images, auto-hide sidebar)
// @homepageURL    https://github.com/humzakh/userscripts/tree/master/Reddit%20-%20Top%20Comments%20Preview
// @require        https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js
// @include        /^https?:\/\/(.+\.)?reddit\.com\/?.*$/
// @exclude        /^https?:\/\/(.+\.)?reddit\.com\/r\/.*\/comments\/.*$/
// @grant          GM_getValue
// @grant          GM_setValue
// ==/UserScript==
(function ($) {
  "use strict";
  /*jshint validthis: true */
  /*jslint browser: true, regexp: true, newcap: true */
  /*global $, jQuery, GM_getValue, GM_setValue, MutationObserver */
  var options = {
      /* Number of comments to display */
      topComments: 3,
      /* Sortings available: top, best, new, hot, controversial, old */
      commentSorting: "top",
      /* Show comments at the top of items */
      commentsAtTop: false,
      /* Don't show (pinned) comments from following users */
      skipCommentsFrom: ["AutoModerator", "WholesomeBot", "PoliticalHumorBot", "SavageAxeBot", "movieDetailsModBot", "WritingPromptsRobot"],
      /* Disable sidebar button in menu bar */
      disableSidebarButton: false,
      /* Disable autoload buttons in menu bar */
      disableAutoloadButton: false,
      /* Disable RES keyboard shortcut 't' to show/hide comments */
      disableShortCut: false
    },
    helper = {
      prefix: {
        item: "item-",
        id: "toplink-",
        box: "commentpreview-"
      },
      layout: {
        prefix: "layoutSwitch--",
        0: "card",
        1: "classic",
        2: "compact",
        active: ""
      },
      findLayout: function () {
        var i, j, colors = [],
          counts = {};

        for (i = 0; i <= 2; i += 1) {
          colors.push($("#" + helper.layout.prefix + helper.layout[i]).find("svg").css("fill"));
        }

        $.each(colors, function (value) {
          if (!counts.hasOwnProperty(value)) {
            counts[value] = 1;
          } else {
            counts[value] += 1;
          }
        });

        for (j in counts) {
          if (counts[j] === 1) {
            for (i = 0; i <= 2; i += 1) {
              if (colors[i] === j) {
                helper.layout.active = helper.layout[i];
                break;
              }
            }
          }
        }
      },
      toggleView: function (className) {
        (function (style) {
          style.display = style.display === "none" ? "" : "none";
        }(document.querySelector(className).style));
      }
    },
    design = {
      active: "new",
      new: {
        style: [
          ".aubox a.disabled{color:#995F5F;font-weight:400} .aubox a.enabled{color:#009D2D;font-weight:400} a#sidebarswitch{cursor:pointer}",
          "div.topbar{padding: 0 10px 0 10px;} div.topbar span{padding: 0 0 0 5px;} div.commentbox hr { border-color: #777; opacity: 0.2; }",
          "div.commentbox{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;border-radius:5px;border:1px solid;white-space:normal;padding:5px;margin:8px 0}",
          "div.commentbox .md{border:1px solid rgb(120,120,120,0.4);-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;margin:3px 0;box-sizing:border-box;padding:2px 8px}",
          ".loaderror:before{content:' loading failed ';color:red} .loading:before{content:'Loading...'} .loading{color:rgb(79, 188, 255)} .res-nightmode .loaderror:before{content:' loading failed ';color:#E63A3A}",
          "div.commentbox .md *{white-space:normal} div.commentbox .md code{white-space:pre} div.commentbox .md pre{overflow:visible} div.commentbox>*{font-size:small}",
          "div.commentbox .ulink,div.commentbox .md a{font-weight:700} .listing-page .buttons li{vertical-align:top} .toplink{color:#FF4500!important;text-decoration:none;height: 14px; padding: 0 4px 0 4px;}",
          ".permalink{float:right;color:#666;margin-left:.5em} .points{font-weight:700;margin-left:.5em}"
        ].join(""),
        items_selector: ".scrollerItem",
        menubar_element: "<div>",
        menubar_parent: $("#view--layout--FUE").parent(),
        expando_button: ".icon-expandoArrowExpand",
        comment_link: "a[data-click-id=comments]"

      },
      old: {
        style: [
          ".aubox a.disabled{color:#995F5F;font-weight:400} .aubox a.enabled{color:#009D2D;font-weight:400} a#sidebarswitch{cursor:pointer}",
          "div.commentbox{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;background:#fff;border-radius:5px;border:1px solid #dbdbdb;white-space:normal;padding:5px;display:inline-block;margin:8px 0}",
          "div.commentbox .md{border:1px solid #ddd;background:#f0f0f0;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;margin:3px 0;box-sizing:border-box;padding:2px 8px}",
          ".loaderror:before{content:\" loading failed \";color:red} .loading:before{content:\"Loading...\"} .res-nightmode .loaderror:before{content:\" loading failed \";color:#E63A3A}",
          "div.commentbox .md *{white-space:normal} div.commentbox .md code{white-space:pre} div.commentbox .md pre{overflow:visible} div.commentbox>*{font-size:small}",
          "div.commentbox .ulink,div.commentbox .md a{font-weight:700;color:#369!important} .listing-page .buttons li{vertical-align:top} .toplink{color:#FF4500!important;text-decoration:none;margin-left:10px!important;}",
          ".permalink{float:right;color:#666;margin-left:.5em} .points{color:#333;font-weight:700;margin-left:.5em}",
          ".res-nightmode div.commentbox pre,.res-nightmode div.commentbox code,.res-nightmode .link .md pre{border:1px solid #222!important;background:#282828!important;background-color:#282828!important}",
          ".res-nightmode div.commentbox .ulink,.res-nightmode div.commentbox .md a{color:#1496dc!important} .res-nightmode div.commentbox{background:#333!important;border-color:#666!important}",
          ".res-nightmode div.commentbox .md{background:#555!important;border-color:#222!important} .res-nightmode .toplink{color:#eee!important}",
          ".res-nightmode div.commentbox .points{color:#ddd!important} .res-nightmode div.commentbox .permalink{color:#ccc!important}",
          ".res-nightmode div.commentbox .md blockquote, .res-nightmode div.commentbox .md del{color:#8C8C8C!important} .res-nightmode div.commentbox hr{border-color:#777!important};}",
          ".res-nightmode div.commentbox hr{border-color:#777!important;}"
        ].join(""),
        items_selector: "div.entry",
        menubar_element: "<li>",
        menubar_parent: $(".tabmenu"),
        expando_button: ".res-show-images a",
        comment_link: "a:contains(comments)"
      }
    },
    addStyle = function () {
      var style = $("<style>", {
        type: "text/css",
        html: design[design.active].style
      });
      $("head").append(style);
    },
    retrieveTopComments = function (toplink) {
      var id = $(toplink).attr("id").replace(new RegExp("^" + helper.prefix.id), ""),
        item = $("#" + helper.prefix.item + id),
        comment_box = $("#" + helper.prefix.box + id),
        url = "//" + document.domain + "/comments/" + id + "/.json";

      if (comment_box.length === 0) {
        comment_box = $("<div>", {
          "class": "commentbox loading",
          "id": helper.prefix.box + id
        });

        if (options.commentsAtTop) {
          if (design.active === "new") {
            if (helper.layout.active === "card") {
              item.children().last().children().first().next().after(comment_box);
            } else if (helper.layout.active === "classic") {
              item.children().last().children().first().after(comment_box);
            } else {
              item.first().children().first().after(comment_box);
            }
          } else {
            item.find(".top-matter").after(comment_box);
          }
        } else {
          item.append(comment_box);
        }
      }
      if (comment_box.hasClass("loading")) {
        $.get(url, {
            limit: options.topComments + 5, // + 5 in case we delete some pinned comments
            sort: options.commentSorting
          }, function (data) {
            var i, newHTML = "",
              comments_count = data[1].data.children.length,
              threadLink = data[0].data.children[0].data.permalink,
              comments_max = options.topComments < comments_count ? options.topComments : comments_count;
            if (comments_count === 0) {
              comment_box.remove();
            } else if (comment_box !== null && comment_box.hasClass("loading")) {
              comment_box.html("");
              for (i = 0; i < comments_max; i += 1) {
                if (options.skipCommentsFrom.indexOf(data[1].data.children[i].data.author) !== -1) {
                  comments_max += 1;
                } else {
                  newHTML += (newHTML === "" ? "" : "<hr>");

                  newHTML += $("<a>", {
                    class: "ulink",
                    target: "_blank",
                    href: "/u/" + data[1].data.children[i].data.author,
                    html: data[1].data.children[i].data.author
                  })[0].outerHTML;

                  newHTML += $("<span>", {
                    class: "points",
                    html: "| score: " + data[1].data.children[i].data.score
                  })[0].outerHTML;

                  newHTML += $("<a>", {
                    class: "permalink",
                    target: "_blank",
                    href: threadLink + data[1].data.children[i].data.id,
                    html: "permalink"
                  })[0].outerHTML;
                  newHTML += "<br />" + $($.parseHTML(data[1].data.children[i].data.body_html)).text();
                }
              }
              comment_box.removeClass("loading");
              comment_box.html(newHTML);
            }
          })
          .fail(function () {
            var retries = 0;
            if (comment_box.data("retries") !== undefined) {
              retries = parseInt(comment_box.data("retries"), 10);
            }
            comment_box.data("retries", retries + 1);
            if (retries > 5) {
              comment_box.removeClass("loading");
              comment_box.addClass("loaderror");
              comment_box.data("retries", 0);
            } else {
              setTimeout(retrieveTopComments(toplink), 2000);
            }
          }, "json");
      } else {
        comment_box.remove();
      }
    },
    addTopLinks = function (items) {
      var java = "java";
      if (items === undefined) {
        return;
      }
      items.each(function () {
        var id_index, comment_id, toplink,
          comment_link = $(this).find(design[design.active].comment_link);
        if (comment_link.length === 0) {
          console.log("No link found for following Item:");
          console.log(this);
          return;
        }
        id_index = comment_link.attr("href").indexOf("/comments/");
        comment_id = comment_link.attr("href").substring(id_index + 10).split("/")[0];
        $(this).attr("id", helper.prefix.item + comment_id);
        toplink = $("<a>", {
          "class": "toplink",
          "id": helper.prefix.id + comment_id,
          "href": java + "script:;",
          "html": options.commentSorting
        }).click(function () {
          retrieveTopComments(this);
        });
        comment_link.after(toplink);
        if (GM_getValue("autoLoadComments", false)) {
          retrieveTopComments(toplink);
        }
      });
    };
  $(function () {
    var sidebar, loadbar, spanImages, spanComments,
      sidebar_view = "hide",
      buttonStatus = "disabled";

    design.active = $(".scrollerItem").length > 0 ? "new" : "old";

    addStyle();

    if (design.active === "new") {
      helper.findLayout();
    }

    addTopLinks($(design[design.active].items_selector));

    // Menu button show/hide sidebar
    if (!options.disableSidebarButton && document.location.pathname.indexOf("/comments/") === -1) {
      if (design.active === "new") {
        $('div a[href="/submit"]').last().parent().parent().parent().addClass("side");
      }

      if (GM_getValue("sideBarToggle", true)) {
        sidebar_view = "show";
        helper.toggleView(".side");
      }

      sidebar = $(design[design.active].menubar_element, {
        html: $("<a>", {
          id: "sidebarswitch",
          html: sidebar_view + " sidebar"
        })
      }).click(function () {
        GM_setValue("sideBarToggle", !GM_getValue("sideBarToggle", true));
        sidebar_view = "hide";
        if (GM_getValue("sideBarToggle", true)) {
          sidebar_view = "show";
        }
        $(this).find("a").html(sidebar_view + " sidebar");
        helper.toggleView(".side");
      });

      design[design.active].menubar_parent.append(sidebar);
    } else {
      GM_setValue("sideBarToggle", false);
    }

    // Menu button auto-load media and comments
    if (!options.disableAutoloadButton && document.location.pathname.indexOf("/comments/") === -1) {
      loadbar = $(design[design.active].menubar_element, {
        class: "aubox topbar",
        html: $("<a>", {
          html: "show"
        })
      });
      if ($("#RESConsoleVersion").length > 0) {
        if (GM_getValue("autoExpandMedia", false)) {
          buttonStatus = "enabled";
        }
        spanImages = $("<span>", {
          html: $("<a>", {
            href: "#",
            class: buttonStatus,
            html: "media"
          })
        }).click(function () {
          GM_setValue("autoExpandMedia", !GM_getValue("autoExpandMedia", false));
          location.reload();
        });
        loadbar.append(spanImages);
      }

      buttonStatus = "disabled";
      if (GM_getValue("autoLoadComments", false)) {
        buttonStatus = "enabled";
      }
      spanComments = $("<span>", {
        html: $("<a>", {
          href: "#",
          class: buttonStatus,
          html: "comments"
        })
      }).click(function () {
        GM_setValue("autoLoadComments", !GM_getValue("autoLoadComments", false));
        location.reload();
      });

      loadbar.append(spanComments);
      design[design.active].menubar_parent.append(loadbar);
    } else if (options.disableAutoloadButton) {
      GM_setValue("autoExpandMedia", false);
      GM_setValue("autoLoadComments", false);
    }

    // Get style from other menu button for new design
    if (design.active === "new") {
      $("#view--layout--FUE").children().each(function () {
        if ($(this).text() === "View") {
          this.classList.forEach(function (cl) {
            if (!/.+-.+/.test(cl)) {
              loadbar.addClass(cl);
              sidebar.addClass(cl);
            }
          });
        }
      });
    }

    // Auto expand images etc
    if (GM_getValue("autoExpandMedia", false)) {
      if (design.active === "new") {
        $(design[design.active].expando_button).click();
      } else {
        document.querySelector(design[design.active].expando_button).click();
      }
    }

    // Listener for layout change
    if (design.active === "new") {
      $("[id^=" + helper.layout.prefix + "]").click(function () {
        setTimeout(function () {
          helper.findLayout();
          addTopLinks($(design[design.active].items_selector));
        }, 100);
      });
    }

    // Listener for newly added items
    $("body").change(function (changes) {
      $.each(changes, function (i, l) {
        var item = $(l.addedNodes).find(design[design.active].items_selector);
        if (item.length > 0) {
          addTopLinks(item);
        }
      });
    });

    // Listener for key 't' to toggle comments
    if (!options.disableShortCut && $("#RESConsoleVersion").length > 0) {
      $("window").keyup(function (e) {
        if (e.keyCode === 84 && $(".RES-keyNav-activeElement").length > 0) { //T: keycode 84
          $(".RES-keyNav-activeElement .toplink").click();
        }
      });
    }
  });

  // A minimal jQuery library for reacting to innerHTML changes - https://jsfiddle.net/ecmanaut/jRbEz
  $.fn.change = function (cb, e) {
    e = e || {
      subtree: true,
      childList: true,
      characterData: true
    };
    $(this).each(function () {
      var node = this;

      function callback(changes) {
        cb.call(node, changes, this);
      }
      (new MutationObserver(callback)).observe(node, e);
    });
  };
}(jQuery));