GitHub Remark

GitHub remark

目前為 2022-04-23 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name GitHub Remark
  3. // @namespace https://blog.cuger.cn/p/5187/
  4. // @version 0.1.0
  5. // @description GitHub remark
  6. // @author Dorad
  7. // @license MIT License
  8. // @match https://github.com/*
  9. // @require https://cdn.jsdelivr.net/npm/jquery@3.4.1/dist/jquery.slim.min.js
  10. // @grant GM_downlaod
  11. // @grant GM_xmlhttpRequest
  12. // ==/UserScript==
  13.  
  14. const key = 'GithubRemark-cache';
  15. const defaultRemark = 'None';
  16.  
  17. /**
  18. * API for cache data.
  19. */
  20.  
  21. function updateRemark(userToken, username, remark) {
  22. let cache = JSON.parse(localStorage.getItem(key));
  23. if(!cache){
  24. cache=[];
  25. }
  26. const matchedItemIdx = cache.findIndex(e => e.username==username && e.userToken==userToken)
  27. if(matchedItemIdx>-1){
  28. // 已存在
  29. cache[matchedItemIdx].remark = remark;
  30. cache[matchedItemIdx].updatedAt = new Date().getTime() / 1000
  31. }else{
  32. const item={
  33. userToken:userToken,
  34. username:username,
  35. remark:remark,
  36. updatedAt: new Date().getTime() / 1000
  37. }
  38. cache.push(item);
  39. }
  40. console.log(cache);
  41. localStorage.setItem(key, JSON.stringify(cache));
  42. // showRemarks(userToken);
  43. }
  44.  
  45. function getRemark(userToken, username, callback) {
  46. let cache = JSON.parse(localStorage.getItem(key));
  47. if(!cache){
  48. callback(defaultRemark);
  49. return
  50. }
  51. const item = cache.find(e => e.username==username && e.userToken==userToken)
  52. if(item){
  53. callback(item.remark);
  54. }else{
  55. callback(defaultRemark);
  56. }
  57. }
  58.  
  59. /**
  60. *
  61. * page functions
  62. */
  63.  
  64. function getGithubLoginUsername() {
  65. var doc = document.querySelector("head > meta[name*='login']");
  66. return doc == null ? null : doc.content;
  67. }
  68.  
  69. function hasLoginFrame() {
  70. var loginBtn = document.querySelector('div.HeaderMenu a[href*=login]');
  71. return loginBtn != null;
  72. }
  73.  
  74. function getMasterOfPage(url) {
  75. var master = /github.com\/([^\/|^\?]+)/.exec(url);
  76. if (master !== null)
  77. master = master[1];
  78. return master;
  79. }
  80.  
  81. function getCurrentTab() {
  82. var homepage = /github.com\/$/.exec(location.href);
  83. if (homepage !== null)
  84. return 'homepage';
  85. var tab = /[\?|\&]tab=([^\&]+)/.exec(location.href);
  86. if (tab !== null)
  87. tab = tab[1];
  88. if(/https:\/\/github.com\/orgs\/([\S\s]+)\/people/.exec(location.href))
  89. tab = 'orgs-people';
  90. if(/https:\/\/github.com\/orgs\/([\S\s]+)\/members/.exec(location.href))
  91. tab = 'orgs-members';
  92. return tab;
  93. }
  94.  
  95. function insertAfter(newEl, targetEl) {
  96. var parentEl = targetEl.parentNode;
  97. if (parentEl.lastChild == targetEl) {
  98. parentEl.appendChild(newEl);
  99. } else {
  100. parentEl.insertBefore(newEl, targetEl.nextSibling);
  101. }
  102. }
  103.  
  104. function generateRemarkSpan(className, userToken, username, remark){
  105. var span = document.createElement('span');
  106. span.className = className;
  107. span.textContent = '('+remark+')';
  108. span.title = '('+remark+')';
  109. span.addEventListener('dblclick', function (event) {
  110. console.log(event);
  111. const newRemark = changeRemarks(userToken, username, remark);
  112. if(newRemark!==remark){
  113. span.replaceWith(generateRemarkSpan(
  114. className,userToken, username,newRemark
  115. ));
  116. }
  117. }, false);
  118. return span;
  119. }
  120.  
  121. function clearRemarkOfCurrentNode(div){
  122. if (!!div.querySelector('span.github-remarks'))
  123. div.removeChild(div.querySelector('span.github-remarks'));
  124. }
  125.  
  126. /**
  127. *
  128. * Show remark functions, adapted for each page
  129. */
  130.  
  131. function showRemarkInHomepage(userToken) {
  132. var news = document.querySelector("#dashboard > div.news");
  133. var userCount = document.querySelectorAll("div.flex-items-baseline > div > a[data-hovercard-type=user]").length;
  134. var observer = new MutationObserver(function (mutations, self) {
  135. var users = document.querySelectorAll("div.flex-items-baseline > div > a[data-hovercard-type=user]");
  136. if (userCount != users.length) {
  137. userCount = users.length
  138. users.forEach(function (element) {
  139. clearRemarkOfCurrentNode(element.parentNode);
  140. var username = getMasterOfPage(element.href);
  141. getRemark(userToken, username, function (remark) {
  142. var remarkEl = generateRemarkSpan('link-gray pl-1 github-remarks', userToken, username, remark);
  143. insertAfter(remarkEl, element);
  144. });
  145. }, this);
  146. }
  147. });
  148. observer.observe(news, { childList: true, subtree: true });
  149. }
  150.  
  151. function showRemarkInLeftPannel(userToken) {
  152. var vcard = document.querySelector('h1.vcard-names');//author in home page
  153. if (!!vcard) {
  154. if (vcard.childElementCount > 2)
  155. vcard.removeChild(vcard.querySelector('span.github-remarks'));
  156. var username = getMasterOfPage(location.href);
  157. getRemark(userToken, username, function (remark) {
  158. vcard.appendChild(generateRemarkSpan('vcard-username d-block github-remarks', userToken, username, remark));
  159. });
  160. }
  161. }
  162.  
  163. function showRemarkInStarsTab(userToken) {
  164. var stars = document.querySelectorAll('div > h3 > a');//in star page
  165. if (stars !== null) {
  166. stars.forEach(function (element) {
  167. clearRemarkOfCurrentNode(element.parentNode);
  168. if (!!element.querySelector('span.text-normal')) {
  169. var text = element.querySelector('span.text-normal').textContent;
  170. var username = text.substring(0, text.indexOf(' /'));
  171. getRemark(userToken, username, function (remark) {
  172. insertAfter(generateRemarkSpan('link-gray pl-1 github-remarks', userToken, username, remark), element);
  173. });
  174. }
  175. }, this);
  176. }
  177. }
  178.  
  179. function showRemarkInFollowersTab(userToken) {
  180. var followers = document.querySelectorAll('div.d-table > div:nth-child(2) > a');//in followers/following page
  181. if (!!followers) {
  182. followers.forEach(function (element) {
  183. clearRemarkOfCurrentNode(element.parentNode);
  184. var username = element.querySelector('span:last-child').textContent;
  185. getRemark(userToken, username, function (remark) {
  186. insertAfter(generateRemarkSpan('link-gray pl-1 github-remarks', userToken, username, remark), element);
  187. });
  188. }, this);
  189. }
  190. }
  191.  
  192. function showRemarkInRepoStargazersPage(userToken) {
  193. var stargazers = document.querySelectorAll('div > h3 > span');
  194. if (!!stargazers) {
  195. stargazers.forEach(function (element) {
  196. clearRemarkOfCurrentNode(element.parentNode);
  197. var a = element.querySelector('a');
  198. var username = getMasterOfPage(a.href);
  199. getRemark(userToken, username, function (remark) {
  200. var remarkEl = generateRemarkSpan('link-gray pl-1 github-remarks', userToken, username, remark)
  201. insertAfter(remarkEl, a);
  202. //如果username太长,截断显示,为remark留点位置
  203. if (a.offsetWidth > element.clientWidth * 4 / 5) {
  204. a.style.width = element.clientWidth * 4 / 5 + 'px';
  205. a.className += 'css-truncate-target';
  206. remarkEl.style.width = element.clientWidth * 1 / 5 + 'px';
  207. remarkEl.className += 'css-truncate-target';
  208. }
  209. });
  210. }, this);
  211. }
  212. }
  213.  
  214. function showRemarkInRepoDetailPage(userToken) {
  215. var author = document.querySelector('span.author > a');//in a repo page
  216. if (!!author) {
  217. var username = getMasterOfPage(location.href);
  218. getRemark(userToken, username, function (remark) {
  219. author.textContent = username + '(' + remark + ')';
  220. });
  221. }
  222. var repoDetail = /\/(stargazers|watchers)(\/you_know)?$/.exec(location.href);
  223. if (repoDetail !== null) {
  224. switch (repoDetail[1]) {
  225. case 'watchers':
  226. case 'stargazers':
  227. showRemarkInRepoStargazersPage(userToken);
  228. break;
  229. }
  230. }
  231. }
  232.  
  233. function showRemarkInOrgPeople(userToken){
  234. var users = document.querySelectorAll('a[data-hovercard-type=user][id]');
  235. if(!!users){
  236. users.forEach(function (element) {
  237. clearRemarkOfCurrentNode(element.parentNode);
  238. var username = getMasterOfPage(element.href);
  239. if(element.href.indexOf('orgs')>-1){
  240. username = /https:\/\/github.com\/orgs\/([\S\s]+)\/people\/([\s\S]+)$/.exec(element.href)[2];
  241. }
  242. getRemark(userToken, username, function (remark) {
  243. insertAfter(generateRemarkSpan('link-gray pl-1 github-remarks', userToken, username, remark), element);
  244. });
  245. }, this)
  246. }
  247. }
  248.  
  249. function showRemarkInOrgMembers(userToken){
  250. var users = document.querySelectorAll('ul.member-listing > li > div > a[data-hovercard-type=user]');
  251. if(!!users){
  252. users.forEach(function (element) {
  253. clearRemarkOfCurrentNode(element.parentNode);
  254. var username = /https:\/\/github.com\/orgs\/([\S\s]+)\/people\/([\s\S]+)$/.exec(element.href)[2];
  255. getRemark(userToken, username, function (remark) {
  256. insertAfter(generateRemarkSpan('link-gray pl-1 github-remarks', userToken, username, remark), element);
  257. });
  258. }, this)
  259. }
  260. }
  261.  
  262. function changeRemarks(userToken, username, oldValue) {
  263. var newValue = window.prompt("请输入新备注", oldValue);
  264. if (newValue !== null && newValue !== oldValue) {
  265. updateRemark(userToken, username, newValue);
  266. return newValue;
  267. }
  268. return oldValue;
  269. }
  270.  
  271. function showRemarks(userToken) {
  272. showRemarkInLeftPannel(userToken);
  273. var tab = getCurrentTab();
  274. switch (tab) {
  275. case 'homepage':
  276. showRemarkInHomepage(userToken);
  277. break;
  278. case 'repositories':
  279. break;
  280. case 'stars':
  281. showRemarkInStarsTab(userToken);
  282. break;
  283. case 'following':
  284. case 'followers':
  285. showRemarkInFollowersTab(userToken);
  286. break;
  287. case 'orgs-members':
  288. showRemarkInOrgMembers(userToken);
  289. break;
  290. case 'orgs-people':
  291. showRemarkInOrgPeople(userToken);
  292. break;
  293. default:
  294. showRemarkInRepoDetailPage(userToken);
  295. break;
  296. }
  297. console.log(tab,'Show remarks')
  298. }
  299.  
  300. (function () {
  301. console.log('GithubRemark-Dorad');
  302. var username = getGithubLoginUsername();
  303. if (username !== null && username != '') {
  304. showRemarks(username);
  305. } else if (hasLoginFrame()) {
  306. alert('你还未登陆github,请先登录你的github账户!');
  307. }
  308. }());
  309.