Skip to main content
View customize pluginを
使いこなす
2016-05-14
第10回redmine.tokyo勉強会
Hirokazu Onozato
@onozaty
自己紹介
• Hirokazu Onozato (onozaty) オノザティ
• https://twitter.com/onozaty
• https://github.com/onozaty
• http://www.enjoyxstudy.com/
• 株式会社ユニスティ所属
• エンジニア
• アプリケーション開発
• マネージメントも少々
個人で作ったもの
• 個人の時間を使って作ったものを公開
• http://www.enjoyxstudy.com/products.html
• Firefoxの拡張機能、JavaScriptライブラリなど
• suggest.js - 入力補完ライブラリ
http://www.enjoyxstudy.com/javascript/suggest/
• ShortcutKey2URL ‐ショートカットキーでURLを開くための
Firefoxの拡張機能
http://www.enjoyxstudy.com/firefox/extension/shortcutkey2url/
• IRCbot Console - ブラウザから操作できる多機能なIRCボット
http://www.enjoyxstudy.com/ircbotconsole/
RedmineのPlugin
• RedmineのPluginも2年くらい前から作り出した
• 業務であったらいいなと思うものを、プライベー
トな時間で作って公開+自分でも利用
• View customize
https://www.redmine.org/plugins/redmine_view_customize
• Parent issue filter
https://www.redmine.org/plugins/redmine_parent_issue_filter
• Copy parent issue id
https://www.redmine.org/plugins/copy_parent_issue_id
Redmineの使用状況
• Redmine使用歴6年
• 初めて触ったのは10年前だったが、その時はあまり
しっかり使わずに、6年前から継続して使用
• 現プロジェクトでは、0.9 から使い始めて、1.x、
2.x とマイグレーションを重ねて、今は3.1を利用
• チケット数は40,000超え
利用プラグイン
• View customize https://www.redmine.org/plugins/redmine_view_customize
• Parent issue filter https://www.redmine.org/plugins/redmine_parent_issue_filter
• Copy parent issue id https://www.redmine.org/plugins/copy_parent_issue_id
• Issue Template https://www.redmine.org/plugins/issue_templates
• Checklists https://www.redmine.org/plugins/redmine_checklists
• News Notification https://github.com/georz/redmine_news_notification
• その他自作Pluginも
View customize plugin
View customize plugin
• Redmineの画面をカスタマイズするためのPlugin
• https://www.redmine.org/plugins/redmine_view_customize
• https://github.com/onozaty/redmine-view-customize
• 特定の画面に対して、JavaScript、CSSを埋め込む
機能を提供
View customize plugin
• Redmine自体のコードを変更したり、プラグイン
を作ったりといった手間無く、手軽にカスタマイ
ズできる
• 再起動不要でカスタマイズを適用
≒UserScript
• UserScriptをクライアントではなく、サーバ側で
設定して、Redmineを使用する全ユーザに適用す
るイメージ
※UserScriptとは、画面ロード時に任意のJavaScriptを実行して
画面カスタマイズを行えるブラウザの機能
できることの例
• プロジェクト毎にヘッダの色を変える
• チケット一覧を識別しやすいように装飾
• チケット作成時にトラッカーに応じてデフォルト値を設定
• サイドバーを開閉式に
• 「全てのチケット一覧」リンクをヘッダに
• 進行中にもかかわらず担当者が未設定の場合に警告を表示
• ユーザ選択のカスタムフィールドで自分を選択する項目を先頭に追加
• プロジェクト一覧からの各プロジェクトへのリンク先を変更
• カスタムフィールドを連動させる(親の値に応じて、子を絞り込む)
• コンテキストメニューを選択しやすくする
注意点
注意点
• View customize pluginでは、画面側(JavaScript、
CSS)でしかカスタマイズできないため、出来ない
こともある
• 画面にない情報を表示するとか
注意点
• 画面だけでもいろいろ解決できることがあるが、
もしも欲しい機能に特化したプラグインがあるな
らば、そちらを使った方が良い
• 画面側だけの制約が無いので、シンプルな実装になっ
ているはず
• その機能の検証も十分行われているはず
使い方
インストール
• Redmineのインストールディレクトリ配下の
pluginsディレクトリに移動して、View customize
pluginのリポジトリをclone
※clone時のディレクトリ名はview_customizeとしてください
cd /var/lib/redmine/plugins
git clone https://github.com/onozaty/redmine-view-customize.git view_customize
rake redmine:plugins:migrate RAILS_ENV=production
インストールしただけでは…
• 何も変わらない
• View customize pluginは、Redmineの拡張方法を
提供するだけで、どう設定するかはユーザ次第
設定方法
• 管理 > View customize で一覧画面へ遷移し、
「New view customize」で設定入力画面へ
設定方法
コードを実行するパス(URL)。
正規表現で記載。
実行するコード。
JavaScript または
StyleSheet(CSS)で書く。
Redmineの画面で使用され
ているjQueryも使える。
(Redmineのバージョンに
よってライブラリが違うの
で注意)
プライベートにチェックを入れると、作成したユーザ
のみに有効
実行
• Pathが一致すると、画面にコードが埋め込まれて
実行される
View customizeを触るうえで
キーとなる技術
キーとなる技術
• JavaScript(ブラウザ上で動作するスクリプト言語)
とCSS(ページのデザインを定義する仕組み)で設定
するので、オリジナルのカスタマイズをしたい場
合には、それらの知識が必要となってくる
• ただ、カスタマイズをするにあたって、そこまで多く
の知識が求められるわけではないので、調べたり、見
よう見まねでもどうにかなるはず
• 実際JavaScriptやCSS知らなかった人でも、調べながらで使え
てたりする
jQuery
jQuery
• JavaScriptライブラリ
• https://jquery.com/
• RedmineではjQueryをすべての画面で読み込んで
いるので、View customizeでもjQueryが利用でき
る
jQuery
• jQueryを使うと、クロスブラウザによる違いの煩
わしさを吸収したり、DOM操作が簡潔に書けるの
で便利
• ただ、最近のブラウザだと標準で代替するようなメ
ソッドが提供されているので、IE8捨てられるならば、
jQuery使うまでもないかも
• WebにjQueryの情報はあふれているので、調べる
のも簡単
CSSセレクタ
CSSセレクタ
• CSSセレクタとは、CSSでスタイルを適用する対象
を示すもの
• View customizeでも良く使うことになる
• JavaScriptで指定要素を取得するとき
• jQueryの$(selector)関数
• CSSで対象を指定するとき
div#header h1
設定に関するノウハウ
対象画面の指定方法
Path pattern
• Path patternに一致した画面の場合、該当のスクリ
プトが埋め込まれる
• 正規表現で記載する
URLとPath
• URLでアプリケーション配下がPath
• クエリパラメータは含まれない
• http://example.com/projects
-> /prjects
• http://example.com/projects/a/issues?set_filter=1
-> /projects/a/issues
• http://example.com/redmine/projects
※ドキュメントルートではなく、/redmineとしてインストール
-> /prjects
Pathを確認する方法
• バージョン1.1.4から、HTMLにPathをコメントと
して埋め込むようになっている
• ブラウザのソース表示で見ればその画面のPathが
わかる!
指定例 (よくつかうもの)
Path pattern 一致する画面
.* 全ての画面
/issues$ チケット一覧
/issues/new$ チケットの新規作成画面
/issues/[0-9]+$ 個々のチケット内容表示画面
/issues/[0-9]+/copy$ チケットのコピーによる作成画面
/issues/gantt ガントチャート
/projects$ プロジェクト一覧
.*[]+$ といった文字は、正規表現におけるメタ文字(特殊な意味をもった文字)
チケットの入力フォーム
• チケットの入力フォームは、いろいろな画面で存
在するので、Pathの指定だけだと面倒
• /issues/1 ○チケット内容表示画面でも編集ボタンでフォームが
• /issues/new ○新規作成
• /issues/1/copy ○コピーによる作成画面
• /issues/gantt ×ガントチャートなので、これは一致させたくない
• /issues ×チケット一覧の場合 ○チケット登録時のValidationエラーの場合
Path pattern + JavaScriptで絞る
• “/issues” と指定して、JavaScript側でチケットの入
力フォームが無かったら処理しないようにする
• チケットの入力フォームでしか存在しない要素
(#issue-form とか)で確認する
• 指定した要素が無かった場合でも処理がスキップされ
るように書いていればOK
jQueryの$(selector)関数
• jQueryの$(selector)関数で返却されるjQueryオブジェクト
は、一致する要素が無かった場合、何も処理されないので、
それを使っていれば大丈夫
• 上記例だと、入力フォームが無かった場合、on関数でのイベント
登録が行われず、何も処理されないことになる
(エラーにもならない)
$('#issue-form input[type="submit"]')
.on('click', function(event) {
// 送信ボタン押下時に何か処理を行わせる
});
プロジェクト毎の指定
• チケット詳細画面(/issues/1 など)は、プロジェク
トをパスに持たないので、Pathだけだとプロジェ
クトを指定できない
• /projects/prj1/issues
• /projects/prj1/issues/1 ×これはパスとして無効
• /issues/1 ○チケット詳細はプロジェクト関係なく固定パス
body要素に付与されるclass属性で判断
• body要素のclass属性に project-プロジェクト識別
子 が設定されるので、これを使ってプロジェクト
を識別する
JavaScriptでプロジェクトを判定
• jQueryの.hasClass()関数で指定のクラス名が存在
するかチェックできる
• または、class属性を取り出して比較するなど
if ($('body').hasClass('project-prj1')) {
// プロジェクト識別子が'prj1'の場合
}
CSSでプロジェクトを指定
• CSSのセレクタでbodyのclassを利用するだけ
body.project-prj1 #top-menu {
background-color: #006400; /* dark green */
}
body.project-prj1 #header {
background-color: #008000; /* green */
}
class属性が振られるもの
• プロジェクト以外にも、class属性が振られるもの
が多々あるので、対象画面や対象箇所を限定する
のに使用できる
class属性が振られるもの
• body要素
• controller-{コントローラ名}
• action-{アクション名}
• チケット一覧の各行
• tracker-{トラッカーID}
• status-{ステータスID}
• priority-{優先度ID}
• created-by-me
class属性が振られるもの
• 他にもいろいろあるので、詳しくは「Redmineの
画面で振られているclass属性について -
Enjoy*Study」にて
• http://blog.enjoyxstudy.com/entry/2014/10/11/000000
コード(JavaScript)の書き方
ブラウザの開発者ツールを活用
ブラウザの開発者ツール
• いきなりView customizeで設定するのではなく、
ブラウザの開発者ツールを使いながら作成、確認
する
• DOMインスペクタ
• コンソール
ブラウザの開発者ツール
• 開発者ツールは、Chrome、Firefox、IE それぞれ
のブラウザに標準でも入っている
• Firefoxだと拡張機能のFirebugでもOK
• 愛用しているので、以降のキャプチャはFirebugにて
DOMインスペクタ
• 選択した要素がHTML上でどういった構造で書か
れているか確認できる
• ソース表示で見るより簡単
コンソール
• 表示している画面に対してのJavaScriptの実行を手
軽に試せる
• 補完も効く(複数行モードの場合はダメ)
コンソール
• 複数行まとめて実行できるものもあり、長めの
コードでも修正、実行を繰り返し行える
実際に試してみる
例:ヘッダにチケット一覧リンクを追加
• やること
1. どこに要素を追加すればよいか調べる
2. その要素を起点に、リンクを追加するコードを書く
3. うまくいったら、View customize で設定
(いったんプライベートで)
4. 動作することが確認できたら、プライベートを外し
て全体に反映
追加位置を調べる
• DOMインスペクタで追加したい位置を選択
追加位置を調べる
• パスを確認
• id属性がtop-menuとなっているdiv要素配下のul要素の
最後に追加してあげればよさそう
追加位置を調べる
• コンソールで追加対象の要素を取得してみる
• div#top-menu > ul (id属性がtop-menuのdiv要素の子
のul要素) で取れた
リンクを追加するコードを書く
• 対象のul要素の子要素として、リンクを追加する
コードを実行し、思った動作になるまで確認
View customizeで設定
• 画面の描画完了時にコードを実行する必要がある
(描画完了前だと、要素が取得できない)ので、
jQueryの$(function)関数を利用
$(function() { // ロード完了時に呼び出される
$('#top-menu > ul')
.append('<li><a href="/issues">全てのチケット</a></li>');
});
View customizeで設定
• いったんプライベートで設定し、動作を確認する
• 動作OKでプライベートを外して、全体に有効へ
コード(CSS)の書き方
JavaScriptの時と同じ
• DOMインスペクタで、変更したい要素を探す
• CSSセレクタがどうなりそうかも確認しておく
• 要素のスタイルを変えて試す
CSSをView customizeに設定
• Path Patternは絞れるならば絞って問題ないが、
CSSセレクタ自体で対象箇所が絞ってかけるので、
全画面対象でもほとんど問題なし
• そのままCSSを書くイメージ
CSSセレクタの書き方
CSSセレクタの確認
• DOMインスペクタを使うことによって、CSSセレ
クタはわかる
CSSセレクタの指定
• bodyからすべてのパスを書く必要はなく、id属性
が付与されているものを起点に考えると良い
• id属性は、一意のものになるので
body div#wrapper div#wrapper2 div#wrapper3 div#header h1
div#header h1
bodyからのフルパス
こっちで十分
良く使うCSSセレクタ
他にもいろいろあるので、詳しくない場合には
”CSSセレクタ”で一度調べておくと良い
セレクタ名 書式 対象
型セレクタ E E要素
idセレクタ E#myid id名がmyidのE要素
classセレクタ E.warning class名がwarinigのE要素
子孫セレクタ E F E要素の子孫にあたるF要素
子セレクタ E > F E要素の子にあたるF要素
(子孫セレクタは、E要素の配下ならば、ど
こにあっても良いが、子セレクタは、1階層
下のみが対象)
CSSセレクタで気を付けること
• 必要のない要素と一致させない
• 一致してしまう場合には、条件をもっときつく
• 単に要素を指定するのではなく、要素+属性で指定す
る(idセレクタ、classセレクタなど)
• 子孫セレクタではなく子セレクタを使うなど
うまく動作しないときの
確認ポイント
Path patternがあっているか
• 画面のソースを表示して、View customizeで指定
したコードが埋め込まれているか確認
• 埋め込まれていない場合、Path patternが間違えている
ので、Path patternを見直す
JavaScriptでエラーが発生していないか
• 開発者ツールで、エラーメッセージが出力されて
いないか確認
• エラーメッセージが出力されていれば、それをもとに
JavaScriptを修正
CSSが上書きされていないか
• 複数のCSSが一致する場合、その要素に対してど
のようなスタイルが適用されるかは、優先度に
よって決まる
• 該当の要素を詳細に指定している方が優先される
• 型セレクタよりidセレクタで指定したものの方が優先
• セレクタのレベルが同じならば、後に書かれたものが
優先される
CSSが上書きされていないか
• 上にあるほどもの優先度が高い
• 取り消し線のものは、優先度が高いものによって上書きさ
れているもの
チケットの入力フォームがらみは面倒
• チケットの入力フォームは、トラッカーまたはス
テータスが変わると、フォームの再読み込みが行
われる(#all_attributes配下が差し替わる)
• これは、トラッカーやステータスによって入力可能な
フィールドや選択肢が変わるため
• これにより入力フォームの各要素に対する変更(内
容変更や、イベントの登録)は、リセットされてし
まう
チケット入力フォームに対するイベント
• 入力フォームが差し替わってもハンドリングでき
るようにする必要がある
• 考え方としては、親の要素に対してイベントを登
録しておいて、イベントが発生した際に発生元が
該当のものか判断するようなイメージ
• jQueryのon関数を使うと簡単に書ける
チケット入力フォームに対するイベント
• ダメな例
これだと、入力フォームが差し替わったタイミングで登録先の要素
(#issue_status_id)が別物に変わってしまうのでうまく動かない
• OKな例
documentに対してイベントハンドラを登録し、該当の要素(#issue_status_id)
が発生元だったら動作するように書くことによって、#issue_status_idが差し
替わってもハンドリング可能に
$('#issue_status_id')
.on('change', function(e) {
// ステータス変更時に実施したい処理
});
$(document)
.on('change', '#issue_status_id', function(e) {
// ステータス変更時に実施したい処理
});
チケット入力フォームに対する変更
• 入力フォームが差し替わると、変更した内容も元
に戻ってしまうので、差し替わったタイミングで
処理する必要がある
• たとえば、カスタムフィールドの値に応じて、他のカ
スタムフィールドで選択可能な値を絞る場合など
チケット入力フォームに対する変更
• 差し替え処理を行っている関数をフックして、差
し替え処理の後に処理を差し込む
• replaceIssueFormWith 関数が、差し替え処理を行って
いる関数なので、そこを対象に
// 関数を別名で退避
var _replaceIssueFormWith = replaceIssueFormWith;
// 関数を中身を変更
// 退避した処理を呼び出すような関数として作り変える
replaceIssueFormWith = function(html) {
// 退避しておいた関数を呼び出し
_replaceIssueFormWith(html);
// ここでフォーム差し替え後に
// やりたい処理を書く
};
View customize導入に向けて
試す環境を作る
• プロジェクトで使っているRedmineにいきなり適
用するのは敷居が高いという場合には、まずは仮
想環境などで試してみる
• Redmineの各バージョンのVagrant boxを公開している
ので、そちらを使えばすぐに
vagrant init onozaty/redmine-3.2
vagrant up
スクリプトを書いてみる
• この資料を参考に書いてみる
• スクリプトのサンプルは、下記リポジトリに貯め
ていっているので参考に
• https://github.com/onozaty/redmine-view-customize-scripts
• これからもだんだん増えていく予定
困ったときには
困ったときには…
• @onozaty まで (follow me!!)
• 即レスとまでいきませんが、毎日確認してます
• スクリプト例などもつぶやいています
困ったときには…
• こういうことできませんか?といった質問も、お
気軽にどうぞ
• 一応、全部答えている(できるものはBlogでも公開)つ
もりですが、拾えてなかったらごめんなさい
おわり