V2EXcellent.js

A Better V2EX

当前为 2017-08-22 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name V2EXcellent.js
  3. // @namespace http://vitovan.github.io/v2excellent.js/
  4. // @version 1.1.3
  5. // @description A Better V2EX
  6. // @author VitoVan
  7. // @include http*://*v2ex.com/*
  8. // @grant none
  9. // ==/UserScript==
  10.  
  11. var POST_PROCESS_FUNCS = [
  12. function done() {
  13. console.log('V2EXcellented!');
  14. },
  15. ];
  16.  
  17. // 图片链接自动转换成图片 代码来自caoyue@v2ex
  18. POST_PROCESS_FUNCS.push(function linksToImgs() {
  19. var links = document.links;
  20. for (var x in links) {
  21. var link = links[x];
  22. if (
  23. /^http.*\.(?:jpg|jpeg|jpe|bmp|png|gif)/i.test(link.href) &&
  24. !/<img\s/i.test(link.innerHTML)
  25. ) {
  26. link.innerHTML =
  27. "<img title='" + link.href + "' src='" + link.href + "' />";
  28. }
  29. }
  30. });
  31.  
  32. POST_PROCESS_FUNCS.push(function markOp() {
  33. //标记楼主
  34. uid = document
  35. .getElementById('Rightbar')
  36. .getElementsByTagName('a')[0]
  37. .href.split('/member/')[1]; //自己用户名
  38. if (location.href.indexOf('.com/t/') != -1) {
  39. var lzname = document
  40. .getElementById('Main')
  41. .getElementsByClassName('avatar')[0]
  42. .parentNode.href.split('/member/')[1];
  43. allname = '@' + lzname + ' ';
  44. all_elem = document.getElementsByClassName('dark');
  45. for (var i = 0; i < all_elem.length; i++) {
  46. if (all_elem[i].innerHTML == lzname) {
  47. var opWord = language === 'zh_CN' ? '楼主' : 'OP';
  48. all_elem[i].innerHTML += ' <font color=green>[' + opWord + ']</font>';
  49. }
  50. //为回复所有人做准备
  51. if (
  52. uid != all_elem[i].innerHTML &&
  53. all_elem[i].href.indexOf('/member/') != -1 &&
  54. all_elem[i].innerText == all_elem[i].innerHTML &&
  55. allname.indexOf('@' + all_elem[i].innerHTML + ' ') == -1
  56. ) {
  57. allname += '@' + all_elem[i].innerHTML + ' ';
  58. }
  59. }
  60. }
  61. });
  62.  
  63. function postProcess() {
  64. $(POST_PROCESS_FUNCS).each(function(i, f) {
  65. if (typeof f === 'function') {
  66. f();
  67. console.log('V2EXcellent Post Processing: ' + f.name);
  68. }
  69. });
  70. }
  71.  
  72. var language = window.navigator.userLanguage || window.navigator.language;
  73.  
  74. var currentLocation = location.href;
  75. //If this is the thread page
  76. if (currentLocation.match(/\/t\/\d+/g)) {
  77. //Enable Reply Directly Feature
  78. $('div.topic_buttons').append(
  79. '<a " href="#;" onclick="$(\'#reply_content\').focus();" class="tb">回复</a>'
  80. );
  81. //Enable Img Uploader Feature
  82. enableUploadImg();
  83. var comments = [];
  84. //loading
  85. showSpinner();
  86. //Get comments from current page
  87. fillComments($('body'));
  88. //Get other pages comments
  89. var CURRENT_PAGE_URLS = [];
  90. $('a[href].page_normal').each(function(i, o) {
  91. if (CURRENT_PAGE_URLS.indexOf(o.href) === -1) {
  92. CURRENT_PAGE_URLS.push(o.href);
  93. }
  94. });
  95. var LEFT_PAGES_COUNT = CURRENT_PAGE_URLS.length;
  96. var CURRENT_PAGE = 0;
  97. var DOMS = [$(document)];
  98. if (LEFT_PAGES_COUNT > 0) {
  99. $(CURRENT_PAGE_URLS).each(function(i, o) {
  100. $.get(o, function(result) {
  101. var resultDom = $('<output>').append($.parseHTML(result));
  102. DOMS.push(resultDom);
  103. fillComments(resultDom);
  104. CURRENT_PAGE++;
  105. //if all comments are sucked.
  106. if (CURRENT_PAGE === LEFT_PAGES_COUNT) {
  107. //stack'em
  108. stackComments();
  109. //reArrange
  110. reArrangeComments();
  111. // post process functions
  112. postProcess();
  113. }
  114. });
  115. });
  116. } else {
  117. stackComments();
  118. //reArrange
  119. reArrangeComments();
  120. // post process functions
  121. postProcess();
  122. }
  123. // Clear Default Pager
  124. $('a[href^="?p="]').parents('div.cell').remove();
  125. } else if (currentLocation.match(/\/new/)) {
  126. $(
  127. '<a href="https://imgur.com/upload" target="_blank" style="padding:0 5px;">上传图片</a>'
  128. ).insertAfter($('button[onclick="previewTopic();"]'));
  129. }
  130.  
  131. function jumpToReply() {
  132. var floorSpecArr = currentLocation.match(/#reply\d+/g);
  133. var floorSpec = floorSpecArr && floorSpecArr.length ? floorSpecArr[0] : false;
  134. if (floorSpec) {
  135. floorSpec = floorSpec.match(/\d+/g)[0];
  136. var specFloor = $('span.no').filter(function() {
  137. return $(this).text() === floorSpec;
  138. });
  139. $('body').scrollTop(specFloor.offset().top - $('body').offset().top);
  140. }
  141. }
  142.  
  143. //Remove #reply42 from index
  144. $('span.item_title>a').attr('href', function(i, val) {
  145. return val.replace(/#reply\d+/g, '');
  146. });
  147.  
  148. function fillComments(jqDom) {
  149. jqDom.find('div[id^="r_"]').each(function(i, o) {
  150. var cmno = parseInt($(o).find('span.no').text());
  151. comments[cmno] = {
  152. id: $(o).attr('id'),
  153. no: cmno,
  154. user: $(o).find('strong>a').text(),
  155. content: $(o).find('div.reply_content').text(),
  156. mentioned: (function() {
  157. var mentionedNames = [];
  158. $(o)
  159. .find('div.reply_content>a[href^="/member/"]:not("dark")')
  160. .each(function(i, o) {
  161. mentionedNames.push(o.innerHTML);
  162. });
  163. return mentionedNames;
  164. })(),
  165. subComments: [],
  166. };
  167. });
  168. }
  169.  
  170. //Enable Floor Specification Feature
  171. $('a[href="#;"]:has(img[alt="Reply"])').click(function(e) {
  172. var floorNo = $(e.currentTarget).parent().find('span.no').text();
  173. replyContent = $('#reply_content');
  174. oldContent = replyContent.val().replace(/^#\d+ /g, '');
  175. postfix = ' ' + '#' + floorNo + ' ';
  176. newContent = '';
  177. if (oldContent.length > 0) {
  178. if (oldContent != postfix) {
  179. newContent = oldContent + postfix;
  180. }
  181. } else {
  182. newContent = postfix;
  183. }
  184. replyContent.focus();
  185. replyContent.val(newContent);
  186. moveEnd($('#reply_content'));
  187. });
  188.  
  189. //Enable Gift ClickOnce Feature
  190. $('a[href="/mission/daily"]')
  191. .attr('id', 'gift_v2excellent')
  192. .attr('href', '#')
  193. .click(function() {
  194. $('#gift_v2excellent').text('正在领取......');
  195. $.get('/mission/daily', function(result) {
  196. var giftLink = $('<output>')
  197. .append($.parseHTML(result))
  198. .find('input[value^="领取"]')
  199. .attr('onclick')
  200. .match(/\/mission\/daily\/redeem\?once=\d+/g)[0];
  201. $.get(giftLink, function(checkResult) {
  202. var okSign = $('<output>')
  203. .append($.parseHTML(checkResult))
  204. .find('li.fa.fa-ok-sign');
  205. if (okSign.length > 0) {
  206. $.get('/balance', function(result) {
  207. var amount = $('<output>')
  208. .append($.parseHTML(result))
  209. .find('table>tbody>tr:contains("每日登录(不可用)"):first>td:nth(2)')
  210. .text();
  211. $('#gift_v2excellent').html(
  212. '已领取 <strong>' + amount + '</strong> 铜币。'
  213. );
  214. setTimeout(function() {
  215. $('#Rightbar>.sep20:nth(1)').remove();
  216. $('#Rightbar>.box:nth(1)').remove();
  217. }, 2000);
  218. });
  219. }
  220. });
  221. });
  222. return false;
  223. });
  224.  
  225. //Get comment's parent
  226. function findParentComment(comment) {
  227. var parent;
  228. if (comment) {
  229. var floorRegex = comment.content.match(/#\d+ /g);
  230. if (floorRegex && floorRegex.length > 0) {
  231. var floorNo = parseInt(floorRegex[0].match(/\d+/g)[0]);
  232. parent = comments[floorNo];
  233. } else {
  234. for (var i = comment.no - 1; i > 0; i--) {
  235. var cc = comments[i];
  236. if (cc) {
  237. if (
  238. $.inArray(cc.user, comment.mentioned) !== -1 &&
  239. parent === undefined
  240. ) {
  241. parent = cc;
  242. }
  243. //If they have conversation, then make them together.
  244. if (
  245. comment.mentioned.length > 0 &&
  246. cc.user === comment.mentioned[0] &&
  247. cc.mentioned[0] === comment.user
  248. ) {
  249. parent = cc;
  250. break;
  251. }
  252. }
  253. }
  254. }
  255. }
  256. return parent;
  257. }
  258.  
  259. //Stack comments, make it a tree
  260. function stackComments() {
  261. for (var i = comments.length - 1; i > 0; i--) {
  262. var parent = findParentComment(comments[i]);
  263. if (parent) {
  264. parent.subComments.unshift(comments[i]);
  265. comments.splice(i, 1);
  266. }
  267. }
  268. }
  269.  
  270. function getCommentDom(id) {
  271. var commentDom;
  272. $.each(DOMS, function(i, o) {
  273. var result = o.find('div[id="' + id + '"]');
  274. if (result.length > 0) {
  275. commentDom = result;
  276. }
  277. });
  278. return commentDom;
  279. }
  280.  
  281. function moveComment(comment, parent) {
  282. if (comment) {
  283. var commentDom = getCommentDom(comment.id);
  284. $.each(comment.subComments, function(i, o) {
  285. moveComment(o, commentDom);
  286. });
  287. commentDom.appendTo(parent);
  288. }
  289. }
  290.  
  291. function getCommentBox() {
  292. var commentBox = $('#Main>div.box:nth(1)');
  293. if (commentBox.length === 0) {
  294. // Maybe using mobile
  295. commentBox = $('#Wrapper>div.content>div.box:nth(1)');
  296. if ($('#v2excellent-mobile-tip').length === 0) {
  297. $(
  298. '<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>'
  299. ).insertBefore('#Wrapper>div.content>div.box:nth(1)>.cell:first');
  300. }
  301. }
  302. return commentBox;
  303. }
  304.  
  305. function showSpinner() {
  306. var commentBox = getCommentBox();
  307. $('body').append(
  308. '<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>'
  309. );
  310. $(
  311. '<div class="spinner"><div class="double-bounce1"></div><div class="double-bounce2"></div></div>'
  312. ).insertBefore(commentBox);
  313. commentBox.hide();
  314. }
  315.  
  316. function reArrangeComments() {
  317. $('div.inner:has(a[href^="/t/"].page_normal)').remove();
  318. var commentBox = getCommentBox();
  319. $.each(comments, function(i, o) {
  320. moveComment(o, commentBox);
  321. });
  322. $('div[id^="r_"]>table>tbody>tr>td:first-child').attr('width', '20');
  323. $('body').append(
  324. '<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>'
  325. );
  326. commentBox.show();
  327. //removeSpinner
  328. $('.spinner').remove();
  329. jumpToReply();
  330. }
  331.  
  332. function enableUploadImg() {
  333. $('div.cell:contains("添加一条新回复")').append(
  334. '<div class="fr"><a href="https://imgur.com/upload" target="_blank"> 上传图片</a> - </div>'
  335. );
  336. }

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址