プロジェクト

全般

プロフィール

mチケット詳細にて、チケット情報(チケットID・題名・URL)をワンクリックでコピーできるボタンを追加する(View Customizeスクリプト)

morioka さんが21日前に追加

チケットの情報をメールやチャット等の他ツールに転記する際、
ブラウザとツールを行き来することに手間を感じるため、1クリックでコピーできるボタンを追加する機能をView Customizeで作成しました。

使い方

スクリプトを適用すると、チケット名の左にボタンが表示されます。

ボタンをクリックすると、「チケットID」「チケット題名」「URL」がクリップボードにコピーされます。
貼り付けると、以下の形式になります。

View Customizeの設定

パスのパターン:/issues
プロジェクトのパターン:
挿入位置:全ページの末尾
種別:JavaScript
// コピーボタンのスタイルを追加
const style = document.createElement('style');
style.innerHTML = `
  .vc_copyIssueInfo {
    position: relative;
    cursor: pointer;
    display: inline-block;
    overflow: hidden;
    text-indent: 100%;
    white-space: nowrap;
    width: 24px;
    height: 24px;
    background-position: center;
    background-repeat: no-repeat;
    background-size: 14px 14px;
    vertical-align: middle;
    background-color: #fff;
    border: 1px solid #bbb;
    font-size: 12px;
    line-height: 16px;
    margin-right: 4px;
    margin-top: -4px;
    padding: 0;
    border-radius: 6px;
    transition: background-image 0.2s;
    box-shadow: 0px 4px 6px -1px rgba(0, 0, 0, 0.10), 0px 2px 4px -2px rgba(0, 0, 0, 0.10);
  }

  .vc_copyIssueInfo:hover {
    background-color: #f0f2f3;
  }

  .vc_copyIssueInfo:active {
    background-color: #dde9ee;
  }
`;
document.head.appendChild(style);

// チケットタイトルの取得
function getCleanTitle(selector) {
  const el = document.querySelector(selector);
  if (!el) return '';

  const excludedElement = el.querySelector('button');

  let text = '';
  el.childNodes.forEach(node => {
    if (node.nodeType === Node.TEXT_NODE) {
      text += node.textContent;
    } else if (node.nodeType === Node.ELEMENT_NODE && node !== excludedElement) {
      text += node.textContent;
    }
  });

  return text;
}

// チケット情報のコピー
function quickCopy() {
  const requiredClasses = ['controller-issues', 'action-show']
  if(!requiredClasses.every(el => document.body.classList.contains(el))) return

  const copyBtn = document.createElement('button')
  copyBtn.textContent = 'チケット情報をコピー'
  copyBtn.title = 'チケット情報をコピー'
  copyBtn.className = 'vc_copyIssueInfo'
  copyBtn.classList.add('icon')
  copyBtn.classList.add('icon-copy')

  const issueIdAndTracker = document.querySelector('#content .issue .subject h3')
  if(issueIdAndTracker) {
    issueIdAndTracker.prepend(copyBtn)
  }

  copyBtn.addEventListener('click', (e) => {
    // urlの取得
    const url = encodeURI(window.location.href);

    // チケットIDの生成
    const pathSegments = new URL(url).pathname.split('/')
    const issueId = pathSegments[pathSegments.length - 1]

    // チケット題名の取得
    const issueSubject = getCleanTitle('#content .issue .subject h3')

    // [チケットID+題名 \n URL]の形を作る
    const issueInfo = `#${issueId} ${issueSubject}\n${url}`

    if(issueInfo) {
      navigator.clipboard.writeText(issueInfo).then(() => {
        copyBtn.classList.add('icon-checked')

        setTimeout(() => {
          copyBtn.classList.remove('icon-checked')
        }, 1250)
      }).catch(error => {
        console.log('チケットIDのコピーに失敗しました', error)
      })
    } else {
      console.log('チケットIDが取得できません')
    }
  })
}

window.addEventListener('DOMContentLoaded', () => {
  quickCopy()
})

注意

  • これらのスクリプトに関して、作者は作者としての権利を一切行使しません。
  • 商用利用ももちろんOKです。改変も自由です。再配布についても出所を示す必要はありません。
  • これらのスクリプトを利用した場合、いかなる支障が起きたとしてもその責任を負いません。ご利用は自己責任でお願いします。
  • また、不具合が発見された場合の改修やRedmineやLychee Redmineのバージョンアップに際してのメンテナンスの義務も負いません。
  • 上記についてご了承いただける方のみ、ご利用ください。

いいね!0