V2EXcellent.js

A Better V2EX

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey, το Greasemonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Userscripts για να εγκαταστήσετε αυτόν τον κώδικα.

You will need to install an extension such as Tampermonkey to install this script.

Θα χρειαστεί να εγκαταστήσετε μια επέκταση διαχείρισης κώδικα χρήστη για να εγκαταστήσετε αυτόν τον κώδικα.

(Έχω ήδη έναν διαχειριστή κώδικα χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(Έχω ήδη έναν διαχειριστή στυλ χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

// ==UserScript==
// @name           V2EXcellent.js
// @namespace      http://vitovan.github.io/v2excellent.js/
// @version        1.1.11
// @description    A Better V2EX
// @author         VitoVan
// @include        http*://*v2ex.com/*
// @require https://cdnjs.cloudflare.com/ajax/libs/markdown-it/8.4.2/markdown-it.min.js
// @grant          none
// ==/UserScript==

$('document').ready(function() {
  window.loaded = true;
});

var POST_PROCESS_FUNCS = [
  function done() {
    console.log('V2EXcellented!');
  },
];

//Fix night mode
var divWrapper = document.getElementById("Wrapper");
if(divWrapper.className == 'Night'){
    divWrapper.style.backgroundColor ='#00000000';
    divWrapper.style.backgroundImage ="url('/static/img/shadow.png'), url('//static.v2ex.com/bgs/pixels.png')";
}

// markdown-it 初始化
var md = window.markdownit({
    html: true,
    linkify: true,
    breaks: true,
    langPrefix: "hljs ",
    highlight: function (str, lang) {
    if (lang && hljs.getLanguage(lang)) {
      try {
        return hljs.highlight(lang, str).value;
      } catch (__) { }
    }
    return ''; // use external default escaping
  }
});

// 图片链接自动转换成图片 代码来自caoyue@v2ex
POST_PROCESS_FUNCS.push(function linksToImgs() {
  var links = document.links;
  for (var x in links) {
    var link = links[x];
    if (
      /^http.*\.(?:jpg|jpeg|jpe|bmp|png|gif)/i.test(link.href) &&
      !/<img\s/i.test(link.innerHTML)
    ) {
      link.innerHTML =
        "<img title='" + link.href + "' src='" + link.href + "' style='max-width:100%' />";
    }
  }
});


// 回复内容做markdown渲染
POST_PROCESS_FUNCS.push(function mdRender() {
   $(".reply_content").each(function(index, item) {
       var replyContent = $(item).html();
       replyContent = replyContent.replace(/<br\s*\/?>/gi,"\r\n");
       $(item).html(md.render(replyContent));
   });
});

function postProcess() {
  $(POST_PROCESS_FUNCS).each(function(i, f) {
    if (typeof f === 'function') {
      f();
      console.log('V2EXcellent Post Processing: ' + f.name);
    }
  });
}

var language = (
  window.navigator.userLanguage || window.navigator.language
).toLowerCase();

var currentLocation = location.href;
//If this is the thread page
if (currentLocation.match(/\/t\/\d+/g)) {
  //Enable Reply Directly Feature
  $('div.topic_buttons').append(
    ' &nbsp;<a " href="#;" onclick="$(\'#reply_content\').focus();" class="tb">回复</a>',
  );
  //Enable Img Uploader Feature
  enableUploadImg();
  var comments = [];
  //loading
  showSpinner();
  //Get comments from current page
  fillComments($('body'));
  //Get other pages comments
  var CURRENT_PAGE_URLS = [];
  $('a[href].page_normal').each(function(i, o) {
    if (CURRENT_PAGE_URLS.indexOf(o.href) === -1) {
      CURRENT_PAGE_URLS.push(o.href);
    }
  });
  var LEFT_PAGES_COUNT = CURRENT_PAGE_URLS.length;
  var CURRENT_PAGE = 0;
  var DOMS = [$(document)];
  if (LEFT_PAGES_COUNT > 0) {
    $(CURRENT_PAGE_URLS).each(function(i, o) {
      $.get(o, function(result) {
        var resultDom = $('<output>').append($.parseHTML(result));
        DOMS.push(resultDom);
        fillComments(resultDom);
        // 替换收藏的链接
        var collectUrl = resultDom
          .find('.topic_buttons .tb:contains("收藏")')
          .attr('href');
        $('.topic_buttons .tb:contains("收藏")').attr('href', collectUrl);
        CURRENT_PAGE++;
        //if all comments are sucked.
        if (CURRENT_PAGE === LEFT_PAGES_COUNT) {
          //stack'em
          stackComments();
          //reArrange
          reArrangeComments();
          // post process functions
          postProcess();
        }
      });
    });
  } else {
    stackComments();
    //reArrange
    reArrangeComments();
    // post process functions
    postProcess();
  }
  // Clear Default Pager
  $('a[href^="?p="]')
    .parents('div.cell')
    .remove();
} else if (currentLocation.match(/\/new/)) {
  $(
    '<a href="https://imgur.com/upload" target="_blank" style="padding:0 5px;">上传图片</a>',
  ).insertAfter($('button[onclick="previewTopic();"]'));
}

function jumpToReply() {
  var floorSpecArr = currentLocation.match(/#reply\d+/g);
  var floorSpec = floorSpecArr && floorSpecArr.length ? floorSpecArr[0] : false;
  if (floorSpec) {
    floorSpec = floorSpec.match(/\d+/g)[0];
    var specFloor = $('span.no').filter(function() {
      return $(this).text() === floorSpec;
    });
    var scrollFunc = function() {
      window.scrollTo(0, specFloor.offset().top - $('body').offset().top);
    };
    if (window.loaded) {
      scrollFunc();
    } else {
      window.onload = function() {
        setTimeout(function() {
          scrollFunc();
        }, 1);
      };
    }
  }
}

//Remove #reply42 from index
$('span.item_title>a').attr('href', function(i, val) {
  return val.replace(/#reply\d+/g, '');
});

function fillComments(jqDom) {
  jqDom.find('div[id^="r_"]').each(function(i, o) {
    var cmno = parseInt(
      $(o)
        .find('span.no')
        .text(),
    );
    comments[cmno] = {
      id: $(o).attr('id'),
      no: cmno,
      user: $(o)
        .find('strong>a')
        .text(),
      content: $(o)
        .find('div.reply_content')
        .text(),
      mentioned: (function() {
        var mentionedNames = [];
        $(o)
          .find('div.reply_content>a[href^="/member/"]:not("dark")')
          .each(function(i, o) {
            mentionedNames.push(o.innerHTML);
          });
        return mentionedNames;
      })(),
      subComments: [],
    };
  });
}

//Enable Floor Specification Feature
$('a[href="#;"]:has(img[alt="Reply"])').click(function(e) {
  var floorNo = $(e.currentTarget)
    .parent()
    .find('span.no')
    .text();
  replyContent = $('#reply_content');
  oldContent = replyContent.val().replace(/^#\d+ /g, '');
  postfix = ' ' + '#' + floorNo + ' ';
  newContent = '';
  if (oldContent.length > 0) {
    if (oldContent != postfix) {
      newContent = oldContent + postfix;
    }
  } else {
    newContent = postfix;
  }
  replyContent.focus();
  replyContent.val(newContent);
  moveEnd($('#reply_content'));
});

//Enable Gift ClickOnce Feature
$('a[href="/mission/daily"]')
  .attr('id', 'gift_v2excellent')
  .attr('href', '#')
  .click(function() {
    $('#gift_v2excellent').text('正在领取......');
    $.get('/mission/daily', function(result) {
      var giftLink = $('<output>')
        .append($.parseHTML(result))
        .find('input[value^="领取"]')
        .attr('onclick')
        .match(/\/mission\/daily\/redeem\?once=\d+/g)[0];
      $.get(giftLink, function(checkResult) {
        var okSign = $('<output>')
          .append($.parseHTML(checkResult))
          .find('li.fa.fa-ok-sign');
        if (okSign.length > 0) {
          $.get('/balance', function(result) {
            var amount = $('<output>')
              .append($.parseHTML(result))
              .find('table>tbody>tr:contains("每日登录"):first>td:nth(2)')
              .text();
            $('#gift_v2excellent').html(
              '已领取 <strong>' + amount + '</strong> 铜币。',
            );
            setTimeout(function() {
              $('#Rightbar>.sep20:nth(1)').remove();
              $('#Rightbar>.box:nth(1)').remove();
            }, 2000);
          });
        }
      });
    });
    return false;
  });

//Get comment's parent
function findParentComment(comment) {
  var parent;
  if (comment) {
    var floorRegex = comment.content.match(/#\d+ /g);
    if (floorRegex && floorRegex.length > 0) {
      var floorNo = parseInt(floorRegex[0].match(/\d+/g)[0]);
      parent = comments[floorNo];
    } else {
      for (var i = comment.no - 1; i > 0; i--) {
        var cc = comments[i];
        if (cc) {
          if (
            $.inArray(cc.user, comment.mentioned) !== -1 &&
            parent === undefined
          ) {
            parent = cc;
          }
          //If they have conversation, then make them together.
          if (
            comment.mentioned.length > 0 &&
            cc.user === comment.mentioned[0] &&
            cc.mentioned[0] === comment.user
          ) {
            parent = cc;
            break;
          }
        }
      }
    }
  }
  return parent;
}

//Stack comments, make it a tree
function stackComments() {
  for (var i = comments.length - 1; i > 0; i--) {
    var parent = findParentComment(comments[i]);
    if (parent) {
      parent.subComments.unshift(comments[i]);
      comments.splice(i, 1);
    }
  }
}

function getCommentDom(id) {
  var commentDom;
  $.each(DOMS, function(i, o) {
    var result = o.find('div[id="' + id + '"]');
    if (result.length > 0) {
      commentDom = result;
    }
  });
  return commentDom;
}

function moveComment(comment, parent) {
  if (comment) {
    var commentDom = getCommentDom(comment.id);
    $.each(comment.subComments, function(i, o) {
      moveComment(o, commentDom);
    });
    commentDom.appendTo(parent);
  }
}

function getCommentBox() {
  var commentBox = $('#Main>div.box:nth(1)');
  if (commentBox.length === 0) {
    // Maybe using mobile
    commentBox = $('#Wrapper>div.content>div.box:nth(1)');
    if ($('#v2excellent-mobile-tip').length === 0) {
      $(
        '<div class="cell" id="v2excellent-mobile-tip" style="background: #CC0000;font-weight: bold;text-align: center;"><span><a style="color:white;text-decoration:underline;" target="_blank" href="https://github.com/VitoVan/v2excellent.js/issues/7#issuecomment-304674654">About V2EXcellent.js on Mobile</a></span></div>',
      ).insertBefore('#Wrapper>div.content>div.box:nth(1)>.cell:first');
    }
  }
  return commentBox;
}

function showSpinner() {
  var commentBox = getCommentBox();
  $('body').append(
    '<style>.spinner{width:40px;height:40px;position:relative;margin:100px auto}.double-bounce1,.double-bounce2{width:100%;height:100%;border-radius:50%;background-color:#333;opacity:.6;position:absolute;top:0;left:0;-webkit-animation:sk-bounce 2.0s infinite ease-in-out;animation:sk-bounce 2.0s infinite ease-in-out}.double-bounce2{-webkit-animation-delay:-1.0s;animation-delay:-1.0s}@-webkit-keyframes sk-bounce{0%,100%{-webkit-transform:scale(0.0)}50%{-webkit-transform:scale(1.0)}}@keyframes sk-bounce{0%,100%{transform:scale(0.0);-webkit-transform:scale(0.0)}50%{transform:scale(1.0);-webkit-transform:scale(1.0)}}</style>',
  );
  $(
    '<div class="spinner"><div class="double-bounce1"></div><div class="double-bounce2"></div></div>',
  ).insertBefore(commentBox);
  commentBox.hide();
}

function reArrangeComments() {
  $('div.inner:has(a[href^="/t/"].page_normal)').remove();
  var commentBox = getCommentBox();
  $.each(comments, function(i, o) {
    moveComment(o, commentBox);
  });
  $('div[id^="r_"]>table>tbody>tr>td:first-child').attr('width', '20');
  $('td img.avatar').css('width', '');
  $('body').append(
    '<style>.cell{background-color: inherit;}.cell .cell{padding-bottom:0;border-bottom:none;min-width: 250px;padding-right:0;}div[id^="r_"] img.avatar{width:20px;height:20px;border-radius:50%;}div[id^="r_"]>div{margin-left: 5px;}</style>',
  );
  commentBox.show();
  //removeSpinner
  $('.spinner').remove();
  jumpToReply();
}

function enableUploadImg() {
  $('div.cell:contains("添加一条新回复")').append(
    '<div class="fr"><a href="https://imgur.com/upload" target="_blank"> 上传图片</a> - </div>',
  );
}