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.7
  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. msg = msg ? msg : "Copied succesfully";
  170. let snackbar = getSnackbar(msg);
  171. snackbar.innerHTML = msg;
  172. snackbar.className = "show";
  173. setTimeout(function(){
  174. snackbar.className = snackbar.className.replace("show", "");
  175. }, 1500);
  176. }
  177.  
  178. function getSnackbar() {
  179. let snackbar = document.getElementById('snackbar');
  180. if(!snackbar) {
  181. snackbar = document.createElement("div");
  182. snackbar.id="snackbar";
  183. document.getElementsByClassName('screen')[0].appendChild(snackbar);
  184. }
  185. GM.addStyle(`
  186. #snackbar {
  187. visibility: hidden;
  188. min-width: 250px;
  189. margin-left: -125px;
  190. background-color: #333;
  191. color: #fff;
  192. text-align: center;
  193. border-radius: 2px;
  194. padding: 16px;
  195. position: fixed;
  196. z-index: 1;
  197. left: 50%;
  198. top: 50px;
  199. font-size: 17px;
  200. }
  201.  
  202. #snackbar.show {
  203. visibility: visible;
  204. -webkit-animation: fadein 0.5s, fadeout 0.5s 2.5s;
  205. animation: fadein 0.5s, fadeout 0.5s 2.5s;
  206. }
  207.  
  208. @-webkit-keyframes fadein {
  209. from {top: 0; opacity: 0;}
  210. to {top: 50px; opacity: 1;}
  211. }
  212.  
  213. @keyframes fadein {
  214. from {top: 0; opacity: 0;}
  215. to {top: 50px; opacity: 1;}
  216. }
  217.  
  218. @-webkit-keyframes fadeout {
  219. from {top: 50px; opacity: 1;}
  220. to {top: 0; opacity: 0;}
  221. }
  222.  
  223. @keyframes fadeout {
  224. from {top: 50px; opacity: 1;}
  225. to {top: 0; opacity: 0;}
  226. }
  227. `);
  228. return snackbar;
  229. }
  230.  
  231. function createButton(text) {
  232. let button = createElement(
  233. {
  234. name:"button",
  235. class:"com-google-gerrit-client-change-ChangeScreen_BinderImpl_GenCss_style-highlight",
  236. }
  237. );
  238. button.type = "button";
  239. button.title = text;
  240. let div = document.createElement('div');
  241. div.innerHTML=text;
  242. button.appendChild(div);
  243. return button;
  244. }
  245.  
  246. function createElement(info) {
  247. if(!info.name) return undefined;
  248. let element = document.createElement(info.name);
  249. if(info.innerHTML) element.innerHTML = info.innerHTML;
  250. if(info.class) {
  251. element.className = info.class;
  252. }
  253. return element;
  254. }
  255.  
  256. function sleep (time) {
  257. return new Promise((resolve) => setTimeout(resolve, time));
  258. }
  259.  
  260. Array.prototype.removeByValue = function (val) {
  261. for (var i = 0; i < this.length; i++) {
  262. if (this[i] === val) {
  263. this.splice(i, 1);
  264. i--;
  265. }
  266. }
  267. return this;
  268. }
  269.  
  270. const observeDOM = (function () {
  271. let MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
  272. let eventListenerSupported = window.addEventListener;
  273.  
  274. return function (obj, onAddCallback, onRemoveCallback) {
  275. if (MutationObserver) {
  276. // define a new observer
  277. let mutationObserver = new MutationObserver(function (mutations, observer) {
  278. // if (mutations[0].addedNodes.length && onAddCallback != undefined) {
  279. onAddCallback();
  280. // }
  281. });
  282. // have the observer observe foo for changes in children
  283. mutationObserver.observe(obj, { attributes: true, childList: true, subtree: true });
  284. } else if (eventListenerSupported) {
  285. obj.addEventListener('DOMNodeInserted', onAddCallback, false);
  286. }
  287. };
  288. })();