Launchpad bug tags helper

LP bugs tags helper

目前為 2017-08-31 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name Launchpad bug tags helper
  3. // @namespace https://launchpad.net/~julian-liu
  4. // @version 0.4
  5. // @description LP bugs tags helper
  6. // @author Julian Liu
  7. // @match https://bugs.launchpad.net/*/+filebug
  8. // @match https://bugs.launchpad.net/*/+bug/*
  9. // @connect cedelivery.access.ly
  10. // @grant GM_xmlhttpRequest
  11. // ==/UserScript==
  12.  
  13. function interceptorSetup() {
  14. // override submit handling
  15. HTMLFormElement.prototype.real_submit = HTMLFormElement.prototype.submit;
  16. HTMLFormElement.prototype.submit = interceptor;
  17.  
  18. document.getElementById('filebug-form').addEventListener('submit', function(e) {
  19. // stop the form from submitting
  20. e.preventDefault();
  21.  
  22. interceptor(e);
  23. }, true);
  24. }
  25.  
  26. function interceptor(e) {
  27. var frm = e ? e.target : this;
  28.  
  29. tagNode = frm.elements['field.tags'];
  30.  
  31. if (tagNode.value.length === 0) {
  32. var check = confirm('No tags entered. Are you sure to submit this bug without any tag?');
  33. if (!check) {
  34. return;
  35. }
  36. }
  37. // submit default is prevented, so we add new submit node instead
  38. submitNode = document.createElement('input');
  39. submitNode.name = 'field.actions.submit_bug';
  40. submitNode.type = 'text';
  41. submitNode.value = 'Submit Bug Report';
  42. frm.appendChild(submitNode);
  43. HTMLFormElement.prototype.real_submit.apply(frm);
  44. }
  45.  
  46. function addTagStyle() {
  47. var menuStyle = `
  48. #wrap {
  49. width: 100px;
  50. height: 50px;
  51. padding-bottom: 10px;
  52. margin: 0; /* Ensures there is no space between sides of the screen and the menu */
  53. z-index: 1; /* Makes sure that your menu remains on top of other page elements */
  54. background-color: GhostWhite;
  55. }
  56. .navbar {
  57. height: 50px;
  58. padding: 0;
  59. padding-bottom: 10px;
  60. margin: 0;
  61. border-right: 1px solid #fafaff;
  62. z-index: 12;
  63. }
  64. .navbar li {
  65. padding-bottom: 10px;
  66. height: auto;
  67. width: 100px; /* Each menu item is 100px wide */
  68. /*float: left; This lines up the menu items horizontally */
  69. object-position: top;
  70. text-align: center; /* All text is placed in the center of the box */
  71. list-style: none; /* Removes the default styling (bullets) for the list */
  72. font: normal bold 12px/1.2em Arial, Verdana, Helvetica;
  73. padding: 0;
  74. margin: 0;
  75. background-color: GhostWhite;
  76. }
  77. .navbar a {
  78. padding: 18px 0; /* Adds a padding on the top and bottom so the text appears centered vertically */
  79. border-left: 1px solid #fafaff; /* Creates a border in a slightly lighter shade of blue than the background. Combined with the right border, this creates a nice effect. */
  80. border-right: 1px solid #fafaff; /* Creates a border in a slightly darker shade of blue than the background. Combined with the left border, this creates a nice effect. */
  81. text-decoration: none; /* Removes the default hyperlink styling. */
  82. color: #000; /* Text color is black */
  83. display: block;
  84. }
  85. .navbar li:hover, a:hover {
  86. background-color: #e5f3ff;
  87. }
  88. .navbar li ul {
  89. display: none; /* Hides the drop-down menu */
  90. margin: 0; /* Aligns drop-down box underneath the menu item */
  91. padding: 0; /* Aligns drop-down box underneath the menu item */
  92. margin-left: 100px;
  93. float:left;
  94. margin-top: -45px;
  95. height: 0;
  96. }
  97. .navbar li:hover ul {
  98. display: block; /* Displays the drop-down box when the menu item is hovered over */
  99. z-index: 12;
  100. padding-left: 1px;
  101. }
  102. .navbar li ul li {
  103. background-color: #e1e1e7;
  104. width: 150px;
  105. font: normal 12px/1.2em Arial, Verdana, Helvetica;
  106. }
  107. .navbar li ul li a {
  108. border-left: 1px solid #0026ff;
  109. border-right: 1px solid #0026ff;
  110. border-top: 1px solid #0026ff;
  111. z-index: 1001;
  112. }
  113. .navbar li ul li:hover {
  114. background-color: #d1d7e8;
  115. z-index: 1000;
  116. }
  117. .checkedmark:before {
  118. content: '✓';
  119. }
  120. `;
  121.  
  122. var css = document.createElement("style");
  123. css.type = "text/css";
  124. css.innerHTML = menuStyle;
  125. document.body.appendChild(css);
  126. }
  127.  
  128. function toggleTagValue(tag) {
  129. var tagNode = document.getElementById('filebug-form').elements['field.tags'];
  130. var liNode = document.getElementById('taglist.' + tag);
  131.  
  132. if (tagNode.value.indexOf(tag) !== -1) {
  133. tagNode.value = tagNode.value.replace(' ' + tag, '');
  134. tagNode.value = tagNode.value.replace(tag, '');
  135. liNode.className = '';
  136. }
  137. else {
  138. tagNode.value = tagNode.value + ' ' + tag;
  139. liNode.className = 'checkedmark';
  140. }
  141. }
  142.  
  143. function insertAfter(newNode, referenceNode) {
  144. referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
  145. }
  146.  
  147. function readExternalTags(url, callback) {
  148. GM_xmlhttpRequest({
  149. method: "GET",
  150. url: url,
  151. onload: function (response) {
  152. if (response.status == 200) {
  153. callback(response.responseText);
  154. }
  155. }
  156. });
  157. }
  158.  
  159. function tagList() {
  160. // ?q= to avoid cache
  161. var extTagUrl = 'https://cedelivery.access.ly/tag.json?q=';
  162. var intTagurl = 'https://bugs.launchpad.net/somerville/+bug/1713956?q=';
  163. var pubTags = {
  164. ihv: ['ihv-amd', 'ihv-broadcom', 'ihv-intel', 'ihv-nvidia', 'ihv-realtek', 'ihv-related'],
  165. status: ['task', 'staging', 'waiting', 'cqa', 'cqa-verified']
  166. };
  167. var tagDiv = document.createElement('div');
  168. tagDiv.id = 'wrap';
  169. var ulLevel1 = document.createElement('ul');
  170. ulLevel1.className = 'navbar';
  171. ulLevel1.id = 'navbartop';
  172. tagDiv.appendChild(ulLevel1);
  173.  
  174. function appendCategory(tagData) {
  175. var topNode = document.getElementById('navbartop');
  176.  
  177. Object.keys(tagData).forEach(function(key, index) {
  178. var liCategory = document.createElement('li');
  179. topNode.appendChild(liCategory);
  180. liCategory.innerHTML = liCategory.innerHTML + key + ' →';
  181.  
  182. var ulLevel2 = document.createElement('ul');
  183. for (var i = 0; i < tagData[key].length; i++) {
  184. var liItem = document.createElement('li');
  185. ulLevel2.appendChild(liItem);
  186. liItem.innerHTML = liItem.innerHTML + tagData[key][i];
  187. liItem.id = 'taglist.' + tagData[key][i];
  188. (function(value){
  189. liItem.addEventListener("click", function() {
  190. toggleTagValue(value);
  191. }, false);})(tagData[key][i]);
  192. }
  193. liCategory.appendChild(ulLevel2);
  194. });
  195. }
  196.  
  197. document.getElementById('filebug-form').elements['field.tags'].size = '40';
  198.  
  199. var targetNode = document.getElementById('filebug-form').elements['field.tags'].parentNode.parentNode.parentNode;
  200. insertAfter(tagDiv, targetNode);
  201. appendCategory(pubTags);
  202. addTagStyle();
  203.  
  204. loadBugDescription(intTagurl, function(text){
  205. var data = JSON.parse(text);
  206. appendCategory(data);
  207. });
  208. }
  209.  
  210. function loadExtHtml(url, callback) {
  211. var ajaxReq = new XMLHttpRequest();
  212. ajaxReq.open('GET', url, true);
  213. ajaxReq.onreadystatechange = function() {
  214. if (ajaxReq.readyState === 4 && ajaxReq.status == '200') {
  215. callback(ajaxReq.responseText);
  216. }
  217. };
  218. ajaxReq.send(null);
  219. }
  220.  
  221. function loadBugDescription(url, callback) {
  222. loadExtHtml(url, function(text){
  223. var doc = document.implementation.createHTMLDocument("");
  224. doc.write(text);
  225. var children = doc.getElementById('edit-description').childNodes;
  226. for (var i=0, len=children.length; i < len; i++){
  227. if (children[i].className == 'yui3-editable_text-text'){
  228. callback(children[i].textContent);
  229. break;
  230. }
  231. }
  232. });
  233. }
  234.  
  235. (function() {
  236. 'use strict';
  237.  
  238. //debugger;
  239. var curUrl = window.location.href;
  240. if (/\+filebug$/.test(curUrl)) {
  241. tagList();
  242. interceptorSetup();
  243. }
  244. else {
  245. console.log('');
  246. }
  247. })();