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

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

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

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