Skip to content

Commit 8ea7cce

Browse files
authored
Merge pull request #65 from onozaty/develop/2.7.0
Develop 2.7.0
2 parents 18872a9 + 9298d08 commit 8ea7cce

24 files changed

+354
-53
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.vagrant/

README.ja.md

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,27 +36,34 @@ bundle exec rake redmine:plugins:migrate RAILS_ENV=production
3636

3737
![Screenshot of new](screenshots/new.en.png)
3838

39-
「Path pattern」は正規表現で指定します。ページのパスと一致すると、コードを挿入して実行します。
39+
「Path pattern」と「Project pattern」を使って、対象のページを指定します。
40+
どちらも指定されていなかった場合には、全てのページが対象になります。
41+
42+
「Path pattern」は正規表現でパスを指定します。
43+
「Path pattern」が設定されていた場合、ページのパスが一致しないと、コードが挿入されません。
44+
4045
以下は設定例です。
41-
* `.*` : 全てのページ
4246
* `/issues$` : チケット一覧
4347
* `/issues/[0-9]+` : 個々のチケットの内容表示画面
4448

49+
「Project pattern」は正規表現でプロジェクトの識別子を指定します。v2.7.0にて追加された項目になります。
50+
「Project pattern」が設定されていた場合、プロジェクトが一致しないと、コードが挿入されません。
51+
4552
「Insertion position」は、コードの挿入位置です。v1.2.0にて追加された項目になります。
4653
* 「Head of all pages」 : 全てのページのヘッダ部分。(v1.2.0より前のバージョンと同じ位置)
4754
* 「Bottom of issue form」 : チケットの入力欄の下部。<br>
4855
チケットの入力欄は、トラッカーやステータスを変えると再構成されますが、「Bottom of issue form」を指定しておくと再構成された際に再度実行されるので、入力欄に対する処理はこれを指定すると便利です。
4956
* 「Bottom of issue detail」 : チケットの詳細表示の下部。
5057

51-
該当ページにコードの挿入位置に該当する箇所が無かった場合、コードは埋め込まれません。たとえば、「Path pattern」`.*`で全ページを指定しても、「Insertion position」に「Bottom of issue detail」を指定していると、チケットの詳細表示画面でしか実行されないことになります
58+
該当ページにコードの挿入位置に該当する箇所が無かった場合、コードは埋め込まれません。たとえば、「Path pattern」と「Project pattern」の設定が無く、全ページが対象となっても、「Insertion position」に「Bottom of issue detail」を指定していると、チケットの詳細表示画面でしかコードが実行されないことになります
5259

5360
「Type」にてコードの種類(「JavaScript」、「CSS」または「HTML」)を選択し、「Code」に実際のコードを入力します。
5461

5562
「Comment」にはカスタマイズに対する概要を記載できます。ここで入力した内容は、一覧表示で表示されます。(Commentが入力されていればComment、Commentが入力されていない場合はCodeが一覧に表示)
5663

5764
「Create」ボタン押下で新規カスタマイズの追加が完了です。
5865

59-
「Path pattern」に一致したページで指定のコードが実行され、画面がカスタマイズされるようになります。
66+
「Path pattern」と「Project pattern」に一致したページで、「Insertion position」で指定した位置にコードが埋め込まれ、画面がカスタマイズされるようになります。
6067

6168
![Screenshot of example](screenshots/example.en.png)
6269

README.md

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,19 @@ Click "New view customize" and enter items.
3636

3737
![Screenshot of new](screenshots/new.en.png)
3838

39-
"Path pattern" is specified by regular expression. If it matches the path of the page, insert the code and execute it.
39+
Use "Path pattern" and "Project pattern" to specify the target page.
40+
If neither is set, all pages will be targeted.
41+
42+
"Path pattern" is a regular expression to specify the page path.
43+
If a path pattern was set, the code will not be inserted if the path of the page do not match.
4044

4145
The following is an example.
42-
* `.*` : All pages
4346
* `/issues$` : Issue list
4447
* `/issues/[0-9]+` : Issue detail page
4548

49+
"Project pattern" is a regular expression to specify the project identifier. It becomes item added in v2.7.0.
50+
If the project pattern was set, the code will not be inserted if the current project do not match.
51+
4652
"Insertion position" is the code insertion position. It becomes item added in v1.2.0.
4753

4854
* "Head of all pages" (The same position as the version before v1.2.0)
@@ -51,7 +57,7 @@ Issue input fields are reconstructed when trackers or statuses are changed. If "
5157
* "Bottom of issue detail"
5258

5359
If there is no part corresponding to the insertion position of the code on the page, the code is not insert.
54-
For example, even if you specify `.*` in "Path pattern", if "Bottom of issue detail" is specified for "Insertion position", it will be executed only on the issue detail page.
60+
For example, even if there are no "Path pattern" and "Project pattern" settings and all pages are targeted, if "Bottom of issue detail" is specified for "Insertion position", it will be executed only on the issue detail page.
5561

5662
In "Type", select the type of code ("JavaScript", "CSS" or "HTML") and enter the actual code in "Code".
5763

@@ -61,7 +67,7 @@ If "Comment" is not entered, "Code" is displayed in the list.
6167

6268
Addition is completed by clicking "Create" button.
6369

64-
The specified code is executed on the page that matches "Path pattern", and the page will be customized.
70+
On the page that matches the "Path pattern" and "Project pattern", the code will be embedded at the position specified in "Insertion position", and the page will be customized.
6571

6672
![Screenshot of example](screenshots/example.en.png)
6773

Vagrantfile

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
Vagrant.configure("2") do |config|
2+
config.vm.box = "onozaty/redmine-4.1"
3+
config.vm.network "private_network", ip: "192.168.33.10"
4+
5+
config.vm.synced_folder ".", "/var/lib/redmine/plugins/view_customize", mount_options: ['dmode=777','fmode=755']
6+
7+
config.vm.provider "virtualbox" do |vb|
8+
vb.memory = "1024"
9+
end
10+
end

app/controllers/view_customizes_controller.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,6 @@ def find_view_customize
6868

6969
def view_customize_params
7070
params.require(:view_customize)
71-
.permit(:path_pattern, :customize_type, :code, :is_enabled, :is_private, :insertion_position, :comments)
71+
.permit(:path_pattern, :project_pattern, :customize_type, :code, :is_enabled, :is_private, :insertion_position, :comments)
7272
end
7373
end

app/models/view_customize.rb

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
class ViewCustomize < ActiveRecord::Base
22
belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
33

4-
validates_presence_of :path_pattern
54
validates_length_of :path_pattern, :maximum => 255
5+
validates_length_of :project_pattern, :maximum => 255
66

77
validates_presence_of :code
88

@@ -61,11 +61,22 @@ def available?(user=User.current)
6161
end
6262

6363
def valid_pattern
64-
begin
65-
Regexp.compile(path_pattern)
66-
rescue
67-
errors.add(:path_pattern, :invalid)
64+
if path_pattern.present?
65+
begin
66+
Regexp.compile(path_pattern)
67+
rescue
68+
errors.add(:path_pattern, :invalid)
69+
end
6870
end
71+
72+
if project_pattern.present?
73+
begin
74+
Regexp.compile(project_pattern)
75+
rescue
76+
errors.add(:project_pattern, :invalid)
77+
end
78+
end
79+
6980
end
7081

7182
def initialize(attributes=nil, *args)

app/views/view_customizes/_form.html.erb

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,20 @@
22
<div class="box tabular">
33
<p>
44
<%= form.text_field :path_pattern,
5-
:size => 100, :required => true %>
5+
:size => 100 %>
66
<em class="info">
77
<%= l(:text_path_pattern_info) %><br />
88
<%= l(:text_path_pattern_match_info) %>
99
</em>
1010
</p>
11+
<p>
12+
<%= form.text_field :project_pattern,
13+
:size => 100 %>
14+
<em class="info">
15+
<%= l(:text_project_pattern_info) %><br />
16+
<%= l(:text_project_pattern_match_info) %>
17+
</em>
18+
</p>
1119
<p>
1220
<%= form.select :insertion_position,
1321
options_for_select(

app/views/view_customizes/index.html.erb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
<tr>
1616
<%= sort_header_tag('id', :caption => '#') %>
1717
<%= sort_header_tag('path_pattern', :caption => l(:field_path_pattern)) %>
18+
<%= sort_header_tag('project_pattern', :caption => l(:field_project_pattern)) %>
1819
<%= sort_header_tag('insertion_position', :caption => l(:field_insertion_position)) %>
1920
<%= sort_header_tag('customize_type', :caption => l(:field_customize_type)) %>
2021
<%= sort_header_tag('comments', :caption => l(:field_comments) + ' / ' + l(:field_code)) %>
@@ -27,6 +28,7 @@
2728
<tr class="<%= cycle('odd', 'even') %><%= ' disable' unless view_customize.is_enabled %><%= ' private' unless !view_customize.is_private %>">
2829
<td class="id"><%= link_to view_customize.id, view_customize_path(view_customize.id) %></td>
2930
<td class="path"><%=h view_customize.path_pattern %></td>
31+
<td class="project_pattern"><%=h view_customize.project_pattern%></td>
3032
<td class="insertion_position"><%=h l(view_customize.insertion_position_label) %></td>
3133
<td><%=h l(view_customize.customize_type_label) %></td>
3234
<td class="comments"><%=h view_customize.comments.present? ? view_customize.comments : truncate(view_customize.code, :length => 80) %></td>

app/views/view_customizes/show.html.erb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@
1717
<th><%=h l(:field_path_pattern) %></th>
1818
<td><%=h @view_customize.path_pattern %></td>
1919
</tr>
20+
<tr>
21+
<th><%=h l(:field_project_pattern) %></th>
22+
<td><%=h @view_customize.project_pattern %></td>
23+
</tr>
2024
<tr>
2125
<th><%=h l(:field_insertion_position) %></th>
2226
<td><%=h l(@view_customize.insertion_position_label) %></td>

config/locales/en.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
# English strings go here for Rails i18n
21
en:
32
label_view_customize: "View customize"
43
label_view_customize_plural: "View customizes"
@@ -12,6 +11,7 @@ en:
1211
label_insertion_position_issue_form: "Bottom of issue form"
1312
label_insertion_position_issue_show: "Bottom of issue detail"
1413
field_path_pattern: "Path pattern"
14+
field_project_pattern: "Project pattern"
1515
field_insertion_position: "Insertion position"
1616
field_customize_type: "Type"
1717
field_code: "Code"
@@ -20,5 +20,7 @@ en:
2020
field_is_enabled: "Enabled"
2121
field_author: "Author"
2222
text_path_pattern_info: "Path pattern is specified with a regular expression. (ex. /issues/[0-9]+)"
23-
text_path_pattern_match_info: "If there is a match with the path of the page, insert the following code and execute it."
23+
text_path_pattern_match_info: "If a path pattern was set, the code will not be inserted if the path of the page do not match."
24+
text_project_pattern_info: "Project (identifier) pattern is specified with a regular expression. (ex. sample-proj-a|sample-proj-b)"
25+
text_project_pattern_match_info: "If the project pattern was set, the code will not be inserted if the current project do not match."
2426
option_create_api_access_key: "Automatically create API access key"

config/locales/ja.yml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,16 @@ ja:
1111
label_insertion_position_issue_form: "チケット入力欄の下"
1212
label_insertion_position_issue_show: "チケット詳細の下"
1313
field_path_pattern: "パスのパターン"
14+
field_project_pattern: "プロジェクトのパターン"
1415
field_insertion_position: "挿入位置"
1516
field_customize_type: "種別"
1617
field_code: "コード"
1718
field_comments: "コメント"
1819
field_is_private: "プライベート"
1920
field_is_enabled: "有効"
2021
field_author: "作成者"
21-
text_path_pattern_info: "パスのパターンは正規表現で指定します。 (例 /issues/[0-9]+)"
22-
text_path_pattern_match_info: "ページのパスが一致した場合、以下のコードを挿入し、実行します。"
23-
option_create_api_access_key: "APIアクセスキーを自動的に作成する"
22+
text_path_pattern_info: "パスを正規表現で指定します。(例 /issues/[0-9]+)"
23+
text_path_pattern_match_info: "パスのパターンが設定されていた場合、ページのパスが一致しないと、コードが挿入されません。"
24+
text_project_pattern_info: "プロジェクト(識別子)を正規表現で指定します。 (例 sample-proj-a|sample-proj-b)"
25+
text_project_pattern_match_info: "プロジェクトのパターンが設定されていた場合、プロジェクトが一致しないと、コードが挿入されません。"
26+
option_create_api_access_key: "APIアクセスキーを自動的に作成する"

config/locales/zh.yml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
# Chinese strings go here for Rails i18n
21
zh:
32
label_view_customize: "自定义视图"
43
label_view_customize_plural: "自定义视图"
@@ -12,13 +11,16 @@ zh:
1211
label_insertion_position_issue_form: "问题(issue)表单底部"
1312
label_insertion_position_issue_show: "问题(issue)详情页面"
1413
field_path_pattern: "路径表达式"
14+
field_project_pattern: "项目表达式"
1515
field_insertion_position: "嵌入位置"
1616
field_customize_type: "类别"
1717
field_code: "代码"
1818
field_comments: "注释"
1919
field_is_private: "私有"
2020
field_is_enabled: "启用"
2121
field_author: "作者"
22-
text_path_pattern_info: "路径表达式是用于匹配特定页面链接的正则表达式。(例如 /issues/[0-9]+)"
23-
text_path_pattern_match_info: "如果页面和表达式匹配,则在页面中嵌入下面的代码。"
22+
text_path_pattern_info: "路径表达式使用正则表达式指定。(例如 /issues/[0-9]+)"
23+
text_path_pattern_match_info: "如果设置了路径表达式,则如果页面的路径不匹配,则不会插入代码。"
24+
text_project_pattern_info: "项目(标识符)表达式使用正则表达式指定。 (例如 sample-proj-a|sample-proj-b)"
25+
text_project_pattern_match_info: "如果设置了项目表达式,则如果当前项目不匹配,则不会插入代码。"
2426
option_create_api_access_key: "自动创建API密钥(API access key)"
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
class AddProjectPatternToViewCustomizes < ActiveRecord::CompatibleLegacyMigration.migration_class
2+
def up
3+
add_column :view_customizes, :project_pattern, :string, :null => false, :default => ""
4+
end
5+
6+
def down
7+
remove_column :view_customizes, :project_pattern
8+
end
9+
end
10+
11+
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
class ChangePathPatternDefaultOnViewCustomizes < ActiveRecord::CompatibleLegacyMigration.migration_class
2+
def change
3+
change_column_default :view_customizes, :path_pattern, from: nil, to: ""
4+
change_column_default :view_customizes, :comments, from: nil, to: ""
5+
change_column_null :view_customizes, :comments, false, ""
6+
end
7+
end

init.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
name 'View Customize plugin'
44
author 'onozaty'
55
description 'View Customize plugin for Redmine'
6-
version '2.6.0'
6+
version '2.7.0'
77
url 'https://github.com/onozaty/redmine-view-customize'
88
author_url 'https://github.com/onozaty'
99

lib/view_customize/view_hook.rb

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,56 +3,67 @@
33
module RedmineViewCustomize
44
class ViewHook < Redmine::Hook::ViewListener
55
def view_layouts_base_html_head(context={})
6-
76
path = Redmine::CodesetUtil.replace_invalid_utf8(context[:request].path_info);
87

98
html = "\n<!-- [view customize plugin] path:#{path} -->\n"
109
html << stylesheet_link_tag("view_customize", plugin: "view_customize")
1110
html << "<script type=\"text/javascript\">\n//<![CDATA[\n"
1211
html << "ViewCustomize = { context: #{create_view_customize_context(context).to_json} };"
13-
html << "\n//]]>\n</script>"
12+
html << "\n//]]>\n</script>\n"
1413

15-
html << create_view_customize_html(path, ViewCustomize::INSERTION_POSITION_HTML_HEAD)
14+
html << create_view_customize_html(context, ViewCustomize::INSERTION_POSITION_HTML_HEAD)
1615

1716
return html
1817
end
1918

2019
def view_issues_form_details_bottom(context={})
2120

22-
path = Redmine::CodesetUtil.replace_invalid_utf8(context[:request].path_info);
23-
return create_view_customize_html(path, ViewCustomize::INSERTION_POSITION_ISSUE_FORM)
21+
return "\n" + create_view_customize_html(context, ViewCustomize::INSERTION_POSITION_ISSUE_FORM)
2422
end
2523

2624
def view_issues_show_details_bottom(context={})
2725

28-
html = "<script type=\"text/javascript\">\n//<![CDATA[\n"
26+
html = "\n<script type=\"text/javascript\">\n//<![CDATA[\n"
2927
html << "ViewCustomize.context.issue = { id: #{context[:issue].id} };"
30-
html << "\n//]]>\n</script>"
28+
html << "\n//]]>\n</script>\n"
3129

32-
path = Redmine::CodesetUtil.replace_invalid_utf8(context[:request].path_info);
33-
html << create_view_customize_html(path, ViewCustomize::INSERTION_POSITION_ISSUE_SHOW)
30+
html << create_view_customize_html(context, ViewCustomize::INSERTION_POSITION_ISSUE_SHOW)
3431

3532
return html
3633
end
3734

3835
private
3936

40-
def create_view_customize_html(path, insertion_position)
37+
def create_view_customize_html(context, insertion_position)
4138

42-
view_customize_html_parts = match_customize(path, insertion_position).map {|item|
39+
view_customize_html_parts = match_customize(context, insertion_position).map {|item|
4340
to_html(item)
4441
}
45-
return view_customize_html_parts.join("\n").html_safe
42+
return view_customize_html_parts.join("\n").html_safe + "\n"
4643

4744
end
4845

49-
def match_customize(path, insertion_position)
46+
def match_customize(context, insertion_position)
47+
path = Redmine::CodesetUtil.replace_invalid_utf8(context[:request].path_info)
48+
project = context[:project].identifier if context[:project]
5049

51-
ViewCustomize.all.select {|item|
52-
item.available? \
53-
&& item.insertion_position == insertion_position \
54-
&& path =~ Regexp.new(item.path_pattern)
55-
}
50+
ViewCustomize.all.order(:id).select {|item| target_customize?(path, project, insertion_position, item)}
51+
end
52+
53+
def target_customize?(path, project, insertion_position, item)
54+
return false unless item.available?
55+
return false unless item.insertion_position == insertion_position
56+
57+
if item.path_pattern.present?
58+
return false unless path =~ Regexp.new(item.path_pattern)
59+
end
60+
61+
if item.project_pattern.present?
62+
return false unless project.present?
63+
return false unless project =~ Regexp.new(item.project_pattern)
64+
end
65+
66+
return true
5667
end
5768

5869
def to_html(view_customize)

screenshots/detail.en.png

-269 Bytes
Loading

screenshots/list_edit.en.png

1.42 KB
Loading

screenshots/list_new.en.png

1.48 KB
Loading

screenshots/new.en.png

8.05 KB
Loading

0 commit comments

Comments
 (0)