A Better V2EX
// ==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( ' <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(r###lt) { var r###ltDom = $('<output>').append($.parseHTML(r###lt)); DOMS.push(r###ltDom); fillComments(r###ltDom); // 替换收藏的链接 var collectUrl = r###ltDom .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(r###lt) { var giftLink = $('<output>') .append($.parseHTML(r###lt)) .find('input[value^="#取"]') .attr('onclick') .match(/\/mission\/daily\/redeem\?once=\d+/g)[0]; $.get(giftLink, function(checkR###lt) { var okSign = $('<output>') .append($.parseHTML(checkR###lt)) .find('li.fa.fa-ok-sign'); if (okSign.length > 0) { $.get('/balance', function(r###lt) { var amount = $('<output>') .append($.parseHTML(r###lt)) .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 r###lt = o.find('div[id="' + id + '"]'); if (r###lt.length > 0) { commentDom = r###lt; } }); 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>', ); }