Jira copy summary

copies summary of Jira ticket

目前为 2023-09-23 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name Jira copy summary
  3. // @namespace https://github.com/rybak/atlassian-tweaks
  4. // @version 4.6
  5. // @license MIT
  6. // @description copies summary of Jira ticket
  7. // @author Sergey Lukashevich, Andrei Rybak, Dmitry Trubin
  8. // @homepage https://github.com/rybak/atlassian-tweaks
  9. // @include https://*jira*/browse/*
  10. // @match https://jira.example.com/browse/*
  11. // @match https://jira.example.com/browse/*
  12. // @icon https://jira.atlassian.com/favicon.ico
  13. //
  14. // @require https://cdn.jsdelivr.net/gh/odyniec/MonkeyConfig@0eaeb525733a36d9e721ec4d9cf3b744b527bfcf/monkeyconfig.js
  15. // @grant GM_registerMenuCommand
  16. // @grant GM_addStyle
  17. // @grant GM_getValue
  18. // @grant GM_setValue
  19. //
  20. // ==/UserScript==
  21.  
  22. /*
  23. * Copyright 2017-2023 Sergey Lukashevich
  24. * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
  25. * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
  26. * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
  27. * persons to whom the Software is furnished to do so, subject to the following conditions:
  28. *
  29. * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
  30. * Software.
  31. *
  32. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  33. * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  34. * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  35. * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  36. */
  37.  
  38. /*
  39. version 4.6
  40. - More precise reference to monkeyconfig.js library.
  41. version 4.5
  42. - Migrated to jsDelivr as CDN for library code
  43. version 4.4
  44. - UX of copy-pasting the summary formatted with italics into a rich
  45. text editor has been improved. Now the text that you type after
  46. pasting will not be formatted in italics automatically.
  47. version 4.2
  48. - Styling of the button has been updated to be compatible with Jira
  49. version 8.20.*
  50. version 4.0
  51. - Resurrection of the button has been made more robust by relying on
  52. Jira's own events about edits on the issue pages.
  53. version 3.8
  54. - Italic formatting is now configurable via extension menu, and the
  55. configuration persists across script updates.
  56. version 3.7
  57. - User script now supports automatic updates via @updateURL.
  58. version 3.6
  59. - User script now has @icon, which can be rendered by the browser
  60. extension in the list of user scripts, dashboard, etc.
  61. version 3.5
  62. - Adding italics to format the summary text is now "configurable" via a
  63. constant in code.
  64. version 3.4.1
  65. - Fixed the button not working in Jira 8
  66. version 3.4
  67. - dependency on jQuery has been removed to improve compatibility with
  68. different versions of Jira, which may use different versions of
  69. jQuery themselves.
  70. version 3.3
  71. - Compatibility with Jira 8 has been improved.
  72. version 3.2
  73. - "Copy Summary" button will now work in "Detail View" of JQL search
  74. results.
  75. version 3.1
  76. - jQuery version has been downgraded to 1.7.2 to avoid clashing with
  77. Jira's version of jQuery
  78. version 3.0
  79. - Resurrection of the button has been made more aggressive to handle
  80. more use-cases.
  81. - User script used to incorrectly use link or summary of a previously
  82. opened ticket, which has been corrected.
  83. version 2.2
  84. - Code clean up
  85. version 2.1
  86. - Summary text (after ticket id) is italicized, to make it easier to see
  87. where the summary ends
  88. version 2.0
  89. - Jira 8 is now supported in addition to Jira 7
  90. version 1.2
  91. - Button "Copy summary" no longer breaks after editing a Jira ticket
  92. */
  93.  
  94. (function () {
  95. 'use strict';
  96.  
  97. /*
  98. * User configuration
  99. */
  100. var cfg = new MonkeyConfig({
  101. title: 'Jira copy summary configuration',
  102. menuCommand: true,
  103. params: {
  104. italic_summary: {
  105. type: 'checkbox',
  106. default: true
  107. }
  108. }
  109. });
  110.  
  111. function getMeta(metaName) {
  112. const metas = document.getElementsByTagName('meta');
  113.  
  114. for (let i = 0; i < metas.length; i++) {
  115. if (metas[i].getAttribute('name') === metaName) {
  116. return metas[i].getAttribute('content');
  117. }
  118. }
  119.  
  120. return '';
  121. }
  122.  
  123. var textResult = '';
  124. var htmlResult = '';
  125.  
  126. function handleCopyEvent(e) {
  127. var clipboardData;
  128.  
  129. // Stop event propogation
  130. e.stopPropagation();
  131. e.preventDefault();
  132.  
  133. clipboardData = e.clipboardData || window.clipboardData;
  134. clipboardData.setData('text/plain', textResult);
  135. clipboardData.setData('text/html', htmlResult);
  136. }
  137.  
  138. var COPY_BUTTON_ID = "copycopy";
  139. var copyButton;
  140.  
  141. function getJiraMajorVersion() {
  142. return document.querySelector('meta[name="application-name"]').attributes.getNamedItem("data-version").value.split(".")[0];
  143. }
  144.  
  145. function createButtonForJira7() {
  146. var ul = document.createElement("ul");
  147. ul.classList.add("toolbar-group");
  148. ul.classList.add("pluggable-ops");
  149.  
  150. var li = document.createElement("li");
  151. li.classList.add("toolbar-item");
  152.  
  153. copyButton = document.createElement("a");
  154. copyButton.id = COPY_BUTTON_ID;
  155. copyButton.classList.add("toolbar-trigger");
  156. copyButton.classList.add("zeroclipboard-is-hover");
  157. copyButton.textContent = "Copy summary*";
  158.  
  159. ul.appendChild(li);
  160. li.appendChild(copyButton);
  161.  
  162. return ul;
  163. }
  164.  
  165. function createButtonForJira8() {
  166. var div = document.createElement("div");
  167. div.id = "opsbar-copycopy_container"
  168. div.classList.add("aui-buttons");
  169. div.classList.add("pluggable-ops");
  170.  
  171. copyButton = document.createElement("a");
  172. copyButton.id = COPY_BUTTON_ID;
  173. copyButton.classList.add("aui-button");
  174. copyButton.classList.add("toolbar-trigger");
  175. copyButton.textContent = "Copy summary*";
  176.  
  177. div.appendChild(copyButton);
  178.  
  179. return div;
  180. }
  181.  
  182. function copyClickAction() {
  183. var summaryText = document.getElementById("summary-val").textContent;
  184. var ticketIdSource = document.querySelector("#dx-issuekey-val-h1 a");
  185. if (!ticketIdSource) {
  186. ticketIdSource = document.querySelector(".aui-page-header-main .issue-link");
  187. }
  188. var ticketId = ticketIdSource.dataset.issueKey;
  189. var jiraUrl = getMeta("ajs-jira-base-url");
  190. var fullLink = jiraUrl + "/browse/" + ticketId;
  191. textResult = '[' + ticketId + '] ' + summaryText;
  192. if (cfg.get('italic_summary')) {
  193. summaryText = '<i>' + summaryText + '</i> &#x200b;';
  194. }
  195. htmlResult = '[<a href="' + fullLink + '">' + ticketId + '</a>] ' + summaryText;
  196. document.addEventListener('copy', handleCopyEvent);
  197. document.execCommand('copy');
  198. document.removeEventListener('copy', handleCopyEvent);
  199. return false;
  200. };
  201.  
  202. function createButton() {
  203. try {
  204. copyButton = document.getElementById(COPY_BUTTON_ID);
  205. // if for some reason it doesn't exist - create one
  206. if (!copyButton) {
  207. const jiraMajorVersion = getJiraMajorVersion();
  208. var container;
  209. var button;
  210. switch (jiraMajorVersion) {
  211. case "7":
  212. container = document.getElementById("stalker").getElementsByClassName("toolbar-split toolbar-split-left")[0];
  213. button = createButtonForJira7();
  214. break;
  215. case "8":
  216. container = document.getElementById("stalker").getElementsByClassName("aui-toolbar2-primary")[0];
  217. button = createButtonForJira8();
  218. break;
  219. default:
  220. console.log("Jira v" + jiraMajorVersion + " is not supported");
  221. return;
  222. }
  223. container.appendChild(button);
  224. console.log("Created the button");
  225. } else {
  226. console.log("Using existing button");
  227. }
  228. copyButton.onclick = copyClickAction;
  229. } catch (e) {
  230. console.warn("Could not create 'Copy summary' button ", e);
  231. }
  232. }
  233.  
  234. createButton();
  235.  
  236. JIRA.bind(JIRA.Events.NEW_CONTENT_ADDED, () => {
  237. console.log("Something changed, recreating button...");
  238. createButton();
  239. });
  240. })();