Copy a Gerrit link for querying CR And add a button to browse branch code

快捷浏览分支代码,快捷拷贝查询CR的链接,快捷选择cherry-pick的分支

当前为 2023-07-24 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Copy a Gerrit link for querying CR And add a button to browse branch code
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.10
  5. // @description 快捷浏览分支代码,快捷拷贝查询CR的链接,快捷选择cherry-pick的分支
  6. // @author Jackie
  7. // @match https://gerrit.mot.com*
  8. // @icon https://www.google.com/s2/favicons?sz=64&domain=mot.com
  9. // @run-at document-end
  10. // @grant GM.addStyle
  11. // @grant GM.setValue
  12. // @grant GM.getValue
  13. // @grant GM.log
  14. // @grant GM.openInTab
  15. // ==/UserScript==
  16.  
  17. (function() {
  18. 'use strict';
  19.  
  20. let action = ()=>{
  21. sleep(100).then(()=>{
  22. addButtons();
  23. });
  24. }
  25. //action();
  26. sleep(1000).then(()=>{
  27. let c = document.getElementById("gerrit_header");
  28. observeDOM(c, /*onAdd*/ action, /*onRemove*/ action);
  29. });
  30. })();
  31.  
  32. const KEY_SUGGEST_BRANCH = "suggested_branches_";
  33. let allSuggestBranches = ["mt-r1/bt", "mt-r2/bt", "mt-r3/bt"];
  34.  
  35. function addButtons() {
  36. console.log(`=======================addButtons`)
  37. if(document.getElementById('btn_cp_link')) return;
  38. let btnCopyCrQueryLink = createButton("CopyQueryLink");
  39. btnCopyCrQueryLink.id = 'btn_cp_link';
  40. btnCopyCrQueryLink.onclick = () => {
  41. let msg = "CR not found!"
  42. let link = getQueryLink();
  43. navigator.clipboard.writeText(link);
  44. showSnackbar(link ? `Copied: ${link}` : 'CR not found!');
  45. }
  46. let btnOpenCrQueryLink = createButton("OpenQueryLink");
  47. btnOpenCrQueryLink.onclick = () => {
  48. let msg = "CR not found!"
  49. let link = getQueryLink();
  50. if(!link) {
  51. showSnackbar('CR not found!')
  52. } else {
  53. GM.openInTab(link, { active: true });
  54. }
  55. }
  56. let parent = document.getElementsByClassName("com-google-gerrit-client-change-ChangeScreen_BinderImpl_GenCss_style-idAndStatus")[0];
  57. if(parent) {
  58. parent.classList.add('com-google-gerrit-client-change-ChangeScreen_BinderImpl_GenCss_style-headerButtons');
  59. parent.appendChild(btnCopyCrQueryLink);
  60. parent.appendChild(btnOpenCrQueryLink);
  61. }
  62.  
  63. let btnBrowseBranch = createElement({
  64. name:"a",
  65. class:"com-google-gerrit-client-change-ChangeScreen_BinderImpl_GenCss_style-projectSettings",
  66. innerHTML: "Browse Branch"
  67. });
  68. btnBrowseBranch.target = `_blank`;
  69.  
  70. let branchTd = document.querySelector('#change_infoTable > tbody > tr:nth-of-type(7) > td:nth-of-type(1)');
  71. let branchName = branchTd.firstChild.text;
  72. btnBrowseBranch.href = `https://gerrit.mot.com/plugins/gitiles/${getProjectName()}/+/refs/heads/${branchName}`;
  73. branchTd.appendChild(btnBrowseBranch);
  74.  
  75. GM.getValue(KEY_SUGGEST_BRANCH + getProjectName(), []).then((it)=>{
  76. GM.log(`allSuggestBranches: ${it}`);
  77. allSuggestBranches = it;
  78. });
  79. let addSuggestBranchAction = ()=>{
  80. sleep(100).then(addSuggestBranchButtons);
  81. }
  82. observeDOM(document.body, /*onAdd*/ addSuggestBranchAction);
  83. }
  84.  
  85. function getQueryLink() {
  86. let link = null;
  87. let crDiv = document.getElementsByClassName("com-google-gerrit-client-change-CommitBox_BinderImpl_GenCss_style-text")[0];
  88. if(crDiv && crDiv.firstElementChild){
  89. link = "https://gerrit.mot.com/#/q/" + crDiv.firstElementChild.text;
  90. }
  91. return link;
  92. }
  93.  
  94. function addSuggestBranchButtons(readd){
  95. GM.addStyle(`.com-google-gerrit-client-change-ChangeScreen_BinderImpl_GenCss_style-label_user{
  96. margin: 3px;
  97. }`);
  98. let parent = getSuggestBranchParent(readd);
  99. if(parent){
  100. for (let branch of allSuggestBranches) {
  101. createBranchSuggestButton(branch, parent);
  102. }
  103. createAddSuggestButton(parent);
  104. }
  105. }
  106.  
  107. function getSuggestBranchParent(readd) {
  108. let parent = document.querySelector('.gwt-DialogBox.commentedActionDialog .smallHeading');
  109. if(parent && parent.textContent && parent.textContent.startsWith('Cherry Pick to')){
  110. let div = document.getElementById('suggested_branches');
  111. if(div && readd){
  112. div.parentElement.removeChild(div);
  113. }
  114. if(!div){
  115. div = document.createElement('div');
  116. div.id = "suggested_branches";
  117. parent.appendChild(div);
  118. }
  119. return div;
  120. }
  121. return null;
  122. }
  123.  
  124. function createAddSuggestButton(parent) {
  125. if(document.getElementById('addSuggestBranch')) return;
  126. let span = document.createElement('span');
  127. span.role = "listitem";
  128. span.id = 'addSuggestBranch';
  129. span.title = "Add Suggest branch";
  130. span.className="com-google-gerrit-client-change-ChangeScreen_BinderImpl_GenCss_style-label_user";
  131. span.innerText = '+';
  132. span.onclick = ()=>{
  133. let branchName = prompt('Branch Name', '');
  134. if(branchName){
  135. getBranchInput().value = branchName;
  136. addSuggestBranch(branchName);
  137. span.before(createBranchSuggestButton(branchName));
  138. }
  139. }
  140. parent.appendChild(span);
  141. }
  142.  
  143. function removeSuggestBranch(branchName) {
  144. allSuggestBranches.removeByValue(branchName);
  145. GM.setValue(KEY_SUGGEST_BRANCH + getProjectName(), allSuggestBranches);
  146. }
  147.  
  148. function addSuggestBranch(branchName) {
  149. allSuggestBranches.push(branchName);
  150. GM.setValue(KEY_SUGGEST_BRANCH + getProjectName(), allSuggestBranches);
  151. }
  152.  
  153. function getProjectName(){
  154. return document.querySelector('#change_infoTable > tbody > tr:nth-of-type(6) > td:nth-of-type(1)').firstChild.text;
  155. }
  156.  
  157. function createBranchSuggestButton(branchName, parent) {
  158. if(document.getElementById(branchName)) return;
  159. let span = document.createElement('span');
  160. span.role = "listitem";
  161. span.title = "Suggested branch";
  162. span.id = branchName;
  163. span.className="com-google-gerrit-client-change-ChangeScreen_BinderImpl_GenCss_style-label_user";
  164. span.innerText = branchName;
  165. span.onclick = ()=>{
  166. let branchInput = getBranchInput();
  167. branchInput.value = branchName;
  168. }
  169. let deleteButton = document.createElement('button');
  170. deleteButton.title = "Remove suggested branch"
  171. deleteButton.innerText = 'X';
  172. deleteButton.onclick = ()=>{
  173. removeSuggestBranch(branchName);
  174. GM.setValue(KEY_SUGGEST_BRANCH, allSuggestBranches);
  175. span.parentElement.removeChild(span);
  176. }
  177. span.appendChild(deleteButton);
  178. if(parent){
  179. parent.appendChild(span);
  180. }
  181. return span;
  182. }
  183.  
  184. function getBranchInput() {
  185. return document.querySelector('.gwt-SuggestBox');
  186. }
  187.  
  188. function showSnackbar(msg) {
  189. msg = msg ? msg : "Copied succesfully";
  190. let snackbar = getSnackbar(msg);
  191. snackbar.innerHTML = msg;
  192. snackbar.className = "show";
  193. setTimeout(function(){
  194. snackbar.className = snackbar.className.replace("show", "");
  195. }, 1500);
  196. }
  197.  
  198. function getSnackbar() {
  199. let snackbar = document.getElementById('snackbar');
  200. if(!snackbar) {
  201. snackbar = document.createElement("div");
  202. snackbar.id="snackbar";
  203. document.getElementsByClassName('screen')[0].appendChild(snackbar);
  204. }
  205. GM.addStyle(`
  206. #snackbar {
  207. visibility: hidden;
  208. min-width: 250px;
  209. margin-left: -125px;
  210. background-color: #333;
  211. color: #fff;
  212. text-align: center;
  213. border-radius: 2px;
  214. padding: 16px;
  215. position: fixed;
  216. z-index: 1;
  217. left: 50%;
  218. top: 50px;
  219. font-size: 17px;
  220. }
  221.  
  222. #snackbar.show {
  223. visibility: visible;
  224. -webkit-animation: fadein 0.5s, fadeout 0.5s 2.5s;
  225. animation: fadein 0.5s, fadeout 0.5s 2.5s;
  226. }
  227.  
  228. @-webkit-keyframes fadein {
  229. from {top: 0; opacity: 0;}
  230. to {top: 50px; opacity: 1;}
  231. }
  232.  
  233. @keyframes fadein {
  234. from {top: 0; opacity: 0;}
  235. to {top: 50px; opacity: 1;}
  236. }
  237.  
  238. @-webkit-keyframes fadeout {
  239. from {top: 50px; opacity: 1;}
  240. to {top: 0; opacity: 0;}
  241. }
  242.  
  243. @keyframes fadeout {
  244. from {top: 50px; opacity: 1;}
  245. to {top: 0; opacity: 0;}
  246. }
  247. `);
  248. return snackbar;
  249. }
  250.  
  251. function createButton(text) {
  252. let button = createElement(
  253. {
  254. name:"button",
  255. class:"com-google-gerrit-client-change-ChangeScreen_BinderImpl_GenCss_style-highlight",
  256. }
  257. );
  258. button.type = "button";
  259. button.title = text;
  260. let div = document.createElement('div');
  261. div.innerHTML=text;
  262. button.appendChild(div);
  263. return button;
  264. }
  265.  
  266. function createElement(info) {
  267. if(!info.name) return undefined;
  268. let element = document.createElement(info.name);
  269. if(info.innerHTML) element.innerHTML = info.innerHTML;
  270. if(info.class) {
  271. element.className = info.class;
  272. }
  273. return element;
  274. }
  275.  
  276. function sleep (time) {
  277. return new Promise((resolve) => setTimeout(resolve, time));
  278. }
  279.  
  280. Array.prototype.removeByValue = function (val) {
  281. for (var i = 0; i < this.length; i++) {
  282. if (this[i] === val) {
  283. this.splice(i, 1);
  284. i--;
  285. }
  286. }
  287. return this;
  288. }
  289.  
  290. const observeDOM = (function () {
  291. let MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
  292. let eventListenerSupported = window.addEventListener;
  293.  
  294. return function (obj, onAddCallback, onRemoveCallback) {
  295. if (MutationObserver) {
  296. // define a new observer
  297. let mutationObserver = new MutationObserver(function (mutations, observer) {
  298. // if (mutations[0].addedNodes.length && onAddCallback != undefined) {
  299. onAddCallback();
  300. // }
  301. });
  302. // have the observer observe foo for changes in children
  303. mutationObserver.observe(obj, { attributes: true, childList: true, subtree: true });
  304. } else if (eventListenerSupported) {
  305. obj.addEventListener('DOMNodeInserted', onAddCallback, false);
  306. }
  307. };
  308. })();