view customize pluginでさらに遊ぶ。そうだ、Redmineに投票機能を付けよう。

[Redmine Advent Calendar 2021](https://adventar.org/calendars/62832)　23日目参加です。
今年はRedmineに関する昔の話を書こうかと思ったのですが、もう少し楽しすぎる[view customize plugin]( 
https://github.com/onozaty/redmine-view-customize) [^1]に関するネタがあるので書き留めておきます。
ちなみに相変わらずバージョンは上がらずネタも古いです。
でも楽しかったので記す。

今回機能は、[【Redmineのカスタムフィールドに＋１ボタン的なものを追加する】](https://qiita.com/tanahashi_kei/items/426992eeb4c8b48934d8) [@tanahashi_kei](https://qiita.com/tanahashi_kei)）さんの記事を参考にさせていただきました。
ありがとうございます。[^2]


#目次
1.[まずはカスタムフィールドを用意する](#1-カスタムフィールド作成)
2.[編集画面に入らなくて投票できるようにしたい](#2-投票ボタンを追加しよう)
3.[新規チケット作成時から投票したい](#3-新規チケット作成画面にも投票ボタンを追加しよう)
4.[おしまいに](#4-おしまいに)

---
#1. カスタムフィールド作成 [^3]
こんな感じで作成。
![00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332990/024595ab-9cdd-5ebe-7261-dd198d3590ed.png)

参考先様[【Redmineのカスタムフィールドに＋１ボタン的なものを追加する】](https://qiita.com/tanahashi_kei/items/426992eeb4c8b48934d8) に従って、さくっとラベルボタンまで追加。
![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332990/05205725-704b-c58d-24dd-fee61400d636.png)

#2. 投票ボタンを追加しよう 
こんな感じの投票ボタンを作ります。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332990/29153332-073d-3d34-8b36-7416d553ffc4.png)

###2-1. まずは箱をつくる
```ruby:qiita.javascript
PathPattern://issues/[0-9]+
Type:CSS
挿入位置:チケット詳細の下
/* Good */
button.button1 {
  width:100px;
  height:30px;
  line-height:30px;
  text-align:center;
  font-size: 12pt;
  text-decoration: none;
  background: #fffffe;
  color: #67c5ff;
  border: solid 1px #67c5ff;
  border-radius: 3px;
  transition: .4s;
}

button.button1:hover {
  background: #67c5ff;
  color: white;
}

/* フォーカスの青枠排除 */
button.button1:focus {
	outline:0;
}

/* No Good */
button.button2 {
  width:100px;
  height:30px;
  line-height:30px;
  text-align:center;
  font-size: 12pt;
  text-decoration: none;
  background: #fffffe;
  color: #FF6786;
  border: solid 1px #FF6786;
  border-radius: 3px;
  transition: .4s;
}

button.button2:hover {
  background: #FF6786;
  color: white;
}

/* フォーカスの青枠排除 */
button.button2:focus {
	outline:0;
}
```
###2-2. チケット詳細画面にぺたり
```ruby:qiita.javascript
PathPattern://issues/[0-9]+
Type:JavaScript
プロジェクトのパターン:redmine_req
$(function () {
    /* 投票用カスタムフィールドがある場合のみ適用 */
    if (!$(".cf_1 div").length) {
        return;
    }

    /* チケット詳細画面に投票ボタン「Good」「No Good」追加 */
    $('div.subject').before('<button id="btn1" class="button1" title="この機能欲しい！">Good</button>');
    $('#btn1').click(function () {
        update_good();
    });

    $('div.subject').before('<button id="btn2" class="button2" title="別にいらない">No Good</button><div>　</div>');
    $('#btn2').click(function () {
        downdate_bad();
    });

 var changeCustomFieldPositon = function(){
   /* 編集画面処理 */
   var field = $('#issue_custom_field_values_1');
   field.hide();

   /* チケット詳細画面に投票ボタン「＋」「－」追加 */
   var plus_btn = '<button type="button" class="count_up_btn">+1</button>';
   field.after(plus_btn);
   
   var minus_btn = '<button type="button" class="count_down_btn">-1</button>';
   $('.count_up_btn').after(minus_btn);

   /* テキスト枠をラベル化する、ベタ打ちで書き換えさせないぞ */
   var count = ' : <span class="issue_custom_field_values_1_label">'+ field.val() +'</span>';
   $('.count_down_btn').after(count)

   $('.count_up_btn').on('click', function () {
     var label = $('.issue_custom_field_values_1_label');
     var num = Number(field.val()) + 1;
     field.val(num);
     label.text(num);
   });

   $('.count_down_btn').on('click', function () {
     var label = $('.issue_custom_field_values_1_label');
     var num = Number(field.val());

     if(num > 0){
        var num = Number(field.val()) - 1;
     }
     field.val(num);
     label.text(num);
   });
 };

  /* 初期変換 */
  changeCustomFieldPositon();

  /* ステータス変更時など、DOMが差し替えられるたびに実施 */
  var _replaceIssueFormWith = replaceIssueFormWith;
  replaceIssueFormWith = function(html){

    _replaceIssueFormWith(html);
    changeCustomFieldPositon();
  };
});

var update_good = function () {
    setTimeout(function() {
        $("#issue_custom_field_values_1").val(parseInt($("#issue_custom_field_values_1").val()) + 1);
        $("#issue-form").submit();
    }, 300);
};

var downdate_bad = function () {
    setTimeout(function() {
        var num = $("#issue_custom_field_values_1").val();

        if(num > 0){
           $("#issue_custom_field_values_1").val(parseInt($("#issue_custom_field_values_1").val()) - 1);
           $("#issue-form").submit();
        }
    }, 300);
};
};
```
こんな感じ。
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332990/443905a4-8f36-db09-fd36-a4f4fb37538e.png)
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332990/d5daad17-33c3-be47-68e1-5ecaff063361.png)
「Good」を投票してみた。
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332990/1405239a-c7c8-e946-d365-5aacace10a52.png)

#3. 新規チケット作成時から投票したい。
新規チケット作成画面から投票できるようにしてみた。
自分で要望だして自分で点数増やすマッチポンプ！
まあよかろう。

```ruby:qiita.javascript
PathPattern://issues/[0-9]+
Type:JavaScript
プロジェクトのパターン:redmine_req
$(function () {
  /* 編集画面処理と同じ */
  var field = $('#issue_custom_field_values_1');
  field.hide();

   var plus_btn = '<button type="button" class="count_up_btn">+1</button>';
   field.after(plus_btn);
   
   var minus_btn = '<button type="button" class="count_down_btn">-1</button>';
   $('.count_up_btn').after(minus_btn);


  /* テキスト枠をラベル化する */
   var count = ' : <span class="issue_custom_field_values_1_label">'+ field.val() +'</span>';
   $('.count_down_btn').after(count)

   $('.count_up_btn').on('click', function () {
     var label = $('.issue_custom_field_values_1_label');
     var num = Number(field.val()) + 1;
     field.val(num);
     label.text(num);
   });

   $('.count_down_btn').on('click', function () {
     var label = $('.issue_custom_field_values_1_label');
     var num = Number(field.val());

     if(num > 0){
        var num = Number(field.val()) - 1;
     }
     field.val(num);
     label.text(num);
   });
});
```
新しいチケット作成画面にも投票ボタンつきました。
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332990/d6267f84-1599-afa5-f4ad-006cccb7fdad.png)
チケット起票時には既に投票されてる状態に出来る。
なんの意味があるのなんてことは言ってはいけない。
![8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332990/bac5eb13-604b-3840-a583-525ded1f18e5.png)
投票結果は履歴にも残ります。
![9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332990/f2798fa1-51fc-0541-dd83-a5bf4fcb19c2.png)


#4. おしまいに
以上、以前に引き続き「素人でもなんとかなる！」を表明する記事でした。
不便と便利を追求すると素人でもなんとかなります。
この部分こう変更したらイケる？と思って試してみられるのがview customize pluginの素晴らしいところです。感謝。


[^1]: いつもお世話になっております。
[^2]: もうお一方いらしたんだけど私がもたもたしている間に404になってしまった……。
[^3]: 前回記事でこんなこと言ってましたが、今回復活させられました。→「本当は投票機能について記事書こうと思ってたんですが、砂場ごっそり消されたorz バックアップは取ってあるけど、生き残っている環境でテストしてないのでまた今度。」
[^3]: 先人の知恵にはいつも助けられています。