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