V2EXcellent.js

A Better V2EX

目前为 2017-05-29 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name V2EXcellent.js
  3. // @namespace http://vitovan.github.io/v2excellent.js/
  4. // @version 1.1.1
  5. // @description A Better V2EX
  6. // @author VitoVan
  7. // @include http*://*v2ex.com/*
  8. // @grant none
  9. // ==/UserScript==
  10.  
  11. var currentLocation = location.href;
  12. //If this is the thread page
  13. if (currentLocation.match(/\/t\/\d+/g)) {
  14. //Enable Reply Directly Feature
  15. $('div.topic_buttons').append('<a " href="#;" onclick="$(\'#reply_content\').focus();" class="tb">回复</a>');
  16. //Enable Img Uploader Feature
  17. enableUploadImg();
  18. var comments = [];
  19. //loading
  20. showSpinner();
  21. //Get comments from current page
  22. fillComments($('body'));
  23. //Get other pages comments
  24. var CURRENT_PAGE_URLS = [];
  25. $('a[href].page_normal').each(function (i, o) {
  26. if (CURRENT_PAGE_URLS.indexOf(o.href) === -1) {
  27. CURRENT_PAGE_URLS.push(o.href);
  28. }
  29. });
  30. var LEFT_PAGES_COUNT = CURRENT_PAGE_URLS.length;
  31. var CURRENT_PAGE = 0;
  32. var DOMS = [$(document)];
  33. if (LEFT_PAGES_COUNT>0) {
  34. $(CURRENT_PAGE_URLS).each(function(i,o) {
  35. $.get(o,function(result) {
  36. var resultDom = $('<output>').append($.parseHTML(result));
  37. DOMS.push(resultDom);
  38. fillComments(resultDom);
  39. CURRENT_PAGE ++;
  40. //if all comments are sucked.
  41. if (CURRENT_PAGE === LEFT_PAGES_COUNT) {
  42. //stack'em
  43. stackComments();
  44. //reArrange
  45. reArrangeComments();
  46. }
  47. });
  48. });
  49. }else{
  50. stackComments();
  51. //reArrange
  52. reArrangeComments();
  53. }
  54. // Clear Default Pager
  55. $('a[href^="?p="]').parents('div.cell').remove();
  56. }else if (currentLocation.match(/\/new/)) {
  57. $('<a href="https://imgur.com/upload" target="_blank" style="padding:0 5px;">上传图片</a>')
  58. .insertAfter($('button[onclick="previewTopic();"]'))
  59. }
  60.  
  61. function jumpToReply () {
  62. var floorSpecArr = currentLocation.match(/#reply\d+/g);
  63. var floorSpec = floorSpecArr && floorSpecArr.length ? floorSpecArr[0] : false;
  64. if (floorSpec) {
  65. floorSpec = floorSpec.match(/\d+/g)[0];
  66. var specFloor = $('span.no').filter(function () {return $(this).text() === floorSpec;});
  67. $('body').scrollTop(specFloor.offset().top - $('body').offset().top);
  68. }
  69. }
  70.  
  71. //Remove #reply42 from index
  72. $('span.item_title>a').attr("href",function (i,val) {return val.replace(/#reply\d+/g,'');});
  73.  
  74. function fillComments (jqDom) {
  75. jqDom.find('div[id^="r_"]').each(function (i,o) {
  76. var cmno = parseInt($(o).find('span.no').text());
  77. comments[cmno] =
  78. {
  79. id: $(o).attr('id'),
  80. no: cmno,
  81. user: $(o).find('strong>a').text(),
  82. content: $(o).find('div.reply_content').text(),
  83. mentioned: (function () {
  84. var mentionedNames = [];
  85. $(o)
  86. .find('div.reply_content>a[href^="/member/"]:not("dark")')
  87. .each(function (i,o) {
  88. mentionedNames.push(o.innerHTML);
  89. });
  90. return mentionedNames;
  91. }()),
  92. subComments: []
  93. };
  94. });
  95. }
  96.  
  97. //Enable Floor Specification Feature
  98. $('a[href="#;"]:has(img[alt="Reply"])').click(function (e) {
  99. var floorNo = $(e.currentTarget).parent().find('span.no').text();
  100. replyContent = $("#reply_content");
  101. oldContent = replyContent.val().replace(/^#\d+ /g,'');
  102. postfix = " " + "#" + floorNo + " ";
  103. newContent = ''
  104. if (oldContent.length > 0) {
  105. if (oldContent != postfix) {
  106. newContent = oldContent + postfix;
  107. }
  108. } else {
  109. newContent = postfix;
  110. }
  111. replyContent.focus();
  112. replyContent.val(newContent);
  113. moveEnd($("#reply_content"));
  114. });
  115.  
  116. //Enable Gift ClickOnce Feature
  117. $('a[href="/mission/daily"]').attr('id','gift_v2excellent').attr('href','#').click(function () {
  118. $('#gift_v2excellent').text('正在领取......');
  119. $.get('/mission/daily',function (result) {
  120. var giftLink = $('<output>')
  121. .append($.parseHTML(result))
  122. .find('input[value^="领取"]')
  123. .attr('onclick').match(/\/mission\/daily\/redeem\?once=\d+/g)[0];
  124. $.get(giftLink,function (checkResult) {
  125. var okSign = $('<output>').append($.parseHTML(checkResult)).find('li.fa.fa-ok-sign');
  126. if (okSign.length>0) {
  127. $.get('/balance',function (result) {
  128. var amount = $('<output>').append($.parseHTML(result)).find('table>tbody>tr:contains("每日登录"):first>td:nth(2)').text();
  129. $('#gift_v2excellent').html('已领取 <strong>' + amount + '</strong> 铜币。' );
  130. setTimeout(function () {
  131. $('#Rightbar>.sep20:nth(1)').remove();
  132. $('#Rightbar>.box:nth(1)').remove();
  133. },2000);
  134. });
  135. }
  136. });
  137. });
  138. return false;
  139. });
  140.  
  141. //Get comment's parent
  142. function findParentComment (comment) {
  143. var parent = undefined;
  144. if (comment) {
  145. var floorRegex = comment.content.match(/#\d+ /g);
  146. if (floorRegex && floorRegex.length>0) {
  147. var floorNo = parseInt(floorRegex[0].match(/\d+/g)[0]);
  148. parent = comments[floorNo];
  149. }else{
  150. for(var i=comment.no-1;i>0;i--) {
  151. var cc = comments[i];
  152. if (cc) {
  153. if ($.inArray(cc.user, comment.mentioned) !== -1 && parent === undefined) {
  154. parent = cc;
  155. }
  156. //If they have conversation, then make them together.
  157. if (comment.mentioned.length>0 && cc.user === comment.mentioned[0] && cc.mentioned[0] === comment.user) {
  158. parent = cc;
  159. break;
  160. }
  161. }
  162. }
  163. }
  164. }
  165. return parent;
  166. }
  167.  
  168. //Stack comments, make it a tree
  169. function stackComments () {
  170. for(var i=comments.length-1;i>0;i--) {
  171. var parent = findParentComment(comments[i]);
  172. if (parent) {
  173. parent.subComments.unshift(comments[i]);
  174. comments.splice(i,1);
  175. }
  176. }
  177. }
  178.  
  179. function getCommentDom (id) {
  180. var commentDom = undefined;
  181. $.each(DOMS,function (i,o) {
  182. var result = o.find('div[id="' + id + '"]');
  183. if (result.length>0) {
  184. commentDom = result;
  185. }
  186. });
  187. return commentDom;
  188. }
  189.  
  190. function moveComment (comment,parent) {
  191. if (comment) {
  192. var commentDom = getCommentDom(comment.id);
  193. $.each(comment.subComments,function (i,o) {
  194. moveComment(o,commentDom);
  195. });
  196. commentDom.appendTo(parent);
  197. }
  198. }
  199.  
  200. function getCommentBox () {
  201. var commentBox = $('#Main>div.box:nth(1)');
  202. if (commentBox.length === 0) { // Maybe using mobile
  203. commentBox = $('#Wrapper>div.content>div.box:nth(1)');
  204. if ($('#v2excellent-mobile-tip').length === 0) {
  205. $('<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">About V2EXcellent.js on Mobile</a></span></div>').insertBefore('#Wrapper>div.content>div.box:nth(1)>.cell:first');
  206. }
  207. }
  208. return commentBox;
  209. };
  210.  
  211. function showSpinner () {
  212. var commentBox = getCommentBox();
  213. $('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>');
  214. $('<div class="spinner"><div class="double-bounce1"></div><div class="double-bounce2"></div></div>').insertBefore(commentBox);
  215. commentBox.hide();
  216. }
  217.  
  218. function reArrangeComments () {
  219. $('div.inner:has(a[href^="/t/"].page_normal)').remove();
  220. var commentBox = getCommentBox();
  221. $.each(comments,function (i,o) {
  222. moveComment(o,commentBox);
  223. });
  224. $('div[id^="r_"]>table>tbody>tr>td:first-child').attr('width','20');
  225. $('body').append('<style>.cell{background-color: inherit;}.cell .cell{border-bottom:none;min-width: 250px;}div[id^="r_"] img.avatar{width:20px;height:20px;border-radius:50%;}div[id^="r_"]>div{margin-left: 5px;}</style>');
  226. commentBox.show();
  227. //removeSpinner
  228. $('.spinner').remove();
  229. jumpToReply();
  230. }
  231.  
  232. function enableUploadImg () {
  233. $('div.cell:contains("添加一条新回复")').append('<div class="fr"><a href="https://imgur.com/upload" target="_blank"> 上传图片</a> - </div>');
  234. }