zhihu-reply-tip

显示被引用的用户的最近一条评论

  1. // ==UserScript==
  2. // @name zhihu-reply-tip
  3. // @namespace https://github.com/QingYun/
  4. // @version 0.1
  5. // @description 显示被引用的用户的最近一条评论
  6. // @match http://www.zhihu.com/*
  7. // @copyright 2012+, QingYun
  8. // ==/UserScript==
  9.  
  10. var HIDE_STYLE = "display: none";
  11.  
  12. function hasClass(node, className) {
  13. return node && node.classList && node.classList.contains(className);
  14. }
  15.  
  16. function createReplyTipNode() {
  17. var a = document.createElement("a");
  18. a.setAttribute("href", "#");
  19. a.setAttribute("class", "like zm-comment-op-link");
  20. var i = document.createElement("i");
  21. i.setAttribute("class", "zg-icon zg-icon-comment-reply");
  22. a.appendChild(i);
  23. a.appendChild(document.createTextNode("查看 TA 的最近一条评论"));
  24. return a;
  25. }
  26.  
  27. function createQuoteBlockNode(content) {
  28. var bq = document.createElement("blockquote");
  29. bq.setAttribute("style", HIDE_STYLE);
  30. var p = document.createElement("p");
  31. p.appendChild(document.createTextNode(content));
  32. bq.appendChild(p);
  33. return bq;
  34. }
  35.  
  36. function latestReply(commentItems, userLookingFor, endIndex) {
  37. for (var i = endIndex - 1; i >= 0 ; i--) {
  38. var curUser = commentItems[i].querySelector(".zg-link").textContent;
  39. if (curUser == userLookingFor) {
  40. return commentItems[i].querySelector(".zm-comment-content").textContent;
  41. }
  42. }
  43. }
  44.  
  45. function addOneReplyTip(commentItems, targetIndex) {
  46. var curItem = commentItems[targetIndex];
  47. if (curItem.querySelector(".zm-comment-hd .like") !== null)
  48. return ;
  49. var headNode = curItem.querySelector(".zm-comment-hd");
  50. if (headNode.childNodes.length > 3) {
  51. var referredUser;
  52. if (headNode.firstChild.nodeValue == "\n 匿名用户")
  53. referredUser = headNode.querySelectorAll(".zg-link")[0];
  54. else
  55. referredUser = headNode.querySelectorAll(".zg-link")[1];
  56. if (referredUser) {
  57. var referredReply = latestReply(commentItems, referredUser.textContent, targetIndex);
  58. if (!referredReply)
  59. return ;
  60. var q = null;
  61. var replyTip = createReplyTipNode();
  62. replyTip.addEventListener("click", function() {
  63. if (q === null) {
  64. q = createQuoteBlockNode(referredReply);
  65. var content = curItem.querySelector(".zm-comment-content");
  66. content.parentNode.insertBefore(q, content);
  67. }
  68. if (q.getAttribute("style") == HIDE_STYLE)
  69. q.removeAttribute("style");
  70. else
  71. q.setAttribute("style", HIDE_STYLE);
  72. });
  73. curItem.querySelector(".zm-comment-hd").appendChild(replyTip);
  74. }
  75. }
  76. }
  77.  
  78. function addReplyTips(commentList) {
  79. var commentItems = commentList.querySelectorAll(".zm-item-comment");
  80. for (var i = 0; i < commentItems.length; i++) {
  81. addOneReplyTip(commentItems, i);
  82. }
  83. }
  84.  
  85. (function(){
  86. var addReplyTipTimer;
  87. var observer = new MutationObserver(function(mutations) {
  88. mutations.forEach(function(mutation) {
  89. if (mutation.type == "childList") {
  90. var firstAddedNode = mutation.addedNodes.length && mutation.addedNodes[0];
  91. var firstRemovedNode = mutation.removedNodes.length && mutation.removedNodes[0];
  92. if (hasClass(firstAddedNode, "zm-comment-box") && hasClass(firstRemovedNode, "zm-comment-box"))
  93. addReplyTips(mutation.addedNodes[0].querySelector(".zm-comment-list"));
  94. else if (hasClass(firstAddedNode, "zm-item-comment")) {
  95. if (addReplyTipTimer) clearTimeout(addReplyTipTimer);
  96. addReplyTipTimer = setTimeout(function() {
  97. addReplyTips(mutation.target);
  98. }, 100);
  99. }
  100. }
  101. });
  102. });
  103. observer.observe(document.body, {
  104. childList: true
  105. , subtree: true
  106. , attributes: false
  107. , characterData: false
  108. });
  109. })();