@@ -1,19 +1,21 | |||||
|
1 | # encoding: utf-8 | |||
|
2 | # | |||
1 | # Redmine - project management software |
|
3 | # Redmine - project management software | |
2 | # Copyright (C) 2006-2011 Jean-Philippe Lang |
|
4 | # Copyright (C) 2006-2011 Jean-Philippe Lang | |
3 | # |
|
5 | # | |
4 | # This program is free software; you can redistribute it and/or |
|
6 | # This program is free software; you can redistribute it and/or | |
5 | # modify it under the terms of the GNU General Public License |
|
7 | # modify it under the terms of the GNU General Public License | |
6 | # as published by the Free Software Foundation; either version 2 |
|
8 | # as published by the Free Software Foundation; either version 2 | |
7 | # of the License, or (at your option) any later version. |
|
9 | # of the License, or (at your option) any later version. | |
8 | # |
|
10 | # | |
9 | # This program is distributed in the hope that it will be useful, |
|
11 | # This program is distributed in the hope that it will be useful, | |
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | # GNU General Public License for more details. |
|
14 | # GNU General Public License for more details. | |
13 | # |
|
15 | # | |
14 | # You should have received a copy of the GNU General Public License |
|
16 | # You should have received a copy of the GNU General Public License | |
15 | # along with this program; if not, write to the Free Software |
|
17 | # along with this program; if not, write to the Free Software | |
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
17 |
|
19 | |||
18 | module AccountHelper |
|
20 | module AccountHelper | |
19 | end |
|
21 | end |
@@ -1,23 +1,25 | |||||
|
1 | # encoding: utf-8 | |||
|
2 | # | |||
1 | # Redmine - project management software |
|
3 | # Redmine - project management software | |
2 | # Copyright (C) 2006-2011 Jean-Philippe Lang |
|
4 | # Copyright (C) 2006-2011 Jean-Philippe Lang | |
3 | # |
|
5 | # | |
4 | # This program is free software; you can redistribute it and/or |
|
6 | # This program is free software; you can redistribute it and/or | |
5 | # modify it under the terms of the GNU General Public License |
|
7 | # modify it under the terms of the GNU General Public License | |
6 | # as published by the Free Software Foundation; either version 2 |
|
8 | # as published by the Free Software Foundation; either version 2 | |
7 | # of the License, or (at your option) any later version. |
|
9 | # of the License, or (at your option) any later version. | |
8 | # |
|
10 | # | |
9 | # This program is distributed in the hope that it will be useful, |
|
11 | # This program is distributed in the hope that it will be useful, | |
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | # GNU General Public License for more details. |
|
14 | # GNU General Public License for more details. | |
13 | # |
|
15 | # | |
14 | # You should have received a copy of the GNU General Public License |
|
16 | # You should have received a copy of the GNU General Public License | |
15 | # along with this program; if not, write to the Free Software |
|
17 | # along with this program; if not, write to the Free Software | |
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
17 |
|
19 | |||
18 | module AdminHelper |
|
20 | module AdminHelper | |
19 | def project_status_options_for_select(selected) |
|
21 | def project_status_options_for_select(selected) | |
20 | options_for_select([[l(:label_all), ''], |
|
22 | options_for_select([[l(:label_all), ''], | |
21 | [l(:status_active), 1]], selected) |
|
23 | [l(:status_active), 1]], selected) | |
22 | end |
|
24 | end | |
23 | end |
|
25 | end |
@@ -1,43 +1,45 | |||||
|
1 | # encoding: utf-8 | |||
|
2 | # | |||
1 | # Redmine - project management software |
|
3 | # Redmine - project management software | |
2 | # Copyright (C) 2006-2011 Jean-Philippe Lang |
|
4 | # Copyright (C) 2006-2011 Jean-Philippe Lang | |
3 | # |
|
5 | # | |
4 | # This program is free software; you can redistribute it and/or |
|
6 | # This program is free software; you can redistribute it and/or | |
5 | # modify it under the terms of the GNU General Public License |
|
7 | # modify it under the terms of the GNU General Public License | |
6 | # as published by the Free Software Foundation; either version 2 |
|
8 | # as published by the Free Software Foundation; either version 2 | |
7 | # of the License, or (at your option) any later version. |
|
9 | # of the License, or (at your option) any later version. | |
8 | # |
|
10 | # | |
9 | # This program is distributed in the hope that it will be useful, |
|
11 | # This program is distributed in the hope that it will be useful, | |
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | # GNU General Public License for more details. |
|
14 | # GNU General Public License for more details. | |
13 | # |
|
15 | # | |
14 | # You should have received a copy of the GNU General Public License |
|
16 | # You should have received a copy of the GNU General Public License | |
15 | # along with this program; if not, write to the Free Software |
|
17 | # along with this program; if not, write to the Free Software | |
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
17 |
|
19 | |||
18 | module AttachmentsHelper |
|
20 | module AttachmentsHelper | |
19 | # Displays view/delete links to the attachments of the given object |
|
21 | # Displays view/delete links to the attachments of the given object | |
20 | # Options: |
|
22 | # Options: | |
21 | # :author -- author names are not displayed if set to false |
|
23 | # :author -- author names are not displayed if set to false | |
22 | def link_to_attachments(container, options = {}) |
|
24 | def link_to_attachments(container, options = {}) | |
23 | options.assert_valid_keys(:author) |
|
25 | options.assert_valid_keys(:author) | |
24 |
|
26 | |||
25 | if container.attachments.any? |
|
27 | if container.attachments.any? | |
26 | options = {:deletable => container.attachments_deletable?, :author => true}.merge(options) |
|
28 | options = {:deletable => container.attachments_deletable?, :author => true}.merge(options) | |
27 | render :partial => 'attachments/links', :locals => {:attachments => container.attachments, :options => options} |
|
29 | render :partial => 'attachments/links', :locals => {:attachments => container.attachments, :options => options} | |
28 | end |
|
30 | end | |
29 | end |
|
31 | end | |
30 |
|
32 | |||
31 | def render_api_attachment(attachment, api) |
|
33 | def render_api_attachment(attachment, api) | |
32 | api.attachment do |
|
34 | api.attachment do | |
33 | api.id attachment.id |
|
35 | api.id attachment.id | |
34 | api.filename attachment.filename |
|
36 | api.filename attachment.filename | |
35 | api.filesize attachment.filesize |
|
37 | api.filesize attachment.filesize | |
36 | api.content_type attachment.content_type |
|
38 | api.content_type attachment.content_type | |
37 | api.description attachment.description |
|
39 | api.description attachment.description | |
38 | api.content_url url_for(:controller => 'attachments', :action => 'download', :id => attachment, :filename => attachment.filename, :only_path => false) |
|
40 | api.content_url url_for(:controller => 'attachments', :action => 'download', :id => attachment, :filename => attachment.filename, :only_path => false) | |
39 | api.author(:id => attachment.author.id, :name => attachment.author.name) if attachment.author |
|
41 | api.author(:id => attachment.author.id, :name => attachment.author.name) if attachment.author | |
40 | api.created_on attachment.created_on |
|
42 | api.created_on attachment.created_on | |
41 | end |
|
43 | end | |
42 | end |
|
44 | end | |
43 | end |
|
45 | end |
@@ -1,19 +1,21 | |||||
|
1 | # encoding: utf-8 | |||
|
2 | # | |||
1 | # Redmine - project management software |
|
3 | # Redmine - project management software | |
2 | # Copyright (C) 2006-2011 Jean-Philippe Lang |
|
4 | # Copyright (C) 2006-2011 Jean-Philippe Lang | |
3 | # |
|
5 | # | |
4 | # This program is free software; you can redistribute it and/or |
|
6 | # This program is free software; you can redistribute it and/or | |
5 | # modify it under the terms of the GNU General Public License |
|
7 | # modify it under the terms of the GNU General Public License | |
6 | # as published by the Free Software Foundation; either version 2 |
|
8 | # as published by the Free Software Foundation; either version 2 | |
7 | # of the License, or (at your option) any later version. |
|
9 | # of the License, or (at your option) any later version. | |
8 | # |
|
10 | # | |
9 | # This program is distributed in the hope that it will be useful, |
|
11 | # This program is distributed in the hope that it will be useful, | |
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | # GNU General Public License for more details. |
|
14 | # GNU General Public License for more details. | |
13 | # |
|
15 | # | |
14 | # You should have received a copy of the GNU General Public License |
|
16 | # You should have received a copy of the GNU General Public License | |
15 | # along with this program; if not, write to the Free Software |
|
17 | # along with this program; if not, write to the Free Software | |
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
17 |
|
19 | |||
18 | module AuthSourcesHelper |
|
20 | module AuthSourcesHelper | |
19 | end |
|
21 | end |
@@ -1,19 +1,21 | |||||
|
1 | # encoding: utf-8 | |||
|
2 | # | |||
1 | # Redmine - project management software |
|
3 | # Redmine - project management software | |
2 | # Copyright (C) 2006-2011 Jean-Philippe Lang |
|
4 | # Copyright (C) 2006-2011 Jean-Philippe Lang | |
3 | # |
|
5 | # | |
4 | # This program is free software; you can redistribute it and/or |
|
6 | # This program is free software; you can redistribute it and/or | |
5 | # modify it under the terms of the GNU General Public License |
|
7 | # modify it under the terms of the GNU General Public License | |
6 | # as published by the Free Software Foundation; either version 2 |
|
8 | # as published by the Free Software Foundation; either version 2 | |
7 | # of the License, or (at your option) any later version. |
|
9 | # of the License, or (at your option) any later version. | |
8 | # |
|
10 | # | |
9 | # This program is distributed in the hope that it will be useful, |
|
11 | # This program is distributed in the hope that it will be useful, | |
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | # GNU General Public License for more details. |
|
14 | # GNU General Public License for more details. | |
13 | # |
|
15 | # | |
14 | # You should have received a copy of the GNU General Public License |
|
16 | # You should have received a copy of the GNU General Public License | |
15 | # along with this program; if not, write to the Free Software |
|
17 | # along with this program; if not, write to the Free Software | |
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
17 |
|
19 | |||
18 | module BoardsHelper |
|
20 | module BoardsHelper | |
19 | end |
|
21 | end |
@@ -1,39 +1,58 | |||||
|
1 | # encoding: utf-8 | |||
|
2 | # | |||
|
3 | # Redmine - project management software | |||
|
4 | # Copyright (C) 2006-2011 Jean-Philippe Lang | |||
|
5 | # | |||
|
6 | # This program is free software; you can redistribute it and/or | |||
|
7 | # modify it under the terms of the GNU General Public License | |||
|
8 | # as published by the Free Software Foundation; either version 2 | |||
|
9 | # of the License, or (at your option) any later version. | |||
|
10 | # | |||
|
11 | # This program is distributed in the hope that it will be useful, | |||
|
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
14 | # GNU General Public License for more details. | |||
|
15 | # | |||
|
16 | # You should have received a copy of the GNU General Public License | |||
|
17 | # along with this program; if not, write to the Free Software | |||
|
18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
|
19 | ||||
1 | module CalendarsHelper |
|
20 | module CalendarsHelper | |
2 | def link_to_previous_month(year, month, options={}) |
|
21 | def link_to_previous_month(year, month, options={}) | |
3 | target_year, target_month = if month == 1 |
|
22 | target_year, target_month = if month == 1 | |
4 | [year - 1, 12] |
|
23 | [year - 1, 12] | |
5 | else |
|
24 | else | |
6 | [year, month - 1] |
|
25 | [year, month - 1] | |
7 | end |
|
26 | end | |
8 |
|
27 | |||
9 | name = if target_month == 12 |
|
28 | name = if target_month == 12 | |
10 | "#{month_name(target_month)} #{target_year}" |
|
29 | "#{month_name(target_month)} #{target_year}" | |
11 | else |
|
30 | else | |
12 | "#{month_name(target_month)}" |
|
31 | "#{month_name(target_month)}" | |
13 | end |
|
32 | end | |
14 |
|
33 | |||
15 | # \xc2\xab(utf-8) = « |
|
34 | # \xc2\xab(utf-8) = « | |
16 | link_to_month(("\xc2\xab " + name), target_year, target_month, options) |
|
35 | link_to_month(("\xc2\xab " + name), target_year, target_month, options) | |
17 | end |
|
36 | end | |
18 |
|
37 | |||
19 | def link_to_next_month(year, month, options={}) |
|
38 | def link_to_next_month(year, month, options={}) | |
20 | target_year, target_month = if month == 12 |
|
39 | target_year, target_month = if month == 12 | |
21 | [year + 1, 1] |
|
40 | [year + 1, 1] | |
22 | else |
|
41 | else | |
23 | [year, month + 1] |
|
42 | [year, month + 1] | |
24 | end |
|
43 | end | |
25 |
|
44 | |||
26 | name = if target_month == 1 |
|
45 | name = if target_month == 1 | |
27 | "#{month_name(target_month)} #{target_year}" |
|
46 | "#{month_name(target_month)} #{target_year}" | |
28 | else |
|
47 | else | |
29 | "#{month_name(target_month)}" |
|
48 | "#{month_name(target_month)}" | |
30 | end |
|
49 | end | |
31 |
|
50 | |||
32 | # \xc2\xbb(utf-8) = » |
|
51 | # \xc2\xbb(utf-8) = » | |
33 | link_to_month((name + " \xc2\xbb"), target_year, target_month, options) |
|
52 | link_to_month((name + " \xc2\xbb"), target_year, target_month, options) | |
34 | end |
|
53 | end | |
35 |
|
54 | |||
36 | def link_to_month(link_name, year, month, options={}) |
|
55 | def link_to_month(link_name, year, month, options={}) | |
37 | link_to_content_update(h(link_name), params.merge(:year => year, :month => month)) |
|
56 | link_to_content_update(h(link_name), params.merge(:year => year, :month => month)) | |
38 | end |
|
57 | end | |
39 | end |
|
58 | end |
@@ -1,118 +1,120 | |||||
|
1 | # encoding: utf-8 | |||
|
2 | # | |||
1 | # Redmine - project management software |
|
3 | # Redmine - project management software | |
2 | # Copyright (C) 2006-2011 Jean-Philippe Lang |
|
4 | # Copyright (C) 2006-2011 Jean-Philippe Lang | |
3 | # |
|
5 | # | |
4 | # This program is free software; you can redistribute it and/or |
|
6 | # This program is free software; you can redistribute it and/or | |
5 | # modify it under the terms of the GNU General Public License |
|
7 | # modify it under the terms of the GNU General Public License | |
6 | # as published by the Free Software Foundation; either version 2 |
|
8 | # as published by the Free Software Foundation; either version 2 | |
7 | # of the License, or (at your option) any later version. |
|
9 | # of the License, or (at your option) any later version. | |
8 | # |
|
10 | # | |
9 | # This program is distributed in the hope that it will be useful, |
|
11 | # This program is distributed in the hope that it will be useful, | |
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | # GNU General Public License for more details. |
|
14 | # GNU General Public License for more details. | |
13 | # |
|
15 | # | |
14 | # You should have received a copy of the GNU General Public License |
|
16 | # You should have received a copy of the GNU General Public License | |
15 | # along with this program; if not, write to the Free Software |
|
17 | # along with this program; if not, write to the Free Software | |
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
17 |
|
19 | |||
18 | module CustomFieldsHelper |
|
20 | module CustomFieldsHelper | |
19 |
|
21 | |||
20 | def custom_fields_tabs |
|
22 | def custom_fields_tabs | |
21 | tabs = [{:name => 'IssueCustomField', :partial => 'custom_fields/index', :label => :label_issue_plural}, |
|
23 | tabs = [{:name => 'IssueCustomField', :partial => 'custom_fields/index', :label => :label_issue_plural}, | |
22 | {:name => 'TimeEntryCustomField', :partial => 'custom_fields/index', :label => :label_spent_time}, |
|
24 | {:name => 'TimeEntryCustomField', :partial => 'custom_fields/index', :label => :label_spent_time}, | |
23 | {:name => 'ProjectCustomField', :partial => 'custom_fields/index', :label => :label_project_plural}, |
|
25 | {:name => 'ProjectCustomField', :partial => 'custom_fields/index', :label => :label_project_plural}, | |
24 | {:name => 'VersionCustomField', :partial => 'custom_fields/index', :label => :label_version_plural}, |
|
26 | {:name => 'VersionCustomField', :partial => 'custom_fields/index', :label => :label_version_plural}, | |
25 | {:name => 'UserCustomField', :partial => 'custom_fields/index', :label => :label_user_plural}, |
|
27 | {:name => 'UserCustomField', :partial => 'custom_fields/index', :label => :label_user_plural}, | |
26 | {:name => 'GroupCustomField', :partial => 'custom_fields/index', :label => :label_group_plural}, |
|
28 | {:name => 'GroupCustomField', :partial => 'custom_fields/index', :label => :label_group_plural}, | |
27 | {:name => 'TimeEntryActivityCustomField', :partial => 'custom_fields/index', :label => TimeEntryActivity::OptionName}, |
|
29 | {:name => 'TimeEntryActivityCustomField', :partial => 'custom_fields/index', :label => TimeEntryActivity::OptionName}, | |
28 | {:name => 'IssuePriorityCustomField', :partial => 'custom_fields/index', :label => IssuePriority::OptionName}, |
|
30 | {:name => 'IssuePriorityCustomField', :partial => 'custom_fields/index', :label => IssuePriority::OptionName}, | |
29 | {:name => 'DocumentCategoryCustomField', :partial => 'custom_fields/index', :label => DocumentCategory::OptionName} |
|
31 | {:name => 'DocumentCategoryCustomField', :partial => 'custom_fields/index', :label => DocumentCategory::OptionName} | |
30 | ] |
|
32 | ] | |
31 | end |
|
33 | end | |
32 |
|
34 | |||
33 | # Return custom field html tag corresponding to its format |
|
35 | # Return custom field html tag corresponding to its format | |
34 | def custom_field_tag(name, custom_value) |
|
36 | def custom_field_tag(name, custom_value) | |
35 | custom_field = custom_value.custom_field |
|
37 | custom_field = custom_value.custom_field | |
36 | field_name = "#{name}[custom_field_values][#{custom_field.id}]" |
|
38 | field_name = "#{name}[custom_field_values][#{custom_field.id}]" | |
37 | field_id = "#{name}_custom_field_values_#{custom_field.id}" |
|
39 | field_id = "#{name}_custom_field_values_#{custom_field.id}" | |
38 |
|
40 | |||
39 | field_format = Redmine::CustomFieldFormat.find_by_name(custom_field.field_format) |
|
41 | field_format = Redmine::CustomFieldFormat.find_by_name(custom_field.field_format) | |
40 | case field_format.try(:edit_as) |
|
42 | case field_format.try(:edit_as) | |
41 | when "date" |
|
43 | when "date" | |
42 | text_field_tag(field_name, custom_value.value, :id => field_id, :size => 10) + |
|
44 | text_field_tag(field_name, custom_value.value, :id => field_id, :size => 10) + | |
43 | calendar_for(field_id) |
|
45 | calendar_for(field_id) | |
44 | when "text" |
|
46 | when "text" | |
45 | text_area_tag(field_name, custom_value.value, :id => field_id, :rows => 3, :style => 'width:90%') |
|
47 | text_area_tag(field_name, custom_value.value, :id => field_id, :rows => 3, :style => 'width:90%') | |
46 | when "bool" |
|
48 | when "bool" | |
47 | hidden_field_tag(field_name, '0') + check_box_tag(field_name, '1', custom_value.true?, :id => field_id) |
|
49 | hidden_field_tag(field_name, '0') + check_box_tag(field_name, '1', custom_value.true?, :id => field_id) | |
48 | when "list" |
|
50 | when "list" | |
49 | blank_option = custom_field.is_required? ? |
|
51 | blank_option = custom_field.is_required? ? | |
50 | (custom_field.default_value.blank? ? "<option value=\"\">--- #{l(:actionview_instancetag_blank_option)} ---</option>" : '') : |
|
52 | (custom_field.default_value.blank? ? "<option value=\"\">--- #{l(:actionview_instancetag_blank_option)} ---</option>" : '') : | |
51 | '<option></option>' |
|
53 | '<option></option>' | |
52 | select_tag(field_name, blank_option + options_for_select(custom_field.possible_values_options(custom_value.customized), custom_value.value), :id => field_id) |
|
54 | select_tag(field_name, blank_option + options_for_select(custom_field.possible_values_options(custom_value.customized), custom_value.value), :id => field_id) | |
53 | else |
|
55 | else | |
54 | text_field_tag(field_name, custom_value.value, :id => field_id) |
|
56 | text_field_tag(field_name, custom_value.value, :id => field_id) | |
55 | end |
|
57 | end | |
56 | end |
|
58 | end | |
57 |
|
59 | |||
58 | # Return custom field label tag |
|
60 | # Return custom field label tag | |
59 | def custom_field_label_tag(name, custom_value) |
|
61 | def custom_field_label_tag(name, custom_value) | |
60 | content_tag "label", h(custom_value.custom_field.name) + |
|
62 | content_tag "label", h(custom_value.custom_field.name) + | |
61 | (custom_value.custom_field.is_required? ? " <span class=\"required\">*</span>".html_safe : ""), |
|
63 | (custom_value.custom_field.is_required? ? " <span class=\"required\">*</span>".html_safe : ""), | |
62 | :for => "#{name}_custom_field_values_#{custom_value.custom_field.id}", |
|
64 | :for => "#{name}_custom_field_values_#{custom_value.custom_field.id}", | |
63 | :class => (custom_value.errors.empty? ? nil : "error" ) |
|
65 | :class => (custom_value.errors.empty? ? nil : "error" ) | |
64 | end |
|
66 | end | |
65 |
|
67 | |||
66 | # Return custom field tag with its label tag |
|
68 | # Return custom field tag with its label tag | |
67 | def custom_field_tag_with_label(name, custom_value) |
|
69 | def custom_field_tag_with_label(name, custom_value) | |
68 | custom_field_label_tag(name, custom_value) + custom_field_tag(name, custom_value) |
|
70 | custom_field_label_tag(name, custom_value) + custom_field_tag(name, custom_value) | |
69 | end |
|
71 | end | |
70 |
|
72 | |||
71 | def custom_field_tag_for_bulk_edit(name, custom_field, projects=nil) |
|
73 | def custom_field_tag_for_bulk_edit(name, custom_field, projects=nil) | |
72 | field_name = "#{name}[custom_field_values][#{custom_field.id}]" |
|
74 | field_name = "#{name}[custom_field_values][#{custom_field.id}]" | |
73 | field_id = "#{name}_custom_field_values_#{custom_field.id}" |
|
75 | field_id = "#{name}_custom_field_values_#{custom_field.id}" | |
74 | field_format = Redmine::CustomFieldFormat.find_by_name(custom_field.field_format) |
|
76 | field_format = Redmine::CustomFieldFormat.find_by_name(custom_field.field_format) | |
75 | case field_format.try(:edit_as) |
|
77 | case field_format.try(:edit_as) | |
76 | when "date" |
|
78 | when "date" | |
77 | text_field_tag(field_name, '', :id => field_id, :size => 10) + |
|
79 | text_field_tag(field_name, '', :id => field_id, :size => 10) + | |
78 | calendar_for(field_id) |
|
80 | calendar_for(field_id) | |
79 | when "text" |
|
81 | when "text" | |
80 | text_area_tag(field_name, '', :id => field_id, :rows => 3, :style => 'width:90%') |
|
82 | text_area_tag(field_name, '', :id => field_id, :rows => 3, :style => 'width:90%') | |
81 | when "bool" |
|
83 | when "bool" | |
82 | select_tag(field_name, options_for_select([[l(:label_no_change_option), ''], |
|
84 | select_tag(field_name, options_for_select([[l(:label_no_change_option), ''], | |
83 | [l(:general_text_yes), '1'], |
|
85 | [l(:general_text_yes), '1'], | |
84 | [l(:general_text_no), '0']]), :id => field_id) |
|
86 | [l(:general_text_no), '0']]), :id => field_id) | |
85 | when "list" |
|
87 | when "list" | |
86 | select_tag(field_name, options_for_select([[l(:label_no_change_option), '']] + custom_field.possible_values_options(projects)), :id => field_id) |
|
88 | select_tag(field_name, options_for_select([[l(:label_no_change_option), '']] + custom_field.possible_values_options(projects)), :id => field_id) | |
87 | else |
|
89 | else | |
88 | text_field_tag(field_name, '', :id => field_id) |
|
90 | text_field_tag(field_name, '', :id => field_id) | |
89 | end |
|
91 | end | |
90 | end |
|
92 | end | |
91 |
|
93 | |||
92 | # Return a string used to display a custom value |
|
94 | # Return a string used to display a custom value | |
93 | def show_value(custom_value) |
|
95 | def show_value(custom_value) | |
94 | return "" unless custom_value |
|
96 | return "" unless custom_value | |
95 | format_value(custom_value.value, custom_value.custom_field.field_format) |
|
97 | format_value(custom_value.value, custom_value.custom_field.field_format) | |
96 | end |
|
98 | end | |
97 |
|
99 | |||
98 | # Return a string used to display a custom value |
|
100 | # Return a string used to display a custom value | |
99 | def format_value(value, field_format) |
|
101 | def format_value(value, field_format) | |
100 | Redmine::CustomFieldFormat.format_value(value, field_format) # Proxy |
|
102 | Redmine::CustomFieldFormat.format_value(value, field_format) # Proxy | |
101 | end |
|
103 | end | |
102 |
|
104 | |||
103 | # Return an array of custom field formats which can be used in select_tag |
|
105 | # Return an array of custom field formats which can be used in select_tag | |
104 | def custom_field_formats_for_select(custom_field) |
|
106 | def custom_field_formats_for_select(custom_field) | |
105 | Redmine::CustomFieldFormat.as_select(custom_field.class.customized_class.name) |
|
107 | Redmine::CustomFieldFormat.as_select(custom_field.class.customized_class.name) | |
106 | end |
|
108 | end | |
107 |
|
109 | |||
108 | # Renders the custom_values in api views |
|
110 | # Renders the custom_values in api views | |
109 | def render_api_custom_values(custom_values, api) |
|
111 | def render_api_custom_values(custom_values, api) | |
110 | api.array :custom_fields do |
|
112 | api.array :custom_fields do | |
111 | custom_values.each do |custom_value| |
|
113 | custom_values.each do |custom_value| | |
112 | api.custom_field :id => custom_value.custom_field_id, :name => custom_value.custom_field.name do |
|
114 | api.custom_field :id => custom_value.custom_field_id, :name => custom_value.custom_field.name do | |
113 | api.value custom_value.value |
|
115 | api.value custom_value.value | |
114 | end |
|
116 | end | |
115 | end |
|
117 | end | |
116 | end unless custom_values.empty? |
|
118 | end unless custom_values.empty? | |
117 | end |
|
119 | end | |
118 | end |
|
120 | end |
@@ -1,19 +1,21 | |||||
|
1 | # encoding: utf-8 | |||
|
2 | # | |||
1 | # Redmine - project management software |
|
3 | # Redmine - project management software | |
2 | # Copyright (C) 2006-2011 Jean-Philippe Lang |
|
4 | # Copyright (C) 2006-2011 Jean-Philippe Lang | |
3 | # |
|
5 | # | |
4 | # This program is free software; you can redistribute it and/or |
|
6 | # This program is free software; you can redistribute it and/or | |
5 | # modify it under the terms of the GNU General Public License |
|
7 | # modify it under the terms of the GNU General Public License | |
6 | # as published by the Free Software Foundation; either version 2 |
|
8 | # as published by the Free Software Foundation; either version 2 | |
7 | # of the License, or (at your option) any later version. |
|
9 | # of the License, or (at your option) any later version. | |
8 | # |
|
10 | # | |
9 | # This program is distributed in the hope that it will be useful, |
|
11 | # This program is distributed in the hope that it will be useful, | |
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | # GNU General Public License for more details. |
|
14 | # GNU General Public License for more details. | |
13 | # |
|
15 | # | |
14 | # You should have received a copy of the GNU General Public License |
|
16 | # You should have received a copy of the GNU General Public License | |
15 | # along with this program; if not, write to the Free Software |
|
17 | # along with this program; if not, write to the Free Software | |
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
17 |
|
19 | |||
18 | module DocumentsHelper |
|
20 | module DocumentsHelper | |
19 | end |
|
21 | end |
@@ -1,19 +1,21 | |||||
|
1 | # encoding: utf-8 | |||
|
2 | # | |||
1 | # Redmine - project management software |
|
3 | # Redmine - project management software | |
2 | # Copyright (C) 2006-2011 Jean-Philippe Lang |
|
4 | # Copyright (C) 2006-2011 Jean-Philippe Lang | |
3 | # |
|
5 | # | |
4 | # This program is free software; you can redistribute it and/or |
|
6 | # This program is free software; you can redistribute it and/or | |
5 | # modify it under the terms of the GNU General Public License |
|
7 | # modify it under the terms of the GNU General Public License | |
6 | # as published by the Free Software Foundation; either version 2 |
|
8 | # as published by the Free Software Foundation; either version 2 | |
7 | # of the License, or (at your option) any later version. |
|
9 | # of the License, or (at your option) any later version. | |
8 | # |
|
10 | # | |
9 | # This program is distributed in the hope that it will be useful, |
|
11 | # This program is distributed in the hope that it will be useful, | |
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | # GNU General Public License for more details. |
|
14 | # GNU General Public License for more details. | |
13 | # |
|
15 | # | |
14 | # You should have received a copy of the GNU General Public License |
|
16 | # You should have received a copy of the GNU General Public License | |
15 | # along with this program; if not, write to the Free Software |
|
17 | # along with this program; if not, write to the Free Software | |
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
17 |
|
19 | |||
18 | module EnumerationsHelper |
|
20 | module EnumerationsHelper | |
19 | end |
|
21 | end |
@@ -1,41 +1,43 | |||||
|
1 | # encoding: utf-8 | |||
|
2 | # | |||
1 | # Redmine - project management software |
|
3 | # Redmine - project management software | |
2 | # Copyright (C) 2006-2011 Jean-Philippe Lang |
|
4 | # Copyright (C) 2006-2011 Jean-Philippe Lang | |
3 | # |
|
5 | # | |
4 | # This program is free software; you can redistribute it and/or |
|
6 | # This program is free software; you can redistribute it and/or | |
5 | # modify it under the terms of the GNU General Public License |
|
7 | # modify it under the terms of the GNU General Public License | |
6 | # as published by the Free Software Foundation; either version 2 |
|
8 | # as published by the Free Software Foundation; either version 2 | |
7 | # of the License, or (at your option) any later version. |
|
9 | # of the License, or (at your option) any later version. | |
8 | # |
|
10 | # | |
9 | # This program is distributed in the hope that it will be useful, |
|
11 | # This program is distributed in the hope that it will be useful, | |
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | # GNU General Public License for more details. |
|
14 | # GNU General Public License for more details. | |
13 | # |
|
15 | # | |
14 | # You should have received a copy of the GNU General Public License |
|
16 | # You should have received a copy of the GNU General Public License | |
15 | # along with this program; if not, write to the Free Software |
|
17 | # along with this program; if not, write to the Free Software | |
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
17 |
|
19 | |||
18 | module GanttHelper |
|
20 | module GanttHelper | |
19 |
|
21 | |||
20 | def gantt_zoom_link(gantt, in_or_out) |
|
22 | def gantt_zoom_link(gantt, in_or_out) | |
21 | case in_or_out |
|
23 | case in_or_out | |
22 | when :in |
|
24 | when :in | |
23 | if gantt.zoom < 4 |
|
25 | if gantt.zoom < 4 | |
24 | link_to_content_update l(:text_zoom_in), |
|
26 | link_to_content_update l(:text_zoom_in), | |
25 | params.merge(gantt.params.merge(:zoom => (gantt.zoom+1))), |
|
27 | params.merge(gantt.params.merge(:zoom => (gantt.zoom+1))), | |
26 | :class => 'icon icon-zoom-in' |
|
28 | :class => 'icon icon-zoom-in' | |
27 | else |
|
29 | else | |
28 | content_tag('span', l(:text_zoom_in), :class => 'icon icon-zoom-in').html_safe |
|
30 | content_tag('span', l(:text_zoom_in), :class => 'icon icon-zoom-in').html_safe | |
29 | end |
|
31 | end | |
30 |
|
32 | |||
31 | when :out |
|
33 | when :out | |
32 | if gantt.zoom > 1 |
|
34 | if gantt.zoom > 1 | |
33 | link_to_content_update l(:text_zoom_out), |
|
35 | link_to_content_update l(:text_zoom_out), | |
34 | params.merge(gantt.params.merge(:zoom => (gantt.zoom-1))), |
|
36 | params.merge(gantt.params.merge(:zoom => (gantt.zoom-1))), | |
35 | :class => 'icon icon-zoom-out' |
|
37 | :class => 'icon icon-zoom-out' | |
36 | else |
|
38 | else | |
37 | content_tag('span', l(:text_zoom_out), :class => 'icon icon-zoom-out').html_safe |
|
39 | content_tag('span', l(:text_zoom_out), :class => 'icon icon-zoom-out').html_safe | |
38 | end |
|
40 | end | |
39 | end |
|
41 | end | |
40 | end |
|
42 | end | |
41 | end |
|
43 | end |
@@ -1,34 +1,36 | |||||
|
1 | # encoding: utf-8 | |||
|
2 | # | |||
1 | # Redmine - project management software |
|
3 | # Redmine - project management software | |
2 | # Copyright (C) 2006-2011 Jean-Philippe Lang |
|
4 | # Copyright (C) 2006-2011 Jean-Philippe Lang | |
3 | # |
|
5 | # | |
4 | # This program is free software; you can redistribute it and/or |
|
6 | # This program is free software; you can redistribute it and/or | |
5 | # modify it under the terms of the GNU General Public License |
|
7 | # modify it under the terms of the GNU General Public License | |
6 | # as published by the Free Software Foundation; either version 2 |
|
8 | # as published by the Free Software Foundation; either version 2 | |
7 | # of the License, or (at your option) any later version. |
|
9 | # of the License, or (at your option) any later version. | |
8 | # |
|
10 | # | |
9 | # This program is distributed in the hope that it will be useful, |
|
11 | # This program is distributed in the hope that it will be useful, | |
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | # GNU General Public License for more details. |
|
14 | # GNU General Public License for more details. | |
13 | # |
|
15 | # | |
14 | # You should have received a copy of the GNU General Public License |
|
16 | # You should have received a copy of the GNU General Public License | |
15 | # along with this program; if not, write to the Free Software |
|
17 | # along with this program; if not, write to the Free Software | |
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
17 |
|
19 | |||
18 | module GroupsHelper |
|
20 | module GroupsHelper | |
19 | # Options for the new membership projects combo-box |
|
21 | # Options for the new membership projects combo-box | |
20 | def options_for_membership_project_select(user, projects) |
|
22 | def options_for_membership_project_select(user, projects) | |
21 | options = content_tag('option', "--- #{l(:actionview_instancetag_blank_option)} ---") |
|
23 | options = content_tag('option', "--- #{l(:actionview_instancetag_blank_option)} ---") | |
22 | options << project_tree_options_for_select(projects) do |p| |
|
24 | options << project_tree_options_for_select(projects) do |p| | |
23 | {:disabled => (user.projects.include?(p))} |
|
25 | {:disabled => (user.projects.include?(p))} | |
24 | end |
|
26 | end | |
25 | options |
|
27 | options | |
26 | end |
|
28 | end | |
27 |
|
29 | |||
28 | def group_settings_tabs |
|
30 | def group_settings_tabs | |
29 | tabs = [{:name => 'general', :partial => 'groups/general', :label => :label_general}, |
|
31 | tabs = [{:name => 'general', :partial => 'groups/general', :label => :label_general}, | |
30 | {:name => 'users', :partial => 'groups/users', :label => :label_user_plural}, |
|
32 | {:name => 'users', :partial => 'groups/users', :label => :label_user_plural}, | |
31 | {:name => 'memberships', :partial => 'groups/memberships', :label => :label_project_plural} |
|
33 | {:name => 'memberships', :partial => 'groups/memberships', :label => :label_project_plural} | |
32 | ] |
|
34 | ] | |
33 | end |
|
35 | end | |
34 | end |
|
36 | end |
@@ -1,19 +1,21 | |||||
|
1 | # encoding: utf-8 | |||
|
2 | # | |||
1 | # Redmine - project management software |
|
3 | # Redmine - project management software | |
2 | # Copyright (C) 2006-2011 Jean-Philippe Lang |
|
4 | # Copyright (C) 2006-2011 Jean-Philippe Lang | |
3 | # |
|
5 | # | |
4 | # This program is free software; you can redistribute it and/or |
|
6 | # This program is free software; you can redistribute it and/or | |
5 | # modify it under the terms of the GNU General Public License |
|
7 | # modify it under the terms of the GNU General Public License | |
6 | # as published by the Free Software Foundation; either version 2 |
|
8 | # as published by the Free Software Foundation; either version 2 | |
7 | # of the License, or (at your option) any later version. |
|
9 | # of the License, or (at your option) any later version. | |
8 | # |
|
10 | # | |
9 | # This program is distributed in the hope that it will be useful, |
|
11 | # This program is distributed in the hope that it will be useful, | |
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | # GNU General Public License for more details. |
|
14 | # GNU General Public License for more details. | |
13 | # |
|
15 | # | |
14 | # You should have received a copy of the GNU General Public License |
|
16 | # You should have received a copy of the GNU General Public License | |
15 | # along with this program; if not, write to the Free Software |
|
17 | # along with this program; if not, write to the Free Software | |
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
17 |
|
19 | |||
18 | module IssueCategoriesHelper |
|
20 | module IssueCategoriesHelper | |
19 | end |
|
21 | end |
@@ -1,2 +1,4 | |||||
|
1 | # encoding: utf-8 | |||
|
2 | # | |||
1 | module IssueMovesHelper |
|
3 | module IssueMovesHelper | |
2 | end |
|
4 | end |
@@ -1,23 +1,25 | |||||
|
1 | # encoding: utf-8 | |||
|
2 | # | |||
1 | # Redmine - project management software |
|
3 | # Redmine - project management software | |
2 | # Copyright (C) 2006-2011 Jean-Philippe Lang |
|
4 | # Copyright (C) 2006-2011 Jean-Philippe Lang | |
3 | # |
|
5 | # | |
4 | # This program is free software; you can redistribute it and/or |
|
6 | # This program is free software; you can redistribute it and/or | |
5 | # modify it under the terms of the GNU General Public License |
|
7 | # modify it under the terms of the GNU General Public License | |
6 | # as published by the Free Software Foundation; either version 2 |
|
8 | # as published by the Free Software Foundation; either version 2 | |
7 | # of the License, or (at your option) any later version. |
|
9 | # of the License, or (at your option) any later version. | |
8 | # |
|
10 | # | |
9 | # This program is distributed in the hope that it will be useful, |
|
11 | # This program is distributed in the hope that it will be useful, | |
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | # GNU General Public License for more details. |
|
14 | # GNU General Public License for more details. | |
13 | # |
|
15 | # | |
14 | # You should have received a copy of the GNU General Public License |
|
16 | # You should have received a copy of the GNU General Public License | |
15 | # along with this program; if not, write to the Free Software |
|
17 | # along with this program; if not, write to the Free Software | |
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
17 |
|
19 | |||
18 | module IssueRelationsHelper |
|
20 | module IssueRelationsHelper | |
19 | def collection_for_relation_type_select |
|
21 | def collection_for_relation_type_select | |
20 | values = IssueRelation::TYPES |
|
22 | values = IssueRelation::TYPES | |
21 | values.keys.sort{|x,y| values[x][:order] <=> values[y][:order]}.collect{|k| [l(values[k][:name]), k]} |
|
23 | values.keys.sort{|x,y| values[x][:order] <=> values[y][:order]}.collect{|k| [l(values[k][:name]), k]} | |
22 | end |
|
24 | end | |
23 | end |
|
25 | end |
@@ -1,19 +1,21 | |||||
|
1 | # encoding: utf-8 | |||
|
2 | # | |||
1 | # Redmine - project management software |
|
3 | # Redmine - project management software | |
2 | # Copyright (C) 2006-2011 Jean-Philippe Lang |
|
4 | # Copyright (C) 2006-2011 Jean-Philippe Lang | |
3 | # |
|
5 | # | |
4 | # This program is free software; you can redistribute it and/or |
|
6 | # This program is free software; you can redistribute it and/or | |
5 | # modify it under the terms of the GNU General Public License |
|
7 | # modify it under the terms of the GNU General Public License | |
6 | # as published by the Free Software Foundation; either version 2 |
|
8 | # as published by the Free Software Foundation; either version 2 | |
7 | # of the License, or (at your option) any later version. |
|
9 | # of the License, or (at your option) any later version. | |
8 | # |
|
10 | # | |
9 | # This program is distributed in the hope that it will be useful, |
|
11 | # This program is distributed in the hope that it will be useful, | |
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | # GNU General Public License for more details. |
|
14 | # GNU General Public License for more details. | |
13 | # |
|
15 | # | |
14 | # You should have received a copy of the GNU General Public License |
|
16 | # You should have received a copy of the GNU General Public License | |
15 | # along with this program; if not, write to the Free Software |
|
17 | # along with this program; if not, write to the Free Software | |
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
17 |
|
19 | |||
18 | module IssueStatusesHelper |
|
20 | module IssueStatusesHelper | |
19 | end |
|
21 | end |
@@ -1,302 +1,304 | |||||
|
1 | # encoding: utf-8 | |||
|
2 | # | |||
1 | # Redmine - project management software |
|
3 | # Redmine - project management software | |
2 | # Copyright (C) 2006-2011 Jean-Philippe Lang |
|
4 | # Copyright (C) 2006-2011 Jean-Philippe Lang | |
3 | # |
|
5 | # | |
4 | # This program is free software; you can redistribute it and/or |
|
6 | # This program is free software; you can redistribute it and/or | |
5 | # modify it under the terms of the GNU General Public License |
|
7 | # modify it under the terms of the GNU General Public License | |
6 | # as published by the Free Software Foundation; either version 2 |
|
8 | # as published by the Free Software Foundation; either version 2 | |
7 | # of the License, or (at your option) any later version. |
|
9 | # of the License, or (at your option) any later version. | |
8 | # |
|
10 | # | |
9 | # This program is distributed in the hope that it will be useful, |
|
11 | # This program is distributed in the hope that it will be useful, | |
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | # GNU General Public License for more details. |
|
14 | # GNU General Public License for more details. | |
13 | # |
|
15 | # | |
14 | # You should have received a copy of the GNU General Public License |
|
16 | # You should have received a copy of the GNU General Public License | |
15 | # along with this program; if not, write to the Free Software |
|
17 | # along with this program; if not, write to the Free Software | |
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
17 |
|
19 | |||
18 | module IssuesHelper |
|
20 | module IssuesHelper | |
19 | include ApplicationHelper |
|
21 | include ApplicationHelper | |
20 |
|
22 | |||
21 | def issue_list(issues, &block) |
|
23 | def issue_list(issues, &block) | |
22 | ancestors = [] |
|
24 | ancestors = [] | |
23 | issues.each do |issue| |
|
25 | issues.each do |issue| | |
24 | while (ancestors.any? && !issue.is_descendant_of?(ancestors.last)) |
|
26 | while (ancestors.any? && !issue.is_descendant_of?(ancestors.last)) | |
25 | ancestors.pop |
|
27 | ancestors.pop | |
26 | end |
|
28 | end | |
27 | yield issue, ancestors.size |
|
29 | yield issue, ancestors.size | |
28 | ancestors << issue unless issue.leaf? |
|
30 | ancestors << issue unless issue.leaf? | |
29 | end |
|
31 | end | |
30 | end |
|
32 | end | |
31 |
|
33 | |||
32 | # Renders a HTML/CSS tooltip |
|
34 | # Renders a HTML/CSS tooltip | |
33 | # |
|
35 | # | |
34 | # To use, a trigger div is needed. This is a div with the class of "tooltip" |
|
36 | # To use, a trigger div is needed. This is a div with the class of "tooltip" | |
35 | # that contains this method wrapped in a span with the class of "tip" |
|
37 | # that contains this method wrapped in a span with the class of "tip" | |
36 | # |
|
38 | # | |
37 | # <div class="tooltip"><%= link_to_issue(issue) %> |
|
39 | # <div class="tooltip"><%= link_to_issue(issue) %> | |
38 | # <span class="tip"><%= render_issue_tooltip(issue) %></span> |
|
40 | # <span class="tip"><%= render_issue_tooltip(issue) %></span> | |
39 | # </div> |
|
41 | # </div> | |
40 | # |
|
42 | # | |
41 | def render_issue_tooltip(issue) |
|
43 | def render_issue_tooltip(issue) | |
42 | @cached_label_status ||= l(:field_status) |
|
44 | @cached_label_status ||= l(:field_status) | |
43 | @cached_label_start_date ||= l(:field_start_date) |
|
45 | @cached_label_start_date ||= l(:field_start_date) | |
44 | @cached_label_due_date ||= l(:field_due_date) |
|
46 | @cached_label_due_date ||= l(:field_due_date) | |
45 | @cached_label_assigned_to ||= l(:field_assigned_to) |
|
47 | @cached_label_assigned_to ||= l(:field_assigned_to) | |
46 | @cached_label_priority ||= l(:field_priority) |
|
48 | @cached_label_priority ||= l(:field_priority) | |
47 | @cached_label_project ||= l(:field_project) |
|
49 | @cached_label_project ||= l(:field_project) | |
48 |
|
50 | |||
49 | (link_to_issue(issue) + "<br /><br />" + |
|
51 | (link_to_issue(issue) + "<br /><br />" + | |
50 | "<strong>#{@cached_label_project}</strong>: #{link_to_project(issue.project)}<br />" + |
|
52 | "<strong>#{@cached_label_project}</strong>: #{link_to_project(issue.project)}<br />" + | |
51 | "<strong>#{@cached_label_status}</strong>: #{h(issue.status.name)}<br />" + |
|
53 | "<strong>#{@cached_label_status}</strong>: #{h(issue.status.name)}<br />" + | |
52 | "<strong>#{@cached_label_start_date}</strong>: #{format_date(issue.start_date)}<br />" + |
|
54 | "<strong>#{@cached_label_start_date}</strong>: #{format_date(issue.start_date)}<br />" + | |
53 | "<strong>#{@cached_label_due_date}</strong>: #{format_date(issue.due_date)}<br />" + |
|
55 | "<strong>#{@cached_label_due_date}</strong>: #{format_date(issue.due_date)}<br />" + | |
54 | "<strong>#{@cached_label_assigned_to}</strong>: #{h(issue.assigned_to)}<br />" + |
|
56 | "<strong>#{@cached_label_assigned_to}</strong>: #{h(issue.assigned_to)}<br />" + | |
55 | "<strong>#{@cached_label_priority}</strong>: #{h(issue.priority.name)}").html_safe |
|
57 | "<strong>#{@cached_label_priority}</strong>: #{h(issue.priority.name)}").html_safe | |
56 | end |
|
58 | end | |
57 |
|
59 | |||
58 | def issue_heading(issue) |
|
60 | def issue_heading(issue) | |
59 | h("#{issue.tracker} ##{issue.id}") |
|
61 | h("#{issue.tracker} ##{issue.id}") | |
60 | end |
|
62 | end | |
61 |
|
63 | |||
62 | def render_issue_subject_with_tree(issue) |
|
64 | def render_issue_subject_with_tree(issue) | |
63 | s = '' |
|
65 | s = '' | |
64 | ancestors = issue.root? ? [] : issue.ancestors.visible.all |
|
66 | ancestors = issue.root? ? [] : issue.ancestors.visible.all | |
65 | ancestors.each do |ancestor| |
|
67 | ancestors.each do |ancestor| | |
66 | s << '<div>' + content_tag('p', link_to_issue(ancestor)) |
|
68 | s << '<div>' + content_tag('p', link_to_issue(ancestor)) | |
67 | end |
|
69 | end | |
68 | s << '<div>' |
|
70 | s << '<div>' | |
69 | subject = h(issue.subject) |
|
71 | subject = h(issue.subject) | |
70 | if issue.is_private? |
|
72 | if issue.is_private? | |
71 | subject = content_tag('span', l(:field_is_private), :class => 'private') + ' ' + subject |
|
73 | subject = content_tag('span', l(:field_is_private), :class => 'private') + ' ' + subject | |
72 | end |
|
74 | end | |
73 | s << content_tag('h3', subject) |
|
75 | s << content_tag('h3', subject) | |
74 | s << '</div>' * (ancestors.size + 1) |
|
76 | s << '</div>' * (ancestors.size + 1) | |
75 | s.html_safe |
|
77 | s.html_safe | |
76 | end |
|
78 | end | |
77 |
|
79 | |||
78 | def render_descendants_tree(issue) |
|
80 | def render_descendants_tree(issue) | |
79 | s = '<form><table class="list issues">' |
|
81 | s = '<form><table class="list issues">' | |
80 | issue_list(issue.descendants.visible.sort_by(&:lft)) do |child, level| |
|
82 | issue_list(issue.descendants.visible.sort_by(&:lft)) do |child, level| | |
81 | s << content_tag('tr', |
|
83 | s << content_tag('tr', | |
82 | content_tag('td', check_box_tag("ids[]", child.id, false, :id => nil), :class => 'checkbox') + |
|
84 | content_tag('td', check_box_tag("ids[]", child.id, false, :id => nil), :class => 'checkbox') + | |
83 | content_tag('td', link_to_issue(child, :truncate => 60), :class => 'subject') + |
|
85 | content_tag('td', link_to_issue(child, :truncate => 60), :class => 'subject') + | |
84 | content_tag('td', h(child.status)) + |
|
86 | content_tag('td', h(child.status)) + | |
85 | content_tag('td', link_to_user(child.assigned_to)) + |
|
87 | content_tag('td', link_to_user(child.assigned_to)) + | |
86 | content_tag('td', progress_bar(child.done_ratio, :width => '80px')), |
|
88 | content_tag('td', progress_bar(child.done_ratio, :width => '80px')), | |
87 | :class => "issue issue-#{child.id} hascontextmenu #{level > 0 ? "idnt idnt-#{level}" : nil}") |
|
89 | :class => "issue issue-#{child.id} hascontextmenu #{level > 0 ? "idnt idnt-#{level}" : nil}") | |
88 | end |
|
90 | end | |
89 | s << '</form></table>' |
|
91 | s << '</form></table>' | |
90 | s.html_safe |
|
92 | s.html_safe | |
91 | end |
|
93 | end | |
92 |
|
94 | |||
93 | def render_custom_fields_rows(issue) |
|
95 | def render_custom_fields_rows(issue) | |
94 | return if issue.custom_field_values.empty? |
|
96 | return if issue.custom_field_values.empty? | |
95 | ordered_values = [] |
|
97 | ordered_values = [] | |
96 | half = (issue.custom_field_values.size / 2.0).ceil |
|
98 | half = (issue.custom_field_values.size / 2.0).ceil | |
97 | half.times do |i| |
|
99 | half.times do |i| | |
98 | ordered_values << issue.custom_field_values[i] |
|
100 | ordered_values << issue.custom_field_values[i] | |
99 | ordered_values << issue.custom_field_values[i + half] |
|
101 | ordered_values << issue.custom_field_values[i + half] | |
100 | end |
|
102 | end | |
101 | s = "<tr>\n" |
|
103 | s = "<tr>\n" | |
102 | n = 0 |
|
104 | n = 0 | |
103 | ordered_values.compact.each do |value| |
|
105 | ordered_values.compact.each do |value| | |
104 | s << "</tr>\n<tr>\n" if n > 0 && (n % 2) == 0 |
|
106 | s << "</tr>\n<tr>\n" if n > 0 && (n % 2) == 0 | |
105 | s << "\t<th>#{ h(value.custom_field.name) }:</th><td>#{ simple_format_without_paragraph(h(show_value(value))) }</td>\n" |
|
107 | s << "\t<th>#{ h(value.custom_field.name) }:</th><td>#{ simple_format_without_paragraph(h(show_value(value))) }</td>\n" | |
106 | n += 1 |
|
108 | n += 1 | |
107 | end |
|
109 | end | |
108 | s << "</tr>\n" |
|
110 | s << "</tr>\n" | |
109 | s.html_safe |
|
111 | s.html_safe | |
110 | end |
|
112 | end | |
111 |
|
113 | |||
112 | def issues_destroy_confirmation_message(issues) |
|
114 | def issues_destroy_confirmation_message(issues) | |
113 | issues = [issues] unless issues.is_a?(Array) |
|
115 | issues = [issues] unless issues.is_a?(Array) | |
114 | message = l(:text_issues_destroy_confirmation) |
|
116 | message = l(:text_issues_destroy_confirmation) | |
115 | descendant_count = issues.inject(0) {|memo, i| memo += (i.right - i.left - 1)/2} |
|
117 | descendant_count = issues.inject(0) {|memo, i| memo += (i.right - i.left - 1)/2} | |
116 | if descendant_count > 0 |
|
118 | if descendant_count > 0 | |
117 | issues.each do |issue| |
|
119 | issues.each do |issue| | |
118 | next if issue.root? |
|
120 | next if issue.root? | |
119 | issues.each do |other_issue| |
|
121 | issues.each do |other_issue| | |
120 | descendant_count -= 1 if issue.is_descendant_of?(other_issue) |
|
122 | descendant_count -= 1 if issue.is_descendant_of?(other_issue) | |
121 | end |
|
123 | end | |
122 | end |
|
124 | end | |
123 | if descendant_count > 0 |
|
125 | if descendant_count > 0 | |
124 | message << "\n" + l(:text_issues_destroy_descendants_confirmation, :count => descendant_count) |
|
126 | message << "\n" + l(:text_issues_destroy_descendants_confirmation, :count => descendant_count) | |
125 | end |
|
127 | end | |
126 | end |
|
128 | end | |
127 | message |
|
129 | message | |
128 | end |
|
130 | end | |
129 |
|
131 | |||
130 | def sidebar_queries |
|
132 | def sidebar_queries | |
131 | unless @sidebar_queries |
|
133 | unless @sidebar_queries | |
132 | # User can see public queries and his own queries |
|
134 | # User can see public queries and his own queries | |
133 | visible = ARCondition.new(["is_public = ? OR user_id = ?", true, (User.current.logged? ? User.current.id : 0)]) |
|
135 | visible = ARCondition.new(["is_public = ? OR user_id = ?", true, (User.current.logged? ? User.current.id : 0)]) | |
134 | # Project specific queries and global queries |
|
136 | # Project specific queries and global queries | |
135 | visible << (@project.nil? ? ["project_id IS NULL"] : ["project_id IS NULL OR project_id = ?", @project.id]) |
|
137 | visible << (@project.nil? ? ["project_id IS NULL"] : ["project_id IS NULL OR project_id = ?", @project.id]) | |
136 | @sidebar_queries = Query.find(:all, |
|
138 | @sidebar_queries = Query.find(:all, | |
137 | :select => 'id, name, is_public', |
|
139 | :select => 'id, name, is_public', | |
138 | :order => "name ASC", |
|
140 | :order => "name ASC", | |
139 | :conditions => visible.conditions) |
|
141 | :conditions => visible.conditions) | |
140 | end |
|
142 | end | |
141 | @sidebar_queries |
|
143 | @sidebar_queries | |
142 | end |
|
144 | end | |
143 |
|
145 | |||
144 | def query_links(title, queries) |
|
146 | def query_links(title, queries) | |
145 | # links to #index on issues/show |
|
147 | # links to #index on issues/show | |
146 | url_params = controller_name == 'issues' ? {:controller => 'issues', :action => 'index', :project_id => @project} : params |
|
148 | url_params = controller_name == 'issues' ? {:controller => 'issues', :action => 'index', :project_id => @project} : params | |
147 |
|
149 | |||
148 | content_tag('h3', h(title)) + |
|
150 | content_tag('h3', h(title)) + | |
149 | queries.collect {|query| |
|
151 | queries.collect {|query| | |
150 | link_to(h(query.name), url_params.merge(:query_id => query)) |
|
152 | link_to(h(query.name), url_params.merge(:query_id => query)) | |
151 | }.join('<br />') |
|
153 | }.join('<br />') | |
152 | end |
|
154 | end | |
153 |
|
155 | |||
154 | def render_sidebar_queries |
|
156 | def render_sidebar_queries | |
155 | out = '' |
|
157 | out = '' | |
156 | queries = sidebar_queries.select {|q| !q.is_public?} |
|
158 | queries = sidebar_queries.select {|q| !q.is_public?} | |
157 | out << query_links(l(:label_my_queries), queries) if queries.any? |
|
159 | out << query_links(l(:label_my_queries), queries) if queries.any? | |
158 | queries = sidebar_queries.select {|q| q.is_public?} |
|
160 | queries = sidebar_queries.select {|q| q.is_public?} | |
159 | out << query_links(l(:label_query_plural), queries) if queries.any? |
|
161 | out << query_links(l(:label_query_plural), queries) if queries.any? | |
160 | out |
|
162 | out | |
161 | end |
|
163 | end | |
162 |
|
164 | |||
163 | def show_detail(detail, no_html=false) |
|
165 | def show_detail(detail, no_html=false) | |
164 | case detail.property |
|
166 | case detail.property | |
165 | when 'attr' |
|
167 | when 'attr' | |
166 | field = detail.prop_key.to_s.gsub(/\_id$/, "") |
|
168 | field = detail.prop_key.to_s.gsub(/\_id$/, "") | |
167 | label = l(("field_" + field).to_sym) |
|
169 | label = l(("field_" + field).to_sym) | |
168 | case |
|
170 | case | |
169 | when ['due_date', 'start_date'].include?(detail.prop_key) |
|
171 | when ['due_date', 'start_date'].include?(detail.prop_key) | |
170 | value = format_date(detail.value.to_date) if detail.value |
|
172 | value = format_date(detail.value.to_date) if detail.value | |
171 | old_value = format_date(detail.old_value.to_date) if detail.old_value |
|
173 | old_value = format_date(detail.old_value.to_date) if detail.old_value | |
172 |
|
174 | |||
173 | when ['project_id', 'status_id', 'tracker_id', 'assigned_to_id', 'priority_id', 'category_id', 'fixed_version_id'].include?(detail.prop_key) |
|
175 | when ['project_id', 'status_id', 'tracker_id', 'assigned_to_id', 'priority_id', 'category_id', 'fixed_version_id'].include?(detail.prop_key) | |
174 | value = find_name_by_reflection(field, detail.value) |
|
176 | value = find_name_by_reflection(field, detail.value) | |
175 | old_value = find_name_by_reflection(field, detail.old_value) |
|
177 | old_value = find_name_by_reflection(field, detail.old_value) | |
176 |
|
178 | |||
177 | when detail.prop_key == 'estimated_hours' |
|
179 | when detail.prop_key == 'estimated_hours' | |
178 | value = "%0.02f" % detail.value.to_f unless detail.value.blank? |
|
180 | value = "%0.02f" % detail.value.to_f unless detail.value.blank? | |
179 | old_value = "%0.02f" % detail.old_value.to_f unless detail.old_value.blank? |
|
181 | old_value = "%0.02f" % detail.old_value.to_f unless detail.old_value.blank? | |
180 |
|
182 | |||
181 | when detail.prop_key == 'parent_id' |
|
183 | when detail.prop_key == 'parent_id' | |
182 | label = l(:field_parent_issue) |
|
184 | label = l(:field_parent_issue) | |
183 | value = "##{detail.value}" unless detail.value.blank? |
|
185 | value = "##{detail.value}" unless detail.value.blank? | |
184 | old_value = "##{detail.old_value}" unless detail.old_value.blank? |
|
186 | old_value = "##{detail.old_value}" unless detail.old_value.blank? | |
185 |
|
187 | |||
186 | when detail.prop_key == 'is_private' |
|
188 | when detail.prop_key == 'is_private' | |
187 | value = l(detail.value == "0" ? :general_text_No : :general_text_Yes) unless detail.value.blank? |
|
189 | value = l(detail.value == "0" ? :general_text_No : :general_text_Yes) unless detail.value.blank? | |
188 | old_value = l(detail.old_value == "0" ? :general_text_No : :general_text_Yes) unless detail.old_value.blank? |
|
190 | old_value = l(detail.old_value == "0" ? :general_text_No : :general_text_Yes) unless detail.old_value.blank? | |
189 | end |
|
191 | end | |
190 | when 'cf' |
|
192 | when 'cf' | |
191 | custom_field = CustomField.find_by_id(detail.prop_key) |
|
193 | custom_field = CustomField.find_by_id(detail.prop_key) | |
192 | if custom_field |
|
194 | if custom_field | |
193 | label = custom_field.name |
|
195 | label = custom_field.name | |
194 | value = format_value(detail.value, custom_field.field_format) if detail.value |
|
196 | value = format_value(detail.value, custom_field.field_format) if detail.value | |
195 | old_value = format_value(detail.old_value, custom_field.field_format) if detail.old_value |
|
197 | old_value = format_value(detail.old_value, custom_field.field_format) if detail.old_value | |
196 | end |
|
198 | end | |
197 | when 'attachment' |
|
199 | when 'attachment' | |
198 | label = l(:label_attachment) |
|
200 | label = l(:label_attachment) | |
199 | end |
|
201 | end | |
200 | call_hook(:helper_issues_show_detail_after_setting, {:detail => detail, :label => label, :value => value, :old_value => old_value }) |
|
202 | call_hook(:helper_issues_show_detail_after_setting, {:detail => detail, :label => label, :value => value, :old_value => old_value }) | |
201 |
|
203 | |||
202 | label ||= detail.prop_key |
|
204 | label ||= detail.prop_key | |
203 | value ||= detail.value |
|
205 | value ||= detail.value | |
204 | old_value ||= detail.old_value |
|
206 | old_value ||= detail.old_value | |
205 |
|
207 | |||
206 | unless no_html |
|
208 | unless no_html | |
207 | label = content_tag('strong', label) |
|
209 | label = content_tag('strong', label) | |
208 | old_value = content_tag("i", h(old_value)) if detail.old_value |
|
210 | old_value = content_tag("i", h(old_value)) if detail.old_value | |
209 | old_value = content_tag("strike", old_value) if detail.old_value and detail.value.blank? |
|
211 | old_value = content_tag("strike", old_value) if detail.old_value and detail.value.blank? | |
210 | if detail.property == 'attachment' && !value.blank? && a = Attachment.find_by_id(detail.prop_key) |
|
212 | if detail.property == 'attachment' && !value.blank? && a = Attachment.find_by_id(detail.prop_key) | |
211 | # Link to the attachment if it has not been removed |
|
213 | # Link to the attachment if it has not been removed | |
212 | value = link_to_attachment(a) |
|
214 | value = link_to_attachment(a) | |
213 | else |
|
215 | else | |
214 | value = content_tag("i", h(value)) if value |
|
216 | value = content_tag("i", h(value)) if value | |
215 | end |
|
217 | end | |
216 | end |
|
218 | end | |
217 |
|
219 | |||
218 | if detail.property == 'attr' && detail.prop_key == 'description' |
|
220 | if detail.property == 'attr' && detail.prop_key == 'description' | |
219 | s = l(:text_journal_changed_no_detail, :label => label) |
|
221 | s = l(:text_journal_changed_no_detail, :label => label) | |
220 | unless no_html |
|
222 | unless no_html | |
221 | diff_link = link_to 'diff', |
|
223 | diff_link = link_to 'diff', | |
222 | {:controller => 'journals', :action => 'diff', :id => detail.journal_id, :detail_id => detail.id}, |
|
224 | {:controller => 'journals', :action => 'diff', :id => detail.journal_id, :detail_id => detail.id}, | |
223 | :title => l(:label_view_diff) |
|
225 | :title => l(:label_view_diff) | |
224 | s << " (#{ diff_link })" |
|
226 | s << " (#{ diff_link })" | |
225 | end |
|
227 | end | |
226 | s |
|
228 | s | |
227 | elsif !detail.value.blank? |
|
229 | elsif !detail.value.blank? | |
228 | case detail.property |
|
230 | case detail.property | |
229 | when 'attr', 'cf' |
|
231 | when 'attr', 'cf' | |
230 | if !detail.old_value.blank? |
|
232 | if !detail.old_value.blank? | |
231 | l(:text_journal_changed, :label => label, :old => old_value, :new => value) |
|
233 | l(:text_journal_changed, :label => label, :old => old_value, :new => value) | |
232 | else |
|
234 | else | |
233 | l(:text_journal_set_to, :label => label, :value => value) |
|
235 | l(:text_journal_set_to, :label => label, :value => value) | |
234 | end |
|
236 | end | |
235 | when 'attachment' |
|
237 | when 'attachment' | |
236 | l(:text_journal_added, :label => label, :value => value) |
|
238 | l(:text_journal_added, :label => label, :value => value) | |
237 | end |
|
239 | end | |
238 | else |
|
240 | else | |
239 | l(:text_journal_deleted, :label => label, :old => old_value) |
|
241 | l(:text_journal_deleted, :label => label, :old => old_value) | |
240 | end |
|
242 | end | |
241 | end |
|
243 | end | |
242 |
|
244 | |||
243 | # Find the name of an associated record stored in the field attribute |
|
245 | # Find the name of an associated record stored in the field attribute | |
244 | def find_name_by_reflection(field, id) |
|
246 | def find_name_by_reflection(field, id) | |
245 | association = Issue.reflect_on_association(field.to_sym) |
|
247 | association = Issue.reflect_on_association(field.to_sym) | |
246 | if association |
|
248 | if association | |
247 | record = association.class_name.constantize.find_by_id(id) |
|
249 | record = association.class_name.constantize.find_by_id(id) | |
248 | return record.name if record |
|
250 | return record.name if record | |
249 | end |
|
251 | end | |
250 | end |
|
252 | end | |
251 |
|
253 | |||
252 | # Renders issue children recursively |
|
254 | # Renders issue children recursively | |
253 | def render_api_issue_children(issue, api) |
|
255 | def render_api_issue_children(issue, api) | |
254 | return if issue.leaf? |
|
256 | return if issue.leaf? | |
255 | api.array :children do |
|
257 | api.array :children do | |
256 | issue.children.each do |child| |
|
258 | issue.children.each do |child| | |
257 | api.issue(:id => child.id) do |
|
259 | api.issue(:id => child.id) do | |
258 | api.tracker(:id => child.tracker_id, :name => child.tracker.name) unless child.tracker.nil? |
|
260 | api.tracker(:id => child.tracker_id, :name => child.tracker.name) unless child.tracker.nil? | |
259 | api.subject child.subject |
|
261 | api.subject child.subject | |
260 | render_api_issue_children(child, api) |
|
262 | render_api_issue_children(child, api) | |
261 | end |
|
263 | end | |
262 | end |
|
264 | end | |
263 | end |
|
265 | end | |
264 | end |
|
266 | end | |
265 |
|
267 | |||
266 | def issues_to_csv(issues, project, query, options={}) |
|
268 | def issues_to_csv(issues, project, query, options={}) | |
267 | decimal_separator = l(:general_csv_decimal_separator) |
|
269 | decimal_separator = l(:general_csv_decimal_separator) | |
268 | encoding = l(:general_csv_encoding) |
|
270 | encoding = l(:general_csv_encoding) | |
269 | columns = (options[:columns] == 'all' ? query.available_columns : query.columns) |
|
271 | columns = (options[:columns] == 'all' ? query.available_columns : query.columns) | |
270 |
|
272 | |||
271 | export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv| |
|
273 | export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv| | |
272 | # csv header fields |
|
274 | # csv header fields | |
273 | csv << [ "#" ] + columns.collect {|c| Redmine::CodesetUtil.from_utf8(c.caption.to_s, encoding) } + |
|
275 | csv << [ "#" ] + columns.collect {|c| Redmine::CodesetUtil.from_utf8(c.caption.to_s, encoding) } + | |
274 | (options[:description] ? [Redmine::CodesetUtil.from_utf8(l(:field_description), encoding)] : []) |
|
276 | (options[:description] ? [Redmine::CodesetUtil.from_utf8(l(:field_description), encoding)] : []) | |
275 |
|
277 | |||
276 | # csv lines |
|
278 | # csv lines | |
277 | issues.each do |issue| |
|
279 | issues.each do |issue| | |
278 | col_values = columns.collect do |column| |
|
280 | col_values = columns.collect do |column| | |
279 | s = if column.is_a?(QueryCustomFieldColumn) |
|
281 | s = if column.is_a?(QueryCustomFieldColumn) | |
280 | cv = issue.custom_values.detect {|v| v.custom_field_id == column.custom_field.id} |
|
282 | cv = issue.custom_values.detect {|v| v.custom_field_id == column.custom_field.id} | |
281 | show_value(cv) |
|
283 | show_value(cv) | |
282 | else |
|
284 | else | |
283 | value = issue.send(column.name) |
|
285 | value = issue.send(column.name) | |
284 | if value.is_a?(Date) |
|
286 | if value.is_a?(Date) | |
285 | format_date(value) |
|
287 | format_date(value) | |
286 | elsif value.is_a?(Time) |
|
288 | elsif value.is_a?(Time) | |
287 | format_time(value) |
|
289 | format_time(value) | |
288 | elsif value.is_a?(Float) |
|
290 | elsif value.is_a?(Float) | |
289 | value.to_s.gsub('.', decimal_separator) |
|
291 | value.to_s.gsub('.', decimal_separator) | |
290 | else |
|
292 | else | |
291 | value |
|
293 | value | |
292 | end |
|
294 | end | |
293 | end |
|
295 | end | |
294 | s.to_s |
|
296 | s.to_s | |
295 | end |
|
297 | end | |
296 | csv << [ issue.id.to_s ] + col_values.collect {|c| Redmine::CodesetUtil.from_utf8(c.to_s, encoding) } + |
|
298 | csv << [ issue.id.to_s ] + col_values.collect {|c| Redmine::CodesetUtil.from_utf8(c.to_s, encoding) } + | |
297 | (options[:description] ? [Redmine::CodesetUtil.from_utf8(issue.description, encoding)] : []) |
|
299 | (options[:description] ? [Redmine::CodesetUtil.from_utf8(issue.description, encoding)] : []) | |
298 | end |
|
300 | end | |
299 | end |
|
301 | end | |
300 | export |
|
302 | export | |
301 | end |
|
303 | end | |
302 | end |
|
304 | end |
@@ -1,42 +1,44 | |||||
|
1 | # encoding: utf-8 | |||
|
2 | # | |||
1 | # Redmine - project management software |
|
3 | # Redmine - project management software | |
2 | # Copyright (C) 2006-2011 Jean-Philippe Lang |
|
4 | # Copyright (C) 2006-2011 Jean-Philippe Lang | |
3 | # |
|
5 | # | |
4 | # This program is free software; you can redistribute it and/or |
|
6 | # This program is free software; you can redistribute it and/or | |
5 | # modify it under the terms of the GNU General Public License |
|
7 | # modify it under the terms of the GNU General Public License | |
6 | # as published by the Free Software Foundation; either version 2 |
|
8 | # as published by the Free Software Foundation; either version 2 | |
7 | # of the License, or (at your option) any later version. |
|
9 | # of the License, or (at your option) any later version. | |
8 | # |
|
10 | # | |
9 | # This program is distributed in the hope that it will be useful, |
|
11 | # This program is distributed in the hope that it will be useful, | |
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | # GNU General Public License for more details. |
|
14 | # GNU General Public License for more details. | |
13 | # |
|
15 | # | |
14 | # You should have received a copy of the GNU General Public License |
|
16 | # You should have received a copy of the GNU General Public License | |
15 | # along with this program; if not, write to the Free Software |
|
17 | # along with this program; if not, write to the Free Software | |
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
17 |
|
19 | |||
18 | module JournalsHelper |
|
20 | module JournalsHelper | |
19 | def render_notes(issue, journal, options={}) |
|
21 | def render_notes(issue, journal, options={}) | |
20 | content = '' |
|
22 | content = '' | |
21 | editable = User.current.logged? && (User.current.allowed_to?(:edit_issue_notes, issue.project) || (journal.user == User.current && User.current.allowed_to?(:edit_own_issue_notes, issue.project))) |
|
23 | editable = User.current.logged? && (User.current.allowed_to?(:edit_issue_notes, issue.project) || (journal.user == User.current && User.current.allowed_to?(:edit_own_issue_notes, issue.project))) | |
22 | links = [] |
|
24 | links = [] | |
23 | if !journal.notes.blank? |
|
25 | if !journal.notes.blank? | |
24 | links << link_to_remote(image_tag('comment.png'), |
|
26 | links << link_to_remote(image_tag('comment.png'), | |
25 | { :url => {:controller => 'journals', :action => 'new', :id => issue, :journal_id => journal} }, |
|
27 | { :url => {:controller => 'journals', :action => 'new', :id => issue, :journal_id => journal} }, | |
26 | :title => l(:button_quote)) if options[:reply_links] |
|
28 | :title => l(:button_quote)) if options[:reply_links] | |
27 | links << link_to_in_place_notes_editor(image_tag('edit.png'), "journal-#{journal.id}-notes", |
|
29 | links << link_to_in_place_notes_editor(image_tag('edit.png'), "journal-#{journal.id}-notes", | |
28 | { :controller => 'journals', :action => 'edit', :id => journal }, |
|
30 | { :controller => 'journals', :action => 'edit', :id => journal }, | |
29 | :title => l(:button_edit)) if editable |
|
31 | :title => l(:button_edit)) if editable | |
30 | end |
|
32 | end | |
31 | content << content_tag('div', links.join(' '), :class => 'contextual') unless links.empty? |
|
33 | content << content_tag('div', links.join(' '), :class => 'contextual') unless links.empty? | |
32 | content << textilizable(journal, :notes) |
|
34 | content << textilizable(journal, :notes) | |
33 | css_classes = "wiki" |
|
35 | css_classes = "wiki" | |
34 | css_classes << " editable" if editable |
|
36 | css_classes << " editable" if editable | |
35 | content_tag('div', content, :id => "journal-#{journal.id}-notes", :class => css_classes) |
|
37 | content_tag('div', content, :id => "journal-#{journal.id}-notes", :class => css_classes) | |
36 | end |
|
38 | end | |
37 |
|
39 | |||
38 | def link_to_in_place_notes_editor(text, field_id, url, options={}) |
|
40 | def link_to_in_place_notes_editor(text, field_id, url, options={}) | |
39 | onclick = "new Ajax.Request('#{url_for(url)}', {asynchronous:true, evalScripts:true, method:'get'}); return false;" |
|
41 | onclick = "new Ajax.Request('#{url_for(url)}', {asynchronous:true, evalScripts:true, method:'get'}); return false;" | |
40 | link_to text, '#', options.merge(:onclick => onclick) |
|
42 | link_to text, '#', options.merge(:onclick => onclick) | |
41 | end |
|
43 | end | |
42 | end |
|
44 | end |
@@ -1,19 +1,21 | |||||
|
1 | # encoding: utf-8 | |||
|
2 | # | |||
1 | # Redmine - project management software |
|
3 | # Redmine - project management software | |
2 | # Copyright (C) 2006-2011 Jean-Philippe Lang |
|
4 | # Copyright (C) 2006-2011 Jean-Philippe Lang | |
3 | # |
|
5 | # | |
4 | # This program is free software; you can redistribute it and/or |
|
6 | # This program is free software; you can redistribute it and/or | |
5 | # modify it under the terms of the GNU General Public License |
|
7 | # modify it under the terms of the GNU General Public License | |
6 | # as published by the Free Software Foundation; either version 2 |
|
8 | # as published by the Free Software Foundation; either version 2 | |
7 | # of the License, or (at your option) any later version. |
|
9 | # of the License, or (at your option) any later version. | |
8 | # |
|
10 | # | |
9 | # This program is distributed in the hope that it will be useful, |
|
11 | # This program is distributed in the hope that it will be useful, | |
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | # GNU General Public License for more details. |
|
14 | # GNU General Public License for more details. | |
13 | # |
|
15 | # | |
14 | # You should have received a copy of the GNU General Public License |
|
16 | # You should have received a copy of the GNU General Public License | |
15 | # along with this program; if not, write to the Free Software |
|
17 | # along with this program; if not, write to the Free Software | |
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
17 |
|
19 | |||
18 | module MailHandlerHelper |
|
20 | module MailHandlerHelper | |
19 | end |
|
21 | end |
@@ -1,19 +1,21 | |||||
|
1 | # encoding: utf-8 | |||
|
2 | # | |||
1 | # Redmine - project management software |
|
3 | # Redmine - project management software | |
2 | # Copyright (C) 2006-2011 Jean-Philippe Lang |
|
4 | # Copyright (C) 2006-2011 Jean-Philippe Lang | |
3 | # |
|
5 | # | |
4 | # This program is free software; you can redistribute it and/or |
|
6 | # This program is free software; you can redistribute it and/or | |
5 | # modify it under the terms of the GNU General Public License |
|
7 | # modify it under the terms of the GNU General Public License | |
6 | # as published by the Free Software Foundation; either version 2 |
|
8 | # as published by the Free Software Foundation; either version 2 | |
7 | # of the License, or (at your option) any later version. |
|
9 | # of the License, or (at your option) any later version. | |
8 | # |
|
10 | # | |
9 | # This program is distributed in the hope that it will be useful, |
|
11 | # This program is distributed in the hope that it will be useful, | |
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | # GNU General Public License for more details. |
|
14 | # GNU General Public License for more details. | |
13 | # |
|
15 | # | |
14 | # You should have received a copy of the GNU General Public License |
|
16 | # You should have received a copy of the GNU General Public License | |
15 | # along with this program; if not, write to the Free Software |
|
17 | # along with this program; if not, write to the Free Software | |
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
17 |
|
19 | |||
18 | module MembersHelper |
|
20 | module MembersHelper | |
19 | end |
|
21 | end |
@@ -1,19 +1,21 | |||||
|
1 | # encoding: utf-8 | |||
|
2 | # | |||
1 | # Redmine - project management software |
|
3 | # Redmine - project management software | |
2 | # Copyright (C) 2006-2011 Jean-Philippe Lang |
|
4 | # Copyright (C) 2006-2011 Jean-Philippe Lang | |
3 | # |
|
5 | # | |
4 | # This program is free software; you can redistribute it and/or |
|
6 | # This program is free software; you can redistribute it and/or | |
5 | # modify it under the terms of the GNU General Public License |
|
7 | # modify it under the terms of the GNU General Public License | |
6 | # as published by the Free Software Foundation; either version 2 |
|
8 | # as published by the Free Software Foundation; either version 2 | |
7 | # of the License, or (at your option) any later version. |
|
9 | # of the License, or (at your option) any later version. | |
8 | # |
|
10 | # | |
9 | # This program is distributed in the hope that it will be useful, |
|
11 | # This program is distributed in the hope that it will be useful, | |
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | # GNU General Public License for more details. |
|
14 | # GNU General Public License for more details. | |
13 | # |
|
15 | # | |
14 | # You should have received a copy of the GNU General Public License |
|
16 | # You should have received a copy of the GNU General Public License | |
15 | # along with this program; if not, write to the Free Software |
|
17 | # along with this program; if not, write to the Free Software | |
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
17 |
|
19 | |||
18 | module MessagesHelper |
|
20 | module MessagesHelper | |
19 | end |
|
21 | end |
@@ -1,19 +1,21 | |||||
|
1 | # encoding: utf-8 | |||
|
2 | # | |||
1 | # Redmine - project management software |
|
3 | # Redmine - project management software | |
2 | # Copyright (C) 2006-2011 Jean-Philippe Lang |
|
4 | # Copyright (C) 2006-2011 Jean-Philippe Lang | |
3 | # |
|
5 | # | |
4 | # This program is free software; you can redistribute it and/or |
|
6 | # This program is free software; you can redistribute it and/or | |
5 | # modify it under the terms of the GNU General Public License |
|
7 | # modify it under the terms of the GNU General Public License | |
6 | # as published by the Free Software Foundation; either version 2 |
|
8 | # as published by the Free Software Foundation; either version 2 | |
7 | # of the License, or (at your option) any later version. |
|
9 | # of the License, or (at your option) any later version. | |
8 | # |
|
10 | # | |
9 | # This program is distributed in the hope that it will be useful, |
|
11 | # This program is distributed in the hope that it will be useful, | |
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | # GNU General Public License for more details. |
|
14 | # GNU General Public License for more details. | |
13 | # |
|
15 | # | |
14 | # You should have received a copy of the GNU General Public License |
|
16 | # You should have received a copy of the GNU General Public License | |
15 | # along with this program; if not, write to the Free Software |
|
17 | # along with this program; if not, write to the Free Software | |
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
17 |
|
19 | |||
18 | module MyHelper |
|
20 | module MyHelper | |
19 | end |
|
21 | end |
@@ -1,19 +1,21 | |||||
|
1 | # encoding: utf-8 | |||
|
2 | # | |||
1 | # Redmine - project management software |
|
3 | # Redmine - project management software | |
2 | # Copyright (C) 2006-2011 Jean-Philippe Lang |
|
4 | # Copyright (C) 2006-2011 Jean-Philippe Lang | |
3 | # |
|
5 | # | |
4 | # This program is free software; you can redistribute it and/or |
|
6 | # This program is free software; you can redistribute it and/or | |
5 | # modify it under the terms of the GNU General Public License |
|
7 | # modify it under the terms of the GNU General Public License | |
6 | # as published by the Free Software Foundation; either version 2 |
|
8 | # as published by the Free Software Foundation; either version 2 | |
7 | # of the License, or (at your option) any later version. |
|
9 | # of the License, or (at your option) any later version. | |
8 | # |
|
10 | # | |
9 | # This program is distributed in the hope that it will be useful, |
|
11 | # This program is distributed in the hope that it will be useful, | |
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | # GNU General Public License for more details. |
|
14 | # GNU General Public License for more details. | |
13 | # |
|
15 | # | |
14 | # You should have received a copy of the GNU General Public License |
|
16 | # You should have received a copy of the GNU General Public License | |
15 | # along with this program; if not, write to the Free Software |
|
17 | # along with this program; if not, write to the Free Software | |
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
17 |
|
19 | |||
18 | module NewsHelper |
|
20 | module NewsHelper | |
19 | end |
|
21 | end |
@@ -1,108 +1,110 | |||||
|
1 | # encoding: utf-8 | |||
|
2 | # | |||
1 | # Redmine - project management software |
|
3 | # Redmine - project management software | |
2 | # Copyright (C) 2006-2011 Jean-Philippe Lang |
|
4 | # Copyright (C) 2006-2011 Jean-Philippe Lang | |
3 | # |
|
5 | # | |
4 | # This program is free software; you can redistribute it and/or |
|
6 | # This program is free software; you can redistribute it and/or | |
5 | # modify it under the terms of the GNU General Public License |
|
7 | # modify it under the terms of the GNU General Public License | |
6 | # as published by the Free Software Foundation; either version 2 |
|
8 | # as published by the Free Software Foundation; either version 2 | |
7 | # of the License, or (at your option) any later version. |
|
9 | # of the License, or (at your option) any later version. | |
8 | # |
|
10 | # | |
9 | # This program is distributed in the hope that it will be useful, |
|
11 | # This program is distributed in the hope that it will be useful, | |
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | # GNU General Public License for more details. |
|
14 | # GNU General Public License for more details. | |
13 | # |
|
15 | # | |
14 | # You should have received a copy of the GNU General Public License |
|
16 | # You should have received a copy of the GNU General Public License | |
15 | # along with this program; if not, write to the Free Software |
|
17 | # along with this program; if not, write to the Free Software | |
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
17 |
|
19 | |||
18 | module ProjectsHelper |
|
20 | module ProjectsHelper | |
19 | def link_to_version(version, options = {}) |
|
21 | def link_to_version(version, options = {}) | |
20 | return '' unless version && version.is_a?(Version) |
|
22 | return '' unless version && version.is_a?(Version) | |
21 | link_to_if version.visible?, format_version_name(version), { :controller => 'versions', :action => 'show', :id => version }, options |
|
23 | link_to_if version.visible?, format_version_name(version), { :controller => 'versions', :action => 'show', :id => version }, options | |
22 | end |
|
24 | end | |
23 |
|
25 | |||
24 | def project_settings_tabs |
|
26 | def project_settings_tabs | |
25 | tabs = [{:name => 'info', :action => :edit_project, :partial => 'projects/edit', :label => :label_information_plural}, |
|
27 | tabs = [{:name => 'info', :action => :edit_project, :partial => 'projects/edit', :label => :label_information_plural}, | |
26 | {:name => 'modules', :action => :select_project_modules, :partial => 'projects/settings/modules', :label => :label_module_plural}, |
|
28 | {:name => 'modules', :action => :select_project_modules, :partial => 'projects/settings/modules', :label => :label_module_plural}, | |
27 | {:name => 'members', :action => :manage_members, :partial => 'projects/settings/members', :label => :label_member_plural}, |
|
29 | {:name => 'members', :action => :manage_members, :partial => 'projects/settings/members', :label => :label_member_plural}, | |
28 | {:name => 'versions', :action => :manage_versions, :partial => 'projects/settings/versions', :label => :label_version_plural}, |
|
30 | {:name => 'versions', :action => :manage_versions, :partial => 'projects/settings/versions', :label => :label_version_plural}, | |
29 | {:name => 'categories', :action => :manage_categories, :partial => 'projects/settings/issue_categories', :label => :label_issue_category_plural}, |
|
31 | {:name => 'categories', :action => :manage_categories, :partial => 'projects/settings/issue_categories', :label => :label_issue_category_plural}, | |
30 | {:name => 'wiki', :action => :manage_wiki, :partial => 'projects/settings/wiki', :label => :label_wiki}, |
|
32 | {:name => 'wiki', :action => :manage_wiki, :partial => 'projects/settings/wiki', :label => :label_wiki}, | |
31 | {:name => 'repository', :action => :manage_repository, :partial => 'projects/settings/repository', :label => :label_repository}, |
|
33 | {:name => 'repository', :action => :manage_repository, :partial => 'projects/settings/repository', :label => :label_repository}, | |
32 | {:name => 'boards', :action => :manage_boards, :partial => 'projects/settings/boards', :label => :label_board_plural}, |
|
34 | {:name => 'boards', :action => :manage_boards, :partial => 'projects/settings/boards', :label => :label_board_plural}, | |
33 | {:name => 'activities', :action => :manage_project_activities, :partial => 'projects/settings/activities', :label => :enumeration_activities} |
|
35 | {:name => 'activities', :action => :manage_project_activities, :partial => 'projects/settings/activities', :label => :enumeration_activities} | |
34 | ] |
|
36 | ] | |
35 | tabs.select {|tab| User.current.allowed_to?(tab[:action], @project)} |
|
37 | tabs.select {|tab| User.current.allowed_to?(tab[:action], @project)} | |
36 | end |
|
38 | end | |
37 |
|
39 | |||
38 | def parent_project_select_tag(project) |
|
40 | def parent_project_select_tag(project) | |
39 | selected = project.parent |
|
41 | selected = project.parent | |
40 | # retrieve the requested parent project |
|
42 | # retrieve the requested parent project | |
41 | parent_id = (params[:project] && params[:project][:parent_id]) || params[:parent_id] |
|
43 | parent_id = (params[:project] && params[:project][:parent_id]) || params[:parent_id] | |
42 | if parent_id |
|
44 | if parent_id | |
43 | selected = (parent_id.blank? ? nil : Project.find(parent_id)) |
|
45 | selected = (parent_id.blank? ? nil : Project.find(parent_id)) | |
44 | end |
|
46 | end | |
45 |
|
47 | |||
46 | options = '' |
|
48 | options = '' | |
47 | options << "<option value=''></option>" if project.allowed_parents.include?(nil) |
|
49 | options << "<option value=''></option>" if project.allowed_parents.include?(nil) | |
48 | options << project_tree_options_for_select(project.allowed_parents.compact, :selected => selected) |
|
50 | options << project_tree_options_for_select(project.allowed_parents.compact, :selected => selected) | |
49 | content_tag('select', options.html_safe, :name => 'project[parent_id]', :id => 'project_parent_id') |
|
51 | content_tag('select', options.html_safe, :name => 'project[parent_id]', :id => 'project_parent_id') | |
50 | end |
|
52 | end | |
51 |
|
53 | |||
52 | # Renders a tree of projects as a nested set of unordered lists |
|
54 | # Renders a tree of projects as a nested set of unordered lists | |
53 | # The given collection may be a subset of the whole project tree |
|
55 | # The given collection may be a subset of the whole project tree | |
54 | # (eg. some intermediate nodes are private and can not be seen) |
|
56 | # (eg. some intermediate nodes are private and can not be seen) | |
55 | def render_project_hierarchy(projects) |
|
57 | def render_project_hierarchy(projects) | |
56 | s = '' |
|
58 | s = '' | |
57 | if projects.any? |
|
59 | if projects.any? | |
58 | ancestors = [] |
|
60 | ancestors = [] | |
59 | original_project = @project |
|
61 | original_project = @project | |
60 | projects.each do |project| |
|
62 | projects.each do |project| | |
61 | # set the project environment to please macros. |
|
63 | # set the project environment to please macros. | |
62 | @project = project |
|
64 | @project = project | |
63 | if (ancestors.empty? || project.is_descendant_of?(ancestors.last)) |
|
65 | if (ancestors.empty? || project.is_descendant_of?(ancestors.last)) | |
64 | s << "<ul class='projects #{ ancestors.empty? ? 'root' : nil}'>\n" |
|
66 | s << "<ul class='projects #{ ancestors.empty? ? 'root' : nil}'>\n" | |
65 | else |
|
67 | else | |
66 | ancestors.pop |
|
68 | ancestors.pop | |
67 | s << "</li>" |
|
69 | s << "</li>" | |
68 | while (ancestors.any? && !project.is_descendant_of?(ancestors.last)) |
|
70 | while (ancestors.any? && !project.is_descendant_of?(ancestors.last)) | |
69 | ancestors.pop |
|
71 | ancestors.pop | |
70 | s << "</ul></li>\n" |
|
72 | s << "</ul></li>\n" | |
71 | end |
|
73 | end | |
72 | end |
|
74 | end | |
73 | classes = (ancestors.empty? ? 'root' : 'child') |
|
75 | classes = (ancestors.empty? ? 'root' : 'child') | |
74 | s << "<li class='#{classes}'><div class='#{classes}'>" + |
|
76 | s << "<li class='#{classes}'><div class='#{classes}'>" + | |
75 | link_to_project(project, {}, :class => "project #{User.current.member_of?(project) ? 'my-project' : nil}") |
|
77 | link_to_project(project, {}, :class => "project #{User.current.member_of?(project) ? 'my-project' : nil}") | |
76 | s << "<div class='wiki description'>#{textilizable(project.short_description, :project => project)}</div>" unless project.description.blank? |
|
78 | s << "<div class='wiki description'>#{textilizable(project.short_description, :project => project)}</div>" unless project.description.blank? | |
77 | s << "</div>\n" |
|
79 | s << "</div>\n" | |
78 | ancestors << project |
|
80 | ancestors << project | |
79 | end |
|
81 | end | |
80 | s << ("</li></ul>\n" * ancestors.size) |
|
82 | s << ("</li></ul>\n" * ancestors.size) | |
81 | @project = original_project |
|
83 | @project = original_project | |
82 | end |
|
84 | end | |
83 | s.html_safe |
|
85 | s.html_safe | |
84 | end |
|
86 | end | |
85 |
|
87 | |||
86 | # Returns a set of options for a select field, grouped by project. |
|
88 | # Returns a set of options for a select field, grouped by project. | |
87 | def version_options_for_select(versions, selected=nil) |
|
89 | def version_options_for_select(versions, selected=nil) | |
88 | grouped = Hash.new {|h,k| h[k] = []} |
|
90 | grouped = Hash.new {|h,k| h[k] = []} | |
89 | versions.each do |version| |
|
91 | versions.each do |version| | |
90 | grouped[version.project.name] << [version.name, version.id] |
|
92 | grouped[version.project.name] << [version.name, version.id] | |
91 | end |
|
93 | end | |
92 | # Add in the selected |
|
94 | # Add in the selected | |
93 | if selected && !versions.include?(selected) |
|
95 | if selected && !versions.include?(selected) | |
94 | grouped[selected.project.name] << [selected.name, selected.id] |
|
96 | grouped[selected.project.name] << [selected.name, selected.id] | |
95 | end |
|
97 | end | |
96 |
|
98 | |||
97 | if grouped.keys.size > 1 |
|
99 | if grouped.keys.size > 1 | |
98 | grouped_options_for_select(grouped, selected && selected.id) |
|
100 | grouped_options_for_select(grouped, selected && selected.id) | |
99 | else |
|
101 | else | |
100 | options_for_select((grouped.values.first || []), selected && selected.id) |
|
102 | options_for_select((grouped.values.first || []), selected && selected.id) | |
101 | end |
|
103 | end | |
102 | end |
|
104 | end | |
103 |
|
105 | |||
104 | def format_version_sharing(sharing) |
|
106 | def format_version_sharing(sharing) | |
105 | sharing = 'none' unless Version::VERSION_SHARINGS.include?(sharing) |
|
107 | sharing = 'none' unless Version::VERSION_SHARINGS.include?(sharing) | |
106 | l("label_version_sharing_#{sharing}") |
|
108 | l("label_version_sharing_#{sharing}") | |
107 | end |
|
109 | end | |
108 | end |
|
110 | end |
@@ -1,103 +1,105 | |||||
|
1 | # encoding: utf-8 | |||
|
2 | # | |||
1 | # Redmine - project management software |
|
3 | # Redmine - project management software | |
2 | # Copyright (C) 2006-2011 Jean-Philippe Lang |
|
4 | # Copyright (C) 2006-2011 Jean-Philippe Lang | |
3 | # |
|
5 | # | |
4 | # This program is free software; you can redistribute it and/or |
|
6 | # This program is free software; you can redistribute it and/or | |
5 | # modify it under the terms of the GNU General Public License |
|
7 | # modify it under the terms of the GNU General Public License | |
6 | # as published by the Free Software Foundation; either version 2 |
|
8 | # as published by the Free Software Foundation; either version 2 | |
7 | # of the License, or (at your option) any later version. |
|
9 | # of the License, or (at your option) any later version. | |
8 | # |
|
10 | # | |
9 | # This program is distributed in the hope that it will be useful, |
|
11 | # This program is distributed in the hope that it will be useful, | |
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | # GNU General Public License for more details. |
|
14 | # GNU General Public License for more details. | |
13 | # |
|
15 | # | |
14 | # You should have received a copy of the GNU General Public License |
|
16 | # You should have received a copy of the GNU General Public License | |
15 | # along with this program; if not, write to the Free Software |
|
17 | # along with this program; if not, write to the Free Software | |
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
17 |
|
19 | |||
18 | module QueriesHelper |
|
20 | module QueriesHelper | |
19 |
|
21 | |||
20 | def operators_for_select(filter_type) |
|
22 | def operators_for_select(filter_type) | |
21 | Query.operators_by_filter_type[filter_type].collect {|o| [l(Query.operators[o]), o]} |
|
23 | Query.operators_by_filter_type[filter_type].collect {|o| [l(Query.operators[o]), o]} | |
22 | end |
|
24 | end | |
23 |
|
25 | |||
24 | def column_header(column) |
|
26 | def column_header(column) | |
25 | column.sortable ? sort_header_tag(column.name.to_s, :caption => column.caption, |
|
27 | column.sortable ? sort_header_tag(column.name.to_s, :caption => column.caption, | |
26 | :default_order => column.default_order) : |
|
28 | :default_order => column.default_order) : | |
27 | content_tag('th', h(column.caption)) |
|
29 | content_tag('th', h(column.caption)) | |
28 | end |
|
30 | end | |
29 |
|
31 | |||
30 | def column_content(column, issue) |
|
32 | def column_content(column, issue) | |
31 | value = column.value(issue) |
|
33 | value = column.value(issue) | |
32 |
|
34 | |||
33 | case value.class.name |
|
35 | case value.class.name | |
34 | when 'String' |
|
36 | when 'String' | |
35 | if column.name == :subject |
|
37 | if column.name == :subject | |
36 | link_to(h(value), :controller => 'issues', :action => 'show', :id => issue) |
|
38 | link_to(h(value), :controller => 'issues', :action => 'show', :id => issue) | |
37 | else |
|
39 | else | |
38 | h(value) |
|
40 | h(value) | |
39 | end |
|
41 | end | |
40 | when 'Time' |
|
42 | when 'Time' | |
41 | format_time(value) |
|
43 | format_time(value) | |
42 | when 'Date' |
|
44 | when 'Date' | |
43 | format_date(value) |
|
45 | format_date(value) | |
44 | when 'Fixnum', 'Float' |
|
46 | when 'Fixnum', 'Float' | |
45 | if column.name == :done_ratio |
|
47 | if column.name == :done_ratio | |
46 | progress_bar(value, :width => '80px') |
|
48 | progress_bar(value, :width => '80px') | |
47 | else |
|
49 | else | |
48 | h(value.to_s) |
|
50 | h(value.to_s) | |
49 | end |
|
51 | end | |
50 | when 'User' |
|
52 | when 'User' | |
51 | link_to_user value |
|
53 | link_to_user value | |
52 | when 'Project' |
|
54 | when 'Project' | |
53 | link_to_project value |
|
55 | link_to_project value | |
54 | when 'Version' |
|
56 | when 'Version' | |
55 | link_to(h(value), :controller => 'versions', :action => 'show', :id => value) |
|
57 | link_to(h(value), :controller => 'versions', :action => 'show', :id => value) | |
56 | when 'TrueClass' |
|
58 | when 'TrueClass' | |
57 | l(:general_text_Yes) |
|
59 | l(:general_text_Yes) | |
58 | when 'FalseClass' |
|
60 | when 'FalseClass' | |
59 | l(:general_text_No) |
|
61 | l(:general_text_No) | |
60 | when 'Issue' |
|
62 | when 'Issue' | |
61 | link_to_issue(value, :subject => false) |
|
63 | link_to_issue(value, :subject => false) | |
62 | else |
|
64 | else | |
63 | h(value) |
|
65 | h(value) | |
64 | end |
|
66 | end | |
65 | end |
|
67 | end | |
66 |
|
68 | |||
67 | # Retrieve query from session or build a new query |
|
69 | # Retrieve query from session or build a new query | |
68 | def retrieve_query |
|
70 | def retrieve_query | |
69 | if !params[:query_id].blank? |
|
71 | if !params[:query_id].blank? | |
70 | cond = "project_id IS NULL" |
|
72 | cond = "project_id IS NULL" | |
71 | cond << " OR project_id = #{@project.id}" if @project |
|
73 | cond << " OR project_id = #{@project.id}" if @project | |
72 | @query = Query.find(params[:query_id], :conditions => cond) |
|
74 | @query = Query.find(params[:query_id], :conditions => cond) | |
73 | raise ::Unauthorized unless @query.visible? |
|
75 | raise ::Unauthorized unless @query.visible? | |
74 | @query.project = @project |
|
76 | @query.project = @project | |
75 | session[:query] = {:id => @query.id, :project_id => @query.project_id} |
|
77 | session[:query] = {:id => @query.id, :project_id => @query.project_id} | |
76 | sort_clear |
|
78 | sort_clear | |
77 | elsif api_request? || params[:set_filter] || session[:query].nil? || session[:query][:project_id] != (@project ? @project.id : nil) |
|
79 | elsif api_request? || params[:set_filter] || session[:query].nil? || session[:query][:project_id] != (@project ? @project.id : nil) | |
78 | # Give it a name, required to be valid |
|
80 | # Give it a name, required to be valid | |
79 | @query = Query.new(:name => "_") |
|
81 | @query = Query.new(:name => "_") | |
80 | @query.project = @project |
|
82 | @query.project = @project | |
81 | build_query_from_params |
|
83 | build_query_from_params | |
82 | session[:query] = {:project_id => @query.project_id, :filters => @query.filters, :group_by => @query.group_by, :column_names => @query.column_names} |
|
84 | session[:query] = {:project_id => @query.project_id, :filters => @query.filters, :group_by => @query.group_by, :column_names => @query.column_names} | |
83 | else |
|
85 | else | |
84 | # retrieve from session |
|
86 | # retrieve from session | |
85 | @query = Query.find_by_id(session[:query][:id]) if session[:query][:id] |
|
87 | @query = Query.find_by_id(session[:query][:id]) if session[:query][:id] | |
86 | @query ||= Query.new(:name => "_", :filters => session[:query][:filters], :group_by => session[:query][:group_by], :column_names => session[:query][:column_names]) |
|
88 | @query ||= Query.new(:name => "_", :filters => session[:query][:filters], :group_by => session[:query][:group_by], :column_names => session[:query][:column_names]) | |
87 | @query.project = @project |
|
89 | @query.project = @project | |
88 | end |
|
90 | end | |
89 | end |
|
91 | end | |
90 |
|
92 | |||
91 | def build_query_from_params |
|
93 | def build_query_from_params | |
92 | if params[:fields] || params[:f] |
|
94 | if params[:fields] || params[:f] | |
93 | @query.filters = {} |
|
95 | @query.filters = {} | |
94 | @query.add_filters(params[:fields] || params[:f], params[:operators] || params[:op], params[:values] || params[:v]) |
|
96 | @query.add_filters(params[:fields] || params[:f], params[:operators] || params[:op], params[:values] || params[:v]) | |
95 | else |
|
97 | else | |
96 | @query.available_filters.keys.each do |field| |
|
98 | @query.available_filters.keys.each do |field| | |
97 | @query.add_short_filter(field, params[field]) if params[field] |
|
99 | @query.add_short_filter(field, params[field]) if params[field] | |
98 | end |
|
100 | end | |
99 | end |
|
101 | end | |
100 | @query.group_by = params[:group_by] || (params[:query] && params[:query][:group_by]) |
|
102 | @query.group_by = params[:group_by] || (params[:query] && params[:query][:group_by]) | |
101 | @query.column_names = params[:c] || (params[:query] && params[:query][:column_names]) |
|
103 | @query.column_names = params[:c] || (params[:query] && params[:query][:column_names]) | |
102 | end |
|
104 | end | |
103 | end |
|
105 | end |
@@ -1,36 +1,38 | |||||
|
1 | # encoding: utf-8 | |||
|
2 | # | |||
1 | # Redmine - project management software |
|
3 | # Redmine - project management software | |
2 | # Copyright (C) 2006-2011 Jean-Philippe Lang |
|
4 | # Copyright (C) 2006-2011 Jean-Philippe Lang | |
3 | # |
|
5 | # | |
4 | # This program is free software; you can redistribute it and/or |
|
6 | # This program is free software; you can redistribute it and/or | |
5 | # modify it under the terms of the GNU General Public License |
|
7 | # modify it under the terms of the GNU General Public License | |
6 | # as published by the Free Software Foundation; either version 2 |
|
8 | # as published by the Free Software Foundation; either version 2 | |
7 | # of the License, or (at your option) any later version. |
|
9 | # of the License, or (at your option) any later version. | |
8 | # |
|
10 | # | |
9 | # This program is distributed in the hope that it will be useful, |
|
11 | # This program is distributed in the hope that it will be useful, | |
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | # GNU General Public License for more details. |
|
14 | # GNU General Public License for more details. | |
13 | # |
|
15 | # | |
14 | # You should have received a copy of the GNU General Public License |
|
16 | # You should have received a copy of the GNU General Public License | |
15 | # along with this program; if not, write to the Free Software |
|
17 | # along with this program; if not, write to the Free Software | |
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
17 |
|
19 | |||
18 | module ReportsHelper |
|
20 | module ReportsHelper | |
19 |
|
21 | |||
20 | def aggregate(data, criteria) |
|
22 | def aggregate(data, criteria) | |
21 | a = 0 |
|
23 | a = 0 | |
22 | data.each { |row| |
|
24 | data.each { |row| | |
23 | match = 1 |
|
25 | match = 1 | |
24 | criteria.each { |k, v| |
|
26 | criteria.each { |k, v| | |
25 | match = 0 unless (row[k].to_s == v.to_s) || (k == 'closed' && row[k] == (v == 0 ? "f" : "t")) |
|
27 | match = 0 unless (row[k].to_s == v.to_s) || (k == 'closed' && row[k] == (v == 0 ? "f" : "t")) | |
26 | } unless criteria.nil? |
|
28 | } unless criteria.nil? | |
27 | a = a + row["total"].to_i if match == 1 |
|
29 | a = a + row["total"].to_i if match == 1 | |
28 | } unless data.nil? |
|
30 | } unless data.nil? | |
29 | a |
|
31 | a | |
30 | end |
|
32 | end | |
31 |
|
33 | |||
32 | def aggregate_link(data, criteria, *args) |
|
34 | def aggregate_link(data, criteria, *args) | |
33 | a = aggregate data, criteria |
|
35 | a = aggregate data, criteria | |
34 | a > 0 ? link_to(h(a), *args) : '-' |
|
36 | a > 0 ? link_to(h(a), *args) : '-' | |
35 | end |
|
37 | end | |
36 | end |
|
38 | end |
@@ -1,311 +1,313 | |||||
|
1 | # encoding: utf-8 | |||
|
2 | # | |||
1 | # Redmine - project management software |
|
3 | # Redmine - project management software | |
2 | # Copyright (C) 2006-2011 Jean-Philippe Lang |
|
4 | # Copyright (C) 2006-2011 Jean-Philippe Lang | |
3 | # |
|
5 | # | |
4 | # This program is free software; you can redistribute it and/or |
|
6 | # This program is free software; you can redistribute it and/or | |
5 | # modify it under the terms of the GNU General Public License |
|
7 | # modify it under the terms of the GNU General Public License | |
6 | # as published by the Free Software Foundation; either version 2 |
|
8 | # as published by the Free Software Foundation; either version 2 | |
7 | # of the License, or (at your option) any later version. |
|
9 | # of the License, or (at your option) any later version. | |
8 | # |
|
10 | # | |
9 | # This program is distributed in the hope that it will be useful, |
|
11 | # This program is distributed in the hope that it will be useful, | |
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | # GNU General Public License for more details. |
|
14 | # GNU General Public License for more details. | |
13 | # |
|
15 | # | |
14 | # You should have received a copy of the GNU General Public License |
|
16 | # You should have received a copy of the GNU General Public License | |
15 | # along with this program; if not, write to the Free Software |
|
17 | # along with this program; if not, write to the Free Software | |
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
17 |
|
19 | |||
18 | require 'iconv' |
|
20 | require 'iconv' | |
19 | require 'redmine/codeset_util' |
|
21 | require 'redmine/codeset_util' | |
20 |
|
22 | |||
21 | module RepositoriesHelper |
|
23 | module RepositoriesHelper | |
22 | def format_revision(revision) |
|
24 | def format_revision(revision) | |
23 | if revision.respond_to? :format_identifier |
|
25 | if revision.respond_to? :format_identifier | |
24 | revision.format_identifier |
|
26 | revision.format_identifier | |
25 | else |
|
27 | else | |
26 | revision.to_s |
|
28 | revision.to_s | |
27 | end |
|
29 | end | |
28 | end |
|
30 | end | |
29 |
|
31 | |||
30 | def truncate_at_line_break(text, length = 255) |
|
32 | def truncate_at_line_break(text, length = 255) | |
31 | if text |
|
33 | if text | |
32 | text.gsub(%r{^(.{#{length}}[^\n]*)\n.+$}m, '\\1...') |
|
34 | text.gsub(%r{^(.{#{length}}[^\n]*)\n.+$}m, '\\1...') | |
33 | end |
|
35 | end | |
34 | end |
|
36 | end | |
35 |
|
37 | |||
36 | def render_properties(properties) |
|
38 | def render_properties(properties) | |
37 | unless properties.nil? || properties.empty? |
|
39 | unless properties.nil? || properties.empty? | |
38 | content = '' |
|
40 | content = '' | |
39 | properties.keys.sort.each do |property| |
|
41 | properties.keys.sort.each do |property| | |
40 | content << content_tag('li', "<b>#{h property}</b>: <span>#{h properties[property]}</span>".html_safe) |
|
42 | content << content_tag('li', "<b>#{h property}</b>: <span>#{h properties[property]}</span>".html_safe) | |
41 | end |
|
43 | end | |
42 | content_tag('ul', content.html_safe, :class => 'properties') |
|
44 | content_tag('ul', content.html_safe, :class => 'properties') | |
43 | end |
|
45 | end | |
44 | end |
|
46 | end | |
45 |
|
47 | |||
46 | def render_changeset_changes |
|
48 | def render_changeset_changes | |
47 | changes = @changeset.changes.find(:all, :limit => 1000, :order => 'path').collect do |change| |
|
49 | changes = @changeset.changes.find(:all, :limit => 1000, :order => 'path').collect do |change| | |
48 | case change.action |
|
50 | case change.action | |
49 | when 'A' |
|
51 | when 'A' | |
50 | # Detects moved/copied files |
|
52 | # Detects moved/copied files | |
51 | if !change.from_path.blank? |
|
53 | if !change.from_path.blank? | |
52 | change.action = |
|
54 | change.action = | |
53 | @changeset.changes.detect {|c| c.action == 'D' && c.path == change.from_path} ? 'R' : 'C' |
|
55 | @changeset.changes.detect {|c| c.action == 'D' && c.path == change.from_path} ? 'R' : 'C' | |
54 | end |
|
56 | end | |
55 | change |
|
57 | change | |
56 | when 'D' |
|
58 | when 'D' | |
57 | @changeset.changes.detect {|c| c.from_path == change.path} ? nil : change |
|
59 | @changeset.changes.detect {|c| c.from_path == change.path} ? nil : change | |
58 | else |
|
60 | else | |
59 | change |
|
61 | change | |
60 | end |
|
62 | end | |
61 | end.compact |
|
63 | end.compact | |
62 |
|
64 | |||
63 | tree = { } |
|
65 | tree = { } | |
64 | changes.each do |change| |
|
66 | changes.each do |change| | |
65 | p = tree |
|
67 | p = tree | |
66 | dirs = change.path.to_s.split('/').select {|d| !d.blank?} |
|
68 | dirs = change.path.to_s.split('/').select {|d| !d.blank?} | |
67 | path = '' |
|
69 | path = '' | |
68 | dirs.each do |dir| |
|
70 | dirs.each do |dir| | |
69 | path += '/' + dir |
|
71 | path += '/' + dir | |
70 | p[:s] ||= {} |
|
72 | p[:s] ||= {} | |
71 | p = p[:s] |
|
73 | p = p[:s] | |
72 | p[path] ||= {} |
|
74 | p[path] ||= {} | |
73 | p = p[path] |
|
75 | p = p[path] | |
74 | end |
|
76 | end | |
75 | p[:c] = change |
|
77 | p[:c] = change | |
76 | end |
|
78 | end | |
77 | render_changes_tree(tree[:s]) |
|
79 | render_changes_tree(tree[:s]) | |
78 | end |
|
80 | end | |
79 |
|
81 | |||
80 | def render_changes_tree(tree) |
|
82 | def render_changes_tree(tree) | |
81 | return '' if tree.nil? |
|
83 | return '' if tree.nil? | |
82 | output = '' |
|
84 | output = '' | |
83 | output << '<ul>' |
|
85 | output << '<ul>' | |
84 | tree.keys.sort.each do |file| |
|
86 | tree.keys.sort.each do |file| | |
85 | style = 'change' |
|
87 | style = 'change' | |
86 | text = File.basename(h(file)) |
|
88 | text = File.basename(h(file)) | |
87 | if s = tree[file][:s] |
|
89 | if s = tree[file][:s] | |
88 | style << ' folder' |
|
90 | style << ' folder' | |
89 | path_param = to_path_param(@repository.relative_path(file)) |
|
91 | path_param = to_path_param(@repository.relative_path(file)) | |
90 | text = link_to(h(text), :controller => 'repositories', |
|
92 | text = link_to(h(text), :controller => 'repositories', | |
91 | :action => 'show', |
|
93 | :action => 'show', | |
92 | :id => @project, |
|
94 | :id => @project, | |
93 | :path => path_param, |
|
95 | :path => path_param, | |
94 | :rev => @changeset.identifier) |
|
96 | :rev => @changeset.identifier) | |
95 | output << "<li class='#{style}'>#{text}</li>" |
|
97 | output << "<li class='#{style}'>#{text}</li>" | |
96 | output << render_changes_tree(s) |
|
98 | output << render_changes_tree(s) | |
97 | elsif c = tree[file][:c] |
|
99 | elsif c = tree[file][:c] | |
98 | style << " change-#{c.action}" |
|
100 | style << " change-#{c.action}" | |
99 | path_param = to_path_param(@repository.relative_path(c.path)) |
|
101 | path_param = to_path_param(@repository.relative_path(c.path)) | |
100 | text = link_to(h(text), :controller => 'repositories', |
|
102 | text = link_to(h(text), :controller => 'repositories', | |
101 | :action => 'entry', |
|
103 | :action => 'entry', | |
102 | :id => @project, |
|
104 | :id => @project, | |
103 | :path => path_param, |
|
105 | :path => path_param, | |
104 | :rev => @changeset.identifier) unless c.action == 'D' |
|
106 | :rev => @changeset.identifier) unless c.action == 'D' | |
105 | text << " - #{h(c.revision)}" unless c.revision.blank? |
|
107 | text << " - #{h(c.revision)}" unless c.revision.blank? | |
106 | text << ' ('.html_safe + link_to(l(:label_diff), :controller => 'repositories', |
|
108 | text << ' ('.html_safe + link_to(l(:label_diff), :controller => 'repositories', | |
107 | :action => 'diff', |
|
109 | :action => 'diff', | |
108 | :id => @project, |
|
110 | :id => @project, | |
109 | :path => path_param, |
|
111 | :path => path_param, | |
110 | :rev => @changeset.identifier) + ') '.html_safe if c.action == 'M' |
|
112 | :rev => @changeset.identifier) + ') '.html_safe if c.action == 'M' | |
111 | text << ' '.html_safe + content_tag('span', h(c.from_path), :class => 'copied-from') unless c.from_path.blank? |
|
113 | text << ' '.html_safe + content_tag('span', h(c.from_path), :class => 'copied-from') unless c.from_path.blank? | |
112 | output << "<li class='#{style}'>#{text}</li>" |
|
114 | output << "<li class='#{style}'>#{text}</li>" | |
113 | end |
|
115 | end | |
114 | end |
|
116 | end | |
115 | output << '</ul>' |
|
117 | output << '</ul>' | |
116 | output.html_safe |
|
118 | output.html_safe | |
117 | end |
|
119 | end | |
118 |
|
120 | |||
119 | def repository_field_tags(form, repository) |
|
121 | def repository_field_tags(form, repository) | |
120 | method = repository.class.name.demodulize.underscore + "_field_tags" |
|
122 | method = repository.class.name.demodulize.underscore + "_field_tags" | |
121 | if repository.is_a?(Repository) && |
|
123 | if repository.is_a?(Repository) && | |
122 | respond_to?(method) && method != 'repository_field_tags' |
|
124 | respond_to?(method) && method != 'repository_field_tags' | |
123 | send(method, form, repository) |
|
125 | send(method, form, repository) | |
124 | end |
|
126 | end | |
125 | end |
|
127 | end | |
126 |
|
128 | |||
127 | def scm_select_tag(repository) |
|
129 | def scm_select_tag(repository) | |
128 | scm_options = [["--- #{l(:actionview_instancetag_blank_option)} ---", '']] |
|
130 | scm_options = [["--- #{l(:actionview_instancetag_blank_option)} ---", '']] | |
129 | Redmine::Scm::Base.all.each do |scm| |
|
131 | Redmine::Scm::Base.all.each do |scm| | |
130 | if Setting.enabled_scm.include?(scm) || |
|
132 | if Setting.enabled_scm.include?(scm) || | |
131 | (repository && repository.class.name.demodulize == scm) |
|
133 | (repository && repository.class.name.demodulize == scm) | |
132 | scm_options << ["Repository::#{scm}".constantize.scm_name, scm] |
|
134 | scm_options << ["Repository::#{scm}".constantize.scm_name, scm] | |
133 | end |
|
135 | end | |
134 | end |
|
136 | end | |
135 | select_tag('repository_scm', |
|
137 | select_tag('repository_scm', | |
136 | options_for_select(scm_options, repository.class.name.demodulize), |
|
138 | options_for_select(scm_options, repository.class.name.demodulize), | |
137 | :disabled => (repository && !repository.new_record?), |
|
139 | :disabled => (repository && !repository.new_record?), | |
138 | :onchange => remote_function( |
|
140 | :onchange => remote_function( | |
139 | :url => { |
|
141 | :url => { | |
140 | :controller => 'repositories', |
|
142 | :controller => 'repositories', | |
141 | :action => 'edit', |
|
143 | :action => 'edit', | |
142 | :id => @project |
|
144 | :id => @project | |
143 | }, |
|
145 | }, | |
144 | :method => :get, |
|
146 | :method => :get, | |
145 | :with => "Form.serialize(this.form)") |
|
147 | :with => "Form.serialize(this.form)") | |
146 | ) |
|
148 | ) | |
147 | end |
|
149 | end | |
148 |
|
150 | |||
149 | def with_leading_slash(path) |
|
151 | def with_leading_slash(path) | |
150 | path.to_s.starts_with?('/') ? path : "/#{path}" |
|
152 | path.to_s.starts_with?('/') ? path : "/#{path}" | |
151 | end |
|
153 | end | |
152 |
|
154 | |||
153 | def without_leading_slash(path) |
|
155 | def without_leading_slash(path) | |
154 | path.gsub(%r{^/+}, '') |
|
156 | path.gsub(%r{^/+}, '') | |
155 | end |
|
157 | end | |
156 |
|
158 | |||
157 | def subversion_field_tags(form, repository) |
|
159 | def subversion_field_tags(form, repository) | |
158 | content_tag('p', form.text_field(:url, :size => 60, :required => true, |
|
160 | content_tag('p', form.text_field(:url, :size => 60, :required => true, | |
159 | :disabled => (repository && !repository.root_url.blank?)) + |
|
161 | :disabled => (repository && !repository.root_url.blank?)) + | |
160 | '<br />'.html_safe + |
|
162 | '<br />'.html_safe + | |
161 | '(file:///, http://, https://, svn://, svn+[tunnelscheme]://)') + |
|
163 | '(file:///, http://, https://, svn://, svn+[tunnelscheme]://)') + | |
162 | content_tag('p', form.text_field(:login, :size => 30)) + |
|
164 | content_tag('p', form.text_field(:login, :size => 30)) + | |
163 | content_tag('p', form.password_field( |
|
165 | content_tag('p', form.password_field( | |
164 | :password, :size => 30, :name => 'ignore', |
|
166 | :password, :size => 30, :name => 'ignore', | |
165 | :value => ((repository.new_record? || repository.password.blank?) ? '' : ('x'*15)), |
|
167 | :value => ((repository.new_record? || repository.password.blank?) ? '' : ('x'*15)), | |
166 | :onfocus => "this.value=''; this.name='repository[password]';", |
|
168 | :onfocus => "this.value=''; this.name='repository[password]';", | |
167 | :onchange => "this.name='repository[password]';")) |
|
169 | :onchange => "this.name='repository[password]';")) | |
168 | end |
|
170 | end | |
169 |
|
171 | |||
170 | def darcs_field_tags(form, repository) |
|
172 | def darcs_field_tags(form, repository) | |
171 | content_tag('p', form.text_field( |
|
173 | content_tag('p', form.text_field( | |
172 | :url, :label => l(:field_path_to_repository), |
|
174 | :url, :label => l(:field_path_to_repository), | |
173 | :size => 60, :required => true, |
|
175 | :size => 60, :required => true, | |
174 | :disabled => (repository && !repository.new_record?))) + |
|
176 | :disabled => (repository && !repository.new_record?))) + | |
175 | content_tag('p', form.select( |
|
177 | content_tag('p', form.select( | |
176 | :log_encoding, [nil] + Setting::ENCODINGS, |
|
178 | :log_encoding, [nil] + Setting::ENCODINGS, | |
177 | :label => l(:field_commit_logs_encoding), :required => true)) |
|
179 | :label => l(:field_commit_logs_encoding), :required => true)) | |
178 | end |
|
180 | end | |
179 |
|
181 | |||
180 | def mercurial_field_tags(form, repository) |
|
182 | def mercurial_field_tags(form, repository) | |
181 | content_tag('p', form.text_field( |
|
183 | content_tag('p', form.text_field( | |
182 | :url, :label => l(:field_path_to_repository), |
|
184 | :url, :label => l(:field_path_to_repository), | |
183 | :size => 60, :required => true, |
|
185 | :size => 60, :required => true, | |
184 | :disabled => (repository && !repository.root_url.blank?) |
|
186 | :disabled => (repository && !repository.root_url.blank?) | |
185 | ) + |
|
187 | ) + | |
186 | '<br />'.html_safe + l(:text_mercurial_repository_note)) + |
|
188 | '<br />'.html_safe + l(:text_mercurial_repository_note)) + | |
187 | content_tag('p', form.select( |
|
189 | content_tag('p', form.select( | |
188 | :path_encoding, [nil] + Setting::ENCODINGS, |
|
190 | :path_encoding, [nil] + Setting::ENCODINGS, | |
189 | :label => l(:field_scm_path_encoding) |
|
191 | :label => l(:field_scm_path_encoding) | |
190 | ) + |
|
192 | ) + | |
191 | '<br />'.html_safe + l(:text_scm_path_encoding_note)) |
|
193 | '<br />'.html_safe + l(:text_scm_path_encoding_note)) | |
192 | end |
|
194 | end | |
193 |
|
195 | |||
194 | def git_field_tags(form, repository) |
|
196 | def git_field_tags(form, repository) | |
195 | content_tag('p', form.text_field( |
|
197 | content_tag('p', form.text_field( | |
196 | :url, :label => l(:field_path_to_repository), |
|
198 | :url, :label => l(:field_path_to_repository), | |
197 | :size => 60, :required => true, |
|
199 | :size => 60, :required => true, | |
198 | :disabled => (repository && !repository.root_url.blank?) |
|
200 | :disabled => (repository && !repository.root_url.blank?) | |
199 | ) + |
|
201 | ) + | |
200 | '<br />'.html_safe + |
|
202 | '<br />'.html_safe + | |
201 | l(:text_git_repository_note)) + |
|
203 | l(:text_git_repository_note)) + | |
202 | content_tag('p', form.select( |
|
204 | content_tag('p', form.select( | |
203 | :path_encoding, [nil] + Setting::ENCODINGS, |
|
205 | :path_encoding, [nil] + Setting::ENCODINGS, | |
204 | :label => l(:field_scm_path_encoding) |
|
206 | :label => l(:field_scm_path_encoding) | |
205 | ) + |
|
207 | ) + | |
206 | '<br />'.html_safe + l(:text_scm_path_encoding_note)) + |
|
208 | '<br />'.html_safe + l(:text_scm_path_encoding_note)) + | |
207 | content_tag('p', form.check_box( |
|
209 | content_tag('p', form.check_box( | |
208 | :extra_report_last_commit, |
|
210 | :extra_report_last_commit, | |
209 | :label => l(:label_git_report_last_commit) |
|
211 | :label => l(:label_git_report_last_commit) | |
210 | )) |
|
212 | )) | |
211 | end |
|
213 | end | |
212 |
|
214 | |||
213 | def cvs_field_tags(form, repository) |
|
215 | def cvs_field_tags(form, repository) | |
214 | content_tag('p', form.text_field( |
|
216 | content_tag('p', form.text_field( | |
215 | :root_url, |
|
217 | :root_url, | |
216 | :label => l(:field_cvsroot), |
|
218 | :label => l(:field_cvsroot), | |
217 | :size => 60, :required => true, |
|
219 | :size => 60, :required => true, | |
218 | :disabled => !repository.new_record?)) + |
|
220 | :disabled => !repository.new_record?)) + | |
219 | content_tag('p', form.text_field( |
|
221 | content_tag('p', form.text_field( | |
220 | :url, |
|
222 | :url, | |
221 | :label => l(:field_cvs_module), |
|
223 | :label => l(:field_cvs_module), | |
222 | :size => 30, :required => true, |
|
224 | :size => 30, :required => true, | |
223 | :disabled => !repository.new_record?)) + |
|
225 | :disabled => !repository.new_record?)) + | |
224 | content_tag('p', form.select( |
|
226 | content_tag('p', form.select( | |
225 | :log_encoding, [nil] + Setting::ENCODINGS, |
|
227 | :log_encoding, [nil] + Setting::ENCODINGS, | |
226 | :label => l(:field_commit_logs_encoding), :required => true)) + |
|
228 | :label => l(:field_commit_logs_encoding), :required => true)) + | |
227 | content_tag('p', form.select( |
|
229 | content_tag('p', form.select( | |
228 | :path_encoding, [nil] + Setting::ENCODINGS, |
|
230 | :path_encoding, [nil] + Setting::ENCODINGS, | |
229 | :label => l(:field_scm_path_encoding) |
|
231 | :label => l(:field_scm_path_encoding) | |
230 | ) + |
|
232 | ) + | |
231 | '<br />'.html_safe + l(:text_scm_path_encoding_note)) |
|
233 | '<br />'.html_safe + l(:text_scm_path_encoding_note)) | |
232 | end |
|
234 | end | |
233 |
|
235 | |||
234 | def bazaar_field_tags(form, repository) |
|
236 | def bazaar_field_tags(form, repository) | |
235 | content_tag('p', form.text_field( |
|
237 | content_tag('p', form.text_field( | |
236 | :url, :label => l(:field_path_to_repository), |
|
238 | :url, :label => l(:field_path_to_repository), | |
237 | :size => 60, :required => true, |
|
239 | :size => 60, :required => true, | |
238 | :disabled => (repository && !repository.new_record?))) + |
|
240 | :disabled => (repository && !repository.new_record?))) + | |
239 | content_tag('p', form.select( |
|
241 | content_tag('p', form.select( | |
240 | :log_encoding, [nil] + Setting::ENCODINGS, |
|
242 | :log_encoding, [nil] + Setting::ENCODINGS, | |
241 | :label => l(:field_commit_logs_encoding), :required => true)) |
|
243 | :label => l(:field_commit_logs_encoding), :required => true)) | |
242 | end |
|
244 | end | |
243 |
|
245 | |||
244 | def filesystem_field_tags(form, repository) |
|
246 | def filesystem_field_tags(form, repository) | |
245 | content_tag('p', form.text_field( |
|
247 | content_tag('p', form.text_field( | |
246 | :url, :label => l(:field_root_directory), |
|
248 | :url, :label => l(:field_root_directory), | |
247 | :size => 60, :required => true, |
|
249 | :size => 60, :required => true, | |
248 | :disabled => (repository && !repository.root_url.blank?))) + |
|
250 | :disabled => (repository && !repository.root_url.blank?))) + | |
249 | content_tag('p', form.select( |
|
251 | content_tag('p', form.select( | |
250 | :path_encoding, [nil] + Setting::ENCODINGS, |
|
252 | :path_encoding, [nil] + Setting::ENCODINGS, | |
251 | :label => l(:field_scm_path_encoding) |
|
253 | :label => l(:field_scm_path_encoding) | |
252 | ) + |
|
254 | ) + | |
253 | '<br />'.html_safe + l(:text_scm_path_encoding_note)) |
|
255 | '<br />'.html_safe + l(:text_scm_path_encoding_note)) | |
254 | end |
|
256 | end | |
255 |
|
257 | |||
256 | def index_commits(commits, heads, href_proc = nil) |
|
258 | def index_commits(commits, heads, href_proc = nil) | |
257 | return nil if commits.nil? or commits.first.parents.nil? |
|
259 | return nil if commits.nil? or commits.first.parents.nil? | |
258 | map = {} |
|
260 | map = {} | |
259 | commit_hashes = [] |
|
261 | commit_hashes = [] | |
260 | refs_map = {} |
|
262 | refs_map = {} | |
261 | href_proc ||= Proc.new {|x|x} |
|
263 | href_proc ||= Proc.new {|x|x} | |
262 | heads.each{|r| refs_map[r.scmid] ||= []; refs_map[r.scmid] << r} |
|
264 | heads.each{|r| refs_map[r.scmid] ||= []; refs_map[r.scmid] << r} | |
263 | commits.reverse.each_with_index do |c, i| |
|
265 | commits.reverse.each_with_index do |c, i| | |
264 | h = {} |
|
266 | h = {} | |
265 | h[:parents] = c.parents.collect do |p| |
|
267 | h[:parents] = c.parents.collect do |p| | |
266 | [p.scmid, 0, 0] |
|
268 | [p.scmid, 0, 0] | |
267 | end |
|
269 | end | |
268 | h[:rdmid] = i |
|
270 | h[:rdmid] = i | |
269 | h[:space] = 0 |
|
271 | h[:space] = 0 | |
270 | h[:refs] = refs_map[c.scmid].join(" ") if refs_map.include? c.scmid |
|
272 | h[:refs] = refs_map[c.scmid].join(" ") if refs_map.include? c.scmid | |
271 | h[:scmid] = c.scmid |
|
273 | h[:scmid] = c.scmid | |
272 | h[:href] = href_proc.call(c.scmid) |
|
274 | h[:href] = href_proc.call(c.scmid) | |
273 | commit_hashes << h |
|
275 | commit_hashes << h | |
274 | map[c.scmid] = h |
|
276 | map[c.scmid] = h | |
275 | end |
|
277 | end | |
276 | heads.sort! do |a,b| |
|
278 | heads.sort! do |a,b| | |
277 | a.to_s <=> b.to_s |
|
279 | a.to_s <=> b.to_s | |
278 | end |
|
280 | end | |
279 | j = 0 |
|
281 | j = 0 | |
280 | heads.each do |h| |
|
282 | heads.each do |h| | |
281 | if map.include? h.scmid then |
|
283 | if map.include? h.scmid then | |
282 | j = mark_chain(j += 1, map[h.scmid], map) |
|
284 | j = mark_chain(j += 1, map[h.scmid], map) | |
283 | end |
|
285 | end | |
284 | end |
|
286 | end | |
285 | # when no head matched anything use first commit |
|
287 | # when no head matched anything use first commit | |
286 | if j == 0 then |
|
288 | if j == 0 then | |
287 | mark_chain(j += 1, map.values.first, map) |
|
289 | mark_chain(j += 1, map.values.first, map) | |
288 | end |
|
290 | end | |
289 | map |
|
291 | map | |
290 | end |
|
292 | end | |
291 |
|
293 | |||
292 | def mark_chain(mark, commit, map) |
|
294 | def mark_chain(mark, commit, map) | |
293 | stack = [[mark, commit]] |
|
295 | stack = [[mark, commit]] | |
294 | markmax = mark |
|
296 | markmax = mark | |
295 | until stack.empty? |
|
297 | until stack.empty? | |
296 | current = stack.pop |
|
298 | current = stack.pop | |
297 | m, commit = current |
|
299 | m, commit = current | |
298 | commit[:space] = m if commit[:space] == 0 |
|
300 | commit[:space] = m if commit[:space] == 0 | |
299 | m1 = m - 1 |
|
301 | m1 = m - 1 | |
300 | commit[:parents].each_with_index do |p, i| |
|
302 | commit[:parents].each_with_index do |p, i| | |
301 | psha = p[0] |
|
303 | psha = p[0] | |
302 | if map.include? psha and map[psha][:space] == 0 then |
|
304 | if map.include? psha and map[psha][:space] == 0 then | |
303 | stack << [m1 += 1, map[psha]] if i == 0 |
|
305 | stack << [m1 += 1, map[psha]] if i == 0 | |
304 | stack = [[m1 += 1, map[psha]]] + stack if i > 0 |
|
306 | stack = [[m1 += 1, map[psha]]] + stack if i > 0 | |
305 | end |
|
307 | end | |
306 | end |
|
308 | end | |
307 | markmax = m1 if markmax < m1 |
|
309 | markmax = m1 if markmax < m1 | |
308 | end |
|
310 | end | |
309 | markmax |
|
311 | markmax | |
310 | end |
|
312 | end | |
311 | end |
|
313 | end |
@@ -1,19 +1,21 | |||||
|
1 | # encoding: utf-8 | |||
|
2 | # | |||
1 | # Redmine - project management software |
|
3 | # Redmine - project management software | |
2 | # Copyright (C) 2006-2011 Jean-Philippe Lang |
|
4 | # Copyright (C) 2006-2011 Jean-Philippe Lang | |
3 | # |
|
5 | # | |
4 | # This program is free software; you can redistribute it and/or |
|
6 | # This program is free software; you can redistribute it and/or | |
5 | # modify it under the terms of the GNU General Public License |
|
7 | # modify it under the terms of the GNU General Public License | |
6 | # as published by the Free Software Foundation; either version 2 |
|
8 | # as published by the Free Software Foundation; either version 2 | |
7 | # of the License, or (at your option) any later version. |
|
9 | # of the License, or (at your option) any later version. | |
8 | # |
|
10 | # | |
9 | # This program is distributed in the hope that it will be useful, |
|
11 | # This program is distributed in the hope that it will be useful, | |
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | # GNU General Public License for more details. |
|
14 | # GNU General Public License for more details. | |
13 | # |
|
15 | # | |
14 | # You should have received a copy of the GNU General Public License |
|
16 | # You should have received a copy of the GNU General Public License | |
15 | # along with this program; if not, write to the Free Software |
|
17 | # along with this program; if not, write to the Free Software | |
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
17 |
|
19 | |||
18 | module RolesHelper |
|
20 | module RolesHelper | |
19 | end |
|
21 | end |
@@ -1,66 +1,68 | |||||
|
1 | # encoding: utf-8 | |||
|
2 | # | |||
1 | # Redmine - project management software |
|
3 | # Redmine - project management software | |
2 | # Copyright (C) 2006-2011 Jean-Philippe Lang |
|
4 | # Copyright (C) 2006-2011 Jean-Philippe Lang | |
3 | # |
|
5 | # | |
4 | # This program is free software; you can redistribute it and/or |
|
6 | # This program is free software; you can redistribute it and/or | |
5 | # modify it under the terms of the GNU General Public License |
|
7 | # modify it under the terms of the GNU General Public License | |
6 | # as published by the Free Software Foundation; either version 2 |
|
8 | # as published by the Free Software Foundation; either version 2 | |
7 | # of the License, or (at your option) any later version. |
|
9 | # of the License, or (at your option) any later version. | |
8 | # |
|
10 | # | |
9 | # This program is distributed in the hope that it will be useful, |
|
11 | # This program is distributed in the hope that it will be useful, | |
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | # GNU General Public License for more details. |
|
14 | # GNU General Public License for more details. | |
13 | # |
|
15 | # | |
14 | # You should have received a copy of the GNU General Public License |
|
16 | # You should have received a copy of the GNU General Public License | |
15 | # along with this program; if not, write to the Free Software |
|
17 | # along with this program; if not, write to the Free Software | |
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
17 |
|
19 | |||
18 | module SearchHelper |
|
20 | module SearchHelper | |
19 | def highlight_tokens(text, tokens) |
|
21 | def highlight_tokens(text, tokens) | |
20 | return text unless text && tokens && !tokens.empty? |
|
22 | return text unless text && tokens && !tokens.empty? | |
21 | re_tokens = tokens.collect {|t| Regexp.escape(t)} |
|
23 | re_tokens = tokens.collect {|t| Regexp.escape(t)} | |
22 | regexp = Regexp.new "(#{re_tokens.join('|')})", Regexp::IGNORECASE |
|
24 | regexp = Regexp.new "(#{re_tokens.join('|')})", Regexp::IGNORECASE | |
23 | result = '' |
|
25 | result = '' | |
24 | text.split(regexp).each_with_index do |words, i| |
|
26 | text.split(regexp).each_with_index do |words, i| | |
25 | if result.length > 1200 |
|
27 | if result.length > 1200 | |
26 | # maximum length of the preview reached |
|
28 | # maximum length of the preview reached | |
27 | result << '...' |
|
29 | result << '...' | |
28 | break |
|
30 | break | |
29 | end |
|
31 | end | |
30 | words = words.mb_chars |
|
32 | words = words.mb_chars | |
31 | if i.even? |
|
33 | if i.even? | |
32 | result << h(words.length > 100 ? "#{words.slice(0..44)} ... #{words.slice(-45..-1)}" : words) |
|
34 | result << h(words.length > 100 ? "#{words.slice(0..44)} ... #{words.slice(-45..-1)}" : words) | |
33 | else |
|
35 | else | |
34 | t = (tokens.index(words.downcase) || 0) % 4 |
|
36 | t = (tokens.index(words.downcase) || 0) % 4 | |
35 | result << content_tag('span', h(words), :class => "highlight token-#{t}") |
|
37 | result << content_tag('span', h(words), :class => "highlight token-#{t}") | |
36 | end |
|
38 | end | |
37 | end |
|
39 | end | |
38 | result |
|
40 | result | |
39 | end |
|
41 | end | |
40 |
|
42 | |||
41 | def type_label(t) |
|
43 | def type_label(t) | |
42 | l("label_#{t.singularize}_plural", :default => t.to_s.humanize) |
|
44 | l("label_#{t.singularize}_plural", :default => t.to_s.humanize) | |
43 | end |
|
45 | end | |
44 |
|
46 | |||
45 | def project_select_tag |
|
47 | def project_select_tag | |
46 | options = [[l(:label_project_all), 'all']] |
|
48 | options = [[l(:label_project_all), 'all']] | |
47 | options << [l(:label_my_projects), 'my_projects'] unless User.current.memberships.empty? |
|
49 | options << [l(:label_my_projects), 'my_projects'] unless User.current.memberships.empty? | |
48 | options << [l(:label_and_its_subprojects, @project.name), 'subprojects'] unless @project.nil? || @project.descendants.active.empty? |
|
50 | options << [l(:label_and_its_subprojects, @project.name), 'subprojects'] unless @project.nil? || @project.descendants.active.empty? | |
49 | options << [@project.name, ''] unless @project.nil? |
|
51 | options << [@project.name, ''] unless @project.nil? | |
50 | label_tag("scope", l(:description_project_scope), :class => "hidden-for-sighted") + |
|
52 | label_tag("scope", l(:description_project_scope), :class => "hidden-for-sighted") + | |
51 | select_tag('scope', options_for_select(options, params[:scope].to_s)) if options.size > 1 |
|
53 | select_tag('scope', options_for_select(options, params[:scope].to_s)) if options.size > 1 | |
52 | end |
|
54 | end | |
53 |
|
55 | |||
54 | def render_results_by_type(results_by_type) |
|
56 | def render_results_by_type(results_by_type) | |
55 | links = [] |
|
57 | links = [] | |
56 | # Sorts types by results count |
|
58 | # Sorts types by results count | |
57 | results_by_type.keys.sort {|a, b| results_by_type[b] <=> results_by_type[a]}.each do |t| |
|
59 | results_by_type.keys.sort {|a, b| results_by_type[b] <=> results_by_type[a]}.each do |t| | |
58 | c = results_by_type[t] |
|
60 | c = results_by_type[t] | |
59 | next if c == 0 |
|
61 | next if c == 0 | |
60 | text = "#{type_label(t)} (#{c})" |
|
62 | text = "#{type_label(t)} (#{c})" | |
61 | links << link_to(h(text), :q => params[:q], :titles_only => params[:titles_only], |
|
63 | links << link_to(h(text), :q => params[:q], :titles_only => params[:titles_only], | |
62 | :all_words => params[:all_words], :scope => params[:scope], t => 1) |
|
64 | :all_words => params[:all_words], :scope => params[:scope], t => 1) | |
63 | end |
|
65 | end | |
64 | ('<ul>' + links.map {|link| content_tag('li', link)}.join(' ') + '</ul>') unless links.empty? |
|
66 | ('<ul>' + links.map {|link| content_tag('li', link)}.join(' ') + '</ul>') unless links.empty? | |
65 | end |
|
67 | end | |
66 | end |
|
68 | end |
@@ -1,91 +1,93 | |||||
|
1 | # encoding: utf-8 | |||
|
2 | # | |||
1 | # Redmine - project management software |
|
3 | # Redmine - project management software | |
2 | # Copyright (C) 2006-2011 Jean-Philippe Lang |
|
4 | # Copyright (C) 2006-2011 Jean-Philippe Lang | |
3 | # |
|
5 | # | |
4 | # This program is free software; you can redistribute it and/or |
|
6 | # This program is free software; you can redistribute it and/or | |
5 | # modify it under the terms of the GNU General Public License |
|
7 | # modify it under the terms of the GNU General Public License | |
6 | # as published by the Free Software Foundation; either version 2 |
|
8 | # as published by the Free Software Foundation; either version 2 | |
7 | # of the License, or (at your option) any later version. |
|
9 | # of the License, or (at your option) any later version. | |
8 | # |
|
10 | # | |
9 | # This program is distributed in the hope that it will be useful, |
|
11 | # This program is distributed in the hope that it will be useful, | |
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | # GNU General Public License for more details. |
|
14 | # GNU General Public License for more details. | |
13 | # |
|
15 | # | |
14 | # You should have received a copy of the GNU General Public License |
|
16 | # You should have received a copy of the GNU General Public License | |
15 | # along with this program; if not, write to the Free Software |
|
17 | # along with this program; if not, write to the Free Software | |
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
17 |
|
19 | |||
18 | module SettingsHelper |
|
20 | module SettingsHelper | |
19 | def administration_settings_tabs |
|
21 | def administration_settings_tabs | |
20 | tabs = [{:name => 'general', :partial => 'settings/general', :label => :label_general}, |
|
22 | tabs = [{:name => 'general', :partial => 'settings/general', :label => :label_general}, | |
21 | {:name => 'display', :partial => 'settings/display', :label => :label_display}, |
|
23 | {:name => 'display', :partial => 'settings/display', :label => :label_display}, | |
22 | {:name => 'authentication', :partial => 'settings/authentication', :label => :label_authentication}, |
|
24 | {:name => 'authentication', :partial => 'settings/authentication', :label => :label_authentication}, | |
23 | {:name => 'projects', :partial => 'settings/projects', :label => :label_project_plural}, |
|
25 | {:name => 'projects', :partial => 'settings/projects', :label => :label_project_plural}, | |
24 | {:name => 'issues', :partial => 'settings/issues', :label => :label_issue_tracking}, |
|
26 | {:name => 'issues', :partial => 'settings/issues', :label => :label_issue_tracking}, | |
25 | {:name => 'notifications', :partial => 'settings/notifications', :label => :field_mail_notification}, |
|
27 | {:name => 'notifications', :partial => 'settings/notifications', :label => :field_mail_notification}, | |
26 | {:name => 'mail_handler', :partial => 'settings/mail_handler', :label => :label_incoming_emails}, |
|
28 | {:name => 'mail_handler', :partial => 'settings/mail_handler', :label => :label_incoming_emails}, | |
27 | {:name => 'repositories', :partial => 'settings/repositories', :label => :label_repository_plural} |
|
29 | {:name => 'repositories', :partial => 'settings/repositories', :label => :label_repository_plural} | |
28 | ] |
|
30 | ] | |
29 | end |
|
31 | end | |
30 |
|
32 | |||
31 | def setting_select(setting, choices, options={}) |
|
33 | def setting_select(setting, choices, options={}) | |
32 | if blank_text = options.delete(:blank) |
|
34 | if blank_text = options.delete(:blank) | |
33 | choices = [[blank_text.is_a?(Symbol) ? l(blank_text) : blank_text, '']] + choices |
|
35 | choices = [[blank_text.is_a?(Symbol) ? l(blank_text) : blank_text, '']] + choices | |
34 | end |
|
36 | end | |
35 | setting_label(setting, options).html_safe + |
|
37 | setting_label(setting, options).html_safe + | |
36 | select_tag("settings[#{setting}]", |
|
38 | select_tag("settings[#{setting}]", | |
37 | options_for_select(choices, Setting.send(setting).to_s), |
|
39 | options_for_select(choices, Setting.send(setting).to_s), | |
38 | options).html_safe |
|
40 | options).html_safe | |
39 | end |
|
41 | end | |
40 |
|
42 | |||
41 | def setting_multiselect(setting, choices, options={}) |
|
43 | def setting_multiselect(setting, choices, options={}) | |
42 | setting_values = Setting.send(setting) |
|
44 | setting_values = Setting.send(setting) | |
43 | setting_values = [] unless setting_values.is_a?(Array) |
|
45 | setting_values = [] unless setting_values.is_a?(Array) | |
44 |
|
46 | |||
45 | setting_label(setting, options).html_safe + |
|
47 | setting_label(setting, options).html_safe + | |
46 | hidden_field_tag("settings[#{setting}][]", '').html_safe + |
|
48 | hidden_field_tag("settings[#{setting}][]", '').html_safe + | |
47 | choices.collect do |choice| |
|
49 | choices.collect do |choice| | |
48 | text, value = (choice.is_a?(Array) ? choice : [choice, choice]) |
|
50 | text, value = (choice.is_a?(Array) ? choice : [choice, choice]) | |
49 | content_tag( |
|
51 | content_tag( | |
50 | 'label', |
|
52 | 'label', | |
51 | check_box_tag( |
|
53 | check_box_tag( | |
52 | "settings[#{setting}][]", |
|
54 | "settings[#{setting}][]", | |
53 | value, |
|
55 | value, | |
54 | Setting.send(setting).include?(value) |
|
56 | Setting.send(setting).include?(value) | |
55 | ) + text.to_s, |
|
57 | ) + text.to_s, | |
56 | :class => 'block' |
|
58 | :class => 'block' | |
57 | ) |
|
59 | ) | |
58 | end.join.html_safe |
|
60 | end.join.html_safe | |
59 | end |
|
61 | end | |
60 |
|
62 | |||
61 | def setting_text_field(setting, options={}) |
|
63 | def setting_text_field(setting, options={}) | |
62 | setting_label(setting, options).html_safe + |
|
64 | setting_label(setting, options).html_safe + | |
63 | text_field_tag("settings[#{setting}]", Setting.send(setting), options).html_safe |
|
65 | text_field_tag("settings[#{setting}]", Setting.send(setting), options).html_safe | |
64 | end |
|
66 | end | |
65 |
|
67 | |||
66 | def setting_text_area(setting, options={}) |
|
68 | def setting_text_area(setting, options={}) | |
67 | setting_label(setting, options).html_safe + |
|
69 | setting_label(setting, options).html_safe + | |
68 | text_area_tag("settings[#{setting}]", Setting.send(setting), options).html_safe |
|
70 | text_area_tag("settings[#{setting}]", Setting.send(setting), options).html_safe | |
69 | end |
|
71 | end | |
70 |
|
72 | |||
71 | def setting_check_box(setting, options={}) |
|
73 | def setting_check_box(setting, options={}) | |
72 | setting_label(setting, options).html_safe + |
|
74 | setting_label(setting, options).html_safe + | |
73 | hidden_field_tag("settings[#{setting}]", 0).html_safe + |
|
75 | hidden_field_tag("settings[#{setting}]", 0).html_safe + | |
74 | check_box_tag("settings[#{setting}]", 1, Setting.send("#{setting}?"), options).html_safe |
|
76 | check_box_tag("settings[#{setting}]", 1, Setting.send("#{setting}?"), options).html_safe | |
75 | end |
|
77 | end | |
76 |
|
78 | |||
77 | def setting_label(setting, options={}) |
|
79 | def setting_label(setting, options={}) | |
78 | label = options.delete(:label) |
|
80 | label = options.delete(:label) | |
79 | label != false ? content_tag("label", l(label || "setting_#{setting}")).html_safe : '' |
|
81 | label != false ? content_tag("label", l(label || "setting_#{setting}")).html_safe : '' | |
80 | end |
|
82 | end | |
81 |
|
83 | |||
82 | # Renders a notification field for a Redmine::Notifiable option |
|
84 | # Renders a notification field for a Redmine::Notifiable option | |
83 | def notification_field(notifiable) |
|
85 | def notification_field(notifiable) | |
84 | return content_tag(:label, |
|
86 | return content_tag(:label, | |
85 | check_box_tag('settings[notified_events][]', |
|
87 | check_box_tag('settings[notified_events][]', | |
86 | notifiable.name, |
|
88 | notifiable.name, | |
87 | Setting.notified_events.include?(notifiable.name)).html_safe + |
|
89 | Setting.notified_events.include?(notifiable.name)).html_safe + | |
88 | l_or_humanize(notifiable.name, :prefix => 'label_').html_safe, |
|
90 | l_or_humanize(notifiable.name, :prefix => 'label_').html_safe, | |
89 | :class => notifiable.parent.present? ? "parent" : '').html_safe |
|
91 | :class => notifiable.parent.present? ? "parent" : '').html_safe | |
90 | end |
|
92 | end | |
91 | end |
|
93 | end |
@@ -1,231 +1,233 | |||||
|
1 | # encoding: utf-8 | |||
|
2 | # | |||
1 | # Helpers to sort tables using clickable column headers. |
|
3 | # Helpers to sort tables using clickable column headers. | |
2 | # |
|
4 | # | |
3 | # Author: Stuart Rackham <srackham@methods.co.nz>, March 2005. |
|
5 | # Author: Stuart Rackham <srackham@methods.co.nz>, March 2005. | |
4 | # Jean-Philippe Lang, 2009 |
|
6 | # Jean-Philippe Lang, 2009 | |
5 | # License: This source code is released under the MIT license. |
|
7 | # License: This source code is released under the MIT license. | |
6 | # |
|
8 | # | |
7 | # - Consecutive clicks toggle the column's sort order. |
|
9 | # - Consecutive clicks toggle the column's sort order. | |
8 | # - Sort state is maintained by a session hash entry. |
|
10 | # - Sort state is maintained by a session hash entry. | |
9 | # - CSS classes identify sort column and state. |
|
11 | # - CSS classes identify sort column and state. | |
10 | # - Typically used in conjunction with the Pagination module. |
|
12 | # - Typically used in conjunction with the Pagination module. | |
11 | # |
|
13 | # | |
12 | # Example code snippets: |
|
14 | # Example code snippets: | |
13 | # |
|
15 | # | |
14 | # Controller: |
|
16 | # Controller: | |
15 | # |
|
17 | # | |
16 | # helper :sort |
|
18 | # helper :sort | |
17 | # include SortHelper |
|
19 | # include SortHelper | |
18 | # |
|
20 | # | |
19 | # def list |
|
21 | # def list | |
20 | # sort_init 'last_name' |
|
22 | # sort_init 'last_name' | |
21 | # sort_update %w(first_name last_name) |
|
23 | # sort_update %w(first_name last_name) | |
22 | # @items = Contact.find_all nil, sort_clause |
|
24 | # @items = Contact.find_all nil, sort_clause | |
23 | # end |
|
25 | # end | |
24 | # |
|
26 | # | |
25 | # Controller (using Pagination module): |
|
27 | # Controller (using Pagination module): | |
26 | # |
|
28 | # | |
27 | # helper :sort |
|
29 | # helper :sort | |
28 | # include SortHelper |
|
30 | # include SortHelper | |
29 | # |
|
31 | # | |
30 | # def list |
|
32 | # def list | |
31 | # sort_init 'last_name' |
|
33 | # sort_init 'last_name' | |
32 | # sort_update %w(first_name last_name) |
|
34 | # sort_update %w(first_name last_name) | |
33 | # @contact_pages, @items = paginate :contacts, |
|
35 | # @contact_pages, @items = paginate :contacts, | |
34 | # :order_by => sort_clause, |
|
36 | # :order_by => sort_clause, | |
35 | # :per_page => 10 |
|
37 | # :per_page => 10 | |
36 | # end |
|
38 | # end | |
37 | # |
|
39 | # | |
38 | # View (table header in list.rhtml): |
|
40 | # View (table header in list.rhtml): | |
39 | # |
|
41 | # | |
40 | # <thead> |
|
42 | # <thead> | |
41 | # <tr> |
|
43 | # <tr> | |
42 | # <%= sort_header_tag('id', :title => 'Sort by contact ID') %> |
|
44 | # <%= sort_header_tag('id', :title => 'Sort by contact ID') %> | |
43 | # <%= sort_header_tag('last_name', :caption => 'Name') %> |
|
45 | # <%= sort_header_tag('last_name', :caption => 'Name') %> | |
44 | # <%= sort_header_tag('phone') %> |
|
46 | # <%= sort_header_tag('phone') %> | |
45 | # <%= sort_header_tag('address', :width => 200) %> |
|
47 | # <%= sort_header_tag('address', :width => 200) %> | |
46 | # </tr> |
|
48 | # </tr> | |
47 | # </thead> |
|
49 | # </thead> | |
48 | # |
|
50 | # | |
49 | # - Introduces instance variables: @sort_default, @sort_criteria |
|
51 | # - Introduces instance variables: @sort_default, @sort_criteria | |
50 | # - Introduces param :sort |
|
52 | # - Introduces param :sort | |
51 | # |
|
53 | # | |
52 |
|
54 | |||
53 | module SortHelper |
|
55 | module SortHelper | |
54 | class SortCriteria |
|
56 | class SortCriteria | |
55 |
|
57 | |||
56 | def initialize |
|
58 | def initialize | |
57 | @criteria = [] |
|
59 | @criteria = [] | |
58 | end |
|
60 | end | |
59 |
|
61 | |||
60 | def available_criteria=(criteria) |
|
62 | def available_criteria=(criteria) | |
61 | unless criteria.is_a?(Hash) |
|
63 | unless criteria.is_a?(Hash) | |
62 | criteria = criteria.inject({}) {|h,k| h[k] = k; h} |
|
64 | criteria = criteria.inject({}) {|h,k| h[k] = k; h} | |
63 | end |
|
65 | end | |
64 | @available_criteria = criteria |
|
66 | @available_criteria = criteria | |
65 | end |
|
67 | end | |
66 |
|
68 | |||
67 | def from_param(param) |
|
69 | def from_param(param) | |
68 | @criteria = param.to_s.split(',').collect {|s| s.split(':')[0..1]} |
|
70 | @criteria = param.to_s.split(',').collect {|s| s.split(':')[0..1]} | |
69 | normalize! |
|
71 | normalize! | |
70 | end |
|
72 | end | |
71 |
|
73 | |||
72 | def criteria=(arg) |
|
74 | def criteria=(arg) | |
73 | @criteria = arg |
|
75 | @criteria = arg | |
74 | normalize! |
|
76 | normalize! | |
75 | end |
|
77 | end | |
76 |
|
78 | |||
77 | def to_param |
|
79 | def to_param | |
78 | @criteria.collect {|k,o| k + (o ? '' : ':desc')}.join(',') |
|
80 | @criteria.collect {|k,o| k + (o ? '' : ':desc')}.join(',') | |
79 | end |
|
81 | end | |
80 |
|
82 | |||
81 | def to_sql |
|
83 | def to_sql | |
82 | sql = @criteria.collect do |k,o| |
|
84 | sql = @criteria.collect do |k,o| | |
83 | if s = @available_criteria[k] |
|
85 | if s = @available_criteria[k] | |
84 | (o ? s.to_a : s.to_a.collect {|c| append_desc(c)}).join(', ') |
|
86 | (o ? s.to_a : s.to_a.collect {|c| append_desc(c)}).join(', ') | |
85 | end |
|
87 | end | |
86 | end.compact.join(', ') |
|
88 | end.compact.join(', ') | |
87 | sql.blank? ? nil : sql |
|
89 | sql.blank? ? nil : sql | |
88 | end |
|
90 | end | |
89 |
|
91 | |||
90 | def add!(key, asc) |
|
92 | def add!(key, asc) | |
91 | @criteria.delete_if {|k,o| k == key} |
|
93 | @criteria.delete_if {|k,o| k == key} | |
92 | @criteria = [[key, asc]] + @criteria |
|
94 | @criteria = [[key, asc]] + @criteria | |
93 | normalize! |
|
95 | normalize! | |
94 | end |
|
96 | end | |
95 |
|
97 | |||
96 | def add(*args) |
|
98 | def add(*args) | |
97 | r = self.class.new.from_param(to_param) |
|
99 | r = self.class.new.from_param(to_param) | |
98 | r.add!(*args) |
|
100 | r.add!(*args) | |
99 | r |
|
101 | r | |
100 | end |
|
102 | end | |
101 |
|
103 | |||
102 | def first_key |
|
104 | def first_key | |
103 | @criteria.first && @criteria.first.first |
|
105 | @criteria.first && @criteria.first.first | |
104 | end |
|
106 | end | |
105 |
|
107 | |||
106 | def first_asc? |
|
108 | def first_asc? | |
107 | @criteria.first && @criteria.first.last |
|
109 | @criteria.first && @criteria.first.last | |
108 | end |
|
110 | end | |
109 |
|
111 | |||
110 | def empty? |
|
112 | def empty? | |
111 | @criteria.empty? |
|
113 | @criteria.empty? | |
112 | end |
|
114 | end | |
113 |
|
115 | |||
114 | private |
|
116 | private | |
115 |
|
117 | |||
116 | def normalize! |
|
118 | def normalize! | |
117 | @criteria ||= [] |
|
119 | @criteria ||= [] | |
118 | @criteria = @criteria.collect {|s| s = s.to_a; [s.first, (s.last == false || s.last == 'desc') ? false : true]} |
|
120 | @criteria = @criteria.collect {|s| s = s.to_a; [s.first, (s.last == false || s.last == 'desc') ? false : true]} | |
119 | @criteria = @criteria.select {|k,o| @available_criteria.has_key?(k)} if @available_criteria |
|
121 | @criteria = @criteria.select {|k,o| @available_criteria.has_key?(k)} if @available_criteria | |
120 | @criteria.slice!(3) |
|
122 | @criteria.slice!(3) | |
121 | self |
|
123 | self | |
122 | end |
|
124 | end | |
123 |
|
125 | |||
124 | # Appends DESC to the sort criterion unless it has a fixed order |
|
126 | # Appends DESC to the sort criterion unless it has a fixed order | |
125 | def append_desc(criterion) |
|
127 | def append_desc(criterion) | |
126 | if criterion =~ / (asc|desc)$/i |
|
128 | if criterion =~ / (asc|desc)$/i | |
127 | criterion |
|
129 | criterion | |
128 | else |
|
130 | else | |
129 | "#{criterion} DESC" |
|
131 | "#{criterion} DESC" | |
130 | end |
|
132 | end | |
131 | end |
|
133 | end | |
132 | end |
|
134 | end | |
133 |
|
135 | |||
134 | def sort_name |
|
136 | def sort_name | |
135 | controller_name + '_' + action_name + '_sort' |
|
137 | controller_name + '_' + action_name + '_sort' | |
136 | end |
|
138 | end | |
137 |
|
139 | |||
138 | # Initializes the default sort. |
|
140 | # Initializes the default sort. | |
139 | # Examples: |
|
141 | # Examples: | |
140 | # |
|
142 | # | |
141 | # sort_init 'name' |
|
143 | # sort_init 'name' | |
142 | # sort_init 'id', 'desc' |
|
144 | # sort_init 'id', 'desc' | |
143 | # sort_init ['name', ['id', 'desc']] |
|
145 | # sort_init ['name', ['id', 'desc']] | |
144 | # sort_init [['name', 'desc'], ['id', 'desc']] |
|
146 | # sort_init [['name', 'desc'], ['id', 'desc']] | |
145 | # |
|
147 | # | |
146 | def sort_init(*args) |
|
148 | def sort_init(*args) | |
147 | case args.size |
|
149 | case args.size | |
148 | when 1 |
|
150 | when 1 | |
149 | @sort_default = args.first.is_a?(Array) ? args.first : [[args.first]] |
|
151 | @sort_default = args.first.is_a?(Array) ? args.first : [[args.first]] | |
150 | when 2 |
|
152 | when 2 | |
151 | @sort_default = [[args.first, args.last]] |
|
153 | @sort_default = [[args.first, args.last]] | |
152 | else |
|
154 | else | |
153 | raise ArgumentError |
|
155 | raise ArgumentError | |
154 | end |
|
156 | end | |
155 | end |
|
157 | end | |
156 |
|
158 | |||
157 | # Updates the sort state. Call this in the controller prior to calling |
|
159 | # Updates the sort state. Call this in the controller prior to calling | |
158 | # sort_clause. |
|
160 | # sort_clause. | |
159 | # - criteria can be either an array or a hash of allowed keys |
|
161 | # - criteria can be either an array or a hash of allowed keys | |
160 | # |
|
162 | # | |
161 | def sort_update(criteria) |
|
163 | def sort_update(criteria) | |
162 | @sort_criteria = SortCriteria.new |
|
164 | @sort_criteria = SortCriteria.new | |
163 | @sort_criteria.available_criteria = criteria |
|
165 | @sort_criteria.available_criteria = criteria | |
164 | @sort_criteria.from_param(params[:sort] || session[sort_name]) |
|
166 | @sort_criteria.from_param(params[:sort] || session[sort_name]) | |
165 | @sort_criteria.criteria = @sort_default if @sort_criteria.empty? |
|
167 | @sort_criteria.criteria = @sort_default if @sort_criteria.empty? | |
166 | session[sort_name] = @sort_criteria.to_param |
|
168 | session[sort_name] = @sort_criteria.to_param | |
167 | end |
|
169 | end | |
168 |
|
170 | |||
169 | # Clears the sort criteria session data |
|
171 | # Clears the sort criteria session data | |
170 | # |
|
172 | # | |
171 | def sort_clear |
|
173 | def sort_clear | |
172 | session[sort_name] = nil |
|
174 | session[sort_name] = nil | |
173 | end |
|
175 | end | |
174 |
|
176 | |||
175 | # Returns an SQL sort clause corresponding to the current sort state. |
|
177 | # Returns an SQL sort clause corresponding to the current sort state. | |
176 | # Use this to sort the controller's table items collection. |
|
178 | # Use this to sort the controller's table items collection. | |
177 | # |
|
179 | # | |
178 | def sort_clause() |
|
180 | def sort_clause() | |
179 | @sort_criteria.to_sql |
|
181 | @sort_criteria.to_sql | |
180 | end |
|
182 | end | |
181 |
|
183 | |||
182 | # Returns a link which sorts by the named column. |
|
184 | # Returns a link which sorts by the named column. | |
183 | # |
|
185 | # | |
184 | # - column is the name of an attribute in the sorted record collection. |
|
186 | # - column is the name of an attribute in the sorted record collection. | |
185 | # - the optional caption explicitly specifies the displayed link text. |
|
187 | # - the optional caption explicitly specifies the displayed link text. | |
186 | # - 2 CSS classes reflect the state of the link: sort and asc or desc |
|
188 | # - 2 CSS classes reflect the state of the link: sort and asc or desc | |
187 | # |
|
189 | # | |
188 | def sort_link(column, caption, default_order) |
|
190 | def sort_link(column, caption, default_order) | |
189 | css, order = nil, default_order |
|
191 | css, order = nil, default_order | |
190 |
|
192 | |||
191 | if column.to_s == @sort_criteria.first_key |
|
193 | if column.to_s == @sort_criteria.first_key | |
192 | if @sort_criteria.first_asc? |
|
194 | if @sort_criteria.first_asc? | |
193 | css = 'sort asc' |
|
195 | css = 'sort asc' | |
194 | order = 'desc' |
|
196 | order = 'desc' | |
195 | else |
|
197 | else | |
196 | css = 'sort desc' |
|
198 | css = 'sort desc' | |
197 | order = 'asc' |
|
199 | order = 'asc' | |
198 | end |
|
200 | end | |
199 | end |
|
201 | end | |
200 | caption = column.to_s.humanize unless caption |
|
202 | caption = column.to_s.humanize unless caption | |
201 |
|
203 | |||
202 | sort_options = { :sort => @sort_criteria.add(column.to_s, order).to_param } |
|
204 | sort_options = { :sort => @sort_criteria.add(column.to_s, order).to_param } | |
203 | url_options = params.merge(sort_options) |
|
205 | url_options = params.merge(sort_options) | |
204 |
|
206 | |||
205 | # Add project_id to url_options |
|
207 | # Add project_id to url_options | |
206 | url_options = url_options.merge(:project_id => params[:project_id]) if params.has_key?(:project_id) |
|
208 | url_options = url_options.merge(:project_id => params[:project_id]) if params.has_key?(:project_id) | |
207 |
|
209 | |||
208 | link_to_content_update(h(caption), url_options, :class => css) |
|
210 | link_to_content_update(h(caption), url_options, :class => css) | |
209 | end |
|
211 | end | |
210 |
|
212 | |||
211 | # Returns a table header <th> tag with a sort link for the named column |
|
213 | # Returns a table header <th> tag with a sort link for the named column | |
212 | # attribute. |
|
214 | # attribute. | |
213 | # |
|
215 | # | |
214 | # Options: |
|
216 | # Options: | |
215 | # :caption The displayed link name (defaults to titleized column name). |
|
217 | # :caption The displayed link name (defaults to titleized column name). | |
216 | # :title The tag's 'title' attribute (defaults to 'Sort by :caption'). |
|
218 | # :title The tag's 'title' attribute (defaults to 'Sort by :caption'). | |
217 | # |
|
219 | # | |
218 | # Other options hash entries generate additional table header tag attributes. |
|
220 | # Other options hash entries generate additional table header tag attributes. | |
219 | # |
|
221 | # | |
220 | # Example: |
|
222 | # Example: | |
221 | # |
|
223 | # | |
222 | # <%= sort_header_tag('id', :title => 'Sort by contact ID', :width => 40) %> |
|
224 | # <%= sort_header_tag('id', :title => 'Sort by contact ID', :width => 40) %> | |
223 | # |
|
225 | # | |
224 | def sort_header_tag(column, options = {}) |
|
226 | def sort_header_tag(column, options = {}) | |
225 | caption = options.delete(:caption) || column.to_s.humanize |
|
227 | caption = options.delete(:caption) || column.to_s.humanize | |
226 | default_order = options.delete(:default_order) || 'asc' |
|
228 | default_order = options.delete(:default_order) || 'asc' | |
227 | options[:title] = l(:label_sort_by, "\"#{caption}\"") unless options[:title] |
|
229 | options[:title] = l(:label_sort_by, "\"#{caption}\"") unless options[:title] | |
228 | content_tag('th', sort_link(column, caption, default_order), options) |
|
230 | content_tag('th', sort_link(column, caption, default_order), options) | |
229 | end |
|
231 | end | |
230 | end |
|
232 | end | |
231 |
|
233 |
@@ -1,194 +1,196 | |||||
|
1 | # encoding: utf-8 | |||
|
2 | # | |||
1 | # Redmine - project management software |
|
3 | # Redmine - project management software | |
2 | # Copyright (C) 2006-2011 Jean-Philippe Lang |
|
4 | # Copyright (C) 2006-2011 Jean-Philippe Lang | |
3 | # |
|
5 | # | |
4 | # This program is free software; you can redistribute it and/or |
|
6 | # This program is free software; you can redistribute it and/or | |
5 | # modify it under the terms of the GNU General Public License |
|
7 | # modify it under the terms of the GNU General Public License | |
6 | # as published by the Free Software Foundation; either version 2 |
|
8 | # as published by the Free Software Foundation; either version 2 | |
7 | # of the License, or (at your option) any later version. |
|
9 | # of the License, or (at your option) any later version. | |
8 | # |
|
10 | # | |
9 | # This program is distributed in the hope that it will be useful, |
|
11 | # This program is distributed in the hope that it will be useful, | |
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | # GNU General Public License for more details. |
|
14 | # GNU General Public License for more details. | |
13 | # |
|
15 | # | |
14 | # You should have received a copy of the GNU General Public License |
|
16 | # You should have received a copy of the GNU General Public License | |
15 | # along with this program; if not, write to the Free Software |
|
17 | # along with this program; if not, write to the Free Software | |
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
17 |
|
19 | |||
18 | module TimelogHelper |
|
20 | module TimelogHelper | |
19 | include ApplicationHelper |
|
21 | include ApplicationHelper | |
20 |
|
22 | |||
21 | def render_timelog_breadcrumb |
|
23 | def render_timelog_breadcrumb | |
22 | links = [] |
|
24 | links = [] | |
23 | links << link_to(l(:label_project_all), {:project_id => nil, :issue_id => nil}) |
|
25 | links << link_to(l(:label_project_all), {:project_id => nil, :issue_id => nil}) | |
24 | links << link_to(h(@project), {:project_id => @project, :issue_id => nil}) if @project |
|
26 | links << link_to(h(@project), {:project_id => @project, :issue_id => nil}) if @project | |
25 | if @issue |
|
27 | if @issue | |
26 | if @issue.visible? |
|
28 | if @issue.visible? | |
27 | links << link_to_issue(@issue, :subject => false) |
|
29 | links << link_to_issue(@issue, :subject => false) | |
28 | else |
|
30 | else | |
29 | links << "##{@issue.id}" |
|
31 | links << "##{@issue.id}" | |
30 | end |
|
32 | end | |
31 | end |
|
33 | end | |
32 | breadcrumb links |
|
34 | breadcrumb links | |
33 | end |
|
35 | end | |
34 |
|
36 | |||
35 | # Returns a collection of activities for a select field. time_entry |
|
37 | # Returns a collection of activities for a select field. time_entry | |
36 | # is optional and will be used to check if the selected TimeEntryActivity |
|
38 | # is optional and will be used to check if the selected TimeEntryActivity | |
37 | # is active. |
|
39 | # is active. | |
38 | def activity_collection_for_select_options(time_entry=nil, project=nil) |
|
40 | def activity_collection_for_select_options(time_entry=nil, project=nil) | |
39 | project ||= @project |
|
41 | project ||= @project | |
40 | if project.nil? |
|
42 | if project.nil? | |
41 | activities = TimeEntryActivity.shared.active |
|
43 | activities = TimeEntryActivity.shared.active | |
42 | else |
|
44 | else | |
43 | activities = project.activities |
|
45 | activities = project.activities | |
44 | end |
|
46 | end | |
45 |
|
47 | |||
46 | collection = [] |
|
48 | collection = [] | |
47 | if time_entry && time_entry.activity && !time_entry.activity.active? |
|
49 | if time_entry && time_entry.activity && !time_entry.activity.active? | |
48 | collection << [ "--- #{l(:actionview_instancetag_blank_option)} ---", '' ] |
|
50 | collection << [ "--- #{l(:actionview_instancetag_blank_option)} ---", '' ] | |
49 | else |
|
51 | else | |
50 | collection << [ "--- #{l(:actionview_instancetag_blank_option)} ---", '' ] unless activities.detect(&:is_default) |
|
52 | collection << [ "--- #{l(:actionview_instancetag_blank_option)} ---", '' ] unless activities.detect(&:is_default) | |
51 | end |
|
53 | end | |
52 | activities.each { |a| collection << [a.name, a.id] } |
|
54 | activities.each { |a| collection << [a.name, a.id] } | |
53 | collection |
|
55 | collection | |
54 | end |
|
56 | end | |
55 |
|
57 | |||
56 | def select_hours(data, criteria, value) |
|
58 | def select_hours(data, criteria, value) | |
57 | if value.to_s.empty? |
|
59 | if value.to_s.empty? | |
58 | data.select {|row| row[criteria].blank? } |
|
60 | data.select {|row| row[criteria].blank? } | |
59 | else |
|
61 | else | |
60 | data.select {|row| row[criteria].to_s == value.to_s} |
|
62 | data.select {|row| row[criteria].to_s == value.to_s} | |
61 | end |
|
63 | end | |
62 | end |
|
64 | end | |
63 |
|
65 | |||
64 | def sum_hours(data) |
|
66 | def sum_hours(data) | |
65 | sum = 0 |
|
67 | sum = 0 | |
66 | data.each do |row| |
|
68 | data.each do |row| | |
67 | sum += row['hours'].to_f |
|
69 | sum += row['hours'].to_f | |
68 | end |
|
70 | end | |
69 | sum |
|
71 | sum | |
70 | end |
|
72 | end | |
71 |
|
73 | |||
72 | def options_for_period_select(value) |
|
74 | def options_for_period_select(value) | |
73 | options_for_select([[l(:label_all_time), 'all'], |
|
75 | options_for_select([[l(:label_all_time), 'all'], | |
74 | [l(:label_today), 'today'], |
|
76 | [l(:label_today), 'today'], | |
75 | [l(:label_yesterday), 'yesterday'], |
|
77 | [l(:label_yesterday), 'yesterday'], | |
76 | [l(:label_this_week), 'current_week'], |
|
78 | [l(:label_this_week), 'current_week'], | |
77 | [l(:label_last_week), 'last_week'], |
|
79 | [l(:label_last_week), 'last_week'], | |
78 | [l(:label_last_n_days, 7), '7_days'], |
|
80 | [l(:label_last_n_days, 7), '7_days'], | |
79 | [l(:label_this_month), 'current_month'], |
|
81 | [l(:label_this_month), 'current_month'], | |
80 | [l(:label_last_month), 'last_month'], |
|
82 | [l(:label_last_month), 'last_month'], | |
81 | [l(:label_last_n_days, 30), '30_days'], |
|
83 | [l(:label_last_n_days, 30), '30_days'], | |
82 | [l(:label_this_year), 'current_year']], |
|
84 | [l(:label_this_year), 'current_year']], | |
83 | value) |
|
85 | value) | |
84 | end |
|
86 | end | |
85 |
|
87 | |||
86 | def entries_to_csv(entries) |
|
88 | def entries_to_csv(entries) | |
87 | decimal_separator = l(:general_csv_decimal_separator) |
|
89 | decimal_separator = l(:general_csv_decimal_separator) | |
88 | custom_fields = TimeEntryCustomField.find(:all) |
|
90 | custom_fields = TimeEntryCustomField.find(:all) | |
89 | export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv| |
|
91 | export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv| | |
90 | # csv header fields |
|
92 | # csv header fields | |
91 | headers = [l(:field_spent_on), |
|
93 | headers = [l(:field_spent_on), | |
92 | l(:field_user), |
|
94 | l(:field_user), | |
93 | l(:field_activity), |
|
95 | l(:field_activity), | |
94 | l(:field_project), |
|
96 | l(:field_project), | |
95 | l(:field_issue), |
|
97 | l(:field_issue), | |
96 | l(:field_tracker), |
|
98 | l(:field_tracker), | |
97 | l(:field_subject), |
|
99 | l(:field_subject), | |
98 | l(:field_hours), |
|
100 | l(:field_hours), | |
99 | l(:field_comments) |
|
101 | l(:field_comments) | |
100 | ] |
|
102 | ] | |
101 | # Export custom fields |
|
103 | # Export custom fields | |
102 | headers += custom_fields.collect(&:name) |
|
104 | headers += custom_fields.collect(&:name) | |
103 |
|
105 | |||
104 | csv << headers.collect {|c| Redmine::CodesetUtil.from_utf8( |
|
106 | csv << headers.collect {|c| Redmine::CodesetUtil.from_utf8( | |
105 | c.to_s, |
|
107 | c.to_s, | |
106 | l(:general_csv_encoding) ) } |
|
108 | l(:general_csv_encoding) ) } | |
107 | # csv lines |
|
109 | # csv lines | |
108 | entries.each do |entry| |
|
110 | entries.each do |entry| | |
109 | fields = [format_date(entry.spent_on), |
|
111 | fields = [format_date(entry.spent_on), | |
110 | entry.user, |
|
112 | entry.user, | |
111 | entry.activity, |
|
113 | entry.activity, | |
112 | entry.project, |
|
114 | entry.project, | |
113 | (entry.issue ? entry.issue.id : nil), |
|
115 | (entry.issue ? entry.issue.id : nil), | |
114 | (entry.issue ? entry.issue.tracker : nil), |
|
116 | (entry.issue ? entry.issue.tracker : nil), | |
115 | (entry.issue ? entry.issue.subject : nil), |
|
117 | (entry.issue ? entry.issue.subject : nil), | |
116 | entry.hours.to_s.gsub('.', decimal_separator), |
|
118 | entry.hours.to_s.gsub('.', decimal_separator), | |
117 | entry.comments |
|
119 | entry.comments | |
118 | ] |
|
120 | ] | |
119 | fields += custom_fields.collect {|f| show_value(entry.custom_value_for(f)) } |
|
121 | fields += custom_fields.collect {|f| show_value(entry.custom_value_for(f)) } | |
120 |
|
122 | |||
121 | csv << fields.collect {|c| Redmine::CodesetUtil.from_utf8( |
|
123 | csv << fields.collect {|c| Redmine::CodesetUtil.from_utf8( | |
122 | c.to_s, |
|
124 | c.to_s, | |
123 | l(:general_csv_encoding) ) } |
|
125 | l(:general_csv_encoding) ) } | |
124 | end |
|
126 | end | |
125 | end |
|
127 | end | |
126 | export |
|
128 | export | |
127 | end |
|
129 | end | |
128 |
|
130 | |||
129 | def format_criteria_value(criteria, value) |
|
131 | def format_criteria_value(criteria, value) | |
130 | if value.blank? |
|
132 | if value.blank? | |
131 | l(:label_none) |
|
133 | l(:label_none) | |
132 | elsif k = @available_criterias[criteria][:klass] |
|
134 | elsif k = @available_criterias[criteria][:klass] | |
133 | obj = k.find_by_id(value.to_i) |
|
135 | obj = k.find_by_id(value.to_i) | |
134 | if obj.is_a?(Issue) |
|
136 | if obj.is_a?(Issue) | |
135 | obj.visible? ? "#{obj.tracker} ##{obj.id}: #{obj.subject}" : "##{obj.id}" |
|
137 | obj.visible? ? "#{obj.tracker} ##{obj.id}: #{obj.subject}" : "##{obj.id}" | |
136 | else |
|
138 | else | |
137 | obj |
|
139 | obj | |
138 | end |
|
140 | end | |
139 | else |
|
141 | else | |
140 | format_value(value, @available_criterias[criteria][:format]) |
|
142 | format_value(value, @available_criterias[criteria][:format]) | |
141 | end |
|
143 | end | |
142 | end |
|
144 | end | |
143 |
|
145 | |||
144 | def report_to_csv(criterias, periods, hours) |
|
146 | def report_to_csv(criterias, periods, hours) | |
145 | decimal_separator = l(:general_csv_decimal_separator) |
|
147 | decimal_separator = l(:general_csv_decimal_separator) | |
146 | export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv| |
|
148 | export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv| | |
147 | # Column headers |
|
149 | # Column headers | |
148 | headers = criterias.collect {|criteria| l(@available_criterias[criteria][:label]) } |
|
150 | headers = criterias.collect {|criteria| l(@available_criterias[criteria][:label]) } | |
149 | headers += periods |
|
151 | headers += periods | |
150 | headers << l(:label_total) |
|
152 | headers << l(:label_total) | |
151 | csv << headers.collect {|c| Redmine::CodesetUtil.from_utf8( |
|
153 | csv << headers.collect {|c| Redmine::CodesetUtil.from_utf8( | |
152 | c.to_s, |
|
154 | c.to_s, | |
153 | l(:general_csv_encoding) ) } |
|
155 | l(:general_csv_encoding) ) } | |
154 | # Content |
|
156 | # Content | |
155 | report_criteria_to_csv(csv, criterias, periods, hours) |
|
157 | report_criteria_to_csv(csv, criterias, periods, hours) | |
156 | # Total row |
|
158 | # Total row | |
157 | str_total = Redmine::CodesetUtil.from_utf8(l(:label_total), l(:general_csv_encoding)) |
|
159 | str_total = Redmine::CodesetUtil.from_utf8(l(:label_total), l(:general_csv_encoding)) | |
158 | row = [ str_total ] + [''] * (criterias.size - 1) |
|
160 | row = [ str_total ] + [''] * (criterias.size - 1) | |
159 | total = 0 |
|
161 | total = 0 | |
160 | periods.each do |period| |
|
162 | periods.each do |period| | |
161 | sum = sum_hours(select_hours(hours, @columns, period.to_s)) |
|
163 | sum = sum_hours(select_hours(hours, @columns, period.to_s)) | |
162 | total += sum |
|
164 | total += sum | |
163 | row << (sum > 0 ? ("%.2f" % sum).gsub('.',decimal_separator) : '') |
|
165 | row << (sum > 0 ? ("%.2f" % sum).gsub('.',decimal_separator) : '') | |
164 | end |
|
166 | end | |
165 | row << ("%.2f" % total).gsub('.',decimal_separator) |
|
167 | row << ("%.2f" % total).gsub('.',decimal_separator) | |
166 | csv << row |
|
168 | csv << row | |
167 | end |
|
169 | end | |
168 | export |
|
170 | export | |
169 | end |
|
171 | end | |
170 |
|
172 | |||
171 | def report_criteria_to_csv(csv, criterias, periods, hours, level=0) |
|
173 | def report_criteria_to_csv(csv, criterias, periods, hours, level=0) | |
172 | decimal_separator = l(:general_csv_decimal_separator) |
|
174 | decimal_separator = l(:general_csv_decimal_separator) | |
173 | hours.collect {|h| h[criterias[level]].to_s}.uniq.each do |value| |
|
175 | hours.collect {|h| h[criterias[level]].to_s}.uniq.each do |value| | |
174 | hours_for_value = select_hours(hours, criterias[level], value) |
|
176 | hours_for_value = select_hours(hours, criterias[level], value) | |
175 | next if hours_for_value.empty? |
|
177 | next if hours_for_value.empty? | |
176 | row = [''] * level |
|
178 | row = [''] * level | |
177 | row << Redmine::CodesetUtil.from_utf8( |
|
179 | row << Redmine::CodesetUtil.from_utf8( | |
178 | format_criteria_value(criterias[level], value).to_s, |
|
180 | format_criteria_value(criterias[level], value).to_s, | |
179 | l(:general_csv_encoding) ) |
|
181 | l(:general_csv_encoding) ) | |
180 | row += [''] * (criterias.length - level - 1) |
|
182 | row += [''] * (criterias.length - level - 1) | |
181 | total = 0 |
|
183 | total = 0 | |
182 | periods.each do |period| |
|
184 | periods.each do |period| | |
183 | sum = sum_hours(select_hours(hours_for_value, @columns, period.to_s)) |
|
185 | sum = sum_hours(select_hours(hours_for_value, @columns, period.to_s)) | |
184 | total += sum |
|
186 | total += sum | |
185 | row << (sum > 0 ? ("%.2f" % sum).gsub('.',decimal_separator) : '') |
|
187 | row << (sum > 0 ? ("%.2f" % sum).gsub('.',decimal_separator) : '') | |
186 | end |
|
188 | end | |
187 | row << ("%.2f" % total).gsub('.',decimal_separator) |
|
189 | row << ("%.2f" % total).gsub('.',decimal_separator) | |
188 | csv << row |
|
190 | csv << row | |
189 | if criterias.length > level + 1 |
|
191 | if criterias.length > level + 1 | |
190 | report_criteria_to_csv(csv, criterias, periods, hours_for_value, level + 1) |
|
192 | report_criteria_to_csv(csv, criterias, periods, hours_for_value, level + 1) | |
191 | end |
|
193 | end | |
192 | end |
|
194 | end | |
193 | end |
|
195 | end | |
194 | end |
|
196 | end |
@@ -1,19 +1,21 | |||||
|
1 | # encoding: utf-8 | |||
|
2 | # | |||
1 | # Redmine - project management software |
|
3 | # Redmine - project management software | |
2 | # Copyright (C) 2006-2011 Jean-Philippe Lang |
|
4 | # Copyright (C) 2006-2011 Jean-Philippe Lang | |
3 | # |
|
5 | # | |
4 | # This program is free software; you can redistribute it and/or |
|
6 | # This program is free software; you can redistribute it and/or | |
5 | # modify it under the terms of the GNU General Public License |
|
7 | # modify it under the terms of the GNU General Public License | |
6 | # as published by the Free Software Foundation; either version 2 |
|
8 | # as published by the Free Software Foundation; either version 2 | |
7 | # of the License, or (at your option) any later version. |
|
9 | # of the License, or (at your option) any later version. | |
8 | # |
|
10 | # | |
9 | # This program is distributed in the hope that it will be useful, |
|
11 | # This program is distributed in the hope that it will be useful, | |
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | # GNU General Public License for more details. |
|
14 | # GNU General Public License for more details. | |
13 | # |
|
15 | # | |
14 | # You should have received a copy of the GNU General Public License |
|
16 | # You should have received a copy of the GNU General Public License | |
15 | # along with this program; if not, write to the Free Software |
|
17 | # along with this program; if not, write to the Free Software | |
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
17 |
|
19 | |||
18 | module TrackersHelper |
|
20 | module TrackersHelper | |
19 | end |
|
21 | end |
@@ -1,61 +1,63 | |||||
|
1 | # encoding: utf-8 | |||
|
2 | # | |||
1 | # Redmine - project management software |
|
3 | # Redmine - project management software | |
2 | # Copyright (C) 2006-2011 Jean-Philippe Lang |
|
4 | # Copyright (C) 2006-2011 Jean-Philippe Lang | |
3 | # |
|
5 | # | |
4 | # This program is free software; you can redistribute it and/or |
|
6 | # This program is free software; you can redistribute it and/or | |
5 | # modify it under the terms of the GNU General Public License |
|
7 | # modify it under the terms of the GNU General Public License | |
6 | # as published by the Free Software Foundation; either version 2 |
|
8 | # as published by the Free Software Foundation; either version 2 | |
7 | # of the License, or (at your option) any later version. |
|
9 | # of the License, or (at your option) any later version. | |
8 | # |
|
10 | # | |
9 | # This program is distributed in the hope that it will be useful, |
|
11 | # This program is distributed in the hope that it will be useful, | |
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | # GNU General Public License for more details. |
|
14 | # GNU General Public License for more details. | |
13 | # |
|
15 | # | |
14 | # You should have received a copy of the GNU General Public License |
|
16 | # You should have received a copy of the GNU General Public License | |
15 | # along with this program; if not, write to the Free Software |
|
17 | # along with this program; if not, write to the Free Software | |
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
17 |
|
19 | |||
18 | module UsersHelper |
|
20 | module UsersHelper | |
19 | def users_status_options_for_select(selected) |
|
21 | def users_status_options_for_select(selected) | |
20 | user_count_by_status = User.count(:group => 'status').to_hash |
|
22 | user_count_by_status = User.count(:group => 'status').to_hash | |
21 | options_for_select([[l(:label_all), ''], |
|
23 | options_for_select([[l(:label_all), ''], | |
22 | ["#{l(:status_active)} (#{user_count_by_status[1].to_i})", 1], |
|
24 | ["#{l(:status_active)} (#{user_count_by_status[1].to_i})", 1], | |
23 | ["#{l(:status_registered)} (#{user_count_by_status[2].to_i})", 2], |
|
25 | ["#{l(:status_registered)} (#{user_count_by_status[2].to_i})", 2], | |
24 | ["#{l(:status_locked)} (#{user_count_by_status[3].to_i})", 3]], selected) |
|
26 | ["#{l(:status_locked)} (#{user_count_by_status[3].to_i})", 3]], selected) | |
25 | end |
|
27 | end | |
26 |
|
28 | |||
27 | # Options for the new membership projects combo-box |
|
29 | # Options for the new membership projects combo-box | |
28 | def options_for_membership_project_select(user, projects) |
|
30 | def options_for_membership_project_select(user, projects) | |
29 | options = content_tag('option', "--- #{l(:actionview_instancetag_blank_option)} ---") |
|
31 | options = content_tag('option', "--- #{l(:actionview_instancetag_blank_option)} ---") | |
30 | options << project_tree_options_for_select(projects) do |p| |
|
32 | options << project_tree_options_for_select(projects) do |p| | |
31 | {:disabled => (user.projects.include?(p))} |
|
33 | {:disabled => (user.projects.include?(p))} | |
32 | end |
|
34 | end | |
33 | options |
|
35 | options | |
34 | end |
|
36 | end | |
35 |
|
37 | |||
36 | def user_mail_notification_options(user) |
|
38 | def user_mail_notification_options(user) | |
37 | user.valid_notification_options.collect {|o| [l(o.last), o.first]} |
|
39 | user.valid_notification_options.collect {|o| [l(o.last), o.first]} | |
38 | end |
|
40 | end | |
39 |
|
41 | |||
40 | def change_status_link(user) |
|
42 | def change_status_link(user) | |
41 | url = {:controller => 'users', :action => 'update', :id => user, :page => params[:page], :status => params[:status], :tab => nil} |
|
43 | url = {:controller => 'users', :action => 'update', :id => user, :page => params[:page], :status => params[:status], :tab => nil} | |
42 |
|
44 | |||
43 | if user.locked? |
|
45 | if user.locked? | |
44 | link_to l(:button_unlock), url.merge(:user => {:status => User::STATUS_ACTIVE}), :method => :put, :class => 'icon icon-unlock' |
|
46 | link_to l(:button_unlock), url.merge(:user => {:status => User::STATUS_ACTIVE}), :method => :put, :class => 'icon icon-unlock' | |
45 | elsif user.registered? |
|
47 | elsif user.registered? | |
46 | link_to l(:button_activate), url.merge(:user => {:status => User::STATUS_ACTIVE}), :method => :put, :class => 'icon icon-unlock' |
|
48 | link_to l(:button_activate), url.merge(:user => {:status => User::STATUS_ACTIVE}), :method => :put, :class => 'icon icon-unlock' | |
47 | elsif user != User.current |
|
49 | elsif user != User.current | |
48 | link_to l(:button_lock), url.merge(:user => {:status => User::STATUS_LOCKED}), :method => :put, :class => 'icon icon-lock' |
|
50 | link_to l(:button_lock), url.merge(:user => {:status => User::STATUS_LOCKED}), :method => :put, :class => 'icon icon-lock' | |
49 | end |
|
51 | end | |
50 | end |
|
52 | end | |
51 |
|
53 | |||
52 | def user_settings_tabs |
|
54 | def user_settings_tabs | |
53 | tabs = [{:name => 'general', :partial => 'users/general', :label => :label_general}, |
|
55 | tabs = [{:name => 'general', :partial => 'users/general', :label => :label_general}, | |
54 | {:name => 'memberships', :partial => 'users/memberships', :label => :label_project_plural} |
|
56 | {:name => 'memberships', :partial => 'users/memberships', :label => :label_project_plural} | |
55 | ] |
|
57 | ] | |
56 | if Group.all.any? |
|
58 | if Group.all.any? | |
57 | tabs.insert 1, {:name => 'groups', :partial => 'users/groups', :label => :label_group_plural} |
|
59 | tabs.insert 1, {:name => 'groups', :partial => 'users/groups', :label => :label_group_plural} | |
58 | end |
|
60 | end | |
59 | tabs |
|
61 | tabs | |
60 | end |
|
62 | end | |
61 | end |
|
63 | end |
@@ -1,46 +1,48 | |||||
|
1 | # encoding: utf-8 | |||
|
2 | # | |||
1 | # Redmine - project management software |
|
3 | # Redmine - project management software | |
2 | # Copyright (C) 2006-2011 Jean-Philippe Lang |
|
4 | # Copyright (C) 2006-2011 Jean-Philippe Lang | |
3 | # |
|
5 | # | |
4 | # This program is free software; you can redistribute it and/or |
|
6 | # This program is free software; you can redistribute it and/or | |
5 | # modify it under the terms of the GNU General Public License |
|
7 | # modify it under the terms of the GNU General Public License | |
6 | # as published by the Free Software Foundation; either version 2 |
|
8 | # as published by the Free Software Foundation; either version 2 | |
7 | # of the License, or (at your option) any later version. |
|
9 | # of the License, or (at your option) any later version. | |
8 | # |
|
10 | # | |
9 | # This program is distributed in the hope that it will be useful, |
|
11 | # This program is distributed in the hope that it will be useful, | |
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | # GNU General Public License for more details. |
|
14 | # GNU General Public License for more details. | |
13 | # |
|
15 | # | |
14 | # You should have received a copy of the GNU General Public License |
|
16 | # You should have received a copy of the GNU General Public License | |
15 | # along with this program; if not, write to the Free Software |
|
17 | # along with this program; if not, write to the Free Software | |
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
17 |
|
19 | |||
18 | module VersionsHelper |
|
20 | module VersionsHelper | |
19 |
|
21 | |||
20 | STATUS_BY_CRITERIAS = %w(category tracker status priority author assigned_to) |
|
22 | STATUS_BY_CRITERIAS = %w(category tracker status priority author assigned_to) | |
21 |
|
23 | |||
22 | def render_issue_status_by(version, criteria) |
|
24 | def render_issue_status_by(version, criteria) | |
23 | criteria = 'category' unless STATUS_BY_CRITERIAS.include?(criteria) |
|
25 | criteria = 'category' unless STATUS_BY_CRITERIAS.include?(criteria) | |
24 |
|
26 | |||
25 | h = Hash.new {|k,v| k[v] = [0, 0]} |
|
27 | h = Hash.new {|k,v| k[v] = [0, 0]} | |
26 | begin |
|
28 | begin | |
27 | # Total issue count |
|
29 | # Total issue count | |
28 | Issue.count(:group => criteria, |
|
30 | Issue.count(:group => criteria, | |
29 | :conditions => ["#{Issue.table_name}.fixed_version_id = ?", version.id]).each {|c,s| h[c][0] = s} |
|
31 | :conditions => ["#{Issue.table_name}.fixed_version_id = ?", version.id]).each {|c,s| h[c][0] = s} | |
30 | # Open issues count |
|
32 | # Open issues count | |
31 | Issue.count(:group => criteria, |
|
33 | Issue.count(:group => criteria, | |
32 | :include => :status, |
|
34 | :include => :status, | |
33 | :conditions => ["#{Issue.table_name}.fixed_version_id = ? AND #{IssueStatus.table_name}.is_closed = ?", version.id, false]).each {|c,s| h[c][1] = s} |
|
35 | :conditions => ["#{Issue.table_name}.fixed_version_id = ? AND #{IssueStatus.table_name}.is_closed = ?", version.id, false]).each {|c,s| h[c][1] = s} | |
34 | rescue ActiveRecord::RecordNotFound |
|
36 | rescue ActiveRecord::RecordNotFound | |
35 | # When grouping by an association, Rails throws this exception if there's no result (bug) |
|
37 | # When grouping by an association, Rails throws this exception if there's no result (bug) | |
36 | end |
|
38 | end | |
37 | counts = h.keys.compact.sort.collect {|k| {:group => k, :total => h[k][0], :open => h[k][1], :closed => (h[k][0] - h[k][1])}} |
|
39 | counts = h.keys.compact.sort.collect {|k| {:group => k, :total => h[k][0], :open => h[k][1], :closed => (h[k][0] - h[k][1])}} | |
38 | max = counts.collect {|c| c[:total]}.max |
|
40 | max = counts.collect {|c| c[:total]}.max | |
39 |
|
41 | |||
40 | render :partial => 'issue_counts', :locals => {:version => version, :criteria => criteria, :counts => counts, :max => max} |
|
42 | render :partial => 'issue_counts', :locals => {:version => version, :criteria => criteria, :counts => counts, :max => max} | |
41 | end |
|
43 | end | |
42 |
|
44 | |||
43 | def status_by_options_for_select(value) |
|
45 | def status_by_options_for_select(value) | |
44 | options_for_select(STATUS_BY_CRITERIAS.collect {|criteria| [l("field_#{criteria}".to_sym), criteria]}, value) |
|
46 | options_for_select(STATUS_BY_CRITERIAS.collect {|criteria| [l("field_#{criteria}".to_sym), criteria]}, value) | |
45 | end |
|
47 | end | |
46 | end |
|
48 | end |
@@ -1,64 +1,66 | |||||
|
1 | # encoding: utf-8 | |||
|
2 | # | |||
1 | # Redmine - project management software |
|
3 | # Redmine - project management software | |
2 | # Copyright (C) 2006-2011 Jean-Philippe Lang |
|
4 | # Copyright (C) 2006-2011 Jean-Philippe Lang | |
3 | # |
|
5 | # | |
4 | # This program is free software; you can redistribute it and/or |
|
6 | # This program is free software; you can redistribute it and/or | |
5 | # modify it under the terms of the GNU General Public License |
|
7 | # modify it under the terms of the GNU General Public License | |
6 | # as published by the Free Software Foundation; either version 2 |
|
8 | # as published by the Free Software Foundation; either version 2 | |
7 | # of the License, or (at your option) any later version. |
|
9 | # of the License, or (at your option) any later version. | |
8 | # |
|
10 | # | |
9 | # This program is distributed in the hope that it will be useful, |
|
11 | # This program is distributed in the hope that it will be useful, | |
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | # GNU General Public License for more details. |
|
14 | # GNU General Public License for more details. | |
13 | # |
|
15 | # | |
14 | # You should have received a copy of the GNU General Public License |
|
16 | # You should have received a copy of the GNU General Public License | |
15 | # along with this program; if not, write to the Free Software |
|
17 | # along with this program; if not, write to the Free Software | |
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
17 |
|
19 | |||
18 | module WatchersHelper |
|
20 | module WatchersHelper | |
19 |
|
21 | |||
20 | def watcher_tag(object, user, options={}) |
|
22 | def watcher_tag(object, user, options={}) | |
21 | content_tag("span", watcher_link(object, user), :class => watcher_css(object)) |
|
23 | content_tag("span", watcher_link(object, user), :class => watcher_css(object)) | |
22 | end |
|
24 | end | |
23 |
|
25 | |||
24 | def watcher_link(object, user) |
|
26 | def watcher_link(object, user) | |
25 | return '' unless user && user.logged? && object.respond_to?('watched_by?') |
|
27 | return '' unless user && user.logged? && object.respond_to?('watched_by?') | |
26 | watched = object.watched_by?(user) |
|
28 | watched = object.watched_by?(user) | |
27 | url = {:controller => 'watchers', |
|
29 | url = {:controller => 'watchers', | |
28 | :action => (watched ? 'unwatch' : 'watch'), |
|
30 | :action => (watched ? 'unwatch' : 'watch'), | |
29 | :object_type => object.class.to_s.underscore, |
|
31 | :object_type => object.class.to_s.underscore, | |
30 | :object_id => object.id} |
|
32 | :object_id => object.id} | |
31 | link_to_remote((watched ? l(:button_unwatch) : l(:button_watch)), |
|
33 | link_to_remote((watched ? l(:button_unwatch) : l(:button_watch)), | |
32 | {:url => url}, |
|
34 | {:url => url}, | |
33 | :href => url_for(url), |
|
35 | :href => url_for(url), | |
34 | :class => (watched ? 'icon icon-fav' : 'icon icon-fav-off')) |
|
36 | :class => (watched ? 'icon icon-fav' : 'icon icon-fav-off')) | |
35 |
|
37 | |||
36 | end |
|
38 | end | |
37 |
|
39 | |||
38 | # Returns the css class used to identify watch links for a given +object+ |
|
40 | # Returns the css class used to identify watch links for a given +object+ | |
39 | def watcher_css(object) |
|
41 | def watcher_css(object) | |
40 | "#{object.class.to_s.underscore}-#{object.id}-watcher" |
|
42 | "#{object.class.to_s.underscore}-#{object.id}-watcher" | |
41 | end |
|
43 | end | |
42 |
|
44 | |||
43 | # Returns a comma separated list of users watching the given object |
|
45 | # Returns a comma separated list of users watching the given object | |
44 | def watchers_list(object) |
|
46 | def watchers_list(object) | |
45 | remove_allowed = User.current.allowed_to?("delete_#{object.class.name.underscore}_watchers".to_sym, object.project) |
|
47 | remove_allowed = User.current.allowed_to?("delete_#{object.class.name.underscore}_watchers".to_sym, object.project) | |
46 | lis = object.watcher_users.collect do |user| |
|
48 | lis = object.watcher_users.collect do |user| | |
47 | s = avatar(user, :size => "16").to_s + link_to_user(user, :class => 'user').to_s |
|
49 | s = avatar(user, :size => "16").to_s + link_to_user(user, :class => 'user').to_s | |
48 | if remove_allowed |
|
50 | if remove_allowed | |
49 | url = {:controller => 'watchers', |
|
51 | url = {:controller => 'watchers', | |
50 | :action => 'destroy', |
|
52 | :action => 'destroy', | |
51 | :object_type => object.class.to_s.underscore, |
|
53 | :object_type => object.class.to_s.underscore, | |
52 | :object_id => object.id, |
|
54 | :object_id => object.id, | |
53 | :user_id => user} |
|
55 | :user_id => user} | |
54 | s += ' ' + link_to_remote(image_tag('delete.png'), |
|
56 | s += ' ' + link_to_remote(image_tag('delete.png'), | |
55 | {:url => url}, |
|
57 | {:url => url}, | |
56 | :href => url_for(url), |
|
58 | :href => url_for(url), | |
57 | :style => "vertical-align: middle", |
|
59 | :style => "vertical-align: middle", | |
58 | :class => "delete") |
|
60 | :class => "delete") | |
59 | end |
|
61 | end | |
60 | "<li>#{ s }</li>" |
|
62 | "<li>#{ s }</li>" | |
61 | end |
|
63 | end | |
62 | lis.empty? ? "" : "<ul>#{ lis.join("\n") }</ul>" |
|
64 | lis.empty? ? "" : "<ul>#{ lis.join("\n") }</ul>" | |
63 | end |
|
65 | end | |
64 | end |
|
66 | end |
@@ -1,19 +1,21 | |||||
|
1 | # encoding: utf-8 | |||
|
2 | # | |||
1 | # Redmine - project management software |
|
3 | # Redmine - project management software | |
2 | # Copyright (C) 2006-2011 Jean-Philippe Lang |
|
4 | # Copyright (C) 2006-2011 Jean-Philippe Lang | |
3 | # |
|
5 | # | |
4 | # This program is free software; you can redistribute it and/or |
|
6 | # This program is free software; you can redistribute it and/or | |
5 | # modify it under the terms of the GNU General Public License |
|
7 | # modify it under the terms of the GNU General Public License | |
6 | # as published by the Free Software Foundation; either version 2 |
|
8 | # as published by the Free Software Foundation; either version 2 | |
7 | # of the License, or (at your option) any later version. |
|
9 | # of the License, or (at your option) any later version. | |
8 | # |
|
10 | # | |
9 | # This program is distributed in the hope that it will be useful, |
|
11 | # This program is distributed in the hope that it will be useful, | |
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | # GNU General Public License for more details. |
|
14 | # GNU General Public License for more details. | |
13 | # |
|
15 | # | |
14 | # You should have received a copy of the GNU General Public License |
|
16 | # You should have received a copy of the GNU General Public License | |
15 | # along with this program; if not, write to the Free Software |
|
17 | # along with this program; if not, write to the Free Software | |
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
17 |
|
19 | |||
18 | module WelcomeHelper |
|
20 | module WelcomeHelper | |
19 | end |
|
21 | end |
@@ -1,41 +1,43 | |||||
|
1 | # encoding: utf-8 | |||
|
2 | # | |||
1 | # Redmine - project management software |
|
3 | # Redmine - project management software | |
2 | # Copyright (C) 2006-2011 Jean-Philippe Lang |
|
4 | # Copyright (C) 2006-2011 Jean-Philippe Lang | |
3 | # |
|
5 | # | |
4 | # This program is free software; you can redistribute it and/or |
|
6 | # This program is free software; you can redistribute it and/or | |
5 | # modify it under the terms of the GNU General Public License |
|
7 | # modify it under the terms of the GNU General Public License | |
6 | # as published by the Free Software Foundation; either version 2 |
|
8 | # as published by the Free Software Foundation; either version 2 | |
7 | # of the License, or (at your option) any later version. |
|
9 | # of the License, or (at your option) any later version. | |
8 | # |
|
10 | # | |
9 | # This program is distributed in the hope that it will be useful, |
|
11 | # This program is distributed in the hope that it will be useful, | |
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | # GNU General Public License for more details. |
|
14 | # GNU General Public License for more details. | |
13 | # |
|
15 | # | |
14 | # You should have received a copy of the GNU General Public License |
|
16 | # You should have received a copy of the GNU General Public License | |
15 | # along with this program; if not, write to the Free Software |
|
17 | # along with this program; if not, write to the Free Software | |
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
17 |
|
19 | |||
18 | module WikiHelper |
|
20 | module WikiHelper | |
19 |
|
21 | |||
20 | def wiki_page_options_for_select(pages, selected = nil, parent = nil, level = 0) |
|
22 | def wiki_page_options_for_select(pages, selected = nil, parent = nil, level = 0) | |
21 | pages = pages.group_by(&:parent) unless pages.is_a?(Hash) |
|
23 | pages = pages.group_by(&:parent) unless pages.is_a?(Hash) | |
22 | s = '' |
|
24 | s = '' | |
23 | if pages.has_key?(parent) |
|
25 | if pages.has_key?(parent) | |
24 | pages[parent].each do |page| |
|
26 | pages[parent].each do |page| | |
25 | attrs = "value='#{page.id}'" |
|
27 | attrs = "value='#{page.id}'" | |
26 | attrs << " selected='selected'" if selected == page |
|
28 | attrs << " selected='selected'" if selected == page | |
27 | indent = (level > 0) ? (' ' * level * 2 + '» ') : nil |
|
29 | indent = (level > 0) ? (' ' * level * 2 + '» ') : nil | |
28 |
|
30 | |||
29 | s << "<option #{attrs}>#{indent}#{h page.pretty_title}</option>\n" + |
|
31 | s << "<option #{attrs}>#{indent}#{h page.pretty_title}</option>\n" + | |
30 | wiki_page_options_for_select(pages, selected, page, level + 1) |
|
32 | wiki_page_options_for_select(pages, selected, page, level + 1) | |
31 | end |
|
33 | end | |
32 | end |
|
34 | end | |
33 | s |
|
35 | s | |
34 | end |
|
36 | end | |
35 |
|
37 | |||
36 | def wiki_page_breadcrumb(page) |
|
38 | def wiki_page_breadcrumb(page) | |
37 | breadcrumb(page.ancestors.reverse.collect {|parent| |
|
39 | breadcrumb(page.ancestors.reverse.collect {|parent| | |
38 | link_to(h(parent.pretty_title), {:controller => 'wiki', :action => 'show', :id => parent.title, :project_id => parent.project}) |
|
40 | link_to(h(parent.pretty_title), {:controller => 'wiki', :action => 'show', :id => parent.title, :project_id => parent.project}) | |
39 | }) |
|
41 | }) | |
40 | end |
|
42 | end | |
41 | end |
|
43 | end |
@@ -1,19 +1,21 | |||||
|
1 | # encoding: utf-8 | |||
|
2 | # | |||
1 | # Redmine - project management software |
|
3 | # Redmine - project management software | |
2 | # Copyright (C) 2006-2011 Jean-Philippe Lang |
|
4 | # Copyright (C) 2006-2011 Jean-Philippe Lang | |
3 | # |
|
5 | # | |
4 | # This program is free software; you can redistribute it and/or |
|
6 | # This program is free software; you can redistribute it and/or | |
5 | # modify it under the terms of the GNU General Public License |
|
7 | # modify it under the terms of the GNU General Public License | |
6 | # as published by the Free Software Foundation; either version 2 |
|
8 | # as published by the Free Software Foundation; either version 2 | |
7 | # of the License, or (at your option) any later version. |
|
9 | # of the License, or (at your option) any later version. | |
8 | # |
|
10 | # | |
9 | # This program is distributed in the hope that it will be useful, |
|
11 | # This program is distributed in the hope that it will be useful, | |
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | # GNU General Public License for more details. |
|
14 | # GNU General Public License for more details. | |
13 | # |
|
15 | # | |
14 | # You should have received a copy of the GNU General Public License |
|
16 | # You should have received a copy of the GNU General Public License | |
15 | # along with this program; if not, write to the Free Software |
|
17 | # along with this program; if not, write to the Free Software | |
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
17 |
|
19 | |||
18 | module WorkflowsHelper |
|
20 | module WorkflowsHelper | |
19 | end |
|
21 | end |
General Comments 0
You need to be logged in to leave comments.
Login now