3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

User JavaScript and CSS (Chrome 拡張機能) を使って Redmine をカスタマイズしてみた

Last updated at Posted at 2019-12-04

こちらの記事は free_dev_com Advent Calendar 2019 - Adventar 7 日目の記事です。

User JavaScript and CSS とは

Chrome の拡張機能として提供されている,既存のウェブサイトに独自の Javascript や CSS を埋め込むライブラリです.
User JavaScript and CSS - Chrome ウェブストア

これを利用して,ダークモードがないウェブサイトにダークモードを実装してみたり, Yahoo! のサイトに自分の好きなキャラクターのイラストを表示させたり,いろいろなことができます.
今回は,社内のタスク管理に使用している Redmine で,チケットの説明に出てくるスニペットの内容をクリップボードにコピーする機能を Javascript で実装してみました.

画面設計

スニペットの枠外,右下部分にコピーのアイコンを配置し,

copy.png

アイコンをクリックすると「コピーしました!」のダイアログを表示することにします.

copied.png

実装

アイコンを読み込む

今回は Font Awesome のアイコンを使用します.
Font Awesome についてはこちら

流れは次の通りです.

  • Font Awesome を読み込む link タグを作成する
  • head タグを取得し,その子要素として先ほど作成した link タグを追加する
redmine.js
const link = document.createElement('link');
link.setAttribute('rel', 'stylesheet');
link.setAttribute('href', 'https://use.fontawesome.com/releases/v5.6.3/css/all.css');

document.getElementsByTagName('head')[0].appendChild(link);

スニペットの枠外,右下部分に要素を配置する

流れは次の通りです.

スニペット (pre タグ) を取得する -> 各スニペットが配列で取れます

各スニペットに対して,次の処理を行う

  • コピーボタンを配置するための p タグを作成する (snippet)
  • 後にコピーボタンとなる span タグを作成する (copyButton)
  • (copyButton に title, innerHTML, className などの属性を設定する)
  • copyButton にクリックのイベントリスナーを付与する (内容は下記)
    • コピー対象となる textarea タグを作成 (textarea タグでなくても行けるかもしれません)
    • スニペット内の文章を textarea タグに設定する
    • 作成した textarea タグを body タグの子要素として配置 -> 選択 -> コピー
    • textarea タグは不要になるので取り除く
    • コピーが完了した旨のメッセージを表示
  • copyButton を snippet の直後に配置する
redmine.js
// スニペットのタグを選択
const snippets = document.getElementsByTagName('pre');
// console.log(snippets); // HTMLCollection
// console.log(typeof snippets); // object

// コピーボタンを配置
Object.keys(snippets).forEach(function (index) {
    let snippet = snippets[index];
    let p = document.createElement('p');
    p.className = 'copy-snippet';

    let copyButton = document.createElement('span');
    copyButton.title = 'Copy to Clipboard';
    copyButton.innerHTML = '<i class="far fa-copy"></i> Copy';
    copyButton.className = 'copy-button';

    copyButton.addEventListener('click', function () {
        let copyTarget = document.createElement('textarea');
        copyTarget.textContent = snippet.innerText.trim(); // 見た目に合わせて文末改行削る?
        let body = document.getElementsByTagName('body')[0];
        body.appendChild(copyTarget);
        copyTarget.select();
        document.execCommand("copy");
        body.removeChild(copyTarget);
        // 後処理まで終わったらおまけ
        (function () {
            alert('コピーしました!');
        })();
    });
    p.appendChild(copyButton);
    snippet.parentNode.insertBefore(p, snippet.nextSibling);
});

その他

画面右下にカエルのイラストを入れて,全体を CSS で整えます.

redmine.js
// カエルがペコペコおじぎする GIF
const imageUrl = 'https://sozai-good.com/download?id=2451&type=7&subnumber=0&extention=gif';

// 画像挿入処理
let img = document.createElement('img');
img.id = 'inserted-image';
img.height = 105;
img.src = imageUrl;
const wrapper = document.getElementById('wrapper');
wrapper.parentNode.insertBefore(img, wrapper.nextSibling);
redmine.css
#wrapper, #main {
    background-image: url("https://www.pakutaso.com/shared/img/thumb/mizuho1102dssd_TP_V.jpg");
    background-repeat: no-repeat;
    background-size: cover;
    background-attachment: fixed;
    opacity: 0.96;
}

#top-menu {
    /*background-color: darkgreen;*/
    background-color: rgba(10, 106, 10, 0.9);
}

#header, #footer {
    /*background-color: forestgreen;*/
    background-color: rgba(0, 0, 0, 0.5);
}

#main-menu li a {
    /*background-color: darkgreen;*/
    background-color: rgba(10, 106, 10, 0.6);
}

#main-menu li .selected {
    color: lightgreen;
}

#content {
    margin-bottom: 20px;
}

#sidebar {
    background-color: white;
}

#footer {
    position: fixed;
    background-color: black;
    right: 0;
    bottom: 0;
}

pre, .CodeRay {
    font-family: Monaco, monospace;
}

#inserted-image {
    position: fixed;
    right: 25px;
    bottom: 45px;
}

.copy-snippet {
    text-align: right;
}

.copy-button {
    cursor: pointer;
    background: none;
    border: 0;

    /* settings when hovered */
    /*transition: color 0.1s linear;*/
}

.copy-button:hover {
    color: red;
}

Redmine の公式ページを表示してみる

Defect #32525: CSV related tests fail with Rails 5.2.4 - Redmine

sample_page.png

やったー!

効用

  • 「コマンドはコピペして貼り付ける」のが暗黙のルールとなっている本番環境へのリリース作業において,逐一スニペットの中身をマウスで選択する手間が省けます.
  • 自分の画面だけに実装されるので,他の人に自慢できます.
  • フロント周りがちょっとだけ楽しくなります.
3
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?