@@ -1,131 +1,134 | |||||
1 | # encoding: utf-8 |
|
1 | # encoding: utf-8 | |
2 | # |
|
2 | # | |
3 | # Redmine - project management software |
|
3 | # Redmine - project management software | |
4 | # Copyright (C) 2006-2012 Jean-Philippe Lang |
|
4 | # Copyright (C) 2006-2012 Jean-Philippe Lang | |
5 | # |
|
5 | # | |
6 | # This program is free software; you can redistribute it and/or |
|
6 | # This program is free software; you can redistribute it and/or | |
7 | # modify it under the terms of the GNU General Public License |
|
7 | # modify it under the terms of the GNU General Public License | |
8 | # as published by the Free Software Foundation; either version 2 |
|
8 | # as published by the Free Software Foundation; either version 2 | |
9 | # of the License, or (at your option) any later version. |
|
9 | # of the License, or (at your option) any later version. | |
10 | # |
|
10 | # | |
11 | # 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, | |
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | # GNU General Public License for more details. |
|
14 | # GNU General Public License for more details. | |
15 | # |
|
15 | # | |
16 | # 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 | |
17 | # along with this program; if not, write to the Free Software |
|
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. |
|
18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
19 |
|
19 | |||
20 | module QueriesHelper |
|
20 | module QueriesHelper | |
21 |
|
21 | def filters_options_for_select(query) | ||
22 | def operators_for_select(filter_type) |
|
22 | options = [[]] | |
23 | Query.operators_by_filter_type[filter_type].collect {|o| [l(Query.operators[o]), o]} |
|
23 | options += query.available_filters.sort {|a,b| a[1][:order] <=> b[1][:order]}.map do |field, field_options| | |
|
24 | [field_options[:name], field] | |||
|
25 | end | |||
|
26 | options_for_select(options) | |||
24 | end |
|
27 | end | |
25 |
|
28 | |||
26 | def column_header(column) |
|
29 | def column_header(column) | |
27 | column.sortable ? sort_header_tag(column.name.to_s, :caption => column.caption, |
|
30 | column.sortable ? sort_header_tag(column.name.to_s, :caption => column.caption, | |
28 | :default_order => column.default_order) : |
|
31 | :default_order => column.default_order) : | |
29 | content_tag('th', h(column.caption)) |
|
32 | content_tag('th', h(column.caption)) | |
30 | end |
|
33 | end | |
31 |
|
34 | |||
32 | def column_content(column, issue) |
|
35 | def column_content(column, issue) | |
33 | value = column.value(issue) |
|
36 | value = column.value(issue) | |
34 | if value.is_a?(Array) |
|
37 | if value.is_a?(Array) | |
35 | value.collect {|v| column_value(column, issue, v)}.compact.sort.join(', ').html_safe |
|
38 | value.collect {|v| column_value(column, issue, v)}.compact.sort.join(', ').html_safe | |
36 | else |
|
39 | else | |
37 | column_value(column, issue, value) |
|
40 | column_value(column, issue, value) | |
38 | end |
|
41 | end | |
39 | end |
|
42 | end | |
40 |
|
43 | |||
41 | def column_value(column, issue, value) |
|
44 | def column_value(column, issue, value) | |
42 | case value.class.name |
|
45 | case value.class.name | |
43 | when 'String' |
|
46 | when 'String' | |
44 | if column.name == :subject |
|
47 | if column.name == :subject | |
45 | link_to(h(value), :controller => 'issues', :action => 'show', :id => issue) |
|
48 | link_to(h(value), :controller => 'issues', :action => 'show', :id => issue) | |
46 | else |
|
49 | else | |
47 | h(value) |
|
50 | h(value) | |
48 | end |
|
51 | end | |
49 | when 'Time' |
|
52 | when 'Time' | |
50 | format_time(value) |
|
53 | format_time(value) | |
51 | when 'Date' |
|
54 | when 'Date' | |
52 | format_date(value) |
|
55 | format_date(value) | |
53 | when 'Fixnum', 'Float' |
|
56 | when 'Fixnum', 'Float' | |
54 | if column.name == :done_ratio |
|
57 | if column.name == :done_ratio | |
55 | progress_bar(value, :width => '80px') |
|
58 | progress_bar(value, :width => '80px') | |
56 | elsif column.name == :spent_hours |
|
59 | elsif column.name == :spent_hours | |
57 | sprintf "%.2f", value |
|
60 | sprintf "%.2f", value | |
58 | else |
|
61 | else | |
59 | h(value.to_s) |
|
62 | h(value.to_s) | |
60 | end |
|
63 | end | |
61 | when 'User' |
|
64 | when 'User' | |
62 | link_to_user value |
|
65 | link_to_user value | |
63 | when 'Project' |
|
66 | when 'Project' | |
64 | link_to_project value |
|
67 | link_to_project value | |
65 | when 'Version' |
|
68 | when 'Version' | |
66 | link_to(h(value), :controller => 'versions', :action => 'show', :id => value) |
|
69 | link_to(h(value), :controller => 'versions', :action => 'show', :id => value) | |
67 | when 'TrueClass' |
|
70 | when 'TrueClass' | |
68 | l(:general_text_Yes) |
|
71 | l(:general_text_Yes) | |
69 | when 'FalseClass' |
|
72 | when 'FalseClass' | |
70 | l(:general_text_No) |
|
73 | l(:general_text_No) | |
71 | when 'Issue' |
|
74 | when 'Issue' | |
72 | link_to_issue(value, :subject => false) |
|
75 | link_to_issue(value, :subject => false) | |
73 | else |
|
76 | else | |
74 | h(value) |
|
77 | h(value) | |
75 | end |
|
78 | end | |
76 | end |
|
79 | end | |
77 |
|
80 | |||
78 | # Retrieve query from session or build a new query |
|
81 | # Retrieve query from session or build a new query | |
79 | def retrieve_query |
|
82 | def retrieve_query | |
80 | if !params[:query_id].blank? |
|
83 | if !params[:query_id].blank? | |
81 | cond = "project_id IS NULL" |
|
84 | cond = "project_id IS NULL" | |
82 | cond << " OR project_id = #{@project.id}" if @project |
|
85 | cond << " OR project_id = #{@project.id}" if @project | |
83 | @query = Query.find(params[:query_id], :conditions => cond) |
|
86 | @query = Query.find(params[:query_id], :conditions => cond) | |
84 | raise ::Unauthorized unless @query.visible? |
|
87 | raise ::Unauthorized unless @query.visible? | |
85 | @query.project = @project |
|
88 | @query.project = @project | |
86 | session[:query] = {:id => @query.id, :project_id => @query.project_id} |
|
89 | session[:query] = {:id => @query.id, :project_id => @query.project_id} | |
87 | sort_clear |
|
90 | sort_clear | |
88 | elsif api_request? || params[:set_filter] || session[:query].nil? || session[:query][:project_id] != (@project ? @project.id : nil) |
|
91 | elsif api_request? || params[:set_filter] || session[:query].nil? || session[:query][:project_id] != (@project ? @project.id : nil) | |
89 | # Give it a name, required to be valid |
|
92 | # Give it a name, required to be valid | |
90 | @query = Query.new(:name => "_") |
|
93 | @query = Query.new(:name => "_") | |
91 | @query.project = @project |
|
94 | @query.project = @project | |
92 | build_query_from_params |
|
95 | build_query_from_params | |
93 | session[:query] = {:project_id => @query.project_id, :filters => @query.filters, :group_by => @query.group_by, :column_names => @query.column_names} |
|
96 | session[:query] = {:project_id => @query.project_id, :filters => @query.filters, :group_by => @query.group_by, :column_names => @query.column_names} | |
94 | else |
|
97 | else | |
95 | # retrieve from session |
|
98 | # retrieve from session | |
96 | @query = Query.find_by_id(session[:query][:id]) if session[:query][:id] |
|
99 | @query = Query.find_by_id(session[:query][:id]) if session[:query][:id] | |
97 | @query ||= Query.new(:name => "_", :filters => session[:query][:filters], :group_by => session[:query][:group_by], :column_names => session[:query][:column_names]) |
|
100 | @query ||= Query.new(:name => "_", :filters => session[:query][:filters], :group_by => session[:query][:group_by], :column_names => session[:query][:column_names]) | |
98 | @query.project = @project |
|
101 | @query.project = @project | |
99 | end |
|
102 | end | |
100 | end |
|
103 | end | |
101 |
|
104 | |||
102 | def retrieve_query_from_session |
|
105 | def retrieve_query_from_session | |
103 | if session[:query] |
|
106 | if session[:query] | |
104 | if session[:query][:id] |
|
107 | if session[:query][:id] | |
105 | @query = Query.find_by_id(session[:query][:id]) |
|
108 | @query = Query.find_by_id(session[:query][:id]) | |
106 | return unless @query |
|
109 | return unless @query | |
107 | else |
|
110 | else | |
108 | @query = Query.new(:name => "_", :filters => session[:query][:filters], :group_by => session[:query][:group_by], :column_names => session[:query][:column_names]) |
|
111 | @query = Query.new(:name => "_", :filters => session[:query][:filters], :group_by => session[:query][:group_by], :column_names => session[:query][:column_names]) | |
109 | end |
|
112 | end | |
110 | if session[:query].has_key?(:project_id) |
|
113 | if session[:query].has_key?(:project_id) | |
111 | @query.project_id = session[:query][:project_id] |
|
114 | @query.project_id = session[:query][:project_id] | |
112 | else |
|
115 | else | |
113 | @query.project = @project |
|
116 | @query.project = @project | |
114 | end |
|
117 | end | |
115 | @query |
|
118 | @query | |
116 | end |
|
119 | end | |
117 | end |
|
120 | end | |
118 |
|
121 | |||
119 | def build_query_from_params |
|
122 | def build_query_from_params | |
120 | if params[:fields] || params[:f] |
|
123 | if params[:fields] || params[:f] | |
121 | @query.filters = {} |
|
124 | @query.filters = {} | |
122 | @query.add_filters(params[:fields] || params[:f], params[:operators] || params[:op], params[:values] || params[:v]) |
|
125 | @query.add_filters(params[:fields] || params[:f], params[:operators] || params[:op], params[:values] || params[:v]) | |
123 | else |
|
126 | else | |
124 | @query.available_filters.keys.each do |field| |
|
127 | @query.available_filters.keys.each do |field| | |
125 | @query.add_short_filter(field, params[field]) if params[field] |
|
128 | @query.add_short_filter(field, params[field]) if params[field] | |
126 | end |
|
129 | end | |
127 | end |
|
130 | end | |
128 | @query.group_by = params[:group_by] || (params[:query] && params[:query][:group_by]) |
|
131 | @query.group_by = params[:group_by] || (params[:query] && params[:query][:group_by]) | |
129 | @query.column_names = params[:c] || (params[:query] && params[:query][:column_names]) |
|
132 | @query.column_names = params[:c] || (params[:query] && params[:query][:column_names]) | |
130 | end |
|
133 | end | |
131 | end |
|
134 | end |
@@ -1,914 +1,932 | |||||
1 | # Redmine - project management software |
|
1 | # Redmine - project management software | |
2 | # Copyright (C) 2006-2012 Jean-Philippe Lang |
|
2 | # Copyright (C) 2006-2012 Jean-Philippe Lang | |
3 | # |
|
3 | # | |
4 | # This program is free software; you can redistribute it and/or |
|
4 | # This program is free software; you can redistribute it and/or | |
5 | # modify it under the terms of the GNU General Public License |
|
5 | # modify it under the terms of the GNU General Public License | |
6 | # as published by the Free Software Foundation; either version 2 |
|
6 | # as published by the Free Software Foundation; either version 2 | |
7 | # of the License, or (at your option) any later version. |
|
7 | # of the License, or (at your option) any later version. | |
8 | # |
|
8 | # | |
9 | # This program is distributed in the hope that it will be useful, |
|
9 | # This program is distributed in the hope that it will be useful, | |
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | # GNU General Public License for more details. |
|
12 | # GNU General Public License for more details. | |
13 | # |
|
13 | # | |
14 | # You should have received a copy of the GNU General Public License |
|
14 | # You should have received a copy of the GNU General Public License | |
15 | # along with this program; if not, write to the Free Software |
|
15 | # along with this program; if not, write to the Free Software | |
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
17 |
|
17 | |||
18 | class QueryColumn |
|
18 | class QueryColumn | |
19 | attr_accessor :name, :sortable, :groupable, :default_order |
|
19 | attr_accessor :name, :sortable, :groupable, :default_order | |
20 | include Redmine::I18n |
|
20 | include Redmine::I18n | |
21 |
|
21 | |||
22 | def initialize(name, options={}) |
|
22 | def initialize(name, options={}) | |
23 | self.name = name |
|
23 | self.name = name | |
24 | self.sortable = options[:sortable] |
|
24 | self.sortable = options[:sortable] | |
25 | self.groupable = options[:groupable] || false |
|
25 | self.groupable = options[:groupable] || false | |
26 | if groupable == true |
|
26 | if groupable == true | |
27 | self.groupable = name.to_s |
|
27 | self.groupable = name.to_s | |
28 | end |
|
28 | end | |
29 | self.default_order = options[:default_order] |
|
29 | self.default_order = options[:default_order] | |
30 | @caption_key = options[:caption] || "field_#{name}" |
|
30 | @caption_key = options[:caption] || "field_#{name}" | |
31 | end |
|
31 | end | |
32 |
|
32 | |||
33 | def caption |
|
33 | def caption | |
34 | l(@caption_key) |
|
34 | l(@caption_key) | |
35 | end |
|
35 | end | |
36 |
|
36 | |||
37 | # Returns true if the column is sortable, otherwise false |
|
37 | # Returns true if the column is sortable, otherwise false | |
38 | def sortable? |
|
38 | def sortable? | |
39 | !@sortable.nil? |
|
39 | !@sortable.nil? | |
40 | end |
|
40 | end | |
41 |
|
41 | |||
42 | def sortable |
|
42 | def sortable | |
43 | @sortable.is_a?(Proc) ? @sortable.call : @sortable |
|
43 | @sortable.is_a?(Proc) ? @sortable.call : @sortable | |
44 | end |
|
44 | end | |
45 |
|
45 | |||
46 | def value(issue) |
|
46 | def value(issue) | |
47 | issue.send name |
|
47 | issue.send name | |
48 | end |
|
48 | end | |
49 |
|
49 | |||
50 | def css_classes |
|
50 | def css_classes | |
51 | name |
|
51 | name | |
52 | end |
|
52 | end | |
53 | end |
|
53 | end | |
54 |
|
54 | |||
55 | class QueryCustomFieldColumn < QueryColumn |
|
55 | class QueryCustomFieldColumn < QueryColumn | |
56 |
|
56 | |||
57 | def initialize(custom_field) |
|
57 | def initialize(custom_field) | |
58 | self.name = "cf_#{custom_field.id}".to_sym |
|
58 | self.name = "cf_#{custom_field.id}".to_sym | |
59 | self.sortable = custom_field.order_statement || false |
|
59 | self.sortable = custom_field.order_statement || false | |
60 | self.groupable = custom_field.group_statement || false |
|
60 | self.groupable = custom_field.group_statement || false | |
61 | @cf = custom_field |
|
61 | @cf = custom_field | |
62 | end |
|
62 | end | |
63 |
|
63 | |||
64 | def caption |
|
64 | def caption | |
65 | @cf.name |
|
65 | @cf.name | |
66 | end |
|
66 | end | |
67 |
|
67 | |||
68 | def custom_field |
|
68 | def custom_field | |
69 | @cf |
|
69 | @cf | |
70 | end |
|
70 | end | |
71 |
|
71 | |||
72 | def value(issue) |
|
72 | def value(issue) | |
73 | cv = issue.custom_values.select {|v| v.custom_field_id == @cf.id}.collect {|v| @cf.cast_value(v.value)} |
|
73 | cv = issue.custom_values.select {|v| v.custom_field_id == @cf.id}.collect {|v| @cf.cast_value(v.value)} | |
74 | cv.size > 1 ? cv : cv.first |
|
74 | cv.size > 1 ? cv : cv.first | |
75 | end |
|
75 | end | |
76 |
|
76 | |||
77 | def css_classes |
|
77 | def css_classes | |
78 | @css_classes ||= "#{name} #{@cf.field_format}" |
|
78 | @css_classes ||= "#{name} #{@cf.field_format}" | |
79 | end |
|
79 | end | |
80 | end |
|
80 | end | |
81 |
|
81 | |||
82 | class Query < ActiveRecord::Base |
|
82 | class Query < ActiveRecord::Base | |
83 | class StatementInvalid < ::ActiveRecord::StatementInvalid |
|
83 | class StatementInvalid < ::ActiveRecord::StatementInvalid | |
84 | end |
|
84 | end | |
85 |
|
85 | |||
86 | belongs_to :project |
|
86 | belongs_to :project | |
87 | belongs_to :user |
|
87 | belongs_to :user | |
88 | serialize :filters |
|
88 | serialize :filters | |
89 | serialize :column_names |
|
89 | serialize :column_names | |
90 | serialize :sort_criteria, Array |
|
90 | serialize :sort_criteria, Array | |
91 |
|
91 | |||
92 | attr_protected :project_id, :user_id |
|
92 | attr_protected :project_id, :user_id | |
93 |
|
93 | |||
94 | validates_presence_of :name |
|
94 | validates_presence_of :name | |
95 | validates_length_of :name, :maximum => 255 |
|
95 | validates_length_of :name, :maximum => 255 | |
96 | validate :validate_query_filters |
|
96 | validate :validate_query_filters | |
97 |
|
97 | |||
98 | @@operators = { "=" => :label_equals, |
|
98 | @@operators = { "=" => :label_equals, | |
99 | "!" => :label_not_equals, |
|
99 | "!" => :label_not_equals, | |
100 | "o" => :label_open_issues, |
|
100 | "o" => :label_open_issues, | |
101 | "c" => :label_closed_issues, |
|
101 | "c" => :label_closed_issues, | |
102 | "!*" => :label_none, |
|
102 | "!*" => :label_none, | |
103 | "*" => :label_all, |
|
103 | "*" => :label_all, | |
104 | ">=" => :label_greater_or_equal, |
|
104 | ">=" => :label_greater_or_equal, | |
105 | "<=" => :label_less_or_equal, |
|
105 | "<=" => :label_less_or_equal, | |
106 | "><" => :label_between, |
|
106 | "><" => :label_between, | |
107 | "<t+" => :label_in_less_than, |
|
107 | "<t+" => :label_in_less_than, | |
108 | ">t+" => :label_in_more_than, |
|
108 | ">t+" => :label_in_more_than, | |
109 | "t+" => :label_in, |
|
109 | "t+" => :label_in, | |
110 | "t" => :label_today, |
|
110 | "t" => :label_today, | |
111 | "w" => :label_this_week, |
|
111 | "w" => :label_this_week, | |
112 | ">t-" => :label_less_than_ago, |
|
112 | ">t-" => :label_less_than_ago, | |
113 | "<t-" => :label_more_than_ago, |
|
113 | "<t-" => :label_more_than_ago, | |
114 | "t-" => :label_ago, |
|
114 | "t-" => :label_ago, | |
115 | "~" => :label_contains, |
|
115 | "~" => :label_contains, | |
116 | "!~" => :label_not_contains } |
|
116 | "!~" => :label_not_contains } | |
117 |
|
117 | |||
118 | cattr_reader :operators |
|
118 | cattr_reader :operators | |
119 |
|
119 | |||
120 | @@operators_by_filter_type = { :list => [ "=", "!" ], |
|
120 | @@operators_by_filter_type = { :list => [ "=", "!" ], | |
121 | :list_status => [ "o", "=", "!", "c", "*" ], |
|
121 | :list_status => [ "o", "=", "!", "c", "*" ], | |
122 | :list_optional => [ "=", "!", "!*", "*" ], |
|
122 | :list_optional => [ "=", "!", "!*", "*" ], | |
123 | :list_subprojects => [ "*", "!*", "=" ], |
|
123 | :list_subprojects => [ "*", "!*", "=" ], | |
124 | :date => [ "=", ">=", "<=", "><", "<t+", ">t+", "t+", "t", "w", ">t-", "<t-", "t-", "!*", "*" ], |
|
124 | :date => [ "=", ">=", "<=", "><", "<t+", ">t+", "t+", "t", "w", ">t-", "<t-", "t-", "!*", "*" ], | |
125 | :date_past => [ "=", ">=", "<=", "><", ">t-", "<t-", "t-", "t", "w", "!*", "*" ], |
|
125 | :date_past => [ "=", ">=", "<=", "><", ">t-", "<t-", "t-", "t", "w", "!*", "*" ], | |
126 | :string => [ "=", "~", "!", "!~", "!*", "*" ], |
|
126 | :string => [ "=", "~", "!", "!~", "!*", "*" ], | |
127 | :text => [ "~", "!~", "!*", "*" ], |
|
127 | :text => [ "~", "!~", "!*", "*" ], | |
128 | :integer => [ "=", ">=", "<=", "><", "!*", "*" ], |
|
128 | :integer => [ "=", ">=", "<=", "><", "!*", "*" ], | |
129 | :float => [ "=", ">=", "<=", "><", "!*", "*" ] } |
|
129 | :float => [ "=", ">=", "<=", "><", "!*", "*" ] } | |
130 |
|
130 | |||
131 | cattr_reader :operators_by_filter_type |
|
131 | cattr_reader :operators_by_filter_type | |
132 |
|
132 | |||
133 | @@available_columns = [ |
|
133 | @@available_columns = [ | |
134 | QueryColumn.new(:project, :sortable => "#{Project.table_name}.name", :groupable => true), |
|
134 | QueryColumn.new(:project, :sortable => "#{Project.table_name}.name", :groupable => true), | |
135 | QueryColumn.new(:tracker, :sortable => "#{Tracker.table_name}.position", :groupable => true), |
|
135 | QueryColumn.new(:tracker, :sortable => "#{Tracker.table_name}.position", :groupable => true), | |
136 | QueryColumn.new(:parent, :sortable => ["#{Issue.table_name}.root_id", "#{Issue.table_name}.lft ASC"], :default_order => 'desc', :caption => :field_parent_issue), |
|
136 | QueryColumn.new(:parent, :sortable => ["#{Issue.table_name}.root_id", "#{Issue.table_name}.lft ASC"], :default_order => 'desc', :caption => :field_parent_issue), | |
137 | QueryColumn.new(:status, :sortable => "#{IssueStatus.table_name}.position", :groupable => true), |
|
137 | QueryColumn.new(:status, :sortable => "#{IssueStatus.table_name}.position", :groupable => true), | |
138 | QueryColumn.new(:priority, :sortable => "#{IssuePriority.table_name}.position", :default_order => 'desc', :groupable => true), |
|
138 | QueryColumn.new(:priority, :sortable => "#{IssuePriority.table_name}.position", :default_order => 'desc', :groupable => true), | |
139 | QueryColumn.new(:subject, :sortable => "#{Issue.table_name}.subject"), |
|
139 | QueryColumn.new(:subject, :sortable => "#{Issue.table_name}.subject"), | |
140 | QueryColumn.new(:author, :sortable => lambda {User.fields_for_order_statement("authors")}, :groupable => true), |
|
140 | QueryColumn.new(:author, :sortable => lambda {User.fields_for_order_statement("authors")}, :groupable => true), | |
141 | QueryColumn.new(:assigned_to, :sortable => lambda {User.fields_for_order_statement}, :groupable => true), |
|
141 | QueryColumn.new(:assigned_to, :sortable => lambda {User.fields_for_order_statement}, :groupable => true), | |
142 | QueryColumn.new(:updated_on, :sortable => "#{Issue.table_name}.updated_on", :default_order => 'desc'), |
|
142 | QueryColumn.new(:updated_on, :sortable => "#{Issue.table_name}.updated_on", :default_order => 'desc'), | |
143 | QueryColumn.new(:category, :sortable => "#{IssueCategory.table_name}.name", :groupable => true), |
|
143 | QueryColumn.new(:category, :sortable => "#{IssueCategory.table_name}.name", :groupable => true), | |
144 | QueryColumn.new(:fixed_version, :sortable => lambda {Version.fields_for_order_statement}, :groupable => true), |
|
144 | QueryColumn.new(:fixed_version, :sortable => lambda {Version.fields_for_order_statement}, :groupable => true), | |
145 | QueryColumn.new(:start_date, :sortable => "#{Issue.table_name}.start_date"), |
|
145 | QueryColumn.new(:start_date, :sortable => "#{Issue.table_name}.start_date"), | |
146 | QueryColumn.new(:due_date, :sortable => "#{Issue.table_name}.due_date"), |
|
146 | QueryColumn.new(:due_date, :sortable => "#{Issue.table_name}.due_date"), | |
147 | QueryColumn.new(:estimated_hours, :sortable => "#{Issue.table_name}.estimated_hours"), |
|
147 | QueryColumn.new(:estimated_hours, :sortable => "#{Issue.table_name}.estimated_hours"), | |
148 | QueryColumn.new(:done_ratio, :sortable => "#{Issue.table_name}.done_ratio", :groupable => true), |
|
148 | QueryColumn.new(:done_ratio, :sortable => "#{Issue.table_name}.done_ratio", :groupable => true), | |
149 | QueryColumn.new(:created_on, :sortable => "#{Issue.table_name}.created_on", :default_order => 'desc'), |
|
149 | QueryColumn.new(:created_on, :sortable => "#{Issue.table_name}.created_on", :default_order => 'desc'), | |
150 | ] |
|
150 | ] | |
151 | cattr_reader :available_columns |
|
151 | cattr_reader :available_columns | |
152 |
|
152 | |||
153 | scope :visible, lambda {|*args| |
|
153 | scope :visible, lambda {|*args| | |
154 | user = args.shift || User.current |
|
154 | user = args.shift || User.current | |
155 | base = Project.allowed_to_condition(user, :view_issues, *args) |
|
155 | base = Project.allowed_to_condition(user, :view_issues, *args) | |
156 | user_id = user.logged? ? user.id : 0 |
|
156 | user_id = user.logged? ? user.id : 0 | |
157 | { |
|
157 | { | |
158 | :conditions => ["(#{table_name}.project_id IS NULL OR (#{base})) AND (#{table_name}.is_public = ? OR #{table_name}.user_id = ?)", true, user_id], |
|
158 | :conditions => ["(#{table_name}.project_id IS NULL OR (#{base})) AND (#{table_name}.is_public = ? OR #{table_name}.user_id = ?)", true, user_id], | |
159 | :include => :project |
|
159 | :include => :project | |
160 | } |
|
160 | } | |
161 | } |
|
161 | } | |
162 |
|
162 | |||
163 | def initialize(attributes=nil, *args) |
|
163 | def initialize(attributes=nil, *args) | |
164 | super attributes |
|
164 | super attributes | |
165 | self.filters ||= { 'status_id' => {:operator => "o", :values => [""]} } |
|
165 | self.filters ||= { 'status_id' => {:operator => "o", :values => [""]} } | |
166 | @is_for_all = project.nil? |
|
166 | @is_for_all = project.nil? | |
167 | end |
|
167 | end | |
168 |
|
168 | |||
169 | def validate_query_filters |
|
169 | def validate_query_filters | |
170 | filters.each_key do |field| |
|
170 | filters.each_key do |field| | |
171 | if values_for(field) |
|
171 | if values_for(field) | |
172 | case type_for(field) |
|
172 | case type_for(field) | |
173 | when :integer |
|
173 | when :integer | |
174 | add_filter_error(field, :invalid) if values_for(field).detect {|v| v.present? && !v.match(/^[+-]?\d+$/) } |
|
174 | add_filter_error(field, :invalid) if values_for(field).detect {|v| v.present? && !v.match(/^[+-]?\d+$/) } | |
175 | when :float |
|
175 | when :float | |
176 | add_filter_error(field, :invalid) if values_for(field).detect {|v| v.present? && !v.match(/^[+-]?\d+(\.\d*)?$/) } |
|
176 | add_filter_error(field, :invalid) if values_for(field).detect {|v| v.present? && !v.match(/^[+-]?\d+(\.\d*)?$/) } | |
177 | when :date, :date_past |
|
177 | when :date, :date_past | |
178 | case operator_for(field) |
|
178 | case operator_for(field) | |
179 | when "=", ">=", "<=", "><" |
|
179 | when "=", ">=", "<=", "><" | |
180 | add_filter_error(field, :invalid) if values_for(field).detect {|v| v.present? && (!v.match(/^\d{4}-\d{2}-\d{2}$/) || (Date.parse(v) rescue nil).nil?) } |
|
180 | add_filter_error(field, :invalid) if values_for(field).detect {|v| v.present? && (!v.match(/^\d{4}-\d{2}-\d{2}$/) || (Date.parse(v) rescue nil).nil?) } | |
181 | when ">t-", "<t-", "t-" |
|
181 | when ">t-", "<t-", "t-" | |
182 | add_filter_error(field, :invalid) if values_for(field).detect {|v| v.present? && !v.match(/^\d+$/) } |
|
182 | add_filter_error(field, :invalid) if values_for(field).detect {|v| v.present? && !v.match(/^\d+$/) } | |
183 | end |
|
183 | end | |
184 | end |
|
184 | end | |
185 | end |
|
185 | end | |
186 |
|
186 | |||
187 | add_filter_error(field, :blank) unless |
|
187 | add_filter_error(field, :blank) unless | |
188 | # filter requires one or more values |
|
188 | # filter requires one or more values | |
189 | (values_for(field) and !values_for(field).first.blank?) or |
|
189 | (values_for(field) and !values_for(field).first.blank?) or | |
190 | # filter doesn't require any value |
|
190 | # filter doesn't require any value | |
191 | ["o", "c", "!*", "*", "t", "w"].include? operator_for(field) |
|
191 | ["o", "c", "!*", "*", "t", "w"].include? operator_for(field) | |
192 | end if filters |
|
192 | end if filters | |
193 | end |
|
193 | end | |
194 |
|
194 | |||
195 | def add_filter_error(field, message) |
|
195 | def add_filter_error(field, message) | |
196 | m = label_for(field) + " " + l(message, :scope => 'activerecord.errors.messages') |
|
196 | m = label_for(field) + " " + l(message, :scope => 'activerecord.errors.messages') | |
197 | errors.add(:base, m) |
|
197 | errors.add(:base, m) | |
198 | end |
|
198 | end | |
199 |
|
199 | |||
200 | # Returns true if the query is visible to +user+ or the current user. |
|
200 | # Returns true if the query is visible to +user+ or the current user. | |
201 | def visible?(user=User.current) |
|
201 | def visible?(user=User.current) | |
202 | (project.nil? || user.allowed_to?(:view_issues, project)) && (self.is_public? || self.user_id == user.id) |
|
202 | (project.nil? || user.allowed_to?(:view_issues, project)) && (self.is_public? || self.user_id == user.id) | |
203 | end |
|
203 | end | |
204 |
|
204 | |||
205 | def editable_by?(user) |
|
205 | def editable_by?(user) | |
206 | return false unless user |
|
206 | return false unless user | |
207 | # Admin can edit them all and regular users can edit their private queries |
|
207 | # Admin can edit them all and regular users can edit their private queries | |
208 | return true if user.admin? || (!is_public && self.user_id == user.id) |
|
208 | return true if user.admin? || (!is_public && self.user_id == user.id) | |
209 | # Members can not edit public queries that are for all project (only admin is allowed to) |
|
209 | # Members can not edit public queries that are for all project (only admin is allowed to) | |
210 | is_public && !@is_for_all && user.allowed_to?(:manage_public_queries, project) |
|
210 | is_public && !@is_for_all && user.allowed_to?(:manage_public_queries, project) | |
211 | end |
|
211 | end | |
212 |
|
212 | |||
213 | def trackers |
|
213 | def trackers | |
214 | @trackers ||= project.nil? ? Tracker.find(:all, :order => 'position') : project.rolled_up_trackers |
|
214 | @trackers ||= project.nil? ? Tracker.find(:all, :order => 'position') : project.rolled_up_trackers | |
215 | end |
|
215 | end | |
216 |
|
216 | |||
|
217 | # Returns a hash of localized labels for all filter operators | |||
|
218 | def self.operators_labels | |||
|
219 | operators.inject({}) {|h, operator| h[operator.first] = l(operator.last); h} | |||
|
220 | end | |||
|
221 | ||||
217 | def available_filters |
|
222 | def available_filters | |
218 | return @available_filters if @available_filters |
|
223 | return @available_filters if @available_filters | |
219 |
|
224 | |||
220 | @available_filters = { "status_id" => { :type => :list_status, :order => 1, :values => IssueStatus.find(:all, :order => 'position').collect{|s| [s.name, s.id.to_s] } }, |
|
225 | @available_filters = { "status_id" => { :type => :list_status, :order => 1, :values => IssueStatus.find(:all, :order => 'position').collect{|s| [s.name, s.id.to_s] } }, | |
221 | "tracker_id" => { :type => :list, :order => 2, :values => trackers.collect{|s| [s.name, s.id.to_s] } }, |
|
226 | "tracker_id" => { :type => :list, :order => 2, :values => trackers.collect{|s| [s.name, s.id.to_s] } }, | |
222 | "priority_id" => { :type => :list, :order => 3, :values => IssuePriority.all.collect{|s| [s.name, s.id.to_s] } }, |
|
227 | "priority_id" => { :type => :list, :order => 3, :values => IssuePriority.all.collect{|s| [s.name, s.id.to_s] } }, | |
223 | "subject" => { :type => :text, :order => 8 }, |
|
228 | "subject" => { :type => :text, :order => 8 }, | |
224 | "created_on" => { :type => :date_past, :order => 9 }, |
|
229 | "created_on" => { :type => :date_past, :order => 9 }, | |
225 | "updated_on" => { :type => :date_past, :order => 10 }, |
|
230 | "updated_on" => { :type => :date_past, :order => 10 }, | |
226 | "start_date" => { :type => :date, :order => 11 }, |
|
231 | "start_date" => { :type => :date, :order => 11 }, | |
227 | "due_date" => { :type => :date, :order => 12 }, |
|
232 | "due_date" => { :type => :date, :order => 12 }, | |
228 | "estimated_hours" => { :type => :float, :order => 13 }, |
|
233 | "estimated_hours" => { :type => :float, :order => 13 }, | |
229 | "done_ratio" => { :type => :integer, :order => 14 }} |
|
234 | "done_ratio" => { :type => :integer, :order => 14 }} | |
230 |
|
235 | |||
231 | principals = [] |
|
236 | principals = [] | |
232 | if project |
|
237 | if project | |
233 | principals += project.principals.sort |
|
238 | principals += project.principals.sort | |
234 | unless project.leaf? |
|
239 | unless project.leaf? | |
235 | subprojects = project.descendants.visible.all |
|
240 | subprojects = project.descendants.visible.all | |
236 | if subprojects.any? |
|
241 | if subprojects.any? | |
237 | @available_filters["subproject_id"] = { :type => :list_subprojects, :order => 13, :values => subprojects.collect{|s| [s.name, s.id.to_s] } } |
|
242 | @available_filters["subproject_id"] = { :type => :list_subprojects, :order => 13, :values => subprojects.collect{|s| [s.name, s.id.to_s] } } | |
238 | principals += Principal.member_of(subprojects) |
|
243 | principals += Principal.member_of(subprojects) | |
239 | end |
|
244 | end | |
240 | end |
|
245 | end | |
241 | else |
|
246 | else | |
242 | all_projects = Project.visible.all |
|
247 | all_projects = Project.visible.all | |
243 | if all_projects.any? |
|
248 | if all_projects.any? | |
244 | # members of visible projects |
|
249 | # members of visible projects | |
245 | principals += Principal.member_of(all_projects) |
|
250 | principals += Principal.member_of(all_projects) | |
246 |
|
251 | |||
247 | # project filter |
|
252 | # project filter | |
248 | project_values = [] |
|
253 | project_values = [] | |
249 | if User.current.logged? && User.current.memberships.any? |
|
254 | if User.current.logged? && User.current.memberships.any? | |
250 | project_values << ["<< #{l(:label_my_projects).downcase} >>", "mine"] |
|
255 | project_values << ["<< #{l(:label_my_projects).downcase} >>", "mine"] | |
251 | end |
|
256 | end | |
252 | Project.project_tree(all_projects) do |p, level| |
|
257 | Project.project_tree(all_projects) do |p, level| | |
253 | prefix = (level > 0 ? ('--' * level + ' ') : '') |
|
258 | prefix = (level > 0 ? ('--' * level + ' ') : '') | |
254 | project_values << ["#{prefix}#{p.name}", p.id.to_s] |
|
259 | project_values << ["#{prefix}#{p.name}", p.id.to_s] | |
255 | end |
|
260 | end | |
256 | @available_filters["project_id"] = { :type => :list, :order => 1, :values => project_values} unless project_values.empty? |
|
261 | @available_filters["project_id"] = { :type => :list, :order => 1, :values => project_values} unless project_values.empty? | |
257 | end |
|
262 | end | |
258 | end |
|
263 | end | |
259 | principals.uniq! |
|
264 | principals.uniq! | |
260 | principals.sort! |
|
265 | principals.sort! | |
261 | users = principals.select {|p| p.is_a?(User)} |
|
266 | users = principals.select {|p| p.is_a?(User)} | |
262 |
|
267 | |||
263 | assigned_to_values = [] |
|
268 | assigned_to_values = [] | |
264 | assigned_to_values << ["<< #{l(:label_me)} >>", "me"] if User.current.logged? |
|
269 | assigned_to_values << ["<< #{l(:label_me)} >>", "me"] if User.current.logged? | |
265 | assigned_to_values += (Setting.issue_group_assignment? ? principals : users).collect{|s| [s.name, s.id.to_s] } |
|
270 | assigned_to_values += (Setting.issue_group_assignment? ? principals : users).collect{|s| [s.name, s.id.to_s] } | |
266 | @available_filters["assigned_to_id"] = { :type => :list_optional, :order => 4, :values => assigned_to_values } unless assigned_to_values.empty? |
|
271 | @available_filters["assigned_to_id"] = { :type => :list_optional, :order => 4, :values => assigned_to_values } unless assigned_to_values.empty? | |
267 |
|
272 | |||
268 | author_values = [] |
|
273 | author_values = [] | |
269 | author_values << ["<< #{l(:label_me)} >>", "me"] if User.current.logged? |
|
274 | author_values << ["<< #{l(:label_me)} >>", "me"] if User.current.logged? | |
270 | author_values += users.collect{|s| [s.name, s.id.to_s] } |
|
275 | author_values += users.collect{|s| [s.name, s.id.to_s] } | |
271 | @available_filters["author_id"] = { :type => :list, :order => 5, :values => author_values } unless author_values.empty? |
|
276 | @available_filters["author_id"] = { :type => :list, :order => 5, :values => author_values } unless author_values.empty? | |
272 |
|
277 | |||
273 | group_values = Group.all.collect {|g| [g.name, g.id.to_s] } |
|
278 | group_values = Group.all.collect {|g| [g.name, g.id.to_s] } | |
274 | @available_filters["member_of_group"] = { :type => :list_optional, :order => 6, :values => group_values } unless group_values.empty? |
|
279 | @available_filters["member_of_group"] = { :type => :list_optional, :order => 6, :values => group_values } unless group_values.empty? | |
275 |
|
280 | |||
276 | role_values = Role.givable.collect {|r| [r.name, r.id.to_s] } |
|
281 | role_values = Role.givable.collect {|r| [r.name, r.id.to_s] } | |
277 | @available_filters["assigned_to_role"] = { :type => :list_optional, :order => 7, :values => role_values } unless role_values.empty? |
|
282 | @available_filters["assigned_to_role"] = { :type => :list_optional, :order => 7, :values => role_values } unless role_values.empty? | |
278 |
|
283 | |||
279 | if User.current.logged? |
|
284 | if User.current.logged? | |
280 | @available_filters["watcher_id"] = { :type => :list, :order => 15, :values => [["<< #{l(:label_me)} >>", "me"]] } |
|
285 | @available_filters["watcher_id"] = { :type => :list, :order => 15, :values => [["<< #{l(:label_me)} >>", "me"]] } | |
281 | end |
|
286 | end | |
282 |
|
287 | |||
283 | if project |
|
288 | if project | |
284 | # project specific filters |
|
289 | # project specific filters | |
285 | categories = project.issue_categories.all |
|
290 | categories = project.issue_categories.all | |
286 | unless categories.empty? |
|
291 | unless categories.empty? | |
287 | @available_filters["category_id"] = { :type => :list_optional, :order => 6, :values => categories.collect{|s| [s.name, s.id.to_s] } } |
|
292 | @available_filters["category_id"] = { :type => :list_optional, :order => 6, :values => categories.collect{|s| [s.name, s.id.to_s] } } | |
288 | end |
|
293 | end | |
289 | versions = project.shared_versions.all |
|
294 | versions = project.shared_versions.all | |
290 | unless versions.empty? |
|
295 | unless versions.empty? | |
291 | @available_filters["fixed_version_id"] = { :type => :list_optional, :order => 7, :values => versions.sort.collect{|s| ["#{s.project.name} - #{s.name}", s.id.to_s] } } |
|
296 | @available_filters["fixed_version_id"] = { :type => :list_optional, :order => 7, :values => versions.sort.collect{|s| ["#{s.project.name} - #{s.name}", s.id.to_s] } } | |
292 | end |
|
297 | end | |
293 | add_custom_fields_filters(project.all_issue_custom_fields) |
|
298 | add_custom_fields_filters(project.all_issue_custom_fields) | |
294 | else |
|
299 | else | |
295 | # global filters for cross project issue list |
|
300 | # global filters for cross project issue list | |
296 | system_shared_versions = Version.visible.find_all_by_sharing('system') |
|
301 | system_shared_versions = Version.visible.find_all_by_sharing('system') | |
297 | unless system_shared_versions.empty? |
|
302 | unless system_shared_versions.empty? | |
298 | @available_filters["fixed_version_id"] = { :type => :list_optional, :order => 7, :values => system_shared_versions.sort.collect{|s| ["#{s.project.name} - #{s.name}", s.id.to_s] } } |
|
303 | @available_filters["fixed_version_id"] = { :type => :list_optional, :order => 7, :values => system_shared_versions.sort.collect{|s| ["#{s.project.name} - #{s.name}", s.id.to_s] } } | |
299 | end |
|
304 | end | |
300 | add_custom_fields_filters(IssueCustomField.find(:all, :conditions => {:is_filter => true, :is_for_all => true})) |
|
305 | add_custom_fields_filters(IssueCustomField.find(:all, :conditions => {:is_filter => true, :is_for_all => true})) | |
301 | end |
|
306 | end | |
302 |
|
307 | |||
303 | if User.current.allowed_to?(:set_issues_private, nil, :global => true) || |
|
308 | if User.current.allowed_to?(:set_issues_private, nil, :global => true) || | |
304 | User.current.allowed_to?(:set_own_issues_private, nil, :global => true) |
|
309 | User.current.allowed_to?(:set_own_issues_private, nil, :global => true) | |
305 | @available_filters["is_private"] = { :type => :list, :order => 15, :values => [[l(:general_text_yes), "1"], [l(:general_text_no), "0"]] } |
|
310 | @available_filters["is_private"] = { :type => :list, :order => 15, :values => [[l(:general_text_yes), "1"], [l(:general_text_no), "0"]] } | |
306 | end |
|
311 | end | |
307 |
|
312 | |||
308 | Tracker.disabled_core_fields(trackers).each {|field| |
|
313 | Tracker.disabled_core_fields(trackers).each {|field| | |
309 | @available_filters.delete field |
|
314 | @available_filters.delete field | |
310 | } |
|
315 | } | |
311 |
|
316 | |||
|
317 | @available_filters.each do |field, options| | |||
|
318 | options[:name] ||= l("field_#{field}".gsub(/_id$/, '')) | |||
|
319 | end | |||
|
320 | ||||
312 | @available_filters |
|
321 | @available_filters | |
313 | end |
|
322 | end | |
314 |
|
323 | |||
|
324 | # Returns a representation of the available filters for JSON serialization | |||
|
325 | def available_filters_as_json | |||
|
326 | json = {} | |||
|
327 | available_filters.each do |field, options| | |||
|
328 | json[field] = options.slice(:type, :name, :values).stringify_keys | |||
|
329 | end | |||
|
330 | json | |||
|
331 | end | |||
|
332 | ||||
315 | def add_filter(field, operator, values) |
|
333 | def add_filter(field, operator, values) | |
316 | # values must be an array |
|
334 | # values must be an array | |
317 | return unless values.nil? || values.is_a?(Array) |
|
335 | return unless values.nil? || values.is_a?(Array) | |
318 | # check if field is defined as an available filter |
|
336 | # check if field is defined as an available filter | |
319 | if available_filters.has_key? field |
|
337 | if available_filters.has_key? field | |
320 | filter_options = available_filters[field] |
|
338 | filter_options = available_filters[field] | |
321 | # check if operator is allowed for that filter |
|
339 | # check if operator is allowed for that filter | |
322 | #if @@operators_by_filter_type[filter_options[:type]].include? operator |
|
340 | #if @@operators_by_filter_type[filter_options[:type]].include? operator | |
323 | # allowed_values = values & ([""] + (filter_options[:values] || []).collect {|val| val[1]}) |
|
341 | # allowed_values = values & ([""] + (filter_options[:values] || []).collect {|val| val[1]}) | |
324 | # filters[field] = {:operator => operator, :values => allowed_values } if (allowed_values.first and !allowed_values.first.empty?) or ["o", "c", "!*", "*", "t"].include? operator |
|
342 | # filters[field] = {:operator => operator, :values => allowed_values } if (allowed_values.first and !allowed_values.first.empty?) or ["o", "c", "!*", "*", "t"].include? operator | |
325 | #end |
|
343 | #end | |
326 | filters[field] = {:operator => operator, :values => (values || [''])} |
|
344 | filters[field] = {:operator => operator, :values => (values || [''])} | |
327 | end |
|
345 | end | |
328 | end |
|
346 | end | |
329 |
|
347 | |||
330 | def add_short_filter(field, expression) |
|
348 | def add_short_filter(field, expression) | |
331 | return unless expression && available_filters.has_key?(field) |
|
349 | return unless expression && available_filters.has_key?(field) | |
332 | field_type = available_filters[field][:type] |
|
350 | field_type = available_filters[field][:type] | |
333 | @@operators_by_filter_type[field_type].sort.reverse.detect do |operator| |
|
351 | @@operators_by_filter_type[field_type].sort.reverse.detect do |operator| | |
334 | next unless expression =~ /^#{Regexp.escape(operator)}(.*)$/ |
|
352 | next unless expression =~ /^#{Regexp.escape(operator)}(.*)$/ | |
335 | add_filter field, operator, $1.present? ? $1.split('|') : [''] |
|
353 | add_filter field, operator, $1.present? ? $1.split('|') : [''] | |
336 | end || add_filter(field, '=', expression.split('|')) |
|
354 | end || add_filter(field, '=', expression.split('|')) | |
337 | end |
|
355 | end | |
338 |
|
356 | |||
339 | # Add multiple filters using +add_filter+ |
|
357 | # Add multiple filters using +add_filter+ | |
340 | def add_filters(fields, operators, values) |
|
358 | def add_filters(fields, operators, values) | |
341 | if fields.is_a?(Array) && operators.is_a?(Hash) && (values.nil? || values.is_a?(Hash)) |
|
359 | if fields.is_a?(Array) && operators.is_a?(Hash) && (values.nil? || values.is_a?(Hash)) | |
342 | fields.each do |field| |
|
360 | fields.each do |field| | |
343 | add_filter(field, operators[field], values && values[field]) |
|
361 | add_filter(field, operators[field], values && values[field]) | |
344 | end |
|
362 | end | |
345 | end |
|
363 | end | |
346 | end |
|
364 | end | |
347 |
|
365 | |||
348 | def has_filter?(field) |
|
366 | def has_filter?(field) | |
349 | filters and filters[field] |
|
367 | filters and filters[field] | |
350 | end |
|
368 | end | |
351 |
|
369 | |||
352 | def type_for(field) |
|
370 | def type_for(field) | |
353 | available_filters[field][:type] if available_filters.has_key?(field) |
|
371 | available_filters[field][:type] if available_filters.has_key?(field) | |
354 | end |
|
372 | end | |
355 |
|
373 | |||
356 | def operator_for(field) |
|
374 | def operator_for(field) | |
357 | has_filter?(field) ? filters[field][:operator] : nil |
|
375 | has_filter?(field) ? filters[field][:operator] : nil | |
358 | end |
|
376 | end | |
359 |
|
377 | |||
360 | def values_for(field) |
|
378 | def values_for(field) | |
361 | has_filter?(field) ? filters[field][:values] : nil |
|
379 | has_filter?(field) ? filters[field][:values] : nil | |
362 | end |
|
380 | end | |
363 |
|
381 | |||
364 | def value_for(field, index=0) |
|
382 | def value_for(field, index=0) | |
365 | (values_for(field) || [])[index] |
|
383 | (values_for(field) || [])[index] | |
366 | end |
|
384 | end | |
367 |
|
385 | |||
368 | def label_for(field) |
|
386 | def label_for(field) | |
369 | label = available_filters[field][:name] if available_filters.has_key?(field) |
|
387 | label = available_filters[field][:name] if available_filters.has_key?(field) | |
370 | label ||= l("field_#{field.to_s.gsub(/_id$/, '')}", :default => field) |
|
388 | label ||= l("field_#{field.to_s.gsub(/_id$/, '')}", :default => field) | |
371 | end |
|
389 | end | |
372 |
|
390 | |||
373 | def available_columns |
|
391 | def available_columns | |
374 | return @available_columns if @available_columns |
|
392 | return @available_columns if @available_columns | |
375 | @available_columns = ::Query.available_columns.dup |
|
393 | @available_columns = ::Query.available_columns.dup | |
376 | @available_columns += (project ? |
|
394 | @available_columns += (project ? | |
377 | project.all_issue_custom_fields : |
|
395 | project.all_issue_custom_fields : | |
378 | IssueCustomField.find(:all) |
|
396 | IssueCustomField.find(:all) | |
379 | ).collect {|cf| QueryCustomFieldColumn.new(cf) } |
|
397 | ).collect {|cf| QueryCustomFieldColumn.new(cf) } | |
380 |
|
398 | |||
381 | if User.current.allowed_to?(:view_time_entries, project, :global => true) |
|
399 | if User.current.allowed_to?(:view_time_entries, project, :global => true) | |
382 | index = nil |
|
400 | index = nil | |
383 | @available_columns.each_with_index {|column, i| index = i if column.name == :estimated_hours} |
|
401 | @available_columns.each_with_index {|column, i| index = i if column.name == :estimated_hours} | |
384 | index = (index ? index + 1 : -1) |
|
402 | index = (index ? index + 1 : -1) | |
385 | # insert the column after estimated_hours or at the end |
|
403 | # insert the column after estimated_hours or at the end | |
386 | @available_columns.insert index, QueryColumn.new(:spent_hours, |
|
404 | @available_columns.insert index, QueryColumn.new(:spent_hours, | |
387 | :sortable => "(SELECT COALESCE(SUM(hours), 0) FROM #{TimeEntry.table_name} WHERE #{TimeEntry.table_name}.issue_id = #{Issue.table_name}.id)", |
|
405 | :sortable => "(SELECT COALESCE(SUM(hours), 0) FROM #{TimeEntry.table_name} WHERE #{TimeEntry.table_name}.issue_id = #{Issue.table_name}.id)", | |
388 | :default_order => 'desc', |
|
406 | :default_order => 'desc', | |
389 | :caption => :label_spent_time |
|
407 | :caption => :label_spent_time | |
390 | ) |
|
408 | ) | |
391 | end |
|
409 | end | |
392 |
|
410 | |||
393 | if User.current.allowed_to?(:set_issues_private, nil, :global => true) || |
|
411 | if User.current.allowed_to?(:set_issues_private, nil, :global => true) || | |
394 | User.current.allowed_to?(:set_own_issues_private, nil, :global => true) |
|
412 | User.current.allowed_to?(:set_own_issues_private, nil, :global => true) | |
395 | @available_columns << QueryColumn.new(:is_private, :sortable => "#{Issue.table_name}.is_private") |
|
413 | @available_columns << QueryColumn.new(:is_private, :sortable => "#{Issue.table_name}.is_private") | |
396 | end |
|
414 | end | |
397 |
|
415 | |||
398 | disabled_fields = Tracker.disabled_core_fields(trackers).map {|field| field.sub(/_id$/, '')} |
|
416 | disabled_fields = Tracker.disabled_core_fields(trackers).map {|field| field.sub(/_id$/, '')} | |
399 | @available_columns.reject! {|column| |
|
417 | @available_columns.reject! {|column| | |
400 | disabled_fields.include?(column.name.to_s) |
|
418 | disabled_fields.include?(column.name.to_s) | |
401 | } |
|
419 | } | |
402 |
|
420 | |||
403 | @available_columns |
|
421 | @available_columns | |
404 | end |
|
422 | end | |
405 |
|
423 | |||
406 | def self.available_columns=(v) |
|
424 | def self.available_columns=(v) | |
407 | self.available_columns = (v) |
|
425 | self.available_columns = (v) | |
408 | end |
|
426 | end | |
409 |
|
427 | |||
410 | def self.add_available_column(column) |
|
428 | def self.add_available_column(column) | |
411 | self.available_columns << (column) if column.is_a?(QueryColumn) |
|
429 | self.available_columns << (column) if column.is_a?(QueryColumn) | |
412 | end |
|
430 | end | |
413 |
|
431 | |||
414 | # Returns an array of columns that can be used to group the results |
|
432 | # Returns an array of columns that can be used to group the results | |
415 | def groupable_columns |
|
433 | def groupable_columns | |
416 | available_columns.select {|c| c.groupable} |
|
434 | available_columns.select {|c| c.groupable} | |
417 | end |
|
435 | end | |
418 |
|
436 | |||
419 | # Returns a Hash of columns and the key for sorting |
|
437 | # Returns a Hash of columns and the key for sorting | |
420 | def sortable_columns |
|
438 | def sortable_columns | |
421 | {'id' => "#{Issue.table_name}.id"}.merge(available_columns.inject({}) {|h, column| |
|
439 | {'id' => "#{Issue.table_name}.id"}.merge(available_columns.inject({}) {|h, column| | |
422 | h[column.name.to_s] = column.sortable |
|
440 | h[column.name.to_s] = column.sortable | |
423 | h |
|
441 | h | |
424 | }) |
|
442 | }) | |
425 | end |
|
443 | end | |
426 |
|
444 | |||
427 | def columns |
|
445 | def columns | |
428 | # preserve the column_names order |
|
446 | # preserve the column_names order | |
429 | (has_default_columns? ? default_columns_names : column_names).collect do |name| |
|
447 | (has_default_columns? ? default_columns_names : column_names).collect do |name| | |
430 | available_columns.find { |col| col.name == name } |
|
448 | available_columns.find { |col| col.name == name } | |
431 | end.compact |
|
449 | end.compact | |
432 | end |
|
450 | end | |
433 |
|
451 | |||
434 | def default_columns_names |
|
452 | def default_columns_names | |
435 | @default_columns_names ||= begin |
|
453 | @default_columns_names ||= begin | |
436 | default_columns = Setting.issue_list_default_columns.map(&:to_sym) |
|
454 | default_columns = Setting.issue_list_default_columns.map(&:to_sym) | |
437 |
|
455 | |||
438 | project.present? ? default_columns : [:project] | default_columns |
|
456 | project.present? ? default_columns : [:project] | default_columns | |
439 | end |
|
457 | end | |
440 | end |
|
458 | end | |
441 |
|
459 | |||
442 | def column_names=(names) |
|
460 | def column_names=(names) | |
443 | if names |
|
461 | if names | |
444 | names = names.select {|n| n.is_a?(Symbol) || !n.blank? } |
|
462 | names = names.select {|n| n.is_a?(Symbol) || !n.blank? } | |
445 | names = names.collect {|n| n.is_a?(Symbol) ? n : n.to_sym } |
|
463 | names = names.collect {|n| n.is_a?(Symbol) ? n : n.to_sym } | |
446 | # Set column_names to nil if default columns |
|
464 | # Set column_names to nil if default columns | |
447 | if names == default_columns_names |
|
465 | if names == default_columns_names | |
448 | names = nil |
|
466 | names = nil | |
449 | end |
|
467 | end | |
450 | end |
|
468 | end | |
451 | write_attribute(:column_names, names) |
|
469 | write_attribute(:column_names, names) | |
452 | end |
|
470 | end | |
453 |
|
471 | |||
454 | def has_column?(column) |
|
472 | def has_column?(column) | |
455 | column_names && column_names.include?(column.is_a?(QueryColumn) ? column.name : column) |
|
473 | column_names && column_names.include?(column.is_a?(QueryColumn) ? column.name : column) | |
456 | end |
|
474 | end | |
457 |
|
475 | |||
458 | def has_default_columns? |
|
476 | def has_default_columns? | |
459 | column_names.nil? || column_names.empty? |
|
477 | column_names.nil? || column_names.empty? | |
460 | end |
|
478 | end | |
461 |
|
479 | |||
462 | def sort_criteria=(arg) |
|
480 | def sort_criteria=(arg) | |
463 | c = [] |
|
481 | c = [] | |
464 | if arg.is_a?(Hash) |
|
482 | if arg.is_a?(Hash) | |
465 | arg = arg.keys.sort.collect {|k| arg[k]} |
|
483 | arg = arg.keys.sort.collect {|k| arg[k]} | |
466 | end |
|
484 | end | |
467 | c = arg.select {|k,o| !k.to_s.blank?}.slice(0,3).collect {|k,o| [k.to_s, o == 'desc' ? o : 'asc']} |
|
485 | c = arg.select {|k,o| !k.to_s.blank?}.slice(0,3).collect {|k,o| [k.to_s, o == 'desc' ? o : 'asc']} | |
468 | write_attribute(:sort_criteria, c) |
|
486 | write_attribute(:sort_criteria, c) | |
469 | end |
|
487 | end | |
470 |
|
488 | |||
471 | def sort_criteria |
|
489 | def sort_criteria | |
472 | read_attribute(:sort_criteria) || [] |
|
490 | read_attribute(:sort_criteria) || [] | |
473 | end |
|
491 | end | |
474 |
|
492 | |||
475 | def sort_criteria_key(arg) |
|
493 | def sort_criteria_key(arg) | |
476 | sort_criteria && sort_criteria[arg] && sort_criteria[arg].first |
|
494 | sort_criteria && sort_criteria[arg] && sort_criteria[arg].first | |
477 | end |
|
495 | end | |
478 |
|
496 | |||
479 | def sort_criteria_order(arg) |
|
497 | def sort_criteria_order(arg) | |
480 | sort_criteria && sort_criteria[arg] && sort_criteria[arg].last |
|
498 | sort_criteria && sort_criteria[arg] && sort_criteria[arg].last | |
481 | end |
|
499 | end | |
482 |
|
500 | |||
483 | # Returns the SQL sort order that should be prepended for grouping |
|
501 | # Returns the SQL sort order that should be prepended for grouping | |
484 | def group_by_sort_order |
|
502 | def group_by_sort_order | |
485 | if grouped? && (column = group_by_column) |
|
503 | if grouped? && (column = group_by_column) | |
486 | column.sortable.is_a?(Array) ? |
|
504 | column.sortable.is_a?(Array) ? | |
487 | column.sortable.collect {|s| "#{s} #{column.default_order}"}.join(',') : |
|
505 | column.sortable.collect {|s| "#{s} #{column.default_order}"}.join(',') : | |
488 | "#{column.sortable} #{column.default_order}" |
|
506 | "#{column.sortable} #{column.default_order}" | |
489 | end |
|
507 | end | |
490 | end |
|
508 | end | |
491 |
|
509 | |||
492 | # Returns true if the query is a grouped query |
|
510 | # Returns true if the query is a grouped query | |
493 | def grouped? |
|
511 | def grouped? | |
494 | !group_by_column.nil? |
|
512 | !group_by_column.nil? | |
495 | end |
|
513 | end | |
496 |
|
514 | |||
497 | def group_by_column |
|
515 | def group_by_column | |
498 | groupable_columns.detect {|c| c.groupable && c.name.to_s == group_by} |
|
516 | groupable_columns.detect {|c| c.groupable && c.name.to_s == group_by} | |
499 | end |
|
517 | end | |
500 |
|
518 | |||
501 | def group_by_statement |
|
519 | def group_by_statement | |
502 | group_by_column.try(:groupable) |
|
520 | group_by_column.try(:groupable) | |
503 | end |
|
521 | end | |
504 |
|
522 | |||
505 | def project_statement |
|
523 | def project_statement | |
506 | project_clauses = [] |
|
524 | project_clauses = [] | |
507 | if project && !project.descendants.active.empty? |
|
525 | if project && !project.descendants.active.empty? | |
508 | ids = [project.id] |
|
526 | ids = [project.id] | |
509 | if has_filter?("subproject_id") |
|
527 | if has_filter?("subproject_id") | |
510 | case operator_for("subproject_id") |
|
528 | case operator_for("subproject_id") | |
511 | when '=' |
|
529 | when '=' | |
512 | # include the selected subprojects |
|
530 | # include the selected subprojects | |
513 | ids += values_for("subproject_id").each(&:to_i) |
|
531 | ids += values_for("subproject_id").each(&:to_i) | |
514 | when '!*' |
|
532 | when '!*' | |
515 | # main project only |
|
533 | # main project only | |
516 | else |
|
534 | else | |
517 | # all subprojects |
|
535 | # all subprojects | |
518 | ids += project.descendants.collect(&:id) |
|
536 | ids += project.descendants.collect(&:id) | |
519 | end |
|
537 | end | |
520 | elsif Setting.display_subprojects_issues? |
|
538 | elsif Setting.display_subprojects_issues? | |
521 | ids += project.descendants.collect(&:id) |
|
539 | ids += project.descendants.collect(&:id) | |
522 | end |
|
540 | end | |
523 | project_clauses << "#{Project.table_name}.id IN (%s)" % ids.join(',') |
|
541 | project_clauses << "#{Project.table_name}.id IN (%s)" % ids.join(',') | |
524 | elsif project |
|
542 | elsif project | |
525 | project_clauses << "#{Project.table_name}.id = %d" % project.id |
|
543 | project_clauses << "#{Project.table_name}.id = %d" % project.id | |
526 | end |
|
544 | end | |
527 | project_clauses.any? ? project_clauses.join(' AND ') : nil |
|
545 | project_clauses.any? ? project_clauses.join(' AND ') : nil | |
528 | end |
|
546 | end | |
529 |
|
547 | |||
530 | def statement |
|
548 | def statement | |
531 | # filters clauses |
|
549 | # filters clauses | |
532 | filters_clauses = [] |
|
550 | filters_clauses = [] | |
533 | filters.each_key do |field| |
|
551 | filters.each_key do |field| | |
534 | next if field == "subproject_id" |
|
552 | next if field == "subproject_id" | |
535 | v = values_for(field).clone |
|
553 | v = values_for(field).clone | |
536 | next unless v and !v.empty? |
|
554 | next unless v and !v.empty? | |
537 | operator = operator_for(field) |
|
555 | operator = operator_for(field) | |
538 |
|
556 | |||
539 | # "me" value subsitution |
|
557 | # "me" value subsitution | |
540 | if %w(assigned_to_id author_id watcher_id).include?(field) |
|
558 | if %w(assigned_to_id author_id watcher_id).include?(field) | |
541 | if v.delete("me") |
|
559 | if v.delete("me") | |
542 | if User.current.logged? |
|
560 | if User.current.logged? | |
543 | v.push(User.current.id.to_s) |
|
561 | v.push(User.current.id.to_s) | |
544 | v += User.current.group_ids.map(&:to_s) if field == 'assigned_to_id' |
|
562 | v += User.current.group_ids.map(&:to_s) if field == 'assigned_to_id' | |
545 | else |
|
563 | else | |
546 | v.push("0") |
|
564 | v.push("0") | |
547 | end |
|
565 | end | |
548 | end |
|
566 | end | |
549 | end |
|
567 | end | |
550 |
|
568 | |||
551 | if field == 'project_id' |
|
569 | if field == 'project_id' | |
552 | if v.delete('mine') |
|
570 | if v.delete('mine') | |
553 | v += User.current.memberships.map(&:project_id).map(&:to_s) |
|
571 | v += User.current.memberships.map(&:project_id).map(&:to_s) | |
554 | end |
|
572 | end | |
555 | end |
|
573 | end | |
556 |
|
574 | |||
557 | if field =~ /^cf_(\d+)$/ |
|
575 | if field =~ /^cf_(\d+)$/ | |
558 | # custom field |
|
576 | # custom field | |
559 | filters_clauses << sql_for_custom_field(field, operator, v, $1) |
|
577 | filters_clauses << sql_for_custom_field(field, operator, v, $1) | |
560 | elsif respond_to?("sql_for_#{field}_field") |
|
578 | elsif respond_to?("sql_for_#{field}_field") | |
561 | # specific statement |
|
579 | # specific statement | |
562 | filters_clauses << send("sql_for_#{field}_field", field, operator, v) |
|
580 | filters_clauses << send("sql_for_#{field}_field", field, operator, v) | |
563 | else |
|
581 | else | |
564 | # regular field |
|
582 | # regular field | |
565 | filters_clauses << '(' + sql_for_field(field, operator, v, Issue.table_name, field) + ')' |
|
583 | filters_clauses << '(' + sql_for_field(field, operator, v, Issue.table_name, field) + ')' | |
566 | end |
|
584 | end | |
567 | end if filters and valid? |
|
585 | end if filters and valid? | |
568 |
|
586 | |||
569 | filters_clauses << project_statement |
|
587 | filters_clauses << project_statement | |
570 | filters_clauses.reject!(&:blank?) |
|
588 | filters_clauses.reject!(&:blank?) | |
571 |
|
589 | |||
572 | filters_clauses.any? ? filters_clauses.join(' AND ') : nil |
|
590 | filters_clauses.any? ? filters_clauses.join(' AND ') : nil | |
573 | end |
|
591 | end | |
574 |
|
592 | |||
575 | # Returns the issue count |
|
593 | # Returns the issue count | |
576 | def issue_count |
|
594 | def issue_count | |
577 | Issue.visible.count(:include => [:status, :project], :conditions => statement) |
|
595 | Issue.visible.count(:include => [:status, :project], :conditions => statement) | |
578 | rescue ::ActiveRecord::StatementInvalid => e |
|
596 | rescue ::ActiveRecord::StatementInvalid => e | |
579 | raise StatementInvalid.new(e.message) |
|
597 | raise StatementInvalid.new(e.message) | |
580 | end |
|
598 | end | |
581 |
|
599 | |||
582 | # Returns the issue count by group or nil if query is not grouped |
|
600 | # Returns the issue count by group or nil if query is not grouped | |
583 | def issue_count_by_group |
|
601 | def issue_count_by_group | |
584 | r = nil |
|
602 | r = nil | |
585 | if grouped? |
|
603 | if grouped? | |
586 | begin |
|
604 | begin | |
587 | # Rails3 will raise an (unexpected) RecordNotFound if there's only a nil group value |
|
605 | # Rails3 will raise an (unexpected) RecordNotFound if there's only a nil group value | |
588 | r = Issue.visible.count(:group => group_by_statement, :include => [:status, :project], :conditions => statement) |
|
606 | r = Issue.visible.count(:group => group_by_statement, :include => [:status, :project], :conditions => statement) | |
589 | rescue ActiveRecord::RecordNotFound |
|
607 | rescue ActiveRecord::RecordNotFound | |
590 | r = {nil => issue_count} |
|
608 | r = {nil => issue_count} | |
591 | end |
|
609 | end | |
592 | c = group_by_column |
|
610 | c = group_by_column | |
593 | if c.is_a?(QueryCustomFieldColumn) |
|
611 | if c.is_a?(QueryCustomFieldColumn) | |
594 | r = r.keys.inject({}) {|h, k| h[c.custom_field.cast_value(k)] = r[k]; h} |
|
612 | r = r.keys.inject({}) {|h, k| h[c.custom_field.cast_value(k)] = r[k]; h} | |
595 | end |
|
613 | end | |
596 | end |
|
614 | end | |
597 | r |
|
615 | r | |
598 | rescue ::ActiveRecord::StatementInvalid => e |
|
616 | rescue ::ActiveRecord::StatementInvalid => e | |
599 | raise StatementInvalid.new(e.message) |
|
617 | raise StatementInvalid.new(e.message) | |
600 | end |
|
618 | end | |
601 |
|
619 | |||
602 | # Returns the issues |
|
620 | # Returns the issues | |
603 | # Valid options are :order, :offset, :limit, :include, :conditions |
|
621 | # Valid options are :order, :offset, :limit, :include, :conditions | |
604 | def issues(options={}) |
|
622 | def issues(options={}) | |
605 | order_option = [group_by_sort_order, options[:order]].reject {|s| s.blank?}.join(',') |
|
623 | order_option = [group_by_sort_order, options[:order]].reject {|s| s.blank?}.join(',') | |
606 | order_option = nil if order_option.blank? |
|
624 | order_option = nil if order_option.blank? | |
607 |
|
625 | |||
608 | issues = Issue.visible.scoped(:conditions => options[:conditions]).find :all, :include => ([:status, :project] + (options[:include] || [])).uniq, |
|
626 | issues = Issue.visible.scoped(:conditions => options[:conditions]).find :all, :include => ([:status, :project] + (options[:include] || [])).uniq, | |
609 | :conditions => statement, |
|
627 | :conditions => statement, | |
610 | :order => order_option, |
|
628 | :order => order_option, | |
611 | :joins => joins_for_order_statement(order_option), |
|
629 | :joins => joins_for_order_statement(order_option), | |
612 | :limit => options[:limit], |
|
630 | :limit => options[:limit], | |
613 | :offset => options[:offset] |
|
631 | :offset => options[:offset] | |
614 |
|
632 | |||
615 | if has_column?(:spent_hours) |
|
633 | if has_column?(:spent_hours) | |
616 | Issue.load_visible_spent_hours(issues) |
|
634 | Issue.load_visible_spent_hours(issues) | |
617 | end |
|
635 | end | |
618 | issues |
|
636 | issues | |
619 | rescue ::ActiveRecord::StatementInvalid => e |
|
637 | rescue ::ActiveRecord::StatementInvalid => e | |
620 | raise StatementInvalid.new(e.message) |
|
638 | raise StatementInvalid.new(e.message) | |
621 | end |
|
639 | end | |
622 |
|
640 | |||
623 | # Returns the issues ids |
|
641 | # Returns the issues ids | |
624 | def issue_ids(options={}) |
|
642 | def issue_ids(options={}) | |
625 | order_option = [group_by_sort_order, options[:order]].reject {|s| s.blank?}.join(',') |
|
643 | order_option = [group_by_sort_order, options[:order]].reject {|s| s.blank?}.join(',') | |
626 | order_option = nil if order_option.blank? |
|
644 | order_option = nil if order_option.blank? | |
627 |
|
645 | |||
628 | Issue.visible.scoped(:conditions => options[:conditions]).scoped(:include => ([:status, :project] + (options[:include] || [])).uniq, |
|
646 | Issue.visible.scoped(:conditions => options[:conditions]).scoped(:include => ([:status, :project] + (options[:include] || [])).uniq, | |
629 | :conditions => statement, |
|
647 | :conditions => statement, | |
630 | :order => order_option, |
|
648 | :order => order_option, | |
631 | :joins => joins_for_order_statement(order_option), |
|
649 | :joins => joins_for_order_statement(order_option), | |
632 | :limit => options[:limit], |
|
650 | :limit => options[:limit], | |
633 | :offset => options[:offset]).find_ids |
|
651 | :offset => options[:offset]).find_ids | |
634 | rescue ::ActiveRecord::StatementInvalid => e |
|
652 | rescue ::ActiveRecord::StatementInvalid => e | |
635 | raise StatementInvalid.new(e.message) |
|
653 | raise StatementInvalid.new(e.message) | |
636 | end |
|
654 | end | |
637 |
|
655 | |||
638 | # Returns the journals |
|
656 | # Returns the journals | |
639 | # Valid options are :order, :offset, :limit |
|
657 | # Valid options are :order, :offset, :limit | |
640 | def journals(options={}) |
|
658 | def journals(options={}) | |
641 | Journal.visible.find :all, :include => [:details, :user, {:issue => [:project, :author, :tracker, :status]}], |
|
659 | Journal.visible.find :all, :include => [:details, :user, {:issue => [:project, :author, :tracker, :status]}], | |
642 | :conditions => statement, |
|
660 | :conditions => statement, | |
643 | :order => options[:order], |
|
661 | :order => options[:order], | |
644 | :limit => options[:limit], |
|
662 | :limit => options[:limit], | |
645 | :offset => options[:offset] |
|
663 | :offset => options[:offset] | |
646 | rescue ::ActiveRecord::StatementInvalid => e |
|
664 | rescue ::ActiveRecord::StatementInvalid => e | |
647 | raise StatementInvalid.new(e.message) |
|
665 | raise StatementInvalid.new(e.message) | |
648 | end |
|
666 | end | |
649 |
|
667 | |||
650 | # Returns the versions |
|
668 | # Returns the versions | |
651 | # Valid options are :conditions |
|
669 | # Valid options are :conditions | |
652 | def versions(options={}) |
|
670 | def versions(options={}) | |
653 | Version.visible.scoped(:conditions => options[:conditions]).find :all, :include => :project, :conditions => project_statement |
|
671 | Version.visible.scoped(:conditions => options[:conditions]).find :all, :include => :project, :conditions => project_statement | |
654 | rescue ::ActiveRecord::StatementInvalid => e |
|
672 | rescue ::ActiveRecord::StatementInvalid => e | |
655 | raise StatementInvalid.new(e.message) |
|
673 | raise StatementInvalid.new(e.message) | |
656 | end |
|
674 | end | |
657 |
|
675 | |||
658 | def sql_for_watcher_id_field(field, operator, value) |
|
676 | def sql_for_watcher_id_field(field, operator, value) | |
659 | db_table = Watcher.table_name |
|
677 | db_table = Watcher.table_name | |
660 | "#{Issue.table_name}.id #{ operator == '=' ? 'IN' : 'NOT IN' } (SELECT #{db_table}.watchable_id FROM #{db_table} WHERE #{db_table}.watchable_type='Issue' AND " + |
|
678 | "#{Issue.table_name}.id #{ operator == '=' ? 'IN' : 'NOT IN' } (SELECT #{db_table}.watchable_id FROM #{db_table} WHERE #{db_table}.watchable_type='Issue' AND " + | |
661 | sql_for_field(field, '=', value, db_table, 'user_id') + ')' |
|
679 | sql_for_field(field, '=', value, db_table, 'user_id') + ')' | |
662 | end |
|
680 | end | |
663 |
|
681 | |||
664 | def sql_for_member_of_group_field(field, operator, value) |
|
682 | def sql_for_member_of_group_field(field, operator, value) | |
665 | if operator == '*' # Any group |
|
683 | if operator == '*' # Any group | |
666 | groups = Group.all |
|
684 | groups = Group.all | |
667 | operator = '=' # Override the operator since we want to find by assigned_to |
|
685 | operator = '=' # Override the operator since we want to find by assigned_to | |
668 | elsif operator == "!*" |
|
686 | elsif operator == "!*" | |
669 | groups = Group.all |
|
687 | groups = Group.all | |
670 | operator = '!' # Override the operator since we want to find by assigned_to |
|
688 | operator = '!' # Override the operator since we want to find by assigned_to | |
671 | else |
|
689 | else | |
672 | groups = Group.find_all_by_id(value) |
|
690 | groups = Group.find_all_by_id(value) | |
673 | end |
|
691 | end | |
674 | groups ||= [] |
|
692 | groups ||= [] | |
675 |
|
693 | |||
676 | members_of_groups = groups.inject([]) {|user_ids, group| |
|
694 | members_of_groups = groups.inject([]) {|user_ids, group| | |
677 | if group && group.user_ids.present? |
|
695 | if group && group.user_ids.present? | |
678 | user_ids << group.user_ids |
|
696 | user_ids << group.user_ids | |
679 | end |
|
697 | end | |
680 | user_ids.flatten.uniq.compact |
|
698 | user_ids.flatten.uniq.compact | |
681 | }.sort.collect(&:to_s) |
|
699 | }.sort.collect(&:to_s) | |
682 |
|
700 | |||
683 | '(' + sql_for_field("assigned_to_id", operator, members_of_groups, Issue.table_name, "assigned_to_id", false) + ')' |
|
701 | '(' + sql_for_field("assigned_to_id", operator, members_of_groups, Issue.table_name, "assigned_to_id", false) + ')' | |
684 | end |
|
702 | end | |
685 |
|
703 | |||
686 | def sql_for_assigned_to_role_field(field, operator, value) |
|
704 | def sql_for_assigned_to_role_field(field, operator, value) | |
687 | case operator |
|
705 | case operator | |
688 | when "*", "!*" # Member / Not member |
|
706 | when "*", "!*" # Member / Not member | |
689 | sw = operator == "!*" ? 'NOT' : '' |
|
707 | sw = operator == "!*" ? 'NOT' : '' | |
690 | nl = operator == "!*" ? "#{Issue.table_name}.assigned_to_id IS NULL OR" : '' |
|
708 | nl = operator == "!*" ? "#{Issue.table_name}.assigned_to_id IS NULL OR" : '' | |
691 | "(#{nl} #{Issue.table_name}.assigned_to_id #{sw} IN (SELECT DISTINCT #{Member.table_name}.user_id FROM #{Member.table_name}" + |
|
709 | "(#{nl} #{Issue.table_name}.assigned_to_id #{sw} IN (SELECT DISTINCT #{Member.table_name}.user_id FROM #{Member.table_name}" + | |
692 | " WHERE #{Member.table_name}.project_id = #{Issue.table_name}.project_id))" |
|
710 | " WHERE #{Member.table_name}.project_id = #{Issue.table_name}.project_id))" | |
693 | when "=", "!" |
|
711 | when "=", "!" | |
694 | role_cond = value.any? ? |
|
712 | role_cond = value.any? ? | |
695 | "#{MemberRole.table_name}.role_id IN (" + value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + ")" : |
|
713 | "#{MemberRole.table_name}.role_id IN (" + value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + ")" : | |
696 | "1=0" |
|
714 | "1=0" | |
697 |
|
715 | |||
698 | sw = operator == "!" ? 'NOT' : '' |
|
716 | sw = operator == "!" ? 'NOT' : '' | |
699 | nl = operator == "!" ? "#{Issue.table_name}.assigned_to_id IS NULL OR" : '' |
|
717 | nl = operator == "!" ? "#{Issue.table_name}.assigned_to_id IS NULL OR" : '' | |
700 | "(#{nl} #{Issue.table_name}.assigned_to_id #{sw} IN (SELECT DISTINCT #{Member.table_name}.user_id FROM #{Member.table_name}, #{MemberRole.table_name}" + |
|
718 | "(#{nl} #{Issue.table_name}.assigned_to_id #{sw} IN (SELECT DISTINCT #{Member.table_name}.user_id FROM #{Member.table_name}, #{MemberRole.table_name}" + | |
701 | " WHERE #{Member.table_name}.project_id = #{Issue.table_name}.project_id AND #{Member.table_name}.id = #{MemberRole.table_name}.member_id AND #{role_cond}))" |
|
719 | " WHERE #{Member.table_name}.project_id = #{Issue.table_name}.project_id AND #{Member.table_name}.id = #{MemberRole.table_name}.member_id AND #{role_cond}))" | |
702 | end |
|
720 | end | |
703 | end |
|
721 | end | |
704 |
|
722 | |||
705 | def sql_for_is_private_field(field, operator, value) |
|
723 | def sql_for_is_private_field(field, operator, value) | |
706 | op = (operator == "=" ? 'IN' : 'NOT IN') |
|
724 | op = (operator == "=" ? 'IN' : 'NOT IN') | |
707 | va = value.map {|v| v == '0' ? connection.quoted_false : connection.quoted_true}.uniq.join(',') |
|
725 | va = value.map {|v| v == '0' ? connection.quoted_false : connection.quoted_true}.uniq.join(',') | |
708 |
|
726 | |||
709 | "#{Issue.table_name}.is_private #{op} (#{va})" |
|
727 | "#{Issue.table_name}.is_private #{op} (#{va})" | |
710 | end |
|
728 | end | |
711 |
|
729 | |||
712 | private |
|
730 | private | |
713 |
|
731 | |||
714 | def sql_for_custom_field(field, operator, value, custom_field_id) |
|
732 | def sql_for_custom_field(field, operator, value, custom_field_id) | |
715 | db_table = CustomValue.table_name |
|
733 | db_table = CustomValue.table_name | |
716 | db_field = 'value' |
|
734 | db_field = 'value' | |
717 | filter = @available_filters[field] |
|
735 | filter = @available_filters[field] | |
718 | if filter && filter[:format] == 'user' |
|
736 | if filter && filter[:format] == 'user' | |
719 | if value.delete('me') |
|
737 | if value.delete('me') | |
720 | value.push User.current.id.to_s |
|
738 | value.push User.current.id.to_s | |
721 | end |
|
739 | end | |
722 | end |
|
740 | end | |
723 | not_in = nil |
|
741 | not_in = nil | |
724 | if operator == '!' |
|
742 | if operator == '!' | |
725 | # Makes ! operator work for custom fields with multiple values |
|
743 | # Makes ! operator work for custom fields with multiple values | |
726 | operator = '=' |
|
744 | operator = '=' | |
727 | not_in = 'NOT' |
|
745 | not_in = 'NOT' | |
728 | end |
|
746 | end | |
729 | "#{Issue.table_name}.id #{not_in} IN (SELECT #{Issue.table_name}.id FROM #{Issue.table_name} LEFT OUTER JOIN #{db_table} ON #{db_table}.customized_type='Issue' AND #{db_table}.customized_id=#{Issue.table_name}.id AND #{db_table}.custom_field_id=#{custom_field_id} WHERE " + |
|
747 | "#{Issue.table_name}.id #{not_in} IN (SELECT #{Issue.table_name}.id FROM #{Issue.table_name} LEFT OUTER JOIN #{db_table} ON #{db_table}.customized_type='Issue' AND #{db_table}.customized_id=#{Issue.table_name}.id AND #{db_table}.custom_field_id=#{custom_field_id} WHERE " + | |
730 | sql_for_field(field, operator, value, db_table, db_field, true) + ')' |
|
748 | sql_for_field(field, operator, value, db_table, db_field, true) + ')' | |
731 | end |
|
749 | end | |
732 |
|
750 | |||
733 | # Helper method to generate the WHERE sql for a +field+, +operator+ and a +value+ |
|
751 | # Helper method to generate the WHERE sql for a +field+, +operator+ and a +value+ | |
734 | def sql_for_field(field, operator, value, db_table, db_field, is_custom_filter=false) |
|
752 | def sql_for_field(field, operator, value, db_table, db_field, is_custom_filter=false) | |
735 | sql = '' |
|
753 | sql = '' | |
736 | case operator |
|
754 | case operator | |
737 | when "=" |
|
755 | when "=" | |
738 | if value.any? |
|
756 | if value.any? | |
739 | case type_for(field) |
|
757 | case type_for(field) | |
740 | when :date, :date_past |
|
758 | when :date, :date_past | |
741 | sql = date_clause(db_table, db_field, (Date.parse(value.first) rescue nil), (Date.parse(value.first) rescue nil)) |
|
759 | sql = date_clause(db_table, db_field, (Date.parse(value.first) rescue nil), (Date.parse(value.first) rescue nil)) | |
742 | when :integer |
|
760 | when :integer | |
743 | if is_custom_filter |
|
761 | if is_custom_filter | |
744 | sql = "(#{db_table}.#{db_field} <> '' AND CAST(#{db_table}.#{db_field} AS decimal(60,3)) = #{value.first.to_i})" |
|
762 | sql = "(#{db_table}.#{db_field} <> '' AND CAST(#{db_table}.#{db_field} AS decimal(60,3)) = #{value.first.to_i})" | |
745 | else |
|
763 | else | |
746 | sql = "#{db_table}.#{db_field} = #{value.first.to_i}" |
|
764 | sql = "#{db_table}.#{db_field} = #{value.first.to_i}" | |
747 | end |
|
765 | end | |
748 | when :float |
|
766 | when :float | |
749 | if is_custom_filter |
|
767 | if is_custom_filter | |
750 | sql = "(#{db_table}.#{db_field} <> '' AND CAST(#{db_table}.#{db_field} AS decimal(60,3)) BETWEEN #{value.first.to_f - 1e-5} AND #{value.first.to_f + 1e-5})" |
|
768 | sql = "(#{db_table}.#{db_field} <> '' AND CAST(#{db_table}.#{db_field} AS decimal(60,3)) BETWEEN #{value.first.to_f - 1e-5} AND #{value.first.to_f + 1e-5})" | |
751 | else |
|
769 | else | |
752 | sql = "#{db_table}.#{db_field} BETWEEN #{value.first.to_f - 1e-5} AND #{value.first.to_f + 1e-5}" |
|
770 | sql = "#{db_table}.#{db_field} BETWEEN #{value.first.to_f - 1e-5} AND #{value.first.to_f + 1e-5}" | |
753 | end |
|
771 | end | |
754 | else |
|
772 | else | |
755 | sql = "#{db_table}.#{db_field} IN (" + value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + ")" |
|
773 | sql = "#{db_table}.#{db_field} IN (" + value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + ")" | |
756 | end |
|
774 | end | |
757 | else |
|
775 | else | |
758 | # IN an empty set |
|
776 | # IN an empty set | |
759 | sql = "1=0" |
|
777 | sql = "1=0" | |
760 | end |
|
778 | end | |
761 | when "!" |
|
779 | when "!" | |
762 | if value.any? |
|
780 | if value.any? | |
763 | sql = "(#{db_table}.#{db_field} IS NULL OR #{db_table}.#{db_field} NOT IN (" + value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + "))" |
|
781 | sql = "(#{db_table}.#{db_field} IS NULL OR #{db_table}.#{db_field} NOT IN (" + value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + "))" | |
764 | else |
|
782 | else | |
765 | # NOT IN an empty set |
|
783 | # NOT IN an empty set | |
766 | sql = "1=1" |
|
784 | sql = "1=1" | |
767 | end |
|
785 | end | |
768 | when "!*" |
|
786 | when "!*" | |
769 | sql = "#{db_table}.#{db_field} IS NULL" |
|
787 | sql = "#{db_table}.#{db_field} IS NULL" | |
770 | sql << " OR #{db_table}.#{db_field} = ''" if is_custom_filter |
|
788 | sql << " OR #{db_table}.#{db_field} = ''" if is_custom_filter | |
771 | when "*" |
|
789 | when "*" | |
772 | sql = "#{db_table}.#{db_field} IS NOT NULL" |
|
790 | sql = "#{db_table}.#{db_field} IS NOT NULL" | |
773 | sql << " AND #{db_table}.#{db_field} <> ''" if is_custom_filter |
|
791 | sql << " AND #{db_table}.#{db_field} <> ''" if is_custom_filter | |
774 | when ">=" |
|
792 | when ">=" | |
775 | if [:date, :date_past].include?(type_for(field)) |
|
793 | if [:date, :date_past].include?(type_for(field)) | |
776 | sql = date_clause(db_table, db_field, (Date.parse(value.first) rescue nil), nil) |
|
794 | sql = date_clause(db_table, db_field, (Date.parse(value.first) rescue nil), nil) | |
777 | else |
|
795 | else | |
778 | if is_custom_filter |
|
796 | if is_custom_filter | |
779 | sql = "(#{db_table}.#{db_field} <> '' AND CAST(#{db_table}.#{db_field} AS decimal(60,3)) >= #{value.first.to_f})" |
|
797 | sql = "(#{db_table}.#{db_field} <> '' AND CAST(#{db_table}.#{db_field} AS decimal(60,3)) >= #{value.first.to_f})" | |
780 | else |
|
798 | else | |
781 | sql = "#{db_table}.#{db_field} >= #{value.first.to_f}" |
|
799 | sql = "#{db_table}.#{db_field} >= #{value.first.to_f}" | |
782 | end |
|
800 | end | |
783 | end |
|
801 | end | |
784 | when "<=" |
|
802 | when "<=" | |
785 | if [:date, :date_past].include?(type_for(field)) |
|
803 | if [:date, :date_past].include?(type_for(field)) | |
786 | sql = date_clause(db_table, db_field, nil, (Date.parse(value.first) rescue nil)) |
|
804 | sql = date_clause(db_table, db_field, nil, (Date.parse(value.first) rescue nil)) | |
787 | else |
|
805 | else | |
788 | if is_custom_filter |
|
806 | if is_custom_filter | |
789 | sql = "(#{db_table}.#{db_field} <> '' AND CAST(#{db_table}.#{db_field} AS decimal(60,3)) <= #{value.first.to_f})" |
|
807 | sql = "(#{db_table}.#{db_field} <> '' AND CAST(#{db_table}.#{db_field} AS decimal(60,3)) <= #{value.first.to_f})" | |
790 | else |
|
808 | else | |
791 | sql = "#{db_table}.#{db_field} <= #{value.first.to_f}" |
|
809 | sql = "#{db_table}.#{db_field} <= #{value.first.to_f}" | |
792 | end |
|
810 | end | |
793 | end |
|
811 | end | |
794 | when "><" |
|
812 | when "><" | |
795 | if [:date, :date_past].include?(type_for(field)) |
|
813 | if [:date, :date_past].include?(type_for(field)) | |
796 | sql = date_clause(db_table, db_field, (Date.parse(value[0]) rescue nil), (Date.parse(value[1]) rescue nil)) |
|
814 | sql = date_clause(db_table, db_field, (Date.parse(value[0]) rescue nil), (Date.parse(value[1]) rescue nil)) | |
797 | else |
|
815 | else | |
798 | if is_custom_filter |
|
816 | if is_custom_filter | |
799 | sql = "(#{db_table}.#{db_field} <> '' AND CAST(#{db_table}.#{db_field} AS decimal(60,3)) BETWEEN #{value[0].to_f} AND #{value[1].to_f})" |
|
817 | sql = "(#{db_table}.#{db_field} <> '' AND CAST(#{db_table}.#{db_field} AS decimal(60,3)) BETWEEN #{value[0].to_f} AND #{value[1].to_f})" | |
800 | else |
|
818 | else | |
801 | sql = "#{db_table}.#{db_field} BETWEEN #{value[0].to_f} AND #{value[1].to_f}" |
|
819 | sql = "#{db_table}.#{db_field} BETWEEN #{value[0].to_f} AND #{value[1].to_f}" | |
802 | end |
|
820 | end | |
803 | end |
|
821 | end | |
804 | when "o" |
|
822 | when "o" | |
805 | sql = "#{Issue.table_name}.status_id IN (SELECT id FROM #{IssueStatus.table_name} WHERE is_closed=#{connection.quoted_false})" if field == "status_id" |
|
823 | sql = "#{Issue.table_name}.status_id IN (SELECT id FROM #{IssueStatus.table_name} WHERE is_closed=#{connection.quoted_false})" if field == "status_id" | |
806 | when "c" |
|
824 | when "c" | |
807 | sql = "#{Issue.table_name}.status_id IN (SELECT id FROM #{IssueStatus.table_name} WHERE is_closed=#{connection.quoted_true})" if field == "status_id" |
|
825 | sql = "#{Issue.table_name}.status_id IN (SELECT id FROM #{IssueStatus.table_name} WHERE is_closed=#{connection.quoted_true})" if field == "status_id" | |
808 | when ">t-" |
|
826 | when ">t-" | |
809 | sql = relative_date_clause(db_table, db_field, - value.first.to_i, 0) |
|
827 | sql = relative_date_clause(db_table, db_field, - value.first.to_i, 0) | |
810 | when "<t-" |
|
828 | when "<t-" | |
811 | sql = relative_date_clause(db_table, db_field, nil, - value.first.to_i) |
|
829 | sql = relative_date_clause(db_table, db_field, nil, - value.first.to_i) | |
812 | when "t-" |
|
830 | when "t-" | |
813 | sql = relative_date_clause(db_table, db_field, - value.first.to_i, - value.first.to_i) |
|
831 | sql = relative_date_clause(db_table, db_field, - value.first.to_i, - value.first.to_i) | |
814 | when ">t+" |
|
832 | when ">t+" | |
815 | sql = relative_date_clause(db_table, db_field, value.first.to_i, nil) |
|
833 | sql = relative_date_clause(db_table, db_field, value.first.to_i, nil) | |
816 | when "<t+" |
|
834 | when "<t+" | |
817 | sql = relative_date_clause(db_table, db_field, 0, value.first.to_i) |
|
835 | sql = relative_date_clause(db_table, db_field, 0, value.first.to_i) | |
818 | when "t+" |
|
836 | when "t+" | |
819 | sql = relative_date_clause(db_table, db_field, value.first.to_i, value.first.to_i) |
|
837 | sql = relative_date_clause(db_table, db_field, value.first.to_i, value.first.to_i) | |
820 | when "t" |
|
838 | when "t" | |
821 | sql = relative_date_clause(db_table, db_field, 0, 0) |
|
839 | sql = relative_date_clause(db_table, db_field, 0, 0) | |
822 | when "w" |
|
840 | when "w" | |
823 | first_day_of_week = l(:general_first_day_of_week).to_i |
|
841 | first_day_of_week = l(:general_first_day_of_week).to_i | |
824 | day_of_week = Date.today.cwday |
|
842 | day_of_week = Date.today.cwday | |
825 | days_ago = (day_of_week >= first_day_of_week ? day_of_week - first_day_of_week : day_of_week + 7 - first_day_of_week) |
|
843 | days_ago = (day_of_week >= first_day_of_week ? day_of_week - first_day_of_week : day_of_week + 7 - first_day_of_week) | |
826 | sql = relative_date_clause(db_table, db_field, - days_ago, - days_ago + 6) |
|
844 | sql = relative_date_clause(db_table, db_field, - days_ago, - days_ago + 6) | |
827 | when "~" |
|
845 | when "~" | |
828 | sql = "LOWER(#{db_table}.#{db_field}) LIKE '%#{connection.quote_string(value.first.to_s.downcase)}%'" |
|
846 | sql = "LOWER(#{db_table}.#{db_field}) LIKE '%#{connection.quote_string(value.first.to_s.downcase)}%'" | |
829 | when "!~" |
|
847 | when "!~" | |
830 | sql = "LOWER(#{db_table}.#{db_field}) NOT LIKE '%#{connection.quote_string(value.first.to_s.downcase)}%'" |
|
848 | sql = "LOWER(#{db_table}.#{db_field}) NOT LIKE '%#{connection.quote_string(value.first.to_s.downcase)}%'" | |
831 | else |
|
849 | else | |
832 | raise "Unknown query operator #{operator}" |
|
850 | raise "Unknown query operator #{operator}" | |
833 | end |
|
851 | end | |
834 |
|
852 | |||
835 | return sql |
|
853 | return sql | |
836 | end |
|
854 | end | |
837 |
|
855 | |||
838 | def add_custom_fields_filters(custom_fields) |
|
856 | def add_custom_fields_filters(custom_fields) | |
839 | @available_filters ||= {} |
|
857 | @available_filters ||= {} | |
840 |
|
858 | |||
841 | custom_fields.select(&:is_filter?).each do |field| |
|
859 | custom_fields.select(&:is_filter?).each do |field| | |
842 | case field.field_format |
|
860 | case field.field_format | |
843 | when "text" |
|
861 | when "text" | |
844 | options = { :type => :text, :order => 20 } |
|
862 | options = { :type => :text, :order => 20 } | |
845 | when "list" |
|
863 | when "list" | |
846 | options = { :type => :list_optional, :values => field.possible_values, :order => 20} |
|
864 | options = { :type => :list_optional, :values => field.possible_values, :order => 20} | |
847 | when "date" |
|
865 | when "date" | |
848 | options = { :type => :date, :order => 20 } |
|
866 | options = { :type => :date, :order => 20 } | |
849 | when "bool" |
|
867 | when "bool" | |
850 | options = { :type => :list, :values => [[l(:general_text_yes), "1"], [l(:general_text_no), "0"]], :order => 20 } |
|
868 | options = { :type => :list, :values => [[l(:general_text_yes), "1"], [l(:general_text_no), "0"]], :order => 20 } | |
851 | when "int" |
|
869 | when "int" | |
852 | options = { :type => :integer, :order => 20 } |
|
870 | options = { :type => :integer, :order => 20 } | |
853 | when "float" |
|
871 | when "float" | |
854 | options = { :type => :float, :order => 20 } |
|
872 | options = { :type => :float, :order => 20 } | |
855 | when "user", "version" |
|
873 | when "user", "version" | |
856 | next unless project |
|
874 | next unless project | |
857 | values = field.possible_values_options(project) |
|
875 | values = field.possible_values_options(project) | |
858 | if User.current.logged? && field.field_format == 'user' |
|
876 | if User.current.logged? && field.field_format == 'user' | |
859 | values.unshift ["<< #{l(:label_me)} >>", "me"] |
|
877 | values.unshift ["<< #{l(:label_me)} >>", "me"] | |
860 | end |
|
878 | end | |
861 | options = { :type => :list_optional, :values => values, :order => 20} |
|
879 | options = { :type => :list_optional, :values => values, :order => 20} | |
862 | else |
|
880 | else | |
863 | options = { :type => :string, :order => 20 } |
|
881 | options = { :type => :string, :order => 20 } | |
864 | end |
|
882 | end | |
865 | @available_filters["cf_#{field.id}"] = options.merge({ :name => field.name, :format => field.field_format }) |
|
883 | @available_filters["cf_#{field.id}"] = options.merge({ :name => field.name, :format => field.field_format }) | |
866 | end |
|
884 | end | |
867 | end |
|
885 | end | |
868 |
|
886 | |||
869 | # Returns a SQL clause for a date or datetime field. |
|
887 | # Returns a SQL clause for a date or datetime field. | |
870 | def date_clause(table, field, from, to) |
|
888 | def date_clause(table, field, from, to) | |
871 | s = [] |
|
889 | s = [] | |
872 | if from |
|
890 | if from | |
873 | from_yesterday = from - 1 |
|
891 | from_yesterday = from - 1 | |
874 | from_yesterday_time = Time.local(from_yesterday.year, from_yesterday.month, from_yesterday.day) |
|
892 | from_yesterday_time = Time.local(from_yesterday.year, from_yesterday.month, from_yesterday.day) | |
875 | if self.class.default_timezone == :utc |
|
893 | if self.class.default_timezone == :utc | |
876 | from_yesterday_time = from_yesterday_time.utc |
|
894 | from_yesterday_time = from_yesterday_time.utc | |
877 | end |
|
895 | end | |
878 | s << ("#{table}.#{field} > '%s'" % [connection.quoted_date(from_yesterday_time.end_of_day)]) |
|
896 | s << ("#{table}.#{field} > '%s'" % [connection.quoted_date(from_yesterday_time.end_of_day)]) | |
879 | end |
|
897 | end | |
880 | if to |
|
898 | if to | |
881 | to_time = Time.local(to.year, to.month, to.day) |
|
899 | to_time = Time.local(to.year, to.month, to.day) | |
882 | if self.class.default_timezone == :utc |
|
900 | if self.class.default_timezone == :utc | |
883 | to_time = to_time.utc |
|
901 | to_time = to_time.utc | |
884 | end |
|
902 | end | |
885 | s << ("#{table}.#{field} <= '%s'" % [connection.quoted_date(to_time.end_of_day)]) |
|
903 | s << ("#{table}.#{field} <= '%s'" % [connection.quoted_date(to_time.end_of_day)]) | |
886 | end |
|
904 | end | |
887 | s.join(' AND ') |
|
905 | s.join(' AND ') | |
888 | end |
|
906 | end | |
889 |
|
907 | |||
890 | # Returns a SQL clause for a date or datetime field using relative dates. |
|
908 | # Returns a SQL clause for a date or datetime field using relative dates. | |
891 | def relative_date_clause(table, field, days_from, days_to) |
|
909 | def relative_date_clause(table, field, days_from, days_to) | |
892 | date_clause(table, field, (days_from ? Date.today + days_from : nil), (days_to ? Date.today + days_to : nil)) |
|
910 | date_clause(table, field, (days_from ? Date.today + days_from : nil), (days_to ? Date.today + days_to : nil)) | |
893 | end |
|
911 | end | |
894 |
|
912 | |||
895 | # Additional joins required for the given sort options |
|
913 | # Additional joins required for the given sort options | |
896 | def joins_for_order_statement(order_options) |
|
914 | def joins_for_order_statement(order_options) | |
897 | joins = [] |
|
915 | joins = [] | |
898 |
|
916 | |||
899 | if order_options |
|
917 | if order_options | |
900 | if order_options.include?('authors') |
|
918 | if order_options.include?('authors') | |
901 | joins << "LEFT OUTER JOIN #{User.table_name} authors ON authors.id = #{Issue.table_name}.author_id" |
|
919 | joins << "LEFT OUTER JOIN #{User.table_name} authors ON authors.id = #{Issue.table_name}.author_id" | |
902 | end |
|
920 | end | |
903 | order_options.scan(/cf_\d+/).uniq.each do |name| |
|
921 | order_options.scan(/cf_\d+/).uniq.each do |name| | |
904 | column = available_columns.detect {|c| c.name.to_s == name} |
|
922 | column = available_columns.detect {|c| c.name.to_s == name} | |
905 | join = column && column.custom_field.join_for_order_statement |
|
923 | join = column && column.custom_field.join_for_order_statement | |
906 | if join |
|
924 | if join | |
907 | joins << join |
|
925 | joins << join | |
908 | end |
|
926 | end | |
909 | end |
|
927 | end | |
910 | end |
|
928 | end | |
911 |
|
929 | |||
912 | joins.any? ? joins.join(' ') : nil |
|
930 | joins.any? ? joins.join(' ') : nil | |
913 | end |
|
931 | end | |
914 | end |
|
932 | end |
@@ -1,53 +1,27 | |||||
|
1 | <%= javascript_tag do %> | |||
|
2 | var operatorLabels = <%= raw Query.operators_labels.to_json %>; | |||
|
3 | var operatorByType = <%= raw Query.operators_by_filter_type.to_json %>; | |||
|
4 | var availableFilters = <%= raw query.available_filters_as_json.to_json %>; | |||
|
5 | var labelDayPlural = "<%= raw escape_javascript(l(:label_day_plural)) %>"; | |||
|
6 | $(document).ready(function(){ | |||
|
7 | initFilters(); | |||
|
8 | <% query.filters.each do |field, options| %> | |||
|
9 | addFilter("<%= field %>", <%= raw query.operator_for(field).to_json %>, <%= raw query.values_for(field).to_json %>); | |||
|
10 | <% end %> | |||
|
11 | }); | |||
|
12 | <% end %> | |||
|
13 | ||||
1 | <table style="width:100%"> |
|
14 | <table style="width:100%"> | |
2 | <tr> |
|
15 | <tr> | |
3 | <td> |
|
16 | <td> | |
4 | <table> |
|
17 | <table id="filters-table"> | |
5 | <% query.available_filters.sort{|a,b| a[1][:order]<=>b[1][:order]}.each do |filter| %> |
|
|||
6 | <% field = filter[0] |
|
|||
7 | options = filter[1] %> |
|
|||
8 | <tr <%= 'style="display:none;"'.html_safe unless query.has_filter?(field) %> id="tr_<%= field %>" class="filter"> |
|
|||
9 | <td class="field"> |
|
|||
10 | <%= check_box_tag 'f[]', field, query.has_filter?(field), :onclick => "toggle_filter('#{field}');", :id => "cb_#{field}" %> |
|
|||
11 | <label for="cb_<%= field %>"><%= filter[1][:name] || l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) %></label> |
|
|||
12 | </td> |
|
|||
13 | <td class="operator"> |
|
|||
14 | <%= label_tag "operators_#{field}", l(:description_filter), :class => "hidden-for-sighted" %> |
|
|||
15 | <%= select_tag "op[#{field}]", options_for_select(operators_for_select(options[:type]), |
|
|||
16 | query.operator_for(field)), :id => "operators_#{field}", |
|
|||
17 | :onchange => "toggle_operator('#{field}');" %> |
|
|||
18 | </td> |
|
|||
19 | <td class="values"> |
|
|||
20 | <div id="div_values_<%= field %>" style="display:none;"> |
|
|||
21 | <% case options[:type] |
|
|||
22 | when :list, :list_optional, :list_status, :list_subprojects %> |
|
|||
23 | <span class="span_values_<%= field %>"> |
|
|||
24 | <%= select_tag "v[#{field}][]", options_for_select(options[:values], query.values_for(field)), :class => "values_#{field}", :id => "values_#{field}_1", :multiple => (query.values_for(field) && query.values_for(field).length > 1) %> |
|
|||
25 | <%= link_to_function image_tag('bullet_toggle_plus.png'), "toggle_multi_select('values_#{field}_1');" %> |
|
|||
26 | </span> |
|
|||
27 | <% when :date, :date_past %> |
|
|||
28 | <span class="span_values_<%= field %>"><%= text_field_tag "v[#{field}][]", query.value_for(field), :size => 10, :class => "values_#{field}", :id => "values_#{field}_1" %> <%= calendar_for "values_#{field}_1" %></span> |
|
|||
29 | <span class="span_values_<%= field %>"><%= text_field_tag "v[#{field}][]", query.value_for(field, 1), :size => 10, :class => "values_#{field}", :id => "values_#{field}_2" %> <%= calendar_for "values_#{field}_2" %></span> |
|
|||
30 | <span class="span_values_<%= field %>"><%= text_field_tag "v[#{field}][]", query.value_for(field), :size => 3, :class => "values_#{field}" %> <%= l(:label_day_plural) %></span> |
|
|||
31 | <% when :string, :text %> |
|
|||
32 | <span class="span_values_<%= field %>"><%= text_field_tag "v[#{field}][]", query.value_for(field), :class => "values_#{field}", :id => "values_#{field}", :size => 30 %></span> |
|
|||
33 | <% when :integer, :float %> |
|
|||
34 | <span class="span_values_<%= field %>"><%= text_field_tag "v[#{field}][]", query.value_for(field), :class => "values_#{field}", :id => "values_#{field}_1", :size => 6 %></span> |
|
|||
35 | <span class="span_values_<%= field %>"><%= text_field_tag "v[#{field}][]", query.value_for(field, 1), :class => "values_#{field}", :id => "values_#{field}_2", :size => 6 %></span> |
|
|||
36 | <% end %> |
|
|||
37 | </div> |
|
|||
38 | <script type="text/javascript">toggle_filter('<%= field %>');</script> |
|
|||
39 | </td> |
|
|||
40 | </tr> |
|
|||
41 | <% end %> |
|
|||
42 | </table> |
|
18 | </table> | |
43 | </td> |
|
19 | </td> | |
44 | <td class="add-filter"> |
|
20 | <td class="add-filter"> | |
45 | <%= label_tag('add_filter_select', l(:label_filter_add)) %> |
|
21 | <%= label_tag('add_filter_select', l(:label_filter_add)) %> | |
46 | <%= select_tag 'add_filter_select', options_for_select([["",""]] + query.available_filters.sort{|a,b| a[1][:order]<=>b[1][:order]}.collect{|field| [ field[1][:name] || l(("field_"+field[0].to_s.gsub(/_id$/, "")).to_sym), field[0]] unless query.has_filter?(field[0])}.compact), |
|
22 | <%= select_tag 'add_filter_select', filters_options_for_select(query), :name => nil %> | |
47 | :onchange => "add_filter();", |
|
|||
48 | :name => nil %> |
|
|||
49 | </td> |
|
23 | </td> | |
50 | </tr> |
|
24 | </tr> | |
51 | </table> |
|
25 | </table> | |
52 | <%= hidden_field_tag 'f[]', '' %> |
|
26 | <%= hidden_field_tag 'f[]', '' %> | |
53 | <%= javascript_tag '$(document).ready(function(){observeIssueFilters();});' %> |
|
27 | <% include_calendar_headers_tags %> |
@@ -1,52 +1,52 | |||||
1 | <%= error_messages_for 'query' %> |
|
1 | <%= error_messages_for 'query' %> | |
2 |
|
2 | |||
3 | <div class="box"> |
|
3 | <div class="box"> | |
4 | <div class="tabular"> |
|
4 | <div class="tabular"> | |
5 | <p><label for="query_name"><%=l(:field_name)%></label> |
|
5 | <p><label for="query_name"><%=l(:field_name)%></label> | |
6 | <%= text_field 'query', 'name', :size => 80 %></p> |
|
6 | <%= text_field 'query', 'name', :size => 80 %></p> | |
7 |
|
7 | |||
8 | <% if User.current.admin? || User.current.allowed_to?(:manage_public_queries, @project) %> |
|
8 | <% if User.current.admin? || User.current.allowed_to?(:manage_public_queries, @project) %> | |
9 | <p><label for="query_is_public"><%=l(:field_is_public)%></label> |
|
9 | <p><label for="query_is_public"><%=l(:field_is_public)%></label> | |
10 | <%= check_box 'query', 'is_public', |
|
10 | <%= check_box 'query', 'is_public', | |
11 | :onchange => (User.current.admin? ? nil : 'if (this.checked) {$("#query_is_for_all").removeAttr("checked"); $("#query_is_for_all").attr("disabled", true);} else {$("#query_is_for_all").removeAttr("disabled");}') %></p> |
|
11 | :onchange => (User.current.admin? ? nil : 'if (this.checked) {$("#query_is_for_all").removeAttr("checked"); $("#query_is_for_all").attr("disabled", true);} else {$("#query_is_for_all").removeAttr("disabled");}') %></p> | |
12 | <% end %> |
|
12 | <% end %> | |
13 |
|
13 | |||
14 | <p><label for="query_is_for_all"><%=l(:field_is_for_all)%></label> |
|
14 | <p><label for="query_is_for_all"><%=l(:field_is_for_all)%></label> | |
15 | <%= check_box_tag 'query_is_for_all', 1, @query.project.nil?, |
|
15 | <%= check_box_tag 'query_is_for_all', 1, @query.project.nil?, | |
16 | :disabled => (!@query.new_record? && (@query.project.nil? || (@query.is_public? && !User.current.admin?))) %></p> |
|
16 | :disabled => (!@query.new_record? && (@query.project.nil? || (@query.is_public? && !User.current.admin?))) %></p> | |
17 |
|
17 | |||
18 | <p><label for="query_default_columns"><%=l(:label_default_columns)%></label> |
|
18 | <p><label for="query_default_columns"><%=l(:label_default_columns)%></label> | |
19 | <%= check_box_tag 'default_columns', 1, @query.has_default_columns?, :id => 'query_default_columns', |
|
19 | <%= check_box_tag 'default_columns', 1, @query.has_default_columns?, :id => 'query_default_columns', | |
20 | :onclick => 'if (this.checked) {$("#columns").hide();} else {$("#columns").show();}' %></p> |
|
20 | :onclick => 'if (this.checked) {$("#columns").hide();} else {$("#columns").show();}' %></p> | |
21 |
|
21 | |||
22 | <p><label for="query_group_by"><%= l(:field_group_by) %></label> |
|
22 | <p><label for="query_group_by"><%= l(:field_group_by) %></label> | |
23 | <%= select 'query', 'group_by', @query.groupable_columns.collect {|c| [c.caption, c.name.to_s]}, :include_blank => true %></p> |
|
23 | <%= select 'query', 'group_by', @query.groupable_columns.collect {|c| [c.caption, c.name.to_s]}, :include_blank => true %></p> | |
24 | </div> |
|
24 | </div> | |
25 |
|
25 | |||
26 | <fieldset><legend><%= l(:label_filter_plural) %></legend> |
|
26 | <fieldset id="filters"><legend><%= l(:label_filter_plural) %></legend> | |
27 | <%= render :partial => 'queries/filters', :locals => {:query => query}%> |
|
27 | <%= render :partial => 'queries/filters', :locals => {:query => query}%> | |
28 | </fieldset> |
|
28 | </fieldset> | |
29 |
|
29 | |||
30 | <fieldset><legend><%= l(:label_sort) %></legend> |
|
30 | <fieldset><legend><%= l(:label_sort) %></legend> | |
31 | <% 3.times do |i| %> |
|
31 | <% 3.times do |i| %> | |
32 | <%= i+1 %>: |
|
32 | <%= i+1 %>: | |
33 | <%= label_tag "query_sort_criteria_attribute_" + i.to_s, |
|
33 | <%= label_tag "query_sort_criteria_attribute_" + i.to_s, | |
34 | l(:description_query_sort_criteria_attribute), :class => "hidden-for-sighted" %> |
|
34 | l(:description_query_sort_criteria_attribute), :class => "hidden-for-sighted" %> | |
35 | <%= select_tag("query[sort_criteria][#{i}][]", |
|
35 | <%= select_tag("query[sort_criteria][#{i}][]", | |
36 | options_for_select([[]] + query.available_columns.select(&:sortable?).collect {|column| [column.caption, column.name.to_s]}, @query.sort_criteria_key(i)), |
|
36 | options_for_select([[]] + query.available_columns.select(&:sortable?).collect {|column| [column.caption, column.name.to_s]}, @query.sort_criteria_key(i)), | |
37 | :id => "query_sort_criteria_attribute_" + i.to_s)%> |
|
37 | :id => "query_sort_criteria_attribute_" + i.to_s)%> | |
38 | <%= label_tag "query_sort_criteria_direction_" + i.to_s, |
|
38 | <%= label_tag "query_sort_criteria_direction_" + i.to_s, | |
39 | l(:description_query_sort_criteria_direction), :class => "hidden-for-sighted" %> |
|
39 | l(:description_query_sort_criteria_direction), :class => "hidden-for-sighted" %> | |
40 | <%= select_tag("query[sort_criteria][#{i}][]", |
|
40 | <%= select_tag("query[sort_criteria][#{i}][]", | |
41 | options_for_select([[], [l(:label_ascending), 'asc'], [l(:label_descending), 'desc']], @query.sort_criteria_order(i)), |
|
41 | options_for_select([[], [l(:label_ascending), 'asc'], [l(:label_descending), 'desc']], @query.sort_criteria_order(i)), | |
42 | :id => "query_sort_criteria_direction_" + i.to_s) %> |
|
42 | :id => "query_sort_criteria_direction_" + i.to_s) %> | |
43 | <br /> |
|
43 | <br /> | |
44 | <% end %> |
|
44 | <% end %> | |
45 | </fieldset> |
|
45 | </fieldset> | |
46 |
|
46 | |||
47 | <%= content_tag 'fieldset', :id => 'columns', :style => (query.has_default_columns? ? 'display:none;' : nil) do %> |
|
47 | <%= content_tag 'fieldset', :id => 'columns', :style => (query.has_default_columns? ? 'display:none;' : nil) do %> | |
48 | <legend><%= l(:field_column_names) %></legend> |
|
48 | <legend><%= l(:field_column_names) %></legend> | |
49 | <%= render :partial => 'queries/columns', :locals => {:query => query}%> |
|
49 | <%= render :partial => 'queries/columns', :locals => {:query => query}%> | |
50 | <% end %> |
|
50 | <% end %> | |
51 |
|
51 | |||
52 | </div> |
|
52 | </div> |
@@ -1,499 +1,583 | |||||
1 | /* Redmine - project management software |
|
1 | /* Redmine - project management software | |
2 | Copyright (C) 2006-2012 Jean-Philippe Lang */ |
|
2 | Copyright (C) 2006-2012 Jean-Philippe Lang */ | |
3 |
|
3 | |||
4 | function checkAll(id, checked) { |
|
4 | function checkAll(id, checked) { | |
5 | if (checked) { |
|
5 | if (checked) { | |
6 | $('#'+id).find('input[type=checkbox]').attr('checked', true); |
|
6 | $('#'+id).find('input[type=checkbox]').attr('checked', true); | |
7 | } else { |
|
7 | } else { | |
8 | $('#'+id).find('input[type=checkbox]').removeAttr('checked'); |
|
8 | $('#'+id).find('input[type=checkbox]').removeAttr('checked'); | |
9 | } |
|
9 | } | |
10 | } |
|
10 | } | |
11 |
|
11 | |||
12 | function toggleCheckboxesBySelector(selector) { |
|
12 | function toggleCheckboxesBySelector(selector) { | |
13 | var all_checked = true; |
|
13 | var all_checked = true; | |
14 | $(selector).each(function(index) { |
|
14 | $(selector).each(function(index) { | |
15 | if (!$(this).is(':checked')) { all_checked = false; } |
|
15 | if (!$(this).is(':checked')) { all_checked = false; } | |
16 | }); |
|
16 | }); | |
17 | $(selector).attr('checked', !all_checked) |
|
17 | $(selector).attr('checked', !all_checked) | |
18 | } |
|
18 | } | |
19 |
|
19 | |||
20 | function showAndScrollTo(id, focus) { |
|
20 | function showAndScrollTo(id, focus) { | |
21 | $('#'+id).show(); |
|
21 | $('#'+id).show(); | |
22 | if (focus!=null) { |
|
22 | if (focus!=null) { | |
23 | $('#'+focus).focus(); |
|
23 | $('#'+focus).focus(); | |
24 | } |
|
24 | } | |
25 | $('html, body').animate({scrollTop: $('#'+id).offset().top}, 100); |
|
25 | $('html, body').animate({scrollTop: $('#'+id).offset().top}, 100); | |
26 | } |
|
26 | } | |
27 |
|
27 | |||
28 | function toggleRowGroup(el) { |
|
28 | function toggleRowGroup(el) { | |
29 | var tr = $(el).parents('tr').first(); |
|
29 | var tr = $(el).parents('tr').first(); | |
30 | var n = tr.next(); |
|
30 | var n = tr.next(); | |
31 | tr.toggleClass('open'); |
|
31 | tr.toggleClass('open'); | |
32 | while (n.length && !n.hasClass('group')) { |
|
32 | while (n.length && !n.hasClass('group')) { | |
33 | n.toggle(); |
|
33 | n.toggle(); | |
34 | n = n.next('tr'); |
|
34 | n = n.next('tr'); | |
35 | } |
|
35 | } | |
36 | } |
|
36 | } | |
37 |
|
37 | |||
38 | function collapseAllRowGroups(el) { |
|
38 | function collapseAllRowGroups(el) { | |
39 | var tbody = $(el).parents('tbody').first(); |
|
39 | var tbody = $(el).parents('tbody').first(); | |
40 | tbody.children('tr').each(function(index) { |
|
40 | tbody.children('tr').each(function(index) { | |
41 | if ($(this).hasClass('group')) { |
|
41 | if ($(this).hasClass('group')) { | |
42 | $(this).removeClass('open'); |
|
42 | $(this).removeClass('open'); | |
43 | } else { |
|
43 | } else { | |
44 | $(this).hide(); |
|
44 | $(this).hide(); | |
45 | } |
|
45 | } | |
46 | }); |
|
46 | }); | |
47 | } |
|
47 | } | |
48 |
|
48 | |||
49 | function expandAllRowGroups(el) { |
|
49 | function expandAllRowGroups(el) { | |
50 | var tbody = $(el).parents('tbody').first(); |
|
50 | var tbody = $(el).parents('tbody').first(); | |
51 | tbody.children('tr').each(function(index) { |
|
51 | tbody.children('tr').each(function(index) { | |
52 | if ($(this).hasClass('group')) { |
|
52 | if ($(this).hasClass('group')) { | |
53 | $(this).addClass('open'); |
|
53 | $(this).addClass('open'); | |
54 | } else { |
|
54 | } else { | |
55 | $(this).show(); |
|
55 | $(this).show(); | |
56 | } |
|
56 | } | |
57 | }); |
|
57 | }); | |
58 | } |
|
58 | } | |
59 |
|
59 | |||
60 | function toggleAllRowGroups(el) { |
|
60 | function toggleAllRowGroups(el) { | |
61 | var tr = $(el).parents('tr').first(); |
|
61 | var tr = $(el).parents('tr').first(); | |
62 | if (tr.hasClass('open')) { |
|
62 | if (tr.hasClass('open')) { | |
63 | collapseAllRowGroups(el); |
|
63 | collapseAllRowGroups(el); | |
64 | } else { |
|
64 | } else { | |
65 | expandAllRowGroups(el); |
|
65 | expandAllRowGroups(el); | |
66 | } |
|
66 | } | |
67 | } |
|
67 | } | |
68 |
|
68 | |||
69 | function toggleFieldset(el) { |
|
69 | function toggleFieldset(el) { | |
70 | var fieldset = $(el).parents('fieldset').first(); |
|
70 | var fieldset = $(el).parents('fieldset').first(); | |
71 | fieldset.toggleClass('collapsed'); |
|
71 | fieldset.toggleClass('collapsed'); | |
72 | fieldset.children('div').toggle(); |
|
72 | fieldset.children('div').toggle(); | |
73 | } |
|
73 | } | |
74 |
|
74 | |||
75 | function hideFieldset(el) { |
|
75 | function hideFieldset(el) { | |
76 | var fieldset = $(el).parents('fieldset').first(); |
|
76 | var fieldset = $(el).parents('fieldset').first(); | |
77 | fieldset.toggleClass('collapsed'); |
|
77 | fieldset.toggleClass('collapsed'); | |
78 | fieldset.children('div').hide(); |
|
78 | fieldset.children('div').hide(); | |
79 | } |
|
79 | } | |
80 |
|
80 | |||
81 |
function |
|
81 | function initFilters(){ | |
82 |
|
|
82 | $('#add_filter_select').change(function(){ | |
83 | var field = select.val(); |
|
83 | addFilter($(this).val(), '', []); | |
84 | $('#tr_'+field).show(); |
|
84 | }); | |
85 | var check_box = $('#cb_' + field); |
|
85 | $('#filters-table td.field input[type=checkbox]').each(function(){ | |
86 | check_box.attr('checked', true); |
|
86 | toggleFilter($(this).val()); | |
87 | toggle_filter(field); |
|
87 | }); | |
88 | select.val(''); |
|
88 | $('#filters-table td.field input[type=checkbox]').live('click',function(){ | |
89 |
|
89 | toggleFilter($(this).val()); | ||
90 | select.children('option').each(function(index) { |
|
90 | }); | |
|
91 | $('#filters-table .toggle-multiselect').live('click',function(){ | |||
|
92 | toggleMultiSelect($(this).siblings('select')); | |||
|
93 | }); | |||
|
94 | $('#filters-table input[type=text]').live('keypress', function(e){ | |||
|
95 | if (e.keyCode == 13) submit_query_form("query_form"); | |||
|
96 | }); | |||
|
97 | } | |||
|
98 | ||||
|
99 | function addFilter(field, operator, values) { | |||
|
100 | var fieldId = field.replace('.', '_'); | |||
|
101 | var tr = $('#tr_'+fieldId); | |||
|
102 | if (tr.length > 0) { | |||
|
103 | tr.show(); | |||
|
104 | } else { | |||
|
105 | buildFilterRow(field, operator, values); | |||
|
106 | } | |||
|
107 | $('#cb_'+fieldId).attr('checked', true); | |||
|
108 | toggleFilter(field); | |||
|
109 | $('#add_filter_select').val('').children('option').each(function(){ | |||
91 | if ($(this).attr('value') == field) { |
|
110 | if ($(this).attr('value') == field) { | |
92 | $(this).attr('disabled', true); |
|
111 | $(this).attr('disabled', true); | |
93 | } |
|
112 | } | |
94 | }); |
|
113 | }); | |
95 | } |
|
114 | } | |
96 |
|
115 | |||
97 | function toggle_filter(field) { |
|
116 | function buildFilterRow(field, operator, values) { | |
98 | check_box = $('#cb_' + field); |
|
117 | var fieldId = field.replace('.', '_'); | |
99 | if (check_box.is(':checked')) { |
|
118 | var filterTable = $("#filters-table"); | |
100 | $("#operators_" + field).show().removeAttr('disabled'); |
|
119 | var filterOptions = availableFilters[field]; | |
101 | toggle_operator(field); |
|
120 | var operators = operatorByType[filterOptions['type']]; | |
|
121 | var filterValues = filterOptions['values']; | |||
|
122 | var i, select; | |||
|
123 | ||||
|
124 | var tr = $('<tr class="filter">').attr('id', 'tr_'+fieldId).html( | |||
|
125 | '<td class="field"><input checked="checked" id="cb_'+fieldId+'" name="f[]" value="'+field+'" type="checkbox"><label for="cb_'+fieldId+'"> '+filterOptions['name']+'</label></td>' + | |||
|
126 | '<td class="operator"><select id="operators_'+fieldId+'" name="op['+field+']"></td>' + | |||
|
127 | '<td class="values"></td>' | |||
|
128 | ); | |||
|
129 | filterTable.append(tr); | |||
|
130 | ||||
|
131 | select = tr.find('td.operator select'); | |||
|
132 | for (i=0;i<operators.length;i++){ | |||
|
133 | var option = $('<option>').val(operators[i]).html(operatorLabels[operators[i]]); | |||
|
134 | if (operators[i] == operator) {option.attr('selected', true)}; | |||
|
135 | select.append(option); | |||
|
136 | } | |||
|
137 | select.change(function(){toggleOperator(field)}); | |||
|
138 | ||||
|
139 | switch (filterOptions['type']){ | |||
|
140 | case "list": | |||
|
141 | case "list_optional": | |||
|
142 | case "list_status": | |||
|
143 | case "list_subprojects": | |||
|
144 | tr.find('td.values').append( | |||
|
145 | '<span style="display:none;"><select class="value" id="values_'+fieldId+'_1" name="v['+field+'][]"></select>' + | |||
|
146 | ' <span class="toggle-multiselect"> </span></span>' | |||
|
147 | ); | |||
|
148 | select = tr.find('td.values select'); | |||
|
149 | if (values.length > 1) {select.attr('multiple', true)}; | |||
|
150 | for (i=0;i<filterValues.length;i++){ | |||
|
151 | var filterValue = filterValues[i]; | |||
|
152 | var option = $('<option>'); | |||
|
153 | if ($.isArray(filterValue)) { | |||
|
154 | option.val(filterValue[1]).html(filterValue[0]); | |||
|
155 | } else { | |||
|
156 | option.val(filterValue).html(filterValue); | |||
|
157 | } | |||
|
158 | if (values.indexOf(filterValues[i][1]) > -1) {option.attr('selected', true)}; | |||
|
159 | select.append(option); | |||
|
160 | } | |||
|
161 | break; | |||
|
162 | case "date": | |||
|
163 | case "date_past": | |||
|
164 | tr.find('td.values').append( | |||
|
165 | '<span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'_1" size="10" class="value date_value" value="'+values[0]+'" /></span>' + | |||
|
166 | ' <span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'_2" size="10" class="value date_value" value="'+values[1]+'" /></span>' + | |||
|
167 | ' <span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'" size="3" class="value" value="'+values[0]+'" /> '+labelDayPlural+'</span>' | |||
|
168 | ); | |||
|
169 | $('#values_'+fieldId+'_1').val(values[0]).datepicker(datepickerOptions); | |||
|
170 | $('#values_'+fieldId+'_2').val(values[1]).datepicker(datepickerOptions); | |||
|
171 | $('#values_'+fieldId).val(values[0]); | |||
|
172 | break; | |||
|
173 | case "string": | |||
|
174 | case "text": | |||
|
175 | tr.find('td.values').append( | |||
|
176 | '<span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'" size="30" class="value" value="'+values[0]+'" /></span>' | |||
|
177 | ); | |||
|
178 | $('#values_'+fieldId).val(values[0]); | |||
|
179 | break; | |||
|
180 | case "integer": | |||
|
181 | case "float": | |||
|
182 | tr.find('td.values').append( | |||
|
183 | '<span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'_1" size="6" class="value" value="'+values[0]+'" /></span>' + | |||
|
184 | ' <span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'_2" size="6" class="value" value="'+values[1]+'" /></span>' | |||
|
185 | ); | |||
|
186 | $('#values_'+fieldId+'_1').val(values[0]); | |||
|
187 | $('#values_'+fieldId+'_2').val(values[1]); | |||
|
188 | break; | |||
|
189 | } | |||
|
190 | } | |||
|
191 | ||||
|
192 | function toggleFilter(field) { | |||
|
193 | var fieldId = field.replace('.', '_'); | |||
|
194 | if ($('#cb_' + fieldId).is(':checked')) { | |||
|
195 | $("#operators_" + fieldId).show().removeAttr('disabled'); | |||
|
196 | toggleOperator(field); | |||
102 | } else { |
|
197 | } else { | |
103 | $("#operators_" + field).hide().attr('disabled', true); |
|
198 | $("#operators_" + fieldId).hide().attr('disabled', true); | |
104 | enableValues(field, []); |
|
199 | enableValues(field, []); | |
105 | } |
|
200 | } | |
106 | } |
|
201 | } | |
107 |
|
202 | |||
108 | function enableValues(field, indexes) { |
|
203 | function enableValues(field, indexes) { | |
109 | $(".values_" + field).each(function(index) { |
|
204 | var fieldId = field.replace('.', '_'); | |
|
205 | $('#tr_'+fieldId+' td.values .value').each(function(index) { | |||
110 | if (indexes.indexOf(index) >= 0) { |
|
206 | if (indexes.indexOf(index) >= 0) { | |
111 | $(this).removeAttr('disabled'); |
|
207 | $(this).removeAttr('disabled'); | |
112 | $(this).parents('span').first().show(); |
|
208 | $(this).parents('span').first().show(); | |
113 | } else { |
|
209 | } else { | |
114 | $(this).val(''); |
|
210 | $(this).val(''); | |
115 | $(this).attr('disabled', true); |
|
211 | $(this).attr('disabled', true); | |
116 | $(this).parents('span').first().hide(); |
|
212 | $(this).parents('span').first().hide(); | |
117 | } |
|
213 | } | |
118 |
|
214 | |||
119 | if ($(this).hasClass('group')) { |
|
215 | if ($(this).hasClass('group')) { | |
120 | $(this).addClass('open'); |
|
216 | $(this).addClass('open'); | |
121 | } else { |
|
217 | } else { | |
122 | $(this).show(); |
|
218 | $(this).show(); | |
123 | } |
|
219 | } | |
124 | }); |
|
220 | }); | |
125 |
|
||||
126 | if (indexes.length > 0) { |
|
|||
127 | $("#div_values_" + field).show(); |
|
|||
128 | } else { |
|
|||
129 | $("#div_values_" + field).hide(); |
|
|||
130 | } |
|
|||
131 | } |
|
221 | } | |
132 |
|
222 | |||
133 |
function toggle |
|
223 | function toggleOperator(field) { | |
134 | operator = $("#operators_" + field); |
|
224 | var fieldId = field.replace('.', '_'); | |
|
225 | var operator = $("#operators_" + fieldId); | |||
135 | switch (operator.val()) { |
|
226 | switch (operator.val()) { | |
136 | case "!*": |
|
227 | case "!*": | |
137 | case "*": |
|
228 | case "*": | |
138 | case "t": |
|
229 | case "t": | |
139 | case "w": |
|
230 | case "w": | |
140 | case "o": |
|
231 | case "o": | |
141 | case "c": |
|
232 | case "c": | |
142 | enableValues(field, []); |
|
233 | enableValues(field, []); | |
143 | break; |
|
234 | break; | |
144 | case "><": |
|
235 | case "><": | |
145 | enableValues(field, [0,1]); |
|
236 | enableValues(field, [0,1]); | |
146 | break; |
|
237 | break; | |
147 | case "<t+": |
|
238 | case "<t+": | |
148 | case ">t+": |
|
239 | case ">t+": | |
149 | case "t+": |
|
240 | case "t+": | |
150 | case ">t-": |
|
241 | case ">t-": | |
151 | case "<t-": |
|
242 | case "<t-": | |
152 | case "t-": |
|
243 | case "t-": | |
153 | enableValues(field, [2]); |
|
244 | enableValues(field, [2]); | |
154 | break; |
|
245 | break; | |
155 | default: |
|
246 | default: | |
156 | enableValues(field, [0]); |
|
247 | enableValues(field, [0]); | |
157 | break; |
|
248 | break; | |
158 | } |
|
249 | } | |
159 | } |
|
250 | } | |
160 |
|
251 | |||
161 |
function toggle |
|
252 | function toggleMultiSelect(el) { | |
162 | var select = $('#'+id); |
|
253 | if (el.attr('multiple')) { | |
163 |
|
|
254 | el.removeAttr('multiple'); | |
164 | select.removeAttr('multiple'); |
|
|||
165 | } else { |
|
255 | } else { | |
166 |
|
|
256 | el.attr('multiple', true); | |
167 | } |
|
257 | } | |
168 | } |
|
258 | } | |
169 |
|
259 | |||
170 | function submit_query_form(id) { |
|
260 | function submit_query_form(id) { | |
171 | selectAllOptions("selected_columns"); |
|
261 | selectAllOptions("selected_columns"); | |
172 | $('#'+id).submit(); |
|
262 | $('#'+id).submit(); | |
173 | } |
|
263 | } | |
174 |
|
264 | |||
175 | function observeIssueFilters() { |
|
|||
176 | $('#query_form input[type=text]').keypress(function(e){ |
|
|||
177 | if (e.keyCode == 13) submit_query_form("query_form"); |
|
|||
178 | }); |
|
|||
179 | } |
|
|||
180 |
|
||||
181 | var fileFieldCount = 1; |
|
265 | var fileFieldCount = 1; | |
182 | function addFileField() { |
|
266 | function addFileField() { | |
183 | var fields = $('#attachments_fields'); |
|
267 | var fields = $('#attachments_fields'); | |
184 | if (fields.children().length >= 10) return false; |
|
268 | if (fields.children().length >= 10) return false; | |
185 | fileFieldCount++; |
|
269 | fileFieldCount++; | |
186 | var s = fields.children('span').first().clone(); |
|
270 | var s = fields.children('span').first().clone(); | |
187 | s.children('input.file').attr('name', "attachments[" + fileFieldCount + "][file]").val(''); |
|
271 | s.children('input.file').attr('name', "attachments[" + fileFieldCount + "][file]").val(''); | |
188 | s.children('input.description').attr('name', "attachments[" + fileFieldCount + "][description]").val(''); |
|
272 | s.children('input.description').attr('name', "attachments[" + fileFieldCount + "][description]").val(''); | |
189 | fields.append(s); |
|
273 | fields.append(s); | |
190 | } |
|
274 | } | |
191 |
|
275 | |||
192 | function removeFileField(el) { |
|
276 | function removeFileField(el) { | |
193 | var fields = $('#attachments_fields'); |
|
277 | var fields = $('#attachments_fields'); | |
194 | var s = $(el).parents('span').first(); |
|
278 | var s = $(el).parents('span').first(); | |
195 | if (fields.children().length > 1) { |
|
279 | if (fields.children().length > 1) { | |
196 | s.remove(); |
|
280 | s.remove(); | |
197 | } else { |
|
281 | } else { | |
198 | s.children('input.file').val(''); |
|
282 | s.children('input.file').val(''); | |
199 | s.children('input.description').val(''); |
|
283 | s.children('input.description').val(''); | |
200 | } |
|
284 | } | |
201 | } |
|
285 | } | |
202 |
|
286 | |||
203 | function checkFileSize(el, maxSize, message) { |
|
287 | function checkFileSize(el, maxSize, message) { | |
204 | var files = el.files; |
|
288 | var files = el.files; | |
205 | if (files) { |
|
289 | if (files) { | |
206 | for (var i=0; i<files.length; i++) { |
|
290 | for (var i=0; i<files.length; i++) { | |
207 | if (files[i].size > maxSize) { |
|
291 | if (files[i].size > maxSize) { | |
208 | alert(message); |
|
292 | alert(message); | |
209 | el.value = ""; |
|
293 | el.value = ""; | |
210 | } |
|
294 | } | |
211 | } |
|
295 | } | |
212 | } |
|
296 | } | |
213 | } |
|
297 | } | |
214 |
|
298 | |||
215 | function showTab(name) { |
|
299 | function showTab(name) { | |
216 | $('div#content .tab-content').hide(); |
|
300 | $('div#content .tab-content').hide(); | |
217 | $('div.tabs a').removeClass('selected'); |
|
301 | $('div.tabs a').removeClass('selected'); | |
218 | $('#tab-content-' + name).show(); |
|
302 | $('#tab-content-' + name).show(); | |
219 | $('#tab-' + name).addClass('selected'); |
|
303 | $('#tab-' + name).addClass('selected'); | |
220 | return false; |
|
304 | return false; | |
221 | } |
|
305 | } | |
222 |
|
306 | |||
223 | function moveTabRight(el) { |
|
307 | function moveTabRight(el) { | |
224 | var lis = $(el).parents('div.tabs').first().find('ul').children(); |
|
308 | var lis = $(el).parents('div.tabs').first().find('ul').children(); | |
225 | var tabsWidth = 0; |
|
309 | var tabsWidth = 0; | |
226 | var i = 0; |
|
310 | var i = 0; | |
227 | lis.each(function(){ |
|
311 | lis.each(function(){ | |
228 | if ($(this).is(':visible')) { |
|
312 | if ($(this).is(':visible')) { | |
229 | tabsWidth += $(this).width() + 6; |
|
313 | tabsWidth += $(this).width() + 6; | |
230 | } |
|
314 | } | |
231 | }); |
|
315 | }); | |
232 | if (tabsWidth < $(el).parents('div.tabs').first().width() - 60) { return; } |
|
316 | if (tabsWidth < $(el).parents('div.tabs').first().width() - 60) { return; } | |
233 | while (i<lis.length && !lis.eq(i).is(':visible')) { i++; } |
|
317 | while (i<lis.length && !lis.eq(i).is(':visible')) { i++; } | |
234 | lis.eq(i).hide(); |
|
318 | lis.eq(i).hide(); | |
235 | } |
|
319 | } | |
236 |
|
320 | |||
237 | function moveTabLeft(el) { |
|
321 | function moveTabLeft(el) { | |
238 | var lis = $(el).parents('div.tabs').first().find('ul').children(); |
|
322 | var lis = $(el).parents('div.tabs').first().find('ul').children(); | |
239 | var i = 0; |
|
323 | var i = 0; | |
240 | while (i<lis.length && !lis.eq(i).is(':visible')) { i++; } |
|
324 | while (i<lis.length && !lis.eq(i).is(':visible')) { i++; } | |
241 | if (i>0) { |
|
325 | if (i>0) { | |
242 | lis.eq(i-1).show(); |
|
326 | lis.eq(i-1).show(); | |
243 | } |
|
327 | } | |
244 | } |
|
328 | } | |
245 |
|
329 | |||
246 | function displayTabsButtons() { |
|
330 | function displayTabsButtons() { | |
247 | var lis; |
|
331 | var lis; | |
248 | var tabsWidth = 0; |
|
332 | var tabsWidth = 0; | |
249 | var el; |
|
333 | var el; | |
250 | $('div.tabs').each(function() { |
|
334 | $('div.tabs').each(function() { | |
251 | el = $(this); |
|
335 | el = $(this); | |
252 | lis = el.find('ul').children(); |
|
336 | lis = el.find('ul').children(); | |
253 | lis.each(function(){ |
|
337 | lis.each(function(){ | |
254 | if ($(this).is(':visible')) { |
|
338 | if ($(this).is(':visible')) { | |
255 | tabsWidth += $(this).width() + 6; |
|
339 | tabsWidth += $(this).width() + 6; | |
256 | } |
|
340 | } | |
257 | }); |
|
341 | }); | |
258 | if ((tabsWidth < el.width() - 60) && (lis.first().is(':visible'))) { |
|
342 | if ((tabsWidth < el.width() - 60) && (lis.first().is(':visible'))) { | |
259 | el.find('div.tabs-buttons').hide(); |
|
343 | el.find('div.tabs-buttons').hide(); | |
260 | } else { |
|
344 | } else { | |
261 | el.find('div.tabs-buttons').show(); |
|
345 | el.find('div.tabs-buttons').show(); | |
262 | } |
|
346 | } | |
263 | }); |
|
347 | }); | |
264 | } |
|
348 | } | |
265 |
|
349 | |||
266 | function setPredecessorFieldsVisibility() { |
|
350 | function setPredecessorFieldsVisibility() { | |
267 | var relationType = $('#relation_relation_type'); |
|
351 | var relationType = $('#relation_relation_type'); | |
268 | if (relationType.val() == "precedes" || relationType.val() == "follows") { |
|
352 | if (relationType.val() == "precedes" || relationType.val() == "follows") { | |
269 | $('#predecessor_fields').show(); |
|
353 | $('#predecessor_fields').show(); | |
270 | } else { |
|
354 | } else { | |
271 | $('#predecessor_fields').hide(); |
|
355 | $('#predecessor_fields').hide(); | |
272 | } |
|
356 | } | |
273 | } |
|
357 | } | |
274 |
|
358 | |||
275 | function showModal(id, width) { |
|
359 | function showModal(id, width) { | |
276 | var el = $('#'+id).first(); |
|
360 | var el = $('#'+id).first(); | |
277 | if (el.length == 0 || el.is(':visible')) {return;} |
|
361 | if (el.length == 0 || el.is(':visible')) {return;} | |
278 | var title = el.find('h3.title').text(); |
|
362 | var title = el.find('h3.title').text(); | |
279 | el.dialog({ |
|
363 | el.dialog({ | |
280 | width: width, |
|
364 | width: width, | |
281 | modal: true, |
|
365 | modal: true, | |
282 | resizable: false, |
|
366 | resizable: false, | |
283 | dialogClass: 'modal', |
|
367 | dialogClass: 'modal', | |
284 | title: title |
|
368 | title: title | |
285 | }); |
|
369 | }); | |
286 | el.find("input[type=text], input[type=submit]").first().focus(); |
|
370 | el.find("input[type=text], input[type=submit]").first().focus(); | |
287 | } |
|
371 | } | |
288 |
|
372 | |||
289 | function hideModal(el) { |
|
373 | function hideModal(el) { | |
290 | var modal; |
|
374 | var modal; | |
291 | if (el) { |
|
375 | if (el) { | |
292 | modal = $(el).parents('.ui-dialog-content'); |
|
376 | modal = $(el).parents('.ui-dialog-content'); | |
293 | } else { |
|
377 | } else { | |
294 | modal = $('#ajax-modal'); |
|
378 | modal = $('#ajax-modal'); | |
295 | } |
|
379 | } | |
296 | modal.dialog("close"); |
|
380 | modal.dialog("close"); | |
297 | } |
|
381 | } | |
298 |
|
382 | |||
299 | function submitPreview(url, form, target) { |
|
383 | function submitPreview(url, form, target) { | |
300 | $.ajax({ |
|
384 | $.ajax({ | |
301 | url: url, |
|
385 | url: url, | |
302 | type: 'post', |
|
386 | type: 'post', | |
303 | data: $('#'+form).serialize(), |
|
387 | data: $('#'+form).serialize(), | |
304 | success: function(data){ |
|
388 | success: function(data){ | |
305 | $('#'+target).html(data); |
|
389 | $('#'+target).html(data); | |
306 | } |
|
390 | } | |
307 | }); |
|
391 | }); | |
308 | } |
|
392 | } | |
309 |
|
393 | |||
310 | function collapseScmEntry(id) { |
|
394 | function collapseScmEntry(id) { | |
311 | $('.'+id).each(function() { |
|
395 | $('.'+id).each(function() { | |
312 | if ($(this).hasClass('open')) { |
|
396 | if ($(this).hasClass('open')) { | |
313 | collapseScmEntry($(this).attr('id')); |
|
397 | collapseScmEntry($(this).attr('id')); | |
314 | } |
|
398 | } | |
315 | $(this).hide(); |
|
399 | $(this).hide(); | |
316 | }); |
|
400 | }); | |
317 | $('#'+id).removeClass('open'); |
|
401 | $('#'+id).removeClass('open'); | |
318 | } |
|
402 | } | |
319 |
|
403 | |||
320 | function expandScmEntry(id) { |
|
404 | function expandScmEntry(id) { | |
321 | $('.'+id).each(function() { |
|
405 | $('.'+id).each(function() { | |
322 | $(this).show(); |
|
406 | $(this).show(); | |
323 | if ($(this).hasClass('loaded') && !$(this).hasClass('collapsed')) { |
|
407 | if ($(this).hasClass('loaded') && !$(this).hasClass('collapsed')) { | |
324 | expandScmEntry($(this).attr('id')); |
|
408 | expandScmEntry($(this).attr('id')); | |
325 | } |
|
409 | } | |
326 | }); |
|
410 | }); | |
327 | $('#'+id).addClass('open'); |
|
411 | $('#'+id).addClass('open'); | |
328 | } |
|
412 | } | |
329 |
|
413 | |||
330 | function scmEntryClick(id, url) { |
|
414 | function scmEntryClick(id, url) { | |
331 | el = $('#'+id); |
|
415 | el = $('#'+id); | |
332 | if (el.hasClass('open')) { |
|
416 | if (el.hasClass('open')) { | |
333 | collapseScmEntry(id); |
|
417 | collapseScmEntry(id); | |
334 | el.addClass('collapsed'); |
|
418 | el.addClass('collapsed'); | |
335 | return false; |
|
419 | return false; | |
336 | } else if (el.hasClass('loaded')) { |
|
420 | } else if (el.hasClass('loaded')) { | |
337 | expandScmEntry(id); |
|
421 | expandScmEntry(id); | |
338 | el.removeClass('collapsed'); |
|
422 | el.removeClass('collapsed'); | |
339 | return false; |
|
423 | return false; | |
340 | } |
|
424 | } | |
341 | if (el.hasClass('loading')) { |
|
425 | if (el.hasClass('loading')) { | |
342 | return false; |
|
426 | return false; | |
343 | } |
|
427 | } | |
344 | el.addClass('loading'); |
|
428 | el.addClass('loading'); | |
345 | $.ajax({ |
|
429 | $.ajax({ | |
346 | url: url, |
|
430 | url: url, | |
347 | success: function(data){ |
|
431 | success: function(data){ | |
348 | el.after(data); |
|
432 | el.after(data); | |
349 | el.addClass('open').addClass('loaded').removeClass('loading'); |
|
433 | el.addClass('open').addClass('loaded').removeClass('loading'); | |
350 | } |
|
434 | } | |
351 | }); |
|
435 | }); | |
352 | return true; |
|
436 | return true; | |
353 | } |
|
437 | } | |
354 |
|
438 | |||
355 | function randomKey(size) { |
|
439 | function randomKey(size) { | |
356 | var chars = new Array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'); |
|
440 | var chars = new Array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'); | |
357 | var key = ''; |
|
441 | var key = ''; | |
358 | for (i = 0; i < size; i++) { |
|
442 | for (i = 0; i < size; i++) { | |
359 | key += chars[Math.floor(Math.random() * chars.length)]; |
|
443 | key += chars[Math.floor(Math.random() * chars.length)]; | |
360 | } |
|
444 | } | |
361 | return key; |
|
445 | return key; | |
362 | } |
|
446 | } | |
363 |
|
447 | |||
364 | // Can't use Rails' remote select because we need the form data |
|
448 | // Can't use Rails' remote select because we need the form data | |
365 | function updateIssueFrom(url) { |
|
449 | function updateIssueFrom(url) { | |
366 | $.ajax({ |
|
450 | $.ajax({ | |
367 | url: url, |
|
451 | url: url, | |
368 | type: 'post', |
|
452 | type: 'post', | |
369 | data: $('#issue-form').serialize() |
|
453 | data: $('#issue-form').serialize() | |
370 | }); |
|
454 | }); | |
371 | } |
|
455 | } | |
372 |
|
456 | |||
373 | function updateBulkEditFrom(url) { |
|
457 | function updateBulkEditFrom(url) { | |
374 | $.ajax({ |
|
458 | $.ajax({ | |
375 | url: url, |
|
459 | url: url, | |
376 | type: 'post', |
|
460 | type: 'post', | |
377 | data: $('#bulk_edit_form').serialize() |
|
461 | data: $('#bulk_edit_form').serialize() | |
378 | }); |
|
462 | }); | |
379 | } |
|
463 | } | |
380 |
|
464 | |||
381 | function observeAutocompleteField(fieldId, url) { |
|
465 | function observeAutocompleteField(fieldId, url) { | |
382 | $('#'+fieldId).autocomplete({ |
|
466 | $('#'+fieldId).autocomplete({ | |
383 | source: url, |
|
467 | source: url, | |
384 | minLength: 2, |
|
468 | minLength: 2, | |
385 | }); |
|
469 | }); | |
386 | } |
|
470 | } | |
387 |
|
471 | |||
388 | function observeSearchfield(fieldId, targetId, url) { |
|
472 | function observeSearchfield(fieldId, targetId, url) { | |
389 | $('#'+fieldId).each(function() { |
|
473 | $('#'+fieldId).each(function() { | |
390 | var $this = $(this); |
|
474 | var $this = $(this); | |
391 | $this.attr('data-value-was', $this.val()); |
|
475 | $this.attr('data-value-was', $this.val()); | |
392 | var check = function() { |
|
476 | var check = function() { | |
393 | var val = $this.val(); |
|
477 | var val = $this.val(); | |
394 | if ($this.attr('data-value-was') != val){ |
|
478 | if ($this.attr('data-value-was') != val){ | |
395 | $this.attr('data-value-was', val); |
|
479 | $this.attr('data-value-was', val); | |
396 | if (val != '') { |
|
480 | if (val != '') { | |
397 | $.ajax({ |
|
481 | $.ajax({ | |
398 | url: url, |
|
482 | url: url, | |
399 | type: 'get', |
|
483 | type: 'get', | |
400 | data: {q: $this.val()}, |
|
484 | data: {q: $this.val()}, | |
401 | success: function(data){ $('#'+targetId).html(data); }, |
|
485 | success: function(data){ $('#'+targetId).html(data); }, | |
402 | beforeSend: function(){ $this.addClass('ajax-loading'); }, |
|
486 | beforeSend: function(){ $this.addClass('ajax-loading'); }, | |
403 | complete: function(){ $this.removeClass('ajax-loading'); } |
|
487 | complete: function(){ $this.removeClass('ajax-loading'); } | |
404 | }); |
|
488 | }); | |
405 | } |
|
489 | } | |
406 | } |
|
490 | } | |
407 | }; |
|
491 | }; | |
408 | var reset = function() { |
|
492 | var reset = function() { | |
409 | if (timer) { |
|
493 | if (timer) { | |
410 | clearInterval(timer); |
|
494 | clearInterval(timer); | |
411 | timer = setInterval(check, 300); |
|
495 | timer = setInterval(check, 300); | |
412 | } |
|
496 | } | |
413 | }; |
|
497 | }; | |
414 | var timer = setInterval(check, 300); |
|
498 | var timer = setInterval(check, 300); | |
415 | $this.bind('keyup click mousemove', reset); |
|
499 | $this.bind('keyup click mousemove', reset); | |
416 | }); |
|
500 | }); | |
417 | } |
|
501 | } | |
418 |
|
502 | |||
419 | function observeProjectModules() { |
|
503 | function observeProjectModules() { | |
420 | var f = function() { |
|
504 | var f = function() { | |
421 | /* Hides trackers and issues custom fields on the new project form when issue_tracking module is disabled */ |
|
505 | /* Hides trackers and issues custom fields on the new project form when issue_tracking module is disabled */ | |
422 | if ($('#project_enabled_module_names_issue_tracking').attr('checked')) { |
|
506 | if ($('#project_enabled_module_names_issue_tracking').attr('checked')) { | |
423 | $('#project_trackers').show(); |
|
507 | $('#project_trackers').show(); | |
424 | }else{ |
|
508 | }else{ | |
425 | $('#project_trackers').hide(); |
|
509 | $('#project_trackers').hide(); | |
426 | } |
|
510 | } | |
427 | }; |
|
511 | }; | |
428 |
|
512 | |||
429 | $(window).load(f); |
|
513 | $(window).load(f); | |
430 | $('#project_enabled_module_names_issue_tracking').change(f); |
|
514 | $('#project_enabled_module_names_issue_tracking').change(f); | |
431 | } |
|
515 | } | |
432 |
|
516 | |||
433 | function initMyPageSortable(list, url) { |
|
517 | function initMyPageSortable(list, url) { | |
434 | $('#list-'+list).sortable({ |
|
518 | $('#list-'+list).sortable({ | |
435 | connectWith: '.block-receiver', |
|
519 | connectWith: '.block-receiver', | |
436 | tolerance: 'pointer', |
|
520 | tolerance: 'pointer', | |
437 | update: function(){ |
|
521 | update: function(){ | |
438 | $.ajax({ |
|
522 | $.ajax({ | |
439 | url: url, |
|
523 | url: url, | |
440 | type: 'post', |
|
524 | type: 'post', | |
441 | data: {'blocks': $.map($('#list-'+list).children(), function(el){return $(el).attr('id');})} |
|
525 | data: {'blocks': $.map($('#list-'+list).children(), function(el){return $(el).attr('id');})} | |
442 | }); |
|
526 | }); | |
443 | } |
|
527 | } | |
444 | }); |
|
528 | }); | |
445 | $("#list-top, #list-left, #list-right").disableSelection(); |
|
529 | $("#list-top, #list-left, #list-right").disableSelection(); | |
446 | } |
|
530 | } | |
447 |
|
531 | |||
448 | var warnLeavingUnsavedMessage; |
|
532 | var warnLeavingUnsavedMessage; | |
449 | function warnLeavingUnsaved(message) { |
|
533 | function warnLeavingUnsaved(message) { | |
450 | warnLeavingUnsavedMessage = message; |
|
534 | warnLeavingUnsavedMessage = message; | |
451 |
|
535 | |||
452 | $('form').submit(function(){ |
|
536 | $('form').submit(function(){ | |
453 | $('textarea').removeData('changed'); |
|
537 | $('textarea').removeData('changed'); | |
454 | }); |
|
538 | }); | |
455 | $('textarea').change(function(){ |
|
539 | $('textarea').change(function(){ | |
456 | $(this).data('changed', 'changed'); |
|
540 | $(this).data('changed', 'changed'); | |
457 | }); |
|
541 | }); | |
458 | window.onbeforeunload = function(){ |
|
542 | window.onbeforeunload = function(){ | |
459 | var warn = false; |
|
543 | var warn = false; | |
460 | $('textarea').blur().each(function(){ |
|
544 | $('textarea').blur().each(function(){ | |
461 | if ($(this).data('changed')) { |
|
545 | if ($(this).data('changed')) { | |
462 | warn = true; |
|
546 | warn = true; | |
463 | } |
|
547 | } | |
464 | }); |
|
548 | }); | |
465 | if (warn) {return warnLeavingUnsavedMessage;} |
|
549 | if (warn) {return warnLeavingUnsavedMessage;} | |
466 | }; |
|
550 | }; | |
467 | }; |
|
551 | }; | |
468 |
|
552 | |||
469 | $(document).ready(function(){ |
|
553 | $(document).ready(function(){ | |
470 | $('#ajax-indicator').bind('ajaxSend', function(){ |
|
554 | $('#ajax-indicator').bind('ajaxSend', function(){ | |
471 | if ($('.ajax-loading').length == 0) { |
|
555 | if ($('.ajax-loading').length == 0) { | |
472 | $('#ajax-indicator').show(); |
|
556 | $('#ajax-indicator').show(); | |
473 | } |
|
557 | } | |
474 | }); |
|
558 | }); | |
475 | $('#ajax-indicator').bind('ajaxStop', function(){ |
|
559 | $('#ajax-indicator').bind('ajaxStop', function(){ | |
476 | $('#ajax-indicator').hide(); |
|
560 | $('#ajax-indicator').hide(); | |
477 | }); |
|
561 | }); | |
478 | }); |
|
562 | }); | |
479 |
|
563 | |||
480 | function hideOnLoad() { |
|
564 | function hideOnLoad() { | |
481 | $('.hol').hide(); |
|
565 | $('.hol').hide(); | |
482 | } |
|
566 | } | |
483 |
|
567 | |||
484 | function addFormObserversForDoubleSubmit() { |
|
568 | function addFormObserversForDoubleSubmit() { | |
485 | $('form[method=post]').each(function() { |
|
569 | $('form[method=post]').each(function() { | |
486 | if (!$(this).hasClass('multiple-submit')) { |
|
570 | if (!$(this).hasClass('multiple-submit')) { | |
487 | $(this).submit(function(form_submission) { |
|
571 | $(this).submit(function(form_submission) { | |
488 | if ($(form_submission.target).attr('data-submitted')) { |
|
572 | if ($(form_submission.target).attr('data-submitted')) { | |
489 | form_submission.preventDefault(); |
|
573 | form_submission.preventDefault(); | |
490 | } else { |
|
574 | } else { | |
491 | $(form_submission.target).attr('data-submitted', true); |
|
575 | $(form_submission.target).attr('data-submitted', true); | |
492 | } |
|
576 | } | |
493 | }); |
|
577 | }); | |
494 | } |
|
578 | } | |
495 | }); |
|
579 | }); | |
496 | } |
|
580 | } | |
497 |
|
581 | |||
498 | $(document).ready(hideOnLoad); |
|
582 | $(document).ready(hideOnLoad); | |
499 | $(document).ready(addFormObserversForDoubleSubmit); |
|
583 | $(document).ready(addFormObserversForDoubleSubmit); |
@@ -1,1124 +1,1125 | |||||
1 | html {overflow-y:scroll;} |
|
1 | html {overflow-y:scroll;} | |
2 | body { font-family: Verdana, sans-serif; font-size: 12px; color:#484848; margin: 0; padding: 0; min-width: 900px; } |
|
2 | body { font-family: Verdana, sans-serif; font-size: 12px; color:#484848; margin: 0; padding: 0; min-width: 900px; } | |
3 |
|
3 | |||
4 | h1, h2, h3, h4 { font-family: "Trebuchet MS", Verdana, sans-serif;} |
|
4 | h1, h2, h3, h4 { font-family: "Trebuchet MS", Verdana, sans-serif;} | |
5 | h1 {margin:0; padding:0; font-size: 24px;} |
|
5 | h1 {margin:0; padding:0; font-size: 24px;} | |
6 | h2, .wiki h1 {font-size: 20px;padding: 2px 10px 1px 0px;margin: 0 0 10px 0; color: #444;} |
|
6 | h2, .wiki h1 {font-size: 20px;padding: 2px 10px 1px 0px;margin: 0 0 10px 0; color: #444;} | |
7 | h3, .wiki h2 {font-size: 16px;padding: 2px 10px 1px 0px;margin: 0 0 10px 0; color: #444;} |
|
7 | h3, .wiki h2 {font-size: 16px;padding: 2px 10px 1px 0px;margin: 0 0 10px 0; color: #444;} | |
8 | h4, .wiki h3 {font-size: 13px;padding: 2px 10px 1px 0px;margin-bottom: 5px; border-bottom: 1px dotted #bbbbbb; color: #444;} |
|
8 | h4, .wiki h3 {font-size: 13px;padding: 2px 10px 1px 0px;margin-bottom: 5px; border-bottom: 1px dotted #bbbbbb; color: #444;} | |
9 |
|
9 | |||
10 | /***** Layout *****/ |
|
10 | /***** Layout *****/ | |
11 | #wrapper {background: white;} |
|
11 | #wrapper {background: white;} | |
12 |
|
12 | |||
13 | #top-menu {background: #3E5B76; color: #fff; height:1.8em; font-size: 0.8em; padding: 2px 2px 0px 6px;} |
|
13 | #top-menu {background: #3E5B76; color: #fff; height:1.8em; font-size: 0.8em; padding: 2px 2px 0px 6px;} | |
14 | #top-menu ul {margin: 0; padding: 0;} |
|
14 | #top-menu ul {margin: 0; padding: 0;} | |
15 | #top-menu li { |
|
15 | #top-menu li { | |
16 | float:left; |
|
16 | float:left; | |
17 | list-style-type:none; |
|
17 | list-style-type:none; | |
18 | margin: 0px 0px 0px 0px; |
|
18 | margin: 0px 0px 0px 0px; | |
19 | padding: 0px 0px 0px 0px; |
|
19 | padding: 0px 0px 0px 0px; | |
20 | white-space:nowrap; |
|
20 | white-space:nowrap; | |
21 | } |
|
21 | } | |
22 | #top-menu a {color: #fff; margin-right: 8px; font-weight: bold;} |
|
22 | #top-menu a {color: #fff; margin-right: 8px; font-weight: bold;} | |
23 | #top-menu #loggedas { float: right; margin-right: 0.5em; color: #fff; } |
|
23 | #top-menu #loggedas { float: right; margin-right: 0.5em; color: #fff; } | |
24 |
|
24 | |||
25 | #account {float:right;} |
|
25 | #account {float:right;} | |
26 |
|
26 | |||
27 | #header {height:5.3em;margin:0;background-color:#628DB6;color:#f8f8f8; padding: 4px 8px 0px 6px; position:relative;} |
|
27 | #header {height:5.3em;margin:0;background-color:#628DB6;color:#f8f8f8; padding: 4px 8px 0px 6px; position:relative;} | |
28 | #header a {color:#f8f8f8;} |
|
28 | #header a {color:#f8f8f8;} | |
29 | #header h1 a.ancestor { font-size: 80%; } |
|
29 | #header h1 a.ancestor { font-size: 80%; } | |
30 | #quick-search {float:right;} |
|
30 | #quick-search {float:right;} | |
31 |
|
31 | |||
32 | #main-menu {position: absolute; bottom: 0px; left:6px; margin-right: -500px;} |
|
32 | #main-menu {position: absolute; bottom: 0px; left:6px; margin-right: -500px;} | |
33 | #main-menu ul {margin: 0; padding: 0;} |
|
33 | #main-menu ul {margin: 0; padding: 0;} | |
34 | #main-menu li { |
|
34 | #main-menu li { | |
35 | float:left; |
|
35 | float:left; | |
36 | list-style-type:none; |
|
36 | list-style-type:none; | |
37 | margin: 0px 2px 0px 0px; |
|
37 | margin: 0px 2px 0px 0px; | |
38 | padding: 0px 0px 0px 0px; |
|
38 | padding: 0px 0px 0px 0px; | |
39 | white-space:nowrap; |
|
39 | white-space:nowrap; | |
40 | } |
|
40 | } | |
41 | #main-menu li a { |
|
41 | #main-menu li a { | |
42 | display: block; |
|
42 | display: block; | |
43 | color: #fff; |
|
43 | color: #fff; | |
44 | text-decoration: none; |
|
44 | text-decoration: none; | |
45 | font-weight: bold; |
|
45 | font-weight: bold; | |
46 | margin: 0; |
|
46 | margin: 0; | |
47 | padding: 4px 10px 4px 10px; |
|
47 | padding: 4px 10px 4px 10px; | |
48 | } |
|
48 | } | |
49 | #main-menu li a:hover {background:#759FCF; color:#fff;} |
|
49 | #main-menu li a:hover {background:#759FCF; color:#fff;} | |
50 | #main-menu li a.selected, #main-menu li a.selected:hover {background:#fff; color:#555;} |
|
50 | #main-menu li a.selected, #main-menu li a.selected:hover {background:#fff; color:#555;} | |
51 |
|
51 | |||
52 | #admin-menu ul {margin: 0; padding: 0;} |
|
52 | #admin-menu ul {margin: 0; padding: 0;} | |
53 | #admin-menu li {margin: 0; padding: 0 0 6px 0; list-style-type:none;} |
|
53 | #admin-menu li {margin: 0; padding: 0 0 6px 0; list-style-type:none;} | |
54 |
|
54 | |||
55 | #admin-menu a { background-position: 0% 40%; background-repeat: no-repeat; padding-left: 20px; padding-top: 2px; padding-bottom: 3px;} |
|
55 | #admin-menu a { background-position: 0% 40%; background-repeat: no-repeat; padding-left: 20px; padding-top: 2px; padding-bottom: 3px;} | |
56 | #admin-menu a.projects { background-image: url(../images/projects.png); } |
|
56 | #admin-menu a.projects { background-image: url(../images/projects.png); } | |
57 | #admin-menu a.users { background-image: url(../images/user.png); } |
|
57 | #admin-menu a.users { background-image: url(../images/user.png); } | |
58 | #admin-menu a.groups { background-image: url(../images/group.png); } |
|
58 | #admin-menu a.groups { background-image: url(../images/group.png); } | |
59 | #admin-menu a.roles { background-image: url(../images/database_key.png); } |
|
59 | #admin-menu a.roles { background-image: url(../images/database_key.png); } | |
60 | #admin-menu a.trackers { background-image: url(../images/ticket.png); } |
|
60 | #admin-menu a.trackers { background-image: url(../images/ticket.png); } | |
61 | #admin-menu a.issue_statuses { background-image: url(../images/ticket_edit.png); } |
|
61 | #admin-menu a.issue_statuses { background-image: url(../images/ticket_edit.png); } | |
62 | #admin-menu a.workflows { background-image: url(../images/ticket_go.png); } |
|
62 | #admin-menu a.workflows { background-image: url(../images/ticket_go.png); } | |
63 | #admin-menu a.custom_fields { background-image: url(../images/textfield.png); } |
|
63 | #admin-menu a.custom_fields { background-image: url(../images/textfield.png); } | |
64 | #admin-menu a.enumerations { background-image: url(../images/text_list_bullets.png); } |
|
64 | #admin-menu a.enumerations { background-image: url(../images/text_list_bullets.png); } | |
65 | #admin-menu a.settings { background-image: url(../images/changeset.png); } |
|
65 | #admin-menu a.settings { background-image: url(../images/changeset.png); } | |
66 | #admin-menu a.plugins { background-image: url(../images/plugin.png); } |
|
66 | #admin-menu a.plugins { background-image: url(../images/plugin.png); } | |
67 | #admin-menu a.info { background-image: url(../images/help.png); } |
|
67 | #admin-menu a.info { background-image: url(../images/help.png); } | |
68 | #admin-menu a.server_authentication { background-image: url(../images/server_key.png); } |
|
68 | #admin-menu a.server_authentication { background-image: url(../images/server_key.png); } | |
69 |
|
69 | |||
70 | #main {background-color:#EEEEEE;} |
|
70 | #main {background-color:#EEEEEE;} | |
71 |
|
71 | |||
72 | #sidebar{ float: right; width: 22%; position: relative; z-index: 9; padding: 0; margin: 0;} |
|
72 | #sidebar{ float: right; width: 22%; position: relative; z-index: 9; padding: 0; margin: 0;} | |
73 | * html #sidebar{ width: 22%; } |
|
73 | * html #sidebar{ width: 22%; } | |
74 | #sidebar h3{ font-size: 14px; margin-top:14px; color: #666; } |
|
74 | #sidebar h3{ font-size: 14px; margin-top:14px; color: #666; } | |
75 | #sidebar hr{ width: 100%; margin: 0 auto; height: 1px; background: #ccc; border: 0; } |
|
75 | #sidebar hr{ width: 100%; margin: 0 auto; height: 1px; background: #ccc; border: 0; } | |
76 | * html #sidebar hr{ width: 95%; position: relative; left: -6px; color: #ccc; } |
|
76 | * html #sidebar hr{ width: 95%; position: relative; left: -6px; color: #ccc; } | |
77 | #sidebar .contextual { margin-right: 1em; } |
|
77 | #sidebar .contextual { margin-right: 1em; } | |
78 |
|
78 | |||
79 | #content { width: 75%; background-color: #fff; margin: 0px; border-right: 1px solid #ddd; padding: 6px 10px 10px 10px; z-index: 10; } |
|
79 | #content { width: 75%; background-color: #fff; margin: 0px; border-right: 1px solid #ddd; padding: 6px 10px 10px 10px; z-index: 10; } | |
80 | * html #content{ width: 75%; padding-left: 0; margin-top: 0px; padding: 6px 10px 10px 10px;} |
|
80 | * html #content{ width: 75%; padding-left: 0; margin-top: 0px; padding: 6px 10px 10px 10px;} | |
81 | html>body #content { min-height: 600px; } |
|
81 | html>body #content { min-height: 600px; } | |
82 | * html body #content { height: 600px; } /* IE */ |
|
82 | * html body #content { height: 600px; } /* IE */ | |
83 |
|
83 | |||
84 | #main.nosidebar #sidebar{ display: none; } |
|
84 | #main.nosidebar #sidebar{ display: none; } | |
85 | #main.nosidebar #content{ width: auto; border-right: 0; } |
|
85 | #main.nosidebar #content{ width: auto; border-right: 0; } | |
86 |
|
86 | |||
87 | #footer {clear: both; border-top: 1px solid #bbb; font-size: 0.9em; color: #aaa; padding: 5px; text-align:center; background:#fff;} |
|
87 | #footer {clear: both; border-top: 1px solid #bbb; font-size: 0.9em; color: #aaa; padding: 5px; text-align:center; background:#fff;} | |
88 |
|
88 | |||
89 | #login-form table {margin-top:5em; padding:1em; margin-left: auto; margin-right: auto; border: 2px solid #FDBF3B; background-color:#FFEBC1; } |
|
89 | #login-form table {margin-top:5em; padding:1em; margin-left: auto; margin-right: auto; border: 2px solid #FDBF3B; background-color:#FFEBC1; } | |
90 | #login-form table td {padding: 6px;} |
|
90 | #login-form table td {padding: 6px;} | |
91 | #login-form label {font-weight: bold;} |
|
91 | #login-form label {font-weight: bold;} | |
92 | #login-form input#username, #login-form input#password { width: 300px; } |
|
92 | #login-form input#username, #login-form input#password { width: 300px; } | |
93 |
|
93 | |||
94 | div.modal { border-radius:5px; background:#fff; z-index:50; padding:4px;} |
|
94 | div.modal { border-radius:5px; background:#fff; z-index:50; padding:4px;} | |
95 | div.modal h3.title {display:none;} |
|
95 | div.modal h3.title {display:none;} | |
96 | div.modal p.buttons {text-align:right; margin-bottom:0;} |
|
96 | div.modal p.buttons {text-align:right; margin-bottom:0;} | |
97 |
|
97 | |||
98 | input#openid_url { background: url(../images/openid-bg.gif) no-repeat; background-color: #fff; background-position: 0 50%; padding-left: 18px; } |
|
98 | input#openid_url { background: url(../images/openid-bg.gif) no-repeat; background-color: #fff; background-position: 0 50%; padding-left: 18px; } | |
99 |
|
99 | |||
100 | .clear:after{ content: "."; display: block; height: 0; clear: both; visibility: hidden; } |
|
100 | .clear:after{ content: "."; display: block; height: 0; clear: both; visibility: hidden; } | |
101 |
|
101 | |||
102 | /***** Links *****/ |
|
102 | /***** Links *****/ | |
103 | a, a:link, a:visited{ color: #169; text-decoration: none; } |
|
103 | a, a:link, a:visited{ color: #169; text-decoration: none; } | |
104 | a:hover, a:active{ color: #c61a1a; text-decoration: underline;} |
|
104 | a:hover, a:active{ color: #c61a1a; text-decoration: underline;} | |
105 | a img{ border: 0; } |
|
105 | a img{ border: 0; } | |
106 |
|
106 | |||
107 | a.issue.closed, a.issue.closed:link, a.issue.closed:visited { color: #999; text-decoration: line-through; } |
|
107 | a.issue.closed, a.issue.closed:link, a.issue.closed:visited { color: #999; text-decoration: line-through; } | |
108 | a.project.closed, a.project.closed:link, a.project.closed:visited { color: #999; } |
|
108 | a.project.closed, a.project.closed:link, a.project.closed:visited { color: #999; } | |
109 |
|
109 | |||
110 | #sidebar a.selected {line-height:1.7em; padding:1px 3px 2px 2px; margin-left:-2px; background-color:#9DB9D5; color:#fff; border-radius:2px;} |
|
110 | #sidebar a.selected {line-height:1.7em; padding:1px 3px 2px 2px; margin-left:-2px; background-color:#9DB9D5; color:#fff; border-radius:2px;} | |
111 | #sidebar a.selected:hover {text-decoration:none;} |
|
111 | #sidebar a.selected:hover {text-decoration:none;} | |
112 | #admin-menu a {line-height:1.7em;} |
|
112 | #admin-menu a {line-height:1.7em;} | |
113 | #admin-menu a.selected {padding-left: 20px !important; background-position: 2px 40%;} |
|
113 | #admin-menu a.selected {padding-left: 20px !important; background-position: 2px 40%;} | |
114 |
|
114 | |||
115 | a.collapsible {padding-left: 12px; background: url(../images/arrow_expanded.png) no-repeat -3px 40%;} |
|
115 | a.collapsible {padding-left: 12px; background: url(../images/arrow_expanded.png) no-repeat -3px 40%;} | |
116 | a.collapsible.collapsed {background: url(../images/arrow_collapsed.png) no-repeat -5px 40%;} |
|
116 | a.collapsible.collapsed {background: url(../images/arrow_collapsed.png) no-repeat -5px 40%;} | |
117 |
|
117 | |||
118 | a#toggle-completed-versions {color:#999;} |
|
118 | a#toggle-completed-versions {color:#999;} | |
119 | /***** Tables *****/ |
|
119 | /***** Tables *****/ | |
120 | table.list { border: 1px solid #e4e4e4; border-collapse: collapse; width: 100%; margin-bottom: 4px; } |
|
120 | table.list { border: 1px solid #e4e4e4; border-collapse: collapse; width: 100%; margin-bottom: 4px; } | |
121 | table.list th { background-color:#EEEEEE; padding: 4px; white-space:nowrap; } |
|
121 | table.list th { background-color:#EEEEEE; padding: 4px; white-space:nowrap; } | |
122 | table.list td { vertical-align: top; } |
|
122 | table.list td { vertical-align: top; } | |
123 | table.list td.id { width: 2%; text-align: center;} |
|
123 | table.list td.id { width: 2%; text-align: center;} | |
124 | table.list td.checkbox { width: 15px; padding: 2px 0 0 0; } |
|
124 | table.list td.checkbox { width: 15px; padding: 2px 0 0 0; } | |
125 | table.list td.checkbox input {padding:0px;} |
|
125 | table.list td.checkbox input {padding:0px;} | |
126 | table.list td.buttons { width: 15%; white-space:nowrap; text-align: right; } |
|
126 | table.list td.buttons { width: 15%; white-space:nowrap; text-align: right; } | |
127 | table.list td.buttons a { padding-right: 0.6em; } |
|
127 | table.list td.buttons a { padding-right: 0.6em; } | |
128 | table.list caption { text-align: left; padding: 0.5em 0.5em 0.5em 0; } |
|
128 | table.list caption { text-align: left; padding: 0.5em 0.5em 0.5em 0; } | |
129 |
|
129 | |||
130 | tr.project td.name a { white-space:nowrap; } |
|
130 | tr.project td.name a { white-space:nowrap; } | |
131 | tr.project.closed, tr.project.archived { color: #aaa; } |
|
131 | tr.project.closed, tr.project.archived { color: #aaa; } | |
132 | tr.project.closed a, tr.project.archived a { color: #aaa; } |
|
132 | tr.project.closed a, tr.project.archived a { color: #aaa; } | |
133 |
|
133 | |||
134 | tr.project.idnt td.name span {background: url(../images/bullet_arrow_right.png) no-repeat 0 50%; padding-left: 16px;} |
|
134 | tr.project.idnt td.name span {background: url(../images/bullet_arrow_right.png) no-repeat 0 50%; padding-left: 16px;} | |
135 | tr.project.idnt-1 td.name {padding-left: 0.5em;} |
|
135 | tr.project.idnt-1 td.name {padding-left: 0.5em;} | |
136 | tr.project.idnt-2 td.name {padding-left: 2em;} |
|
136 | tr.project.idnt-2 td.name {padding-left: 2em;} | |
137 | tr.project.idnt-3 td.name {padding-left: 3.5em;} |
|
137 | tr.project.idnt-3 td.name {padding-left: 3.5em;} | |
138 | tr.project.idnt-4 td.name {padding-left: 5em;} |
|
138 | tr.project.idnt-4 td.name {padding-left: 5em;} | |
139 | tr.project.idnt-5 td.name {padding-left: 6.5em;} |
|
139 | tr.project.idnt-5 td.name {padding-left: 6.5em;} | |
140 | tr.project.idnt-6 td.name {padding-left: 8em;} |
|
140 | tr.project.idnt-6 td.name {padding-left: 8em;} | |
141 | tr.project.idnt-7 td.name {padding-left: 9.5em;} |
|
141 | tr.project.idnt-7 td.name {padding-left: 9.5em;} | |
142 | tr.project.idnt-8 td.name {padding-left: 11em;} |
|
142 | tr.project.idnt-8 td.name {padding-left: 11em;} | |
143 | tr.project.idnt-9 td.name {padding-left: 12.5em;} |
|
143 | tr.project.idnt-9 td.name {padding-left: 12.5em;} | |
144 |
|
144 | |||
145 | tr.issue { text-align: center; white-space: nowrap; } |
|
145 | tr.issue { text-align: center; white-space: nowrap; } | |
146 | tr.issue td.subject, tr.issue td.category, td.assigned_to, tr.issue td.string, tr.issue td.text { white-space: normal; } |
|
146 | tr.issue td.subject, tr.issue td.category, td.assigned_to, tr.issue td.string, tr.issue td.text { white-space: normal; } | |
147 | tr.issue td.subject { text-align: left; } |
|
147 | tr.issue td.subject { text-align: left; } | |
148 | tr.issue td.done_ratio table.progress { margin-left:auto; margin-right: auto;} |
|
148 | tr.issue td.done_ratio table.progress { margin-left:auto; margin-right: auto;} | |
149 |
|
149 | |||
150 | tr.issue.idnt td.subject a {background: url(../images/bullet_arrow_right.png) no-repeat 0 50%; padding-left: 16px;} |
|
150 | tr.issue.idnt td.subject a {background: url(../images/bullet_arrow_right.png) no-repeat 0 50%; padding-left: 16px;} | |
151 | tr.issue.idnt-1 td.subject {padding-left: 0.5em;} |
|
151 | tr.issue.idnt-1 td.subject {padding-left: 0.5em;} | |
152 | tr.issue.idnt-2 td.subject {padding-left: 2em;} |
|
152 | tr.issue.idnt-2 td.subject {padding-left: 2em;} | |
153 | tr.issue.idnt-3 td.subject {padding-left: 3.5em;} |
|
153 | tr.issue.idnt-3 td.subject {padding-left: 3.5em;} | |
154 | tr.issue.idnt-4 td.subject {padding-left: 5em;} |
|
154 | tr.issue.idnt-4 td.subject {padding-left: 5em;} | |
155 | tr.issue.idnt-5 td.subject {padding-left: 6.5em;} |
|
155 | tr.issue.idnt-5 td.subject {padding-left: 6.5em;} | |
156 | tr.issue.idnt-6 td.subject {padding-left: 8em;} |
|
156 | tr.issue.idnt-6 td.subject {padding-left: 8em;} | |
157 | tr.issue.idnt-7 td.subject {padding-left: 9.5em;} |
|
157 | tr.issue.idnt-7 td.subject {padding-left: 9.5em;} | |
158 | tr.issue.idnt-8 td.subject {padding-left: 11em;} |
|
158 | tr.issue.idnt-8 td.subject {padding-left: 11em;} | |
159 | tr.issue.idnt-9 td.subject {padding-left: 12.5em;} |
|
159 | tr.issue.idnt-9 td.subject {padding-left: 12.5em;} | |
160 |
|
160 | |||
161 | tr.entry { border: 1px solid #f8f8f8; } |
|
161 | tr.entry { border: 1px solid #f8f8f8; } | |
162 | tr.entry td { white-space: nowrap; } |
|
162 | tr.entry td { white-space: nowrap; } | |
163 | tr.entry td.filename { width: 30%; } |
|
163 | tr.entry td.filename { width: 30%; } | |
164 | tr.entry td.filename_no_report { width: 70%; } |
|
164 | tr.entry td.filename_no_report { width: 70%; } | |
165 | tr.entry td.size { text-align: right; font-size: 90%; } |
|
165 | tr.entry td.size { text-align: right; font-size: 90%; } | |
166 | tr.entry td.revision, tr.entry td.author { text-align: center; } |
|
166 | tr.entry td.revision, tr.entry td.author { text-align: center; } | |
167 | tr.entry td.age { text-align: right; } |
|
167 | tr.entry td.age { text-align: right; } | |
168 | tr.entry.file td.filename a { margin-left: 16px; } |
|
168 | tr.entry.file td.filename a { margin-left: 16px; } | |
169 | tr.entry.file td.filename_no_report a { margin-left: 16px; } |
|
169 | tr.entry.file td.filename_no_report a { margin-left: 16px; } | |
170 |
|
170 | |||
171 | tr span.expander {background-image: url(../images/bullet_toggle_plus.png); padding-left: 8px; margin-left: 0; cursor: pointer;} |
|
171 | tr span.expander {background-image: url(../images/bullet_toggle_plus.png); padding-left: 8px; margin-left: 0; cursor: pointer;} | |
172 | tr.open span.expander {background-image: url(../images/bullet_toggle_minus.png);} |
|
172 | tr.open span.expander {background-image: url(../images/bullet_toggle_minus.png);} | |
173 |
|
173 | |||
174 | tr.changeset { height: 20px } |
|
174 | tr.changeset { height: 20px } | |
175 | tr.changeset ul, ol { margin-top: 0px; margin-bottom: 0px; } |
|
175 | tr.changeset ul, ol { margin-top: 0px; margin-bottom: 0px; } | |
176 | tr.changeset td.revision_graph { width: 15%; background-color: #fffffb; } |
|
176 | tr.changeset td.revision_graph { width: 15%; background-color: #fffffb; } | |
177 | tr.changeset td.author { text-align: center; width: 15%; white-space:nowrap;} |
|
177 | tr.changeset td.author { text-align: center; width: 15%; white-space:nowrap;} | |
178 | tr.changeset td.committed_on { text-align: center; width: 15%; white-space:nowrap;} |
|
178 | tr.changeset td.committed_on { text-align: center; width: 15%; white-space:nowrap;} | |
179 |
|
179 | |||
180 | table.files tr.file td { text-align: center; } |
|
180 | table.files tr.file td { text-align: center; } | |
181 | table.files tr.file td.filename { text-align: left; padding-left: 24px; } |
|
181 | table.files tr.file td.filename { text-align: left; padding-left: 24px; } | |
182 | table.files tr.file td.digest { font-size: 80%; } |
|
182 | table.files tr.file td.digest { font-size: 80%; } | |
183 |
|
183 | |||
184 | table.members td.roles, table.memberships td.roles { width: 45%; } |
|
184 | table.members td.roles, table.memberships td.roles { width: 45%; } | |
185 |
|
185 | |||
186 | tr.message { height: 2.6em; } |
|
186 | tr.message { height: 2.6em; } | |
187 | tr.message td.subject { padding-left: 20px; } |
|
187 | tr.message td.subject { padding-left: 20px; } | |
188 | tr.message td.created_on { white-space: nowrap; } |
|
188 | tr.message td.created_on { white-space: nowrap; } | |
189 | tr.message td.last_message { font-size: 80%; white-space: nowrap; } |
|
189 | tr.message td.last_message { font-size: 80%; white-space: nowrap; } | |
190 | tr.message.locked td.subject { background: url(../images/locked.png) no-repeat 0 1px; } |
|
190 | tr.message.locked td.subject { background: url(../images/locked.png) no-repeat 0 1px; } | |
191 | tr.message.sticky td.subject { background: url(../images/bullet_go.png) no-repeat 0 1px; font-weight: bold; } |
|
191 | tr.message.sticky td.subject { background: url(../images/bullet_go.png) no-repeat 0 1px; font-weight: bold; } | |
192 |
|
192 | |||
193 | tr.version.closed, tr.version.closed a { color: #999; } |
|
193 | tr.version.closed, tr.version.closed a { color: #999; } | |
194 | tr.version td.name { padding-left: 20px; } |
|
194 | tr.version td.name { padding-left: 20px; } | |
195 | tr.version.shared td.name { background: url(../images/link.png) no-repeat 0% 70%; } |
|
195 | tr.version.shared td.name { background: url(../images/link.png) no-repeat 0% 70%; } | |
196 | tr.version td.date, tr.version td.status, tr.version td.sharing { text-align: center; white-space:nowrap; } |
|
196 | tr.version td.date, tr.version td.status, tr.version td.sharing { text-align: center; white-space:nowrap; } | |
197 |
|
197 | |||
198 | tr.user td { width:13%; } |
|
198 | tr.user td { width:13%; } | |
199 | tr.user td.email { width:18%; } |
|
199 | tr.user td.email { width:18%; } | |
200 | tr.user td { white-space: nowrap; } |
|
200 | tr.user td { white-space: nowrap; } | |
201 | tr.user.locked, tr.user.registered { color: #aaa; } |
|
201 | tr.user.locked, tr.user.registered { color: #aaa; } | |
202 | tr.user.locked a, tr.user.registered a { color: #aaa; } |
|
202 | tr.user.locked a, tr.user.registered a { color: #aaa; } | |
203 |
|
203 | |||
204 | table.permissions td.role {color:#999;font-size:90%;font-weight:normal !important;text-align:center;vertical-align:bottom;} |
|
204 | table.permissions td.role {color:#999;font-size:90%;font-weight:normal !important;text-align:center;vertical-align:bottom;} | |
205 |
|
205 | |||
206 | tr.wiki-page-version td.updated_on, tr.wiki-page-version td.author {text-align:center;} |
|
206 | tr.wiki-page-version td.updated_on, tr.wiki-page-version td.author {text-align:center;} | |
207 |
|
207 | |||
208 | tr.time-entry { text-align: center; white-space: nowrap; } |
|
208 | tr.time-entry { text-align: center; white-space: nowrap; } | |
209 | tr.time-entry td.subject, tr.time-entry td.comments { text-align: left; white-space: normal; } |
|
209 | tr.time-entry td.subject, tr.time-entry td.comments { text-align: left; white-space: normal; } | |
210 | td.hours { text-align: right; font-weight: bold; padding-right: 0.5em; } |
|
210 | td.hours { text-align: right; font-weight: bold; padding-right: 0.5em; } | |
211 | td.hours .hours-dec { font-size: 0.9em; } |
|
211 | td.hours .hours-dec { font-size: 0.9em; } | |
212 |
|
212 | |||
213 | table.plugins td { vertical-align: middle; } |
|
213 | table.plugins td { vertical-align: middle; } | |
214 | table.plugins td.configure { text-align: right; padding-right: 1em; } |
|
214 | table.plugins td.configure { text-align: right; padding-right: 1em; } | |
215 | table.plugins span.name { font-weight: bold; display: block; margin-bottom: 6px; } |
|
215 | table.plugins span.name { font-weight: bold; display: block; margin-bottom: 6px; } | |
216 | table.plugins span.description { display: block; font-size: 0.9em; } |
|
216 | table.plugins span.description { display: block; font-size: 0.9em; } | |
217 | table.plugins span.url { display: block; font-size: 0.9em; } |
|
217 | table.plugins span.url { display: block; font-size: 0.9em; } | |
218 |
|
218 | |||
219 | table.list tbody tr.group td { padding: 0.8em 0 0.5em 0.3em; font-weight: bold; border-bottom: 1px solid #ccc; } |
|
219 | table.list tbody tr.group td { padding: 0.8em 0 0.5em 0.3em; font-weight: bold; border-bottom: 1px solid #ccc; } | |
220 | table.list tbody tr.group span.count { color: #aaa; font-size: 80%; } |
|
220 | table.list tbody tr.group span.count { color: #aaa; font-size: 80%; } | |
221 | tr.group a.toggle-all { color: #aaa; font-size: 80%; font-weight: normal; display:none;} |
|
221 | tr.group a.toggle-all { color: #aaa; font-size: 80%; font-weight: normal; display:none;} | |
222 | tr.group:hover a.toggle-all { display:inline;} |
|
222 | tr.group:hover a.toggle-all { display:inline;} | |
223 | a.toggle-all:hover {text-decoration:none;} |
|
223 | a.toggle-all:hover {text-decoration:none;} | |
224 |
|
224 | |||
225 | table.list tbody tr:hover { background-color:#ffffdd; } |
|
225 | table.list tbody tr:hover { background-color:#ffffdd; } | |
226 | table.list tbody tr.group:hover { background-color:inherit; } |
|
226 | table.list tbody tr.group:hover { background-color:inherit; } | |
227 | table td {padding:2px;} |
|
227 | table td {padding:2px;} | |
228 | table p {margin:0;} |
|
228 | table p {margin:0;} | |
229 | .odd {background-color:#f6f7f8;} |
|
229 | .odd {background-color:#f6f7f8;} | |
230 | .even {background-color: #fff;} |
|
230 | .even {background-color: #fff;} | |
231 |
|
231 | |||
232 | a.sort { padding-right: 16px; background-position: 100% 50%; background-repeat: no-repeat; } |
|
232 | a.sort { padding-right: 16px; background-position: 100% 50%; background-repeat: no-repeat; } | |
233 | a.sort.asc { background-image: url(../images/sort_asc.png); } |
|
233 | a.sort.asc { background-image: url(../images/sort_asc.png); } | |
234 | a.sort.desc { background-image: url(../images/sort_desc.png); } |
|
234 | a.sort.desc { background-image: url(../images/sort_desc.png); } | |
235 |
|
235 | |||
236 | table.attributes { width: 100% } |
|
236 | table.attributes { width: 100% } | |
237 | table.attributes th { vertical-align: top; text-align: left; } |
|
237 | table.attributes th { vertical-align: top; text-align: left; } | |
238 | table.attributes td { vertical-align: top; } |
|
238 | table.attributes td { vertical-align: top; } | |
239 |
|
239 | |||
240 | table.boards a.board, h3.comments { background: url(../images/comment.png) no-repeat 0% 50%; padding-left: 20px; } |
|
240 | table.boards a.board, h3.comments { background: url(../images/comment.png) no-repeat 0% 50%; padding-left: 20px; } | |
241 | table.boards td.topic-count, table.boards td.message-count {text-align:center;} |
|
241 | table.boards td.topic-count, table.boards td.message-count {text-align:center;} | |
242 | table.boards td.last-message {font-size:80%;} |
|
242 | table.boards td.last-message {font-size:80%;} | |
243 |
|
243 | |||
244 | table.messages td.author, table.messages td.created_on, table.messages td.reply-count {text-align:center;} |
|
244 | table.messages td.author, table.messages td.created_on, table.messages td.reply-count {text-align:center;} | |
245 |
|
245 | |||
246 | table.query-columns { |
|
246 | table.query-columns { | |
247 | border-collapse: collapse; |
|
247 | border-collapse: collapse; | |
248 | border: 0; |
|
248 | border: 0; | |
249 | } |
|
249 | } | |
250 |
|
250 | |||
251 | table.query-columns td.buttons { |
|
251 | table.query-columns td.buttons { | |
252 | vertical-align: middle; |
|
252 | vertical-align: middle; | |
253 | text-align: center; |
|
253 | text-align: center; | |
254 | } |
|
254 | } | |
255 |
|
255 | |||
256 | td.center {text-align:center;} |
|
256 | td.center {text-align:center;} | |
257 |
|
257 | |||
258 | h3.version { background: url(../images/package.png) no-repeat 0% 50%; padding-left: 20px; } |
|
258 | h3.version { background: url(../images/package.png) no-repeat 0% 50%; padding-left: 20px; } | |
259 |
|
259 | |||
260 | div.issues h3 { background: url(../images/ticket.png) no-repeat 0% 50%; padding-left: 20px; } |
|
260 | div.issues h3 { background: url(../images/ticket.png) no-repeat 0% 50%; padding-left: 20px; } | |
261 | div.members h3 { background: url(../images/group.png) no-repeat 0% 50%; padding-left: 20px; } |
|
261 | div.members h3 { background: url(../images/group.png) no-repeat 0% 50%; padding-left: 20px; } | |
262 | div.news h3 { background: url(../images/news.png) no-repeat 0% 50%; padding-left: 20px; } |
|
262 | div.news h3 { background: url(../images/news.png) no-repeat 0% 50%; padding-left: 20px; } | |
263 | div.projects h3 { background: url(../images/projects.png) no-repeat 0% 50%; padding-left: 20px; } |
|
263 | div.projects h3 { background: url(../images/projects.png) no-repeat 0% 50%; padding-left: 20px; } | |
264 |
|
264 | |||
265 | #watchers ul {margin: 0; padding: 0;} |
|
265 | #watchers ul {margin: 0; padding: 0;} | |
266 | #watchers li {list-style-type:none;margin: 0px 2px 0px 0px; padding: 0px 0px 0px 0px;} |
|
266 | #watchers li {list-style-type:none;margin: 0px 2px 0px 0px; padding: 0px 0px 0px 0px;} | |
267 | #watchers select {width: 95%; display: block;} |
|
267 | #watchers select {width: 95%; display: block;} | |
268 | #watchers a.delete {opacity: 0.4;} |
|
268 | #watchers a.delete {opacity: 0.4;} | |
269 | #watchers a.delete:hover {opacity: 1;} |
|
269 | #watchers a.delete:hover {opacity: 1;} | |
270 | #watchers img.gravatar {margin: 0 4px 2px 0;} |
|
270 | #watchers img.gravatar {margin: 0 4px 2px 0;} | |
271 |
|
271 | |||
272 | span#watchers_inputs {overflow:auto; display:block;} |
|
272 | span#watchers_inputs {overflow:auto; display:block;} | |
273 | span.search_for_watchers {display:block;} |
|
273 | span.search_for_watchers {display:block;} | |
274 | span.search_for_watchers, span.add_attachment {font-size:80%; line-height:2.5em;} |
|
274 | span.search_for_watchers, span.add_attachment {font-size:80%; line-height:2.5em;} | |
275 | span.search_for_watchers a, span.add_attachment a {padding-left:16px; background: url(../images/bullet_add.png) no-repeat 0 50%; } |
|
275 | span.search_for_watchers a, span.add_attachment a {padding-left:16px; background: url(../images/bullet_add.png) no-repeat 0 50%; } | |
276 |
|
276 | |||
277 |
|
277 | |||
278 | .highlight { background-color: #FCFD8D;} |
|
278 | .highlight { background-color: #FCFD8D;} | |
279 | .highlight.token-1 { background-color: #faa;} |
|
279 | .highlight.token-1 { background-color: #faa;} | |
280 | .highlight.token-2 { background-color: #afa;} |
|
280 | .highlight.token-2 { background-color: #afa;} | |
281 | .highlight.token-3 { background-color: #aaf;} |
|
281 | .highlight.token-3 { background-color: #aaf;} | |
282 |
|
282 | |||
283 | .box{ |
|
283 | .box{ | |
284 | padding:6px; |
|
284 | padding:6px; | |
285 | margin-bottom: 10px; |
|
285 | margin-bottom: 10px; | |
286 | background-color:#f6f6f6; |
|
286 | background-color:#f6f6f6; | |
287 | color:#505050; |
|
287 | color:#505050; | |
288 | line-height:1.5em; |
|
288 | line-height:1.5em; | |
289 | border: 1px solid #e4e4e4; |
|
289 | border: 1px solid #e4e4e4; | |
290 | } |
|
290 | } | |
291 |
|
291 | |||
292 | div.square { |
|
292 | div.square { | |
293 | border: 1px solid #999; |
|
293 | border: 1px solid #999; | |
294 | float: left; |
|
294 | float: left; | |
295 | margin: .3em .4em 0 .4em; |
|
295 | margin: .3em .4em 0 .4em; | |
296 | overflow: hidden; |
|
296 | overflow: hidden; | |
297 | width: .6em; height: .6em; |
|
297 | width: .6em; height: .6em; | |
298 | } |
|
298 | } | |
299 | .contextual {float:right; white-space: nowrap; line-height:1.4em;margin-top:5px; padding-left: 10px; font-size:0.9em;} |
|
299 | .contextual {float:right; white-space: nowrap; line-height:1.4em;margin-top:5px; padding-left: 10px; font-size:0.9em;} | |
300 | .contextual input, .contextual select {font-size:0.9em;} |
|
300 | .contextual input, .contextual select {font-size:0.9em;} | |
301 | .message .contextual { margin-top: 0; } |
|
301 | .message .contextual { margin-top: 0; } | |
302 |
|
302 | |||
303 | .splitcontent {overflow:auto;} |
|
303 | .splitcontent {overflow:auto;} | |
304 | .splitcontentleft{float:left; width:49%;} |
|
304 | .splitcontentleft{float:left; width:49%;} | |
305 | .splitcontentright{float:right; width:49%;} |
|
305 | .splitcontentright{float:right; width:49%;} | |
306 | form {display: inline;} |
|
306 | form {display: inline;} | |
307 | input, select {vertical-align: middle; margin-top: 1px; margin-bottom: 1px;} |
|
307 | input, select {vertical-align: middle; margin-top: 1px; margin-bottom: 1px;} | |
308 | fieldset {border: 1px solid #e4e4e4; margin:0;} |
|
308 | fieldset {border: 1px solid #e4e4e4; margin:0;} | |
309 | legend {color: #484848;} |
|
309 | legend {color: #484848;} | |
310 | hr { width: 100%; height: 1px; background: #ccc; border: 0;} |
|
310 | hr { width: 100%; height: 1px; background: #ccc; border: 0;} | |
311 | blockquote { font-style: italic; border-left: 3px solid #e0e0e0; padding-left: 0.6em; margin-left: 2.4em;} |
|
311 | blockquote { font-style: italic; border-left: 3px solid #e0e0e0; padding-left: 0.6em; margin-left: 2.4em;} | |
312 | blockquote blockquote { margin-left: 0;} |
|
312 | blockquote blockquote { margin-left: 0;} | |
313 | acronym { border-bottom: 1px dotted; cursor: help; } |
|
313 | acronym { border-bottom: 1px dotted; cursor: help; } | |
314 | textarea.wiki-edit { width: 99%; } |
|
314 | textarea.wiki-edit { width: 99%; } | |
315 | li p {margin-top: 0;} |
|
315 | li p {margin-top: 0;} | |
316 | div.issue {background:#ffffdd; padding:6px; margin-bottom:6px;border: 1px solid #d7d7d7;} |
|
316 | div.issue {background:#ffffdd; padding:6px; margin-bottom:6px;border: 1px solid #d7d7d7;} | |
317 | p.breadcrumb { font-size: 0.9em; margin: 4px 0 4px 0;} |
|
317 | p.breadcrumb { font-size: 0.9em; margin: 4px 0 4px 0;} | |
318 | p.subtitle { font-size: 0.9em; margin: -6px 0 12px 0; font-style: italic; } |
|
318 | p.subtitle { font-size: 0.9em; margin: -6px 0 12px 0; font-style: italic; } | |
319 | p.footnote { font-size: 0.9em; margin-top: 0px; margin-bottom: 0px; } |
|
319 | p.footnote { font-size: 0.9em; margin-top: 0px; margin-bottom: 0px; } | |
320 |
|
320 | |||
321 | div.issue div.subject div div { padding-left: 16px; } |
|
321 | div.issue div.subject div div { padding-left: 16px; } | |
322 | div.issue div.subject p {margin: 0; margin-bottom: 0.1em; font-size: 90%; color: #999;} |
|
322 | div.issue div.subject p {margin: 0; margin-bottom: 0.1em; font-size: 90%; color: #999;} | |
323 | div.issue div.subject>div>p { margin-top: 0.5em; } |
|
323 | div.issue div.subject>div>p { margin-top: 0.5em; } | |
324 | div.issue div.subject h3 {margin: 0; margin-bottom: 0.1em;} |
|
324 | div.issue div.subject h3 {margin: 0; margin-bottom: 0.1em;} | |
325 | div.issue span.private { position:relative; bottom: 2px; text-transform: uppercase; background: #d22; color: #fff; font-weight:bold; padding: 0px 2px 0px 2px; font-size: 60%; margin-right: 2px; border-radius: 2px;} |
|
325 | div.issue span.private { position:relative; bottom: 2px; text-transform: uppercase; background: #d22; color: #fff; font-weight:bold; padding: 0px 2px 0px 2px; font-size: 60%; margin-right: 2px; border-radius: 2px;} | |
326 | div.issue .next-prev-links {color:#999;} |
|
326 | div.issue .next-prev-links {color:#999;} | |
327 | div.issue table.attributes th {width:22%;} |
|
327 | div.issue table.attributes th {width:22%;} | |
328 | div.issue table.attributes td {width:28%;} |
|
328 | div.issue table.attributes td {width:28%;} | |
329 |
|
329 | |||
330 | #issue_tree table.issues, #relations table.issues { border: 0; } |
|
330 | #issue_tree table.issues, #relations table.issues { border: 0; } | |
331 | #issue_tree td.checkbox, #relations td.checkbox {display:none;} |
|
331 | #issue_tree td.checkbox, #relations td.checkbox {display:none;} | |
332 | #relations td.buttons {padding:0;} |
|
332 | #relations td.buttons {padding:0;} | |
333 |
|
333 | |||
334 | fieldset.collapsible { border-width: 1px 0 0 0; font-size: 0.9em; } |
|
334 | fieldset.collapsible { border-width: 1px 0 0 0; font-size: 0.9em; } | |
335 | fieldset.collapsible legend { padding-left: 16px; background: url(../images/arrow_expanded.png) no-repeat 0% 40%; cursor:pointer; } |
|
335 | fieldset.collapsible legend { padding-left: 16px; background: url(../images/arrow_expanded.png) no-repeat 0% 40%; cursor:pointer; } | |
336 | fieldset.collapsible.collapsed legend { background-image: url(../images/arrow_collapsed.png); } |
|
336 | fieldset.collapsible.collapsed legend { background-image: url(../images/arrow_collapsed.png); } | |
337 |
|
337 | |||
338 | fieldset#date-range p { margin: 2px 0 2px 0; } |
|
338 | fieldset#date-range p { margin: 2px 0 2px 0; } | |
339 | fieldset#filters table { border-collapse: collapse; } |
|
339 | fieldset#filters table { border-collapse: collapse; } | |
340 | fieldset#filters table td { padding: 0; vertical-align: middle; } |
|
340 | fieldset#filters table td { padding: 0; vertical-align: middle; } | |
341 | fieldset#filters tr.filter { height: 2em; } |
|
341 | fieldset#filters tr.filter { height: 2.1em; } | |
342 | fieldset#filters td.field { width:200px; } |
|
342 | fieldset#filters td.field { width:200px; } | |
343 | fieldset#filters td.operator { width:170px; } |
|
343 | fieldset#filters td.operator { width:170px; } | |
344 | fieldset#filters td.values { white-space:nowrap; } |
|
344 | fieldset#filters td.values { white-space:nowrap; } | |
345 | fieldset#filters td.values select {min-width:130px;} |
|
345 | fieldset#filters td.values select {min-width:130px;} | |
346 |
fieldset#filters td.values i |
|
346 | fieldset#filters td.values input {height:1em;} | |
347 | fieldset#filters td.add-filter { text-align: right; vertical-align: top; } |
|
347 | fieldset#filters td.add-filter { text-align: right; vertical-align: top; } | |
|
348 | .toggle-multiselect {background: url(../images/bullet_toggle_plus.png) no-repeat 0% 40%; padding-left:8px; margin-left:0; cursor:pointer;} | |||
348 | .buttons { font-size: 0.9em; margin-bottom: 1.4em; margin-top: 1em; } |
|
349 | .buttons { font-size: 0.9em; margin-bottom: 1.4em; margin-top: 1em; } | |
349 |
|
350 | |||
350 | div#issue-changesets {float:right; width:45%; margin-left: 1em; margin-bottom: 1em; background: #fff; padding-left: 1em; font-size: 90%;} |
|
351 | div#issue-changesets {float:right; width:45%; margin-left: 1em; margin-bottom: 1em; background: #fff; padding-left: 1em; font-size: 90%;} | |
351 | div#issue-changesets div.changeset { padding: 4px;} |
|
352 | div#issue-changesets div.changeset { padding: 4px;} | |
352 | div#issue-changesets div.changeset { border-bottom: 1px solid #ddd; } |
|
353 | div#issue-changesets div.changeset { border-bottom: 1px solid #ddd; } | |
353 | div#issue-changesets p { margin-top: 0; margin-bottom: 1em;} |
|
354 | div#issue-changesets p { margin-top: 0; margin-bottom: 1em;} | |
354 |
|
355 | |||
355 | .journal ul.details img {margin:0 0 -3px 4px;} |
|
356 | .journal ul.details img {margin:0 0 -3px 4px;} | |
356 |
|
357 | |||
357 | div#activity dl, #search-results { margin-left: 2em; } |
|
358 | div#activity dl, #search-results { margin-left: 2em; } | |
358 | div#activity dd, #search-results dd { margin-bottom: 1em; padding-left: 18px; font-size: 0.9em; } |
|
359 | div#activity dd, #search-results dd { margin-bottom: 1em; padding-left: 18px; font-size: 0.9em; } | |
359 | div#activity dt, #search-results dt { margin-bottom: 0px; padding-left: 20px; line-height: 18px; background-position: 0 50%; background-repeat: no-repeat; } |
|
360 | div#activity dt, #search-results dt { margin-bottom: 0px; padding-left: 20px; line-height: 18px; background-position: 0 50%; background-repeat: no-repeat; } | |
360 | div#activity dt.me .time { border-bottom: 1px solid #999; } |
|
361 | div#activity dt.me .time { border-bottom: 1px solid #999; } | |
361 | div#activity dt .time { color: #777; font-size: 80%; } |
|
362 | div#activity dt .time { color: #777; font-size: 80%; } | |
362 | div#activity dd .description, #search-results dd .description { font-style: italic; } |
|
363 | div#activity dd .description, #search-results dd .description { font-style: italic; } | |
363 | div#activity span.project:after, #search-results span.project:after { content: " -"; } |
|
364 | div#activity span.project:after, #search-results span.project:after { content: " -"; } | |
364 | div#activity dd span.description, #search-results dd span.description { display:block; color: #808080; } |
|
365 | div#activity dd span.description, #search-results dd span.description { display:block; color: #808080; } | |
365 |
|
366 | |||
366 | #search-results dd { margin-bottom: 1em; padding-left: 20px; margin-left:0px; } |
|
367 | #search-results dd { margin-bottom: 1em; padding-left: 20px; margin-left:0px; } | |
367 |
|
368 | |||
368 | div#search-results-counts {float:right;} |
|
369 | div#search-results-counts {float:right;} | |
369 | div#search-results-counts ul { margin-top: 0.5em; } |
|
370 | div#search-results-counts ul { margin-top: 0.5em; } | |
370 | div#search-results-counts li { list-style-type:none; float: left; margin-left: 1em; } |
|
371 | div#search-results-counts li { list-style-type:none; float: left; margin-left: 1em; } | |
371 |
|
372 | |||
372 | dt.issue { background-image: url(../images/ticket.png); } |
|
373 | dt.issue { background-image: url(../images/ticket.png); } | |
373 | dt.issue-edit { background-image: url(../images/ticket_edit.png); } |
|
374 | dt.issue-edit { background-image: url(../images/ticket_edit.png); } | |
374 | dt.issue-closed { background-image: url(../images/ticket_checked.png); } |
|
375 | dt.issue-closed { background-image: url(../images/ticket_checked.png); } | |
375 | dt.issue-note { background-image: url(../images/ticket_note.png); } |
|
376 | dt.issue-note { background-image: url(../images/ticket_note.png); } | |
376 | dt.changeset { background-image: url(../images/changeset.png); } |
|
377 | dt.changeset { background-image: url(../images/changeset.png); } | |
377 | dt.news { background-image: url(../images/news.png); } |
|
378 | dt.news { background-image: url(../images/news.png); } | |
378 | dt.message { background-image: url(../images/message.png); } |
|
379 | dt.message { background-image: url(../images/message.png); } | |
379 | dt.reply { background-image: url(../images/comments.png); } |
|
380 | dt.reply { background-image: url(../images/comments.png); } | |
380 | dt.wiki-page { background-image: url(../images/wiki_edit.png); } |
|
381 | dt.wiki-page { background-image: url(../images/wiki_edit.png); } | |
381 | dt.attachment { background-image: url(../images/attachment.png); } |
|
382 | dt.attachment { background-image: url(../images/attachment.png); } | |
382 | dt.document { background-image: url(../images/document.png); } |
|
383 | dt.document { background-image: url(../images/document.png); } | |
383 | dt.project { background-image: url(../images/projects.png); } |
|
384 | dt.project { background-image: url(../images/projects.png); } | |
384 | dt.time-entry { background-image: url(../images/time.png); } |
|
385 | dt.time-entry { background-image: url(../images/time.png); } | |
385 |
|
386 | |||
386 | #search-results dt.issue.closed { background-image: url(../images/ticket_checked.png); } |
|
387 | #search-results dt.issue.closed { background-image: url(../images/ticket_checked.png); } | |
387 |
|
388 | |||
388 | div#roadmap .related-issues { margin-bottom: 1em; } |
|
389 | div#roadmap .related-issues { margin-bottom: 1em; } | |
389 | div#roadmap .related-issues td.checkbox { display: none; } |
|
390 | div#roadmap .related-issues td.checkbox { display: none; } | |
390 | div#roadmap .wiki h1:first-child { display: none; } |
|
391 | div#roadmap .wiki h1:first-child { display: none; } | |
391 | div#roadmap .wiki h1 { font-size: 120%; } |
|
392 | div#roadmap .wiki h1 { font-size: 120%; } | |
392 | div#roadmap .wiki h2 { font-size: 110%; } |
|
393 | div#roadmap .wiki h2 { font-size: 110%; } | |
393 | body.controller-versions.action-show div#roadmap .related-issues {width:70%;} |
|
394 | body.controller-versions.action-show div#roadmap .related-issues {width:70%;} | |
394 |
|
395 | |||
395 | div#version-summary { float:right; width:28%; margin-left: 16px; margin-bottom: 16px; background-color: #fff; } |
|
396 | div#version-summary { float:right; width:28%; margin-left: 16px; margin-bottom: 16px; background-color: #fff; } | |
396 | div#version-summary fieldset { margin-bottom: 1em; } |
|
397 | div#version-summary fieldset { margin-bottom: 1em; } | |
397 | div#version-summary fieldset.time-tracking table { width:100%; } |
|
398 | div#version-summary fieldset.time-tracking table { width:100%; } | |
398 | div#version-summary th, div#version-summary td.total-hours { text-align: right; } |
|
399 | div#version-summary th, div#version-summary td.total-hours { text-align: right; } | |
399 |
|
400 | |||
400 | table#time-report td.hours, table#time-report th.period, table#time-report th.total { text-align: right; padding-right: 0.5em; } |
|
401 | table#time-report td.hours, table#time-report th.period, table#time-report th.total { text-align: right; padding-right: 0.5em; } | |
401 | table#time-report tbody tr.subtotal { font-style: italic; color:#777;} |
|
402 | table#time-report tbody tr.subtotal { font-style: italic; color:#777;} | |
402 | table#time-report tbody tr.subtotal td.hours { color:#b0b0b0; } |
|
403 | table#time-report tbody tr.subtotal td.hours { color:#b0b0b0; } | |
403 | table#time-report tbody tr.total { font-weight: bold; background-color:#EEEEEE; border-top:1px solid #e4e4e4;} |
|
404 | table#time-report tbody tr.total { font-weight: bold; background-color:#EEEEEE; border-top:1px solid #e4e4e4;} | |
404 | table#time-report .hours-dec { font-size: 0.9em; } |
|
405 | table#time-report .hours-dec { font-size: 0.9em; } | |
405 |
|
406 | |||
406 | div.wiki-page .contextual a {opacity: 0.4} |
|
407 | div.wiki-page .contextual a {opacity: 0.4} | |
407 | div.wiki-page .contextual a:hover {opacity: 1} |
|
408 | div.wiki-page .contextual a:hover {opacity: 1} | |
408 |
|
409 | |||
409 | form .attributes select { width: 60%; } |
|
410 | form .attributes select { width: 60%; } | |
410 | input#issue_subject { width: 99%; } |
|
411 | input#issue_subject { width: 99%; } | |
411 | select#issue_done_ratio { width: 95px; } |
|
412 | select#issue_done_ratio { width: 95px; } | |
412 |
|
413 | |||
413 | ul.projects { margin: 0; padding-left: 1em; } |
|
414 | ul.projects { margin: 0; padding-left: 1em; } | |
414 | ul.projects.root { margin: 0; padding: 0; } |
|
415 | ul.projects.root { margin: 0; padding: 0; } | |
415 | ul.projects ul.projects { border-left: 3px solid #e0e0e0; } |
|
416 | ul.projects ul.projects { border-left: 3px solid #e0e0e0; } | |
416 | ul.projects li.root { list-style-type:none; margin-bottom: 1em; } |
|
417 | ul.projects li.root { list-style-type:none; margin-bottom: 1em; } | |
417 | ul.projects li.child { list-style-type:none; margin-top: 1em;} |
|
418 | ul.projects li.child { list-style-type:none; margin-top: 1em;} | |
418 | ul.projects div.root a.project { font-family: "Trebuchet MS", Verdana, sans-serif; font-weight: bold; font-size: 16px; margin: 0 0 10px 0; } |
|
419 | ul.projects div.root a.project { font-family: "Trebuchet MS", Verdana, sans-serif; font-weight: bold; font-size: 16px; margin: 0 0 10px 0; } | |
419 | .my-project { padding-left: 18px; background: url(../images/fav.png) no-repeat 0 50%; } |
|
420 | .my-project { padding-left: 18px; background: url(../images/fav.png) no-repeat 0 50%; } | |
420 |
|
421 | |||
421 | #tracker_project_ids ul { margin: 0; padding-left: 1em; } |
|
422 | #tracker_project_ids ul { margin: 0; padding-left: 1em; } | |
422 | #tracker_project_ids li { list-style-type:none; } |
|
423 | #tracker_project_ids li { list-style-type:none; } | |
423 |
|
424 | |||
424 | #related-issues li img {vertical-align:middle;} |
|
425 | #related-issues li img {vertical-align:middle;} | |
425 |
|
426 | |||
426 | ul.properties {padding:0; font-size: 0.9em; color: #777;} |
|
427 | ul.properties {padding:0; font-size: 0.9em; color: #777;} | |
427 | ul.properties li {list-style-type:none;} |
|
428 | ul.properties li {list-style-type:none;} | |
428 | ul.properties li span {font-style:italic;} |
|
429 | ul.properties li span {font-style:italic;} | |
429 |
|
430 | |||
430 | .total-hours { font-size: 110%; font-weight: bold; } |
|
431 | .total-hours { font-size: 110%; font-weight: bold; } | |
431 | .total-hours span.hours-int { font-size: 120%; } |
|
432 | .total-hours span.hours-int { font-size: 120%; } | |
432 |
|
433 | |||
433 | .autoscroll {overflow-x: auto; padding:1px; margin-bottom: 1.2em;} |
|
434 | .autoscroll {overflow-x: auto; padding:1px; margin-bottom: 1.2em;} | |
434 | #user_login, #user_firstname, #user_lastname, #user_mail, #my_account_form select, #user_form select, #user_identity_url { width: 90%; } |
|
435 | #user_login, #user_firstname, #user_lastname, #user_mail, #my_account_form select, #user_form select, #user_identity_url { width: 90%; } | |
435 |
|
436 | |||
436 | #workflow_copy_form select { width: 200px; } |
|
437 | #workflow_copy_form select { width: 200px; } | |
437 | table.transitions td.enabled {background: #bfb;} |
|
438 | table.transitions td.enabled {background: #bfb;} | |
438 | table.fields_permissions select {font-size:90%} |
|
439 | table.fields_permissions select {font-size:90%} | |
439 | table.fields_permissions td.readonly {background:#ddd;} |
|
440 | table.fields_permissions td.readonly {background:#ddd;} | |
440 | table.fields_permissions td.required {background:#d88;} |
|
441 | table.fields_permissions td.required {background:#d88;} | |
441 |
|
442 | |||
442 | textarea#custom_field_possible_values {width: 99%} |
|
443 | textarea#custom_field_possible_values {width: 99%} | |
443 | input#content_comments {width: 99%} |
|
444 | input#content_comments {width: 99%} | |
444 |
|
445 | |||
445 | .pagination {font-size: 90%} |
|
446 | .pagination {font-size: 90%} | |
446 | p.pagination {margin-top:8px;} |
|
447 | p.pagination {margin-top:8px;} | |
447 |
|
448 | |||
448 | /***** Tabular forms ******/ |
|
449 | /***** Tabular forms ******/ | |
449 | .tabular p{ |
|
450 | .tabular p{ | |
450 | margin: 0; |
|
451 | margin: 0; | |
451 | padding: 3px 0 3px 0; |
|
452 | padding: 3px 0 3px 0; | |
452 | padding-left: 180px; /* width of left column containing the label elements */ |
|
453 | padding-left: 180px; /* width of left column containing the label elements */ | |
453 | min-height: 1.8em; |
|
454 | min-height: 1.8em; | |
454 | clear:left; |
|
455 | clear:left; | |
455 | } |
|
456 | } | |
456 |
|
457 | |||
457 | html>body .tabular p {overflow:hidden;} |
|
458 | html>body .tabular p {overflow:hidden;} | |
458 |
|
459 | |||
459 | .tabular label{ |
|
460 | .tabular label{ | |
460 | font-weight: bold; |
|
461 | font-weight: bold; | |
461 | float: left; |
|
462 | float: left; | |
462 | text-align: right; |
|
463 | text-align: right; | |
463 | /* width of left column */ |
|
464 | /* width of left column */ | |
464 | margin-left: -180px; |
|
465 | margin-left: -180px; | |
465 | /* width of labels. Should be smaller than left column to create some right margin */ |
|
466 | /* width of labels. Should be smaller than left column to create some right margin */ | |
466 | width: 175px; |
|
467 | width: 175px; | |
467 | } |
|
468 | } | |
468 |
|
469 | |||
469 | .tabular label.floating{ |
|
470 | .tabular label.floating{ | |
470 | font-weight: normal; |
|
471 | font-weight: normal; | |
471 | margin-left: 0px; |
|
472 | margin-left: 0px; | |
472 | text-align: left; |
|
473 | text-align: left; | |
473 | width: 270px; |
|
474 | width: 270px; | |
474 | } |
|
475 | } | |
475 |
|
476 | |||
476 | .tabular label.block{ |
|
477 | .tabular label.block{ | |
477 | font-weight: normal; |
|
478 | font-weight: normal; | |
478 | margin-left: 0px !important; |
|
479 | margin-left: 0px !important; | |
479 | text-align: left; |
|
480 | text-align: left; | |
480 | float: none; |
|
481 | float: none; | |
481 | display: block; |
|
482 | display: block; | |
482 | width: auto; |
|
483 | width: auto; | |
483 | } |
|
484 | } | |
484 |
|
485 | |||
485 | .tabular label.inline{ |
|
486 | .tabular label.inline{ | |
486 | float:none; |
|
487 | float:none; | |
487 | margin-left: 5px !important; |
|
488 | margin-left: 5px !important; | |
488 | width: auto; |
|
489 | width: auto; | |
489 | } |
|
490 | } | |
490 |
|
491 | |||
491 | label.no-css { |
|
492 | label.no-css { | |
492 | font-weight: inherit; |
|
493 | font-weight: inherit; | |
493 | float:none; |
|
494 | float:none; | |
494 | text-align:left; |
|
495 | text-align:left; | |
495 | margin-left:0px; |
|
496 | margin-left:0px; | |
496 | width:auto; |
|
497 | width:auto; | |
497 | } |
|
498 | } | |
498 | input#time_entry_comments { width: 90%;} |
|
499 | input#time_entry_comments { width: 90%;} | |
499 |
|
500 | |||
500 | #preview fieldset {margin-top: 1em; background: url(../images/draft.png)} |
|
501 | #preview fieldset {margin-top: 1em; background: url(../images/draft.png)} | |
501 |
|
502 | |||
502 | .tabular.settings p{ padding-left: 300px; } |
|
503 | .tabular.settings p{ padding-left: 300px; } | |
503 | .tabular.settings label{ margin-left: -300px; width: 295px; } |
|
504 | .tabular.settings label{ margin-left: -300px; width: 295px; } | |
504 | .tabular.settings textarea { width: 99%; } |
|
505 | .tabular.settings textarea { width: 99%; } | |
505 |
|
506 | |||
506 | .settings.enabled_scm table {width:100%} |
|
507 | .settings.enabled_scm table {width:100%} | |
507 | .settings.enabled_scm td.scm_name{ font-weight: bold; } |
|
508 | .settings.enabled_scm td.scm_name{ font-weight: bold; } | |
508 |
|
509 | |||
509 | fieldset.settings label { display: block; } |
|
510 | fieldset.settings label { display: block; } | |
510 | fieldset#notified_events .parent { padding-left: 20px; } |
|
511 | fieldset#notified_events .parent { padding-left: 20px; } | |
511 |
|
512 | |||
512 | span.required {color: #bb0000;} |
|
513 | span.required {color: #bb0000;} | |
513 | .summary {font-style: italic;} |
|
514 | .summary {font-style: italic;} | |
514 |
|
515 | |||
515 | #attachments_fields input.description {margin-left: 8px; width:340px;} |
|
516 | #attachments_fields input.description {margin-left: 8px; width:340px;} | |
516 | #attachments_fields span {display:block; white-space:nowrap;} |
|
517 | #attachments_fields span {display:block; white-space:nowrap;} | |
517 | #attachments_fields img {vertical-align: middle;} |
|
518 | #attachments_fields img {vertical-align: middle;} | |
518 |
|
519 | |||
519 | div.attachments { margin-top: 12px; } |
|
520 | div.attachments { margin-top: 12px; } | |
520 | div.attachments p { margin:4px 0 2px 0; } |
|
521 | div.attachments p { margin:4px 0 2px 0; } | |
521 | div.attachments img { vertical-align: middle; } |
|
522 | div.attachments img { vertical-align: middle; } | |
522 | div.attachments span.author { font-size: 0.9em; color: #888; } |
|
523 | div.attachments span.author { font-size: 0.9em; color: #888; } | |
523 |
|
524 | |||
524 | div.thumbnails {margin-top:0.6em;} |
|
525 | div.thumbnails {margin-top:0.6em;} | |
525 | div.thumbnails div {background:#fff;border:2px solid #ddd;display:inline-block;margin-right:2px;} |
|
526 | div.thumbnails div {background:#fff;border:2px solid #ddd;display:inline-block;margin-right:2px;} | |
526 | div.thumbnails img {margin: 3px;} |
|
527 | div.thumbnails img {margin: 3px;} | |
527 |
|
528 | |||
528 | p.other-formats { text-align: right; font-size:0.9em; color: #666; } |
|
529 | p.other-formats { text-align: right; font-size:0.9em; color: #666; } | |
529 | .other-formats span + span:before { content: "| "; } |
|
530 | .other-formats span + span:before { content: "| "; } | |
530 |
|
531 | |||
531 | a.atom { background: url(../images/feed.png) no-repeat 1px 50%; padding: 2px 0px 3px 16px; } |
|
532 | a.atom { background: url(../images/feed.png) no-repeat 1px 50%; padding: 2px 0px 3px 16px; } | |
532 |
|
533 | |||
533 | em.info {font-style:normal;font-size:90%;color:#888;display:block;} |
|
534 | em.info {font-style:normal;font-size:90%;color:#888;display:block;} | |
534 | em.info.error {padding-left:20px; background:url(../images/exclamation.png) no-repeat 0 50%;} |
|
535 | em.info.error {padding-left:20px; background:url(../images/exclamation.png) no-repeat 0 50%;} | |
535 |
|
536 | |||
536 | textarea.text_cf {width:90%;} |
|
537 | textarea.text_cf {width:90%;} | |
537 |
|
538 | |||
538 | /* Project members tab */ |
|
539 | /* Project members tab */ | |
539 | div#tab-content-members .splitcontentleft, div#tab-content-memberships .splitcontentleft, div#tab-content-users .splitcontentleft { width: 64% } |
|
540 | div#tab-content-members .splitcontentleft, div#tab-content-memberships .splitcontentleft, div#tab-content-users .splitcontentleft { width: 64% } | |
540 | div#tab-content-members .splitcontentright, div#tab-content-memberships .splitcontentright, div#tab-content-users .splitcontentright { width: 34% } |
|
541 | div#tab-content-members .splitcontentright, div#tab-content-memberships .splitcontentright, div#tab-content-users .splitcontentright { width: 34% } | |
541 | div#tab-content-members fieldset, div#tab-content-memberships fieldset, div#tab-content-users fieldset { padding:1em; margin-bottom: 1em; } |
|
542 | div#tab-content-members fieldset, div#tab-content-memberships fieldset, div#tab-content-users fieldset { padding:1em; margin-bottom: 1em; } | |
542 | div#tab-content-members fieldset legend, div#tab-content-memberships fieldset legend, div#tab-content-users fieldset legend { font-weight: bold; } |
|
543 | div#tab-content-members fieldset legend, div#tab-content-memberships fieldset legend, div#tab-content-users fieldset legend { font-weight: bold; } | |
543 | div#tab-content-members fieldset label, div#tab-content-memberships fieldset label, div#tab-content-users fieldset label { display: block; } |
|
544 | div#tab-content-members fieldset label, div#tab-content-memberships fieldset label, div#tab-content-users fieldset label { display: block; } | |
544 | div#tab-content-members fieldset div, div#tab-content-users fieldset div { max-height: 400px; overflow:auto; } |
|
545 | div#tab-content-members fieldset div, div#tab-content-users fieldset div { max-height: 400px; overflow:auto; } | |
545 |
|
546 | |||
546 | #users_for_watcher {height: 200px; overflow:auto;} |
|
547 | #users_for_watcher {height: 200px; overflow:auto;} | |
547 | #users_for_watcher label {display: block;} |
|
548 | #users_for_watcher label {display: block;} | |
548 |
|
549 | |||
549 | table.members td.group { padding-left: 20px; background: url(../images/group.png) no-repeat 0% 50%; } |
|
550 | table.members td.group { padding-left: 20px; background: url(../images/group.png) no-repeat 0% 50%; } | |
550 |
|
551 | |||
551 | input#principal_search, input#user_search {width:100%} |
|
552 | input#principal_search, input#user_search {width:100%} | |
552 | input#principal_search, input#user_search { |
|
553 | input#principal_search, input#user_search { | |
553 | background: url(../images/magnifier.png) no-repeat 2px 50%; padding-left:20px; |
|
554 | background: url(../images/magnifier.png) no-repeat 2px 50%; padding-left:20px; | |
554 | border:1px solid #9EB1C2; border-radius:3px; height:1.5em; width:95%; |
|
555 | border:1px solid #9EB1C2; border-radius:3px; height:1.5em; width:95%; | |
555 | } |
|
556 | } | |
556 | input#principal_search.ajax-loading, input#user_search.ajax-loading { |
|
557 | input#principal_search.ajax-loading, input#user_search.ajax-loading { | |
557 | background-image: url(../images/loading.gif); |
|
558 | background-image: url(../images/loading.gif); | |
558 | } |
|
559 | } | |
559 |
|
560 | |||
560 | * html div#tab-content-members fieldset div { height: 450px; } |
|
561 | * html div#tab-content-members fieldset div { height: 450px; } | |
561 |
|
562 | |||
562 | /***** Flash & error messages ****/ |
|
563 | /***** Flash & error messages ****/ | |
563 | #errorExplanation, div.flash, .nodata, .warning, .conflict { |
|
564 | #errorExplanation, div.flash, .nodata, .warning, .conflict { | |
564 | padding: 4px 4px 4px 30px; |
|
565 | padding: 4px 4px 4px 30px; | |
565 | margin-bottom: 12px; |
|
566 | margin-bottom: 12px; | |
566 | font-size: 1.1em; |
|
567 | font-size: 1.1em; | |
567 | border: 2px solid; |
|
568 | border: 2px solid; | |
568 | } |
|
569 | } | |
569 |
|
570 | |||
570 | div.flash {margin-top: 8px;} |
|
571 | div.flash {margin-top: 8px;} | |
571 |
|
572 | |||
572 | div.flash.error, #errorExplanation { |
|
573 | div.flash.error, #errorExplanation { | |
573 | background: url(../images/exclamation.png) 8px 50% no-repeat; |
|
574 | background: url(../images/exclamation.png) 8px 50% no-repeat; | |
574 | background-color: #ffe3e3; |
|
575 | background-color: #ffe3e3; | |
575 | border-color: #dd0000; |
|
576 | border-color: #dd0000; | |
576 | color: #880000; |
|
577 | color: #880000; | |
577 | } |
|
578 | } | |
578 |
|
579 | |||
579 | div.flash.notice { |
|
580 | div.flash.notice { | |
580 | background: url(../images/true.png) 8px 5px no-repeat; |
|
581 | background: url(../images/true.png) 8px 5px no-repeat; | |
581 | background-color: #dfffdf; |
|
582 | background-color: #dfffdf; | |
582 | border-color: #9fcf9f; |
|
583 | border-color: #9fcf9f; | |
583 | color: #005f00; |
|
584 | color: #005f00; | |
584 | } |
|
585 | } | |
585 |
|
586 | |||
586 | div.flash.warning, .conflict { |
|
587 | div.flash.warning, .conflict { | |
587 | background: url(../images/warning.png) 8px 5px no-repeat; |
|
588 | background: url(../images/warning.png) 8px 5px no-repeat; | |
588 | background-color: #FFEBC1; |
|
589 | background-color: #FFEBC1; | |
589 | border-color: #FDBF3B; |
|
590 | border-color: #FDBF3B; | |
590 | color: #A6750C; |
|
591 | color: #A6750C; | |
591 | text-align: left; |
|
592 | text-align: left; | |
592 | } |
|
593 | } | |
593 |
|
594 | |||
594 | .nodata, .warning { |
|
595 | .nodata, .warning { | |
595 | text-align: center; |
|
596 | text-align: center; | |
596 | background-color: #FFEBC1; |
|
597 | background-color: #FFEBC1; | |
597 | border-color: #FDBF3B; |
|
598 | border-color: #FDBF3B; | |
598 | color: #A6750C; |
|
599 | color: #A6750C; | |
599 | } |
|
600 | } | |
600 |
|
601 | |||
601 | #errorExplanation ul { font-size: 0.9em;} |
|
602 | #errorExplanation ul { font-size: 0.9em;} | |
602 | #errorExplanation h2, #errorExplanation p { display: none; } |
|
603 | #errorExplanation h2, #errorExplanation p { display: none; } | |
603 |
|
604 | |||
604 | .conflict-details {font-size:80%;} |
|
605 | .conflict-details {font-size:80%;} | |
605 |
|
606 | |||
606 | /***** Ajax indicator ******/ |
|
607 | /***** Ajax indicator ******/ | |
607 | #ajax-indicator { |
|
608 | #ajax-indicator { | |
608 | position: absolute; /* fixed not supported by IE */ |
|
609 | position: absolute; /* fixed not supported by IE */ | |
609 | background-color:#eee; |
|
610 | background-color:#eee; | |
610 | border: 1px solid #bbb; |
|
611 | border: 1px solid #bbb; | |
611 | top:35%; |
|
612 | top:35%; | |
612 | left:40%; |
|
613 | left:40%; | |
613 | width:20%; |
|
614 | width:20%; | |
614 | font-weight:bold; |
|
615 | font-weight:bold; | |
615 | text-align:center; |
|
616 | text-align:center; | |
616 | padding:0.6em; |
|
617 | padding:0.6em; | |
617 | z-index:100; |
|
618 | z-index:100; | |
618 | opacity: 0.5; |
|
619 | opacity: 0.5; | |
619 | } |
|
620 | } | |
620 |
|
621 | |||
621 | html>body #ajax-indicator { position: fixed; } |
|
622 | html>body #ajax-indicator { position: fixed; } | |
622 |
|
623 | |||
623 | #ajax-indicator span { |
|
624 | #ajax-indicator span { | |
624 | background-position: 0% 40%; |
|
625 | background-position: 0% 40%; | |
625 | background-repeat: no-repeat; |
|
626 | background-repeat: no-repeat; | |
626 | background-image: url(../images/loading.gif); |
|
627 | background-image: url(../images/loading.gif); | |
627 | padding-left: 26px; |
|
628 | padding-left: 26px; | |
628 | vertical-align: bottom; |
|
629 | vertical-align: bottom; | |
629 | } |
|
630 | } | |
630 |
|
631 | |||
631 | /***** Calendar *****/ |
|
632 | /***** Calendar *****/ | |
632 | table.cal {border-collapse: collapse; width: 100%; margin: 0px 0 6px 0;border: 1px solid #d7d7d7;} |
|
633 | table.cal {border-collapse: collapse; width: 100%; margin: 0px 0 6px 0;border: 1px solid #d7d7d7;} | |
633 | table.cal thead th {width: 14%; background-color:#EEEEEE; padding: 4px; } |
|
634 | table.cal thead th {width: 14%; background-color:#EEEEEE; padding: 4px; } | |
634 | table.cal thead th.week-number {width: auto;} |
|
635 | table.cal thead th.week-number {width: auto;} | |
635 | table.cal tbody tr {height: 100px;} |
|
636 | table.cal tbody tr {height: 100px;} | |
636 | table.cal td {border: 1px solid #d7d7d7; vertical-align: top; font-size: 0.9em;} |
|
637 | table.cal td {border: 1px solid #d7d7d7; vertical-align: top; font-size: 0.9em;} | |
637 | table.cal td.week-number { background-color:#EEEEEE; padding: 4px; border:none; font-size: 1em;} |
|
638 | table.cal td.week-number { background-color:#EEEEEE; padding: 4px; border:none; font-size: 1em;} | |
638 | table.cal td p.day-num {font-size: 1.1em; text-align:right;} |
|
639 | table.cal td p.day-num {font-size: 1.1em; text-align:right;} | |
639 | table.cal td.odd p.day-num {color: #bbb;} |
|
640 | table.cal td.odd p.day-num {color: #bbb;} | |
640 | table.cal td.today {background:#ffffdd;} |
|
641 | table.cal td.today {background:#ffffdd;} | |
641 | table.cal td.today p.day-num {font-weight: bold;} |
|
642 | table.cal td.today p.day-num {font-weight: bold;} | |
642 | table.cal .starting a, p.cal.legend .starting {background: url(../images/bullet_go.png) no-repeat -1px -2px; padding-left:16px;} |
|
643 | table.cal .starting a, p.cal.legend .starting {background: url(../images/bullet_go.png) no-repeat -1px -2px; padding-left:16px;} | |
643 | table.cal .ending a, p.cal.legend .ending {background: url(../images/bullet_end.png) no-repeat -1px -2px; padding-left:16px;} |
|
644 | table.cal .ending a, p.cal.legend .ending {background: url(../images/bullet_end.png) no-repeat -1px -2px; padding-left:16px;} | |
644 | table.cal .starting.ending a, p.cal.legend .starting.ending {background: url(../images/bullet_diamond.png) no-repeat -1px -2px; padding-left:16px;} |
|
645 | table.cal .starting.ending a, p.cal.legend .starting.ending {background: url(../images/bullet_diamond.png) no-repeat -1px -2px; padding-left:16px;} | |
645 | p.cal.legend span {display:block;} |
|
646 | p.cal.legend span {display:block;} | |
646 |
|
647 | |||
647 | /***** Tooltips ******/ |
|
648 | /***** Tooltips ******/ | |
648 | .tooltip{position:relative;z-index:24;} |
|
649 | .tooltip{position:relative;z-index:24;} | |
649 | .tooltip:hover{z-index:25;color:#000;} |
|
650 | .tooltip:hover{z-index:25;color:#000;} | |
650 | .tooltip span.tip{display: none; text-align:left;} |
|
651 | .tooltip span.tip{display: none; text-align:left;} | |
651 |
|
652 | |||
652 | div.tooltip:hover span.tip{ |
|
653 | div.tooltip:hover span.tip{ | |
653 | display:block; |
|
654 | display:block; | |
654 | position:absolute; |
|
655 | position:absolute; | |
655 | top:12px; left:24px; width:270px; |
|
656 | top:12px; left:24px; width:270px; | |
656 | border:1px solid #555; |
|
657 | border:1px solid #555; | |
657 | background-color:#fff; |
|
658 | background-color:#fff; | |
658 | padding: 4px; |
|
659 | padding: 4px; | |
659 | font-size: 0.8em; |
|
660 | font-size: 0.8em; | |
660 | color:#505050; |
|
661 | color:#505050; | |
661 | } |
|
662 | } | |
662 |
|
663 | |||
663 | img.ui-datepicker-trigger { |
|
664 | img.ui-datepicker-trigger { | |
664 | cursor: pointer; |
|
665 | cursor: pointer; | |
665 | vertical-align: middle; |
|
666 | vertical-align: middle; | |
666 | margin-left: 4px; |
|
667 | margin-left: 4px; | |
667 | } |
|
668 | } | |
668 |
|
669 | |||
669 | /***** Progress bar *****/ |
|
670 | /***** Progress bar *****/ | |
670 | table.progress { |
|
671 | table.progress { | |
671 | border-collapse: collapse; |
|
672 | border-collapse: collapse; | |
672 | border-spacing: 0pt; |
|
673 | border-spacing: 0pt; | |
673 | empty-cells: show; |
|
674 | empty-cells: show; | |
674 | text-align: center; |
|
675 | text-align: center; | |
675 | float:left; |
|
676 | float:left; | |
676 | margin: 1px 6px 1px 0px; |
|
677 | margin: 1px 6px 1px 0px; | |
677 | } |
|
678 | } | |
678 |
|
679 | |||
679 | table.progress td { height: 1em; } |
|
680 | table.progress td { height: 1em; } | |
680 | table.progress td.closed { background: #BAE0BA none repeat scroll 0%; } |
|
681 | table.progress td.closed { background: #BAE0BA none repeat scroll 0%; } | |
681 | table.progress td.done { background: #D3EDD3 none repeat scroll 0%; } |
|
682 | table.progress td.done { background: #D3EDD3 none repeat scroll 0%; } | |
682 | table.progress td.todo { background: #eee none repeat scroll 0%; } |
|
683 | table.progress td.todo { background: #eee none repeat scroll 0%; } | |
683 | p.pourcent {font-size: 80%;} |
|
684 | p.pourcent {font-size: 80%;} | |
684 | p.progress-info {clear: left; font-size: 80%; margin-top:-4px; color:#777;} |
|
685 | p.progress-info {clear: left; font-size: 80%; margin-top:-4px; color:#777;} | |
685 |
|
686 | |||
686 | #roadmap table.progress td { height: 1.2em; } |
|
687 | #roadmap table.progress td { height: 1.2em; } | |
687 | /***** Tabs *****/ |
|
688 | /***** Tabs *****/ | |
688 | #content .tabs {height: 2.6em; margin-bottom:1.2em; position:relative; overflow:hidden;} |
|
689 | #content .tabs {height: 2.6em; margin-bottom:1.2em; position:relative; overflow:hidden;} | |
689 | #content .tabs ul {margin:0; position:absolute; bottom:0; padding-left:0.5em; width: 2000px; border-bottom: 1px solid #bbbbbb;} |
|
690 | #content .tabs ul {margin:0; position:absolute; bottom:0; padding-left:0.5em; width: 2000px; border-bottom: 1px solid #bbbbbb;} | |
690 | #content .tabs ul li { |
|
691 | #content .tabs ul li { | |
691 | float:left; |
|
692 | float:left; | |
692 | list-style-type:none; |
|
693 | list-style-type:none; | |
693 | white-space:nowrap; |
|
694 | white-space:nowrap; | |
694 | margin-right:4px; |
|
695 | margin-right:4px; | |
695 | background:#fff; |
|
696 | background:#fff; | |
696 | position:relative; |
|
697 | position:relative; | |
697 | margin-bottom:-1px; |
|
698 | margin-bottom:-1px; | |
698 | } |
|
699 | } | |
699 | #content .tabs ul li a{ |
|
700 | #content .tabs ul li a{ | |
700 | display:block; |
|
701 | display:block; | |
701 | font-size: 0.9em; |
|
702 | font-size: 0.9em; | |
702 | text-decoration:none; |
|
703 | text-decoration:none; | |
703 | line-height:1.3em; |
|
704 | line-height:1.3em; | |
704 | padding:4px 6px 4px 6px; |
|
705 | padding:4px 6px 4px 6px; | |
705 | border: 1px solid #ccc; |
|
706 | border: 1px solid #ccc; | |
706 | border-bottom: 1px solid #bbbbbb; |
|
707 | border-bottom: 1px solid #bbbbbb; | |
707 | background-color: #f6f6f6; |
|
708 | background-color: #f6f6f6; | |
708 | color:#999; |
|
709 | color:#999; | |
709 | font-weight:bold; |
|
710 | font-weight:bold; | |
710 | border-top-left-radius:3px; |
|
711 | border-top-left-radius:3px; | |
711 | border-top-right-radius:3px; |
|
712 | border-top-right-radius:3px; | |
712 | } |
|
713 | } | |
713 |
|
714 | |||
714 | #content .tabs ul li a:hover { |
|
715 | #content .tabs ul li a:hover { | |
715 | background-color: #ffffdd; |
|
716 | background-color: #ffffdd; | |
716 | text-decoration:none; |
|
717 | text-decoration:none; | |
717 | } |
|
718 | } | |
718 |
|
719 | |||
719 | #content .tabs ul li a.selected { |
|
720 | #content .tabs ul li a.selected { | |
720 | background-color: #fff; |
|
721 | background-color: #fff; | |
721 | border: 1px solid #bbbbbb; |
|
722 | border: 1px solid #bbbbbb; | |
722 | border-bottom: 1px solid #fff; |
|
723 | border-bottom: 1px solid #fff; | |
723 | color:#444; |
|
724 | color:#444; | |
724 | } |
|
725 | } | |
725 |
|
726 | |||
726 | #content .tabs ul li a.selected:hover {background-color: #fff;} |
|
727 | #content .tabs ul li a.selected:hover {background-color: #fff;} | |
727 |
|
728 | |||
728 | div.tabs-buttons { position:absolute; right: 0; width: 48px; height: 24px; background: white; bottom: 0; border-bottom: 1px solid #bbbbbb; } |
|
729 | div.tabs-buttons { position:absolute; right: 0; width: 48px; height: 24px; background: white; bottom: 0; border-bottom: 1px solid #bbbbbb; } | |
729 |
|
730 | |||
730 | button.tab-left, button.tab-right { |
|
731 | button.tab-left, button.tab-right { | |
731 | font-size: 0.9em; |
|
732 | font-size: 0.9em; | |
732 | cursor: pointer; |
|
733 | cursor: pointer; | |
733 | height:24px; |
|
734 | height:24px; | |
734 | border: 1px solid #ccc; |
|
735 | border: 1px solid #ccc; | |
735 | border-bottom: 1px solid #bbbbbb; |
|
736 | border-bottom: 1px solid #bbbbbb; | |
736 | position:absolute; |
|
737 | position:absolute; | |
737 | padding:4px; |
|
738 | padding:4px; | |
738 | width: 20px; |
|
739 | width: 20px; | |
739 | bottom: -1px; |
|
740 | bottom: -1px; | |
740 | } |
|
741 | } | |
741 |
|
742 | |||
742 | button.tab-left { |
|
743 | button.tab-left { | |
743 | right: 20px; |
|
744 | right: 20px; | |
744 | background: #eeeeee url(../images/bullet_arrow_left.png) no-repeat 50% 50%; |
|
745 | background: #eeeeee url(../images/bullet_arrow_left.png) no-repeat 50% 50%; | |
745 | border-top-left-radius:3px; |
|
746 | border-top-left-radius:3px; | |
746 | } |
|
747 | } | |
747 |
|
748 | |||
748 | button.tab-right { |
|
749 | button.tab-right { | |
749 | right: 0; |
|
750 | right: 0; | |
750 | background: #eeeeee url(../images/bullet_arrow_right.png) no-repeat 50% 50%; |
|
751 | background: #eeeeee url(../images/bullet_arrow_right.png) no-repeat 50% 50%; | |
751 | border-top-right-radius:3px; |
|
752 | border-top-right-radius:3px; | |
752 | } |
|
753 | } | |
753 |
|
754 | |||
754 | /***** Diff *****/ |
|
755 | /***** Diff *****/ | |
755 | .diff_out { background: #fcc; } |
|
756 | .diff_out { background: #fcc; } | |
756 | .diff_out span { background: #faa; } |
|
757 | .diff_out span { background: #faa; } | |
757 | .diff_in { background: #cfc; } |
|
758 | .diff_in { background: #cfc; } | |
758 | .diff_in span { background: #afa; } |
|
759 | .diff_in span { background: #afa; } | |
759 |
|
760 | |||
760 | .text-diff { |
|
761 | .text-diff { | |
761 | padding: 1em; |
|
762 | padding: 1em; | |
762 | background-color:#f6f6f6; |
|
763 | background-color:#f6f6f6; | |
763 | color:#505050; |
|
764 | color:#505050; | |
764 | border: 1px solid #e4e4e4; |
|
765 | border: 1px solid #e4e4e4; | |
765 | } |
|
766 | } | |
766 |
|
767 | |||
767 | /***** Wiki *****/ |
|
768 | /***** Wiki *****/ | |
768 | div.wiki table { |
|
769 | div.wiki table { | |
769 | border-collapse: collapse; |
|
770 | border-collapse: collapse; | |
770 | margin-bottom: 1em; |
|
771 | margin-bottom: 1em; | |
771 | } |
|
772 | } | |
772 |
|
773 | |||
773 | div.wiki table, div.wiki td, div.wiki th { |
|
774 | div.wiki table, div.wiki td, div.wiki th { | |
774 | border: 1px solid #bbb; |
|
775 | border: 1px solid #bbb; | |
775 | padding: 4px; |
|
776 | padding: 4px; | |
776 | } |
|
777 | } | |
777 |
|
778 | |||
778 | div.wiki .noborder, div.wiki .noborder td, div.wiki .noborder th {border:0;} |
|
779 | div.wiki .noborder, div.wiki .noborder td, div.wiki .noborder th {border:0;} | |
779 |
|
780 | |||
780 | div.wiki .external { |
|
781 | div.wiki .external { | |
781 | background-position: 0% 60%; |
|
782 | background-position: 0% 60%; | |
782 | background-repeat: no-repeat; |
|
783 | background-repeat: no-repeat; | |
783 | padding-left: 12px; |
|
784 | padding-left: 12px; | |
784 | background-image: url(../images/external.png); |
|
785 | background-image: url(../images/external.png); | |
785 | } |
|
786 | } | |
786 |
|
787 | |||
787 | div.wiki a.new {color: #b73535;} |
|
788 | div.wiki a.new {color: #b73535;} | |
788 |
|
789 | |||
789 | div.wiki ul, div.wiki ol {margin-bottom:1em;} |
|
790 | div.wiki ul, div.wiki ol {margin-bottom:1em;} | |
790 |
|
791 | |||
791 | div.wiki pre { |
|
792 | div.wiki pre { | |
792 | margin: 1em 1em 1em 1.6em; |
|
793 | margin: 1em 1em 1em 1.6em; | |
793 | padding: 8px; |
|
794 | padding: 8px; | |
794 | background-color: #fafafa; |
|
795 | background-color: #fafafa; | |
795 | border: 1px solid #e2e2e2; |
|
796 | border: 1px solid #e2e2e2; | |
796 | width:auto; |
|
797 | width:auto; | |
797 | overflow-x: auto; |
|
798 | overflow-x: auto; | |
798 | overflow-y: hidden; |
|
799 | overflow-y: hidden; | |
799 | } |
|
800 | } | |
800 |
|
801 | |||
801 | div.wiki ul.toc { |
|
802 | div.wiki ul.toc { | |
802 | background-color: #ffffdd; |
|
803 | background-color: #ffffdd; | |
803 | border: 1px solid #e4e4e4; |
|
804 | border: 1px solid #e4e4e4; | |
804 | padding: 4px; |
|
805 | padding: 4px; | |
805 | line-height: 1.2em; |
|
806 | line-height: 1.2em; | |
806 | margin-bottom: 12px; |
|
807 | margin-bottom: 12px; | |
807 | margin-right: 12px; |
|
808 | margin-right: 12px; | |
808 | margin-left: 0; |
|
809 | margin-left: 0; | |
809 | display: table |
|
810 | display: table | |
810 | } |
|
811 | } | |
811 | * html div.wiki ul.toc { width: 50%; } /* IE6 doesn't autosize div */ |
|
812 | * html div.wiki ul.toc { width: 50%; } /* IE6 doesn't autosize div */ | |
812 |
|
813 | |||
813 | div.wiki ul.toc.right { float: right; margin-left: 12px; margin-right: 0; width: auto; } |
|
814 | div.wiki ul.toc.right { float: right; margin-left: 12px; margin-right: 0; width: auto; } | |
814 | div.wiki ul.toc.left { float: left; margin-right: 12px; margin-left: 0; width: auto; } |
|
815 | div.wiki ul.toc.left { float: left; margin-right: 12px; margin-left: 0; width: auto; } | |
815 | div.wiki ul.toc ul { margin: 0; padding: 0; } |
|
816 | div.wiki ul.toc ul { margin: 0; padding: 0; } | |
816 | div.wiki ul.toc li { list-style-type:none; margin: 0;} |
|
817 | div.wiki ul.toc li { list-style-type:none; margin: 0;} | |
817 | div.wiki ul.toc li li { margin-left: 1.5em; } |
|
818 | div.wiki ul.toc li li { margin-left: 1.5em; } | |
818 | div.wiki ul.toc li li li { font-size: 0.8em; } |
|
819 | div.wiki ul.toc li li li { font-size: 0.8em; } | |
819 | div.wiki ul.toc a { |
|
820 | div.wiki ul.toc a { | |
820 | font-size: 0.9em; |
|
821 | font-size: 0.9em; | |
821 | font-weight: normal; |
|
822 | font-weight: normal; | |
822 | text-decoration: none; |
|
823 | text-decoration: none; | |
823 | color: #606060; |
|
824 | color: #606060; | |
824 | } |
|
825 | } | |
825 | div.wiki ul.toc a:hover { color: #c61a1a; text-decoration: underline;} |
|
826 | div.wiki ul.toc a:hover { color: #c61a1a; text-decoration: underline;} | |
826 |
|
827 | |||
827 | a.wiki-anchor { display: none; margin-left: 6px; text-decoration: none; } |
|
828 | a.wiki-anchor { display: none; margin-left: 6px; text-decoration: none; } | |
828 | a.wiki-anchor:hover { color: #aaa !important; text-decoration: none; } |
|
829 | a.wiki-anchor:hover { color: #aaa !important; text-decoration: none; } | |
829 | h1:hover a.wiki-anchor, h2:hover a.wiki-anchor, h3:hover a.wiki-anchor { display: inline; color: #ddd; } |
|
830 | h1:hover a.wiki-anchor, h2:hover a.wiki-anchor, h3:hover a.wiki-anchor { display: inline; color: #ddd; } | |
830 |
|
831 | |||
831 | div.wiki img { vertical-align: middle; } |
|
832 | div.wiki img { vertical-align: middle; } | |
832 |
|
833 | |||
833 | /***** My page layout *****/ |
|
834 | /***** My page layout *****/ | |
834 | .block-receiver { |
|
835 | .block-receiver { | |
835 | border:1px dashed #c0c0c0; |
|
836 | border:1px dashed #c0c0c0; | |
836 | margin-bottom: 20px; |
|
837 | margin-bottom: 20px; | |
837 | padding: 15px 0 15px 0; |
|
838 | padding: 15px 0 15px 0; | |
838 | } |
|
839 | } | |
839 |
|
840 | |||
840 | .mypage-box { |
|
841 | .mypage-box { | |
841 | margin:0 0 20px 0; |
|
842 | margin:0 0 20px 0; | |
842 | color:#505050; |
|
843 | color:#505050; | |
843 | line-height:1.5em; |
|
844 | line-height:1.5em; | |
844 | } |
|
845 | } | |
845 |
|
846 | |||
846 | .handle {cursor: move;} |
|
847 | .handle {cursor: move;} | |
847 |
|
848 | |||
848 | a.close-icon { |
|
849 | a.close-icon { | |
849 | display:block; |
|
850 | display:block; | |
850 | margin-top:3px; |
|
851 | margin-top:3px; | |
851 | overflow:hidden; |
|
852 | overflow:hidden; | |
852 | width:12px; |
|
853 | width:12px; | |
853 | height:12px; |
|
854 | height:12px; | |
854 | background-repeat: no-repeat; |
|
855 | background-repeat: no-repeat; | |
855 | cursor:pointer; |
|
856 | cursor:pointer; | |
856 | background-image:url('../images/close.png'); |
|
857 | background-image:url('../images/close.png'); | |
857 | } |
|
858 | } | |
858 | a.close-icon:hover {background-image:url('../images/close_hl.png');} |
|
859 | a.close-icon:hover {background-image:url('../images/close_hl.png');} | |
859 |
|
860 | |||
860 | /***** Gantt chart *****/ |
|
861 | /***** Gantt chart *****/ | |
861 | .gantt_hdr { |
|
862 | .gantt_hdr { | |
862 | position:absolute; |
|
863 | position:absolute; | |
863 | top:0; |
|
864 | top:0; | |
864 | height:16px; |
|
865 | height:16px; | |
865 | border-top: 1px solid #c0c0c0; |
|
866 | border-top: 1px solid #c0c0c0; | |
866 | border-bottom: 1px solid #c0c0c0; |
|
867 | border-bottom: 1px solid #c0c0c0; | |
867 | border-right: 1px solid #c0c0c0; |
|
868 | border-right: 1px solid #c0c0c0; | |
868 | text-align: center; |
|
869 | text-align: center; | |
869 | overflow: hidden; |
|
870 | overflow: hidden; | |
870 | } |
|
871 | } | |
871 |
|
872 | |||
872 | .gantt_subjects { font-size: 0.8em; } |
|
873 | .gantt_subjects { font-size: 0.8em; } | |
873 | .gantt_subjects div { line-height:16px;height:16px;overflow:hidden;white-space:nowrap;text-overflow: ellipsis; } |
|
874 | .gantt_subjects div { line-height:16px;height:16px;overflow:hidden;white-space:nowrap;text-overflow: ellipsis; } | |
874 |
|
875 | |||
875 | .task { |
|
876 | .task { | |
876 | position: absolute; |
|
877 | position: absolute; | |
877 | height:8px; |
|
878 | height:8px; | |
878 | font-size:0.8em; |
|
879 | font-size:0.8em; | |
879 | color:#888; |
|
880 | color:#888; | |
880 | padding:0; |
|
881 | padding:0; | |
881 | margin:0; |
|
882 | margin:0; | |
882 | line-height:16px; |
|
883 | line-height:16px; | |
883 | white-space:nowrap; |
|
884 | white-space:nowrap; | |
884 | } |
|
885 | } | |
885 |
|
886 | |||
886 | .task.label {width:100%;} |
|
887 | .task.label {width:100%;} | |
887 | .task.label.project, .task.label.version { font-weight: bold; } |
|
888 | .task.label.project, .task.label.version { font-weight: bold; } | |
888 |
|
889 | |||
889 | .task_late { background:#f66 url(../images/task_late.png); border: 1px solid #f66; } |
|
890 | .task_late { background:#f66 url(../images/task_late.png); border: 1px solid #f66; } | |
890 | .task_done { background:#00c600 url(../images/task_done.png); border: 1px solid #00c600; } |
|
891 | .task_done { background:#00c600 url(../images/task_done.png); border: 1px solid #00c600; } | |
891 | .task_todo { background:#aaa url(../images/task_todo.png); border: 1px solid #aaa; } |
|
892 | .task_todo { background:#aaa url(../images/task_todo.png); border: 1px solid #aaa; } | |
892 |
|
893 | |||
893 | .task_todo.parent { background: #888; border: 1px solid #888; height: 3px;} |
|
894 | .task_todo.parent { background: #888; border: 1px solid #888; height: 3px;} | |
894 | .task_late.parent, .task_done.parent { height: 3px;} |
|
895 | .task_late.parent, .task_done.parent { height: 3px;} | |
895 | .task.parent.marker.starting { position: absolute; background: url(../images/task_parent_end.png) no-repeat 0 0; width: 8px; height: 16px; margin-left: -4px; left: 0px; top: -1px;} |
|
896 | .task.parent.marker.starting { position: absolute; background: url(../images/task_parent_end.png) no-repeat 0 0; width: 8px; height: 16px; margin-left: -4px; left: 0px; top: -1px;} | |
896 | .task.parent.marker.ending { position: absolute; background: url(../images/task_parent_end.png) no-repeat 0 0; width: 8px; height: 16px; margin-left: -4px; right: 0px; top: -1px;} |
|
897 | .task.parent.marker.ending { position: absolute; background: url(../images/task_parent_end.png) no-repeat 0 0; width: 8px; height: 16px; margin-left: -4px; right: 0px; top: -1px;} | |
897 |
|
898 | |||
898 | .version.task_late { background:#f66 url(../images/milestone_late.png); border: 1px solid #f66; height: 2px; margin-top: 3px;} |
|
899 | .version.task_late { background:#f66 url(../images/milestone_late.png); border: 1px solid #f66; height: 2px; margin-top: 3px;} | |
899 | .version.task_done { background:#00c600 url(../images/milestone_done.png); border: 1px solid #00c600; height: 2px; margin-top: 3px;} |
|
900 | .version.task_done { background:#00c600 url(../images/milestone_done.png); border: 1px solid #00c600; height: 2px; margin-top: 3px;} | |
900 | .version.task_todo { background:#fff url(../images/milestone_todo.png); border: 1px solid #fff; height: 2px; margin-top: 3px;} |
|
901 | .version.task_todo { background:#fff url(../images/milestone_todo.png); border: 1px solid #fff; height: 2px; margin-top: 3px;} | |
901 | .version.marker { background-image:url(../images/version_marker.png); background-repeat: no-repeat; border: 0; margin-left: -4px; margin-top: 1px; } |
|
902 | .version.marker { background-image:url(../images/version_marker.png); background-repeat: no-repeat; border: 0; margin-left: -4px; margin-top: 1px; } | |
902 |
|
903 | |||
903 | .project.task_late { background:#f66 url(../images/milestone_late.png); border: 1px solid #f66; height: 2px; margin-top: 3px;} |
|
904 | .project.task_late { background:#f66 url(../images/milestone_late.png); border: 1px solid #f66; height: 2px; margin-top: 3px;} | |
904 | .project.task_done { background:#00c600 url(../images/milestone_done.png); border: 1px solid #00c600; height: 2px; margin-top: 3px;} |
|
905 | .project.task_done { background:#00c600 url(../images/milestone_done.png); border: 1px solid #00c600; height: 2px; margin-top: 3px;} | |
905 | .project.task_todo { background:#fff url(../images/milestone_todo.png); border: 1px solid #fff; height: 2px; margin-top: 3px;} |
|
906 | .project.task_todo { background:#fff url(../images/milestone_todo.png); border: 1px solid #fff; height: 2px; margin-top: 3px;} | |
906 | .project.marker { background-image:url(../images/project_marker.png); background-repeat: no-repeat; border: 0; margin-left: -4px; margin-top: 1px; } |
|
907 | .project.marker { background-image:url(../images/project_marker.png); background-repeat: no-repeat; border: 0; margin-left: -4px; margin-top: 1px; } | |
907 |
|
908 | |||
908 | .version-behind-schedule a, .issue-behind-schedule a {color: #f66914;} |
|
909 | .version-behind-schedule a, .issue-behind-schedule a {color: #f66914;} | |
909 | .version-overdue a, .issue-overdue a, .project-overdue a {color: #f00;} |
|
910 | .version-overdue a, .issue-overdue a, .project-overdue a {color: #f00;} | |
910 |
|
911 | |||
911 | /***** Icons *****/ |
|
912 | /***** Icons *****/ | |
912 | .icon { |
|
913 | .icon { | |
913 | background-position: 0% 50%; |
|
914 | background-position: 0% 50%; | |
914 | background-repeat: no-repeat; |
|
915 | background-repeat: no-repeat; | |
915 | padding-left: 20px; |
|
916 | padding-left: 20px; | |
916 | padding-top: 2px; |
|
917 | padding-top: 2px; | |
917 | padding-bottom: 3px; |
|
918 | padding-bottom: 3px; | |
918 | } |
|
919 | } | |
919 |
|
920 | |||
920 | .icon-add { background-image: url(../images/add.png); } |
|
921 | .icon-add { background-image: url(../images/add.png); } | |
921 | .icon-edit { background-image: url(../images/edit.png); } |
|
922 | .icon-edit { background-image: url(../images/edit.png); } | |
922 | .icon-copy { background-image: url(../images/copy.png); } |
|
923 | .icon-copy { background-image: url(../images/copy.png); } | |
923 | .icon-duplicate { background-image: url(../images/duplicate.png); } |
|
924 | .icon-duplicate { background-image: url(../images/duplicate.png); } | |
924 | .icon-del { background-image: url(../images/delete.png); } |
|
925 | .icon-del { background-image: url(../images/delete.png); } | |
925 | .icon-move { background-image: url(../images/move.png); } |
|
926 | .icon-move { background-image: url(../images/move.png); } | |
926 | .icon-save { background-image: url(../images/save.png); } |
|
927 | .icon-save { background-image: url(../images/save.png); } | |
927 | .icon-cancel { background-image: url(../images/cancel.png); } |
|
928 | .icon-cancel { background-image: url(../images/cancel.png); } | |
928 | .icon-multiple { background-image: url(../images/table_multiple.png); } |
|
929 | .icon-multiple { background-image: url(../images/table_multiple.png); } | |
929 | .icon-folder { background-image: url(../images/folder.png); } |
|
930 | .icon-folder { background-image: url(../images/folder.png); } | |
930 | .open .icon-folder { background-image: url(../images/folder_open.png); } |
|
931 | .open .icon-folder { background-image: url(../images/folder_open.png); } | |
931 | .icon-package { background-image: url(../images/package.png); } |
|
932 | .icon-package { background-image: url(../images/package.png); } | |
932 | .icon-user { background-image: url(../images/user.png); } |
|
933 | .icon-user { background-image: url(../images/user.png); } | |
933 | .icon-projects { background-image: url(../images/projects.png); } |
|
934 | .icon-projects { background-image: url(../images/projects.png); } | |
934 | .icon-help { background-image: url(../images/help.png); } |
|
935 | .icon-help { background-image: url(../images/help.png); } | |
935 | .icon-attachment { background-image: url(../images/attachment.png); } |
|
936 | .icon-attachment { background-image: url(../images/attachment.png); } | |
936 | .icon-history { background-image: url(../images/history.png); } |
|
937 | .icon-history { background-image: url(../images/history.png); } | |
937 | .icon-time { background-image: url(../images/time.png); } |
|
938 | .icon-time { background-image: url(../images/time.png); } | |
938 | .icon-time-add { background-image: url(../images/time_add.png); } |
|
939 | .icon-time-add { background-image: url(../images/time_add.png); } | |
939 | .icon-stats { background-image: url(../images/stats.png); } |
|
940 | .icon-stats { background-image: url(../images/stats.png); } | |
940 | .icon-warning { background-image: url(../images/warning.png); } |
|
941 | .icon-warning { background-image: url(../images/warning.png); } | |
941 | .icon-fav { background-image: url(../images/fav.png); } |
|
942 | .icon-fav { background-image: url(../images/fav.png); } | |
942 | .icon-fav-off { background-image: url(../images/fav_off.png); } |
|
943 | .icon-fav-off { background-image: url(../images/fav_off.png); } | |
943 | .icon-reload { background-image: url(../images/reload.png); } |
|
944 | .icon-reload { background-image: url(../images/reload.png); } | |
944 | .icon-lock { background-image: url(../images/locked.png); } |
|
945 | .icon-lock { background-image: url(../images/locked.png); } | |
945 | .icon-unlock { background-image: url(../images/unlock.png); } |
|
946 | .icon-unlock { background-image: url(../images/unlock.png); } | |
946 | .icon-checked { background-image: url(../images/true.png); } |
|
947 | .icon-checked { background-image: url(../images/true.png); } | |
947 | .icon-details { background-image: url(../images/zoom_in.png); } |
|
948 | .icon-details { background-image: url(../images/zoom_in.png); } | |
948 | .icon-report { background-image: url(../images/report.png); } |
|
949 | .icon-report { background-image: url(../images/report.png); } | |
949 | .icon-comment { background-image: url(../images/comment.png); } |
|
950 | .icon-comment { background-image: url(../images/comment.png); } | |
950 | .icon-summary { background-image: url(../images/lightning.png); } |
|
951 | .icon-summary { background-image: url(../images/lightning.png); } | |
951 | .icon-server-authentication { background-image: url(../images/server_key.png); } |
|
952 | .icon-server-authentication { background-image: url(../images/server_key.png); } | |
952 | .icon-issue { background-image: url(../images/ticket.png); } |
|
953 | .icon-issue { background-image: url(../images/ticket.png); } | |
953 | .icon-zoom-in { background-image: url(../images/zoom_in.png); } |
|
954 | .icon-zoom-in { background-image: url(../images/zoom_in.png); } | |
954 | .icon-zoom-out { background-image: url(../images/zoom_out.png); } |
|
955 | .icon-zoom-out { background-image: url(../images/zoom_out.png); } | |
955 | .icon-passwd { background-image: url(../images/textfield_key.png); } |
|
956 | .icon-passwd { background-image: url(../images/textfield_key.png); } | |
956 | .icon-test { background-image: url(../images/bullet_go.png); } |
|
957 | .icon-test { background-image: url(../images/bullet_go.png); } | |
957 |
|
958 | |||
958 | .icon-file { background-image: url(../images/files/default.png); } |
|
959 | .icon-file { background-image: url(../images/files/default.png); } | |
959 | .icon-file.text-plain { background-image: url(../images/files/text.png); } |
|
960 | .icon-file.text-plain { background-image: url(../images/files/text.png); } | |
960 | .icon-file.text-x-c { background-image: url(../images/files/c.png); } |
|
961 | .icon-file.text-x-c { background-image: url(../images/files/c.png); } | |
961 | .icon-file.text-x-csharp { background-image: url(../images/files/csharp.png); } |
|
962 | .icon-file.text-x-csharp { background-image: url(../images/files/csharp.png); } | |
962 | .icon-file.text-x-java { background-image: url(../images/files/java.png); } |
|
963 | .icon-file.text-x-java { background-image: url(../images/files/java.png); } | |
963 | .icon-file.text-x-javascript { background-image: url(../images/files/js.png); } |
|
964 | .icon-file.text-x-javascript { background-image: url(../images/files/js.png); } | |
964 | .icon-file.text-x-php { background-image: url(../images/files/php.png); } |
|
965 | .icon-file.text-x-php { background-image: url(../images/files/php.png); } | |
965 | .icon-file.text-x-ruby { background-image: url(../images/files/ruby.png); } |
|
966 | .icon-file.text-x-ruby { background-image: url(../images/files/ruby.png); } | |
966 | .icon-file.text-xml { background-image: url(../images/files/xml.png); } |
|
967 | .icon-file.text-xml { background-image: url(../images/files/xml.png); } | |
967 | .icon-file.text-css { background-image: url(../images/files/css.png); } |
|
968 | .icon-file.text-css { background-image: url(../images/files/css.png); } | |
968 | .icon-file.text-html { background-image: url(../images/files/html.png); } |
|
969 | .icon-file.text-html { background-image: url(../images/files/html.png); } | |
969 | .icon-file.image-gif { background-image: url(../images/files/image.png); } |
|
970 | .icon-file.image-gif { background-image: url(../images/files/image.png); } | |
970 | .icon-file.image-jpeg { background-image: url(../images/files/image.png); } |
|
971 | .icon-file.image-jpeg { background-image: url(../images/files/image.png); } | |
971 | .icon-file.image-png { background-image: url(../images/files/image.png); } |
|
972 | .icon-file.image-png { background-image: url(../images/files/image.png); } | |
972 | .icon-file.image-tiff { background-image: url(../images/files/image.png); } |
|
973 | .icon-file.image-tiff { background-image: url(../images/files/image.png); } | |
973 | .icon-file.application-pdf { background-image: url(../images/files/pdf.png); } |
|
974 | .icon-file.application-pdf { background-image: url(../images/files/pdf.png); } | |
974 | .icon-file.application-zip { background-image: url(../images/files/zip.png); } |
|
975 | .icon-file.application-zip { background-image: url(../images/files/zip.png); } | |
975 | .icon-file.application-x-gzip { background-image: url(../images/files/zip.png); } |
|
976 | .icon-file.application-x-gzip { background-image: url(../images/files/zip.png); } | |
976 |
|
977 | |||
977 | img.gravatar { |
|
978 | img.gravatar { | |
978 | padding: 2px; |
|
979 | padding: 2px; | |
979 | border: solid 1px #d5d5d5; |
|
980 | border: solid 1px #d5d5d5; | |
980 | background: #fff; |
|
981 | background: #fff; | |
981 | vertical-align: middle; |
|
982 | vertical-align: middle; | |
982 | } |
|
983 | } | |
983 |
|
984 | |||
984 | div.issue img.gravatar { |
|
985 | div.issue img.gravatar { | |
985 | float: left; |
|
986 | float: left; | |
986 | margin: 0 6px 0 0; |
|
987 | margin: 0 6px 0 0; | |
987 | padding: 5px; |
|
988 | padding: 5px; | |
988 | } |
|
989 | } | |
989 |
|
990 | |||
990 | div.issue table img.gravatar { |
|
991 | div.issue table img.gravatar { | |
991 | height: 14px; |
|
992 | height: 14px; | |
992 | width: 14px; |
|
993 | width: 14px; | |
993 | padding: 2px; |
|
994 | padding: 2px; | |
994 | float: left; |
|
995 | float: left; | |
995 | margin: 0 0.5em 0 0; |
|
996 | margin: 0 0.5em 0 0; | |
996 | } |
|
997 | } | |
997 |
|
998 | |||
998 | h2 img.gravatar {margin: -2px 4px -4px 0;} |
|
999 | h2 img.gravatar {margin: -2px 4px -4px 0;} | |
999 | h3 img.gravatar {margin: -4px 4px -4px 0;} |
|
1000 | h3 img.gravatar {margin: -4px 4px -4px 0;} | |
1000 | h4 img.gravatar {margin: -6px 4px -4px 0;} |
|
1001 | h4 img.gravatar {margin: -6px 4px -4px 0;} | |
1001 | td.username img.gravatar {margin: 0 0.5em 0 0; vertical-align: top;} |
|
1002 | td.username img.gravatar {margin: 0 0.5em 0 0; vertical-align: top;} | |
1002 | #activity dt img.gravatar {float: left; margin: 0 1em 1em 0;} |
|
1003 | #activity dt img.gravatar {float: left; margin: 0 1em 1em 0;} | |
1003 | /* Used on 12px Gravatar img tags without the icon background */ |
|
1004 | /* Used on 12px Gravatar img tags without the icon background */ | |
1004 | .icon-gravatar {float: left; margin-right: 4px;} |
|
1005 | .icon-gravatar {float: left; margin-right: 4px;} | |
1005 |
|
1006 | |||
1006 | #activity dt, .journal {clear: left;} |
|
1007 | #activity dt, .journal {clear: left;} | |
1007 |
|
1008 | |||
1008 | .journal-link {float: right;} |
|
1009 | .journal-link {float: right;} | |
1009 |
|
1010 | |||
1010 | h2 img { vertical-align:middle; } |
|
1011 | h2 img { vertical-align:middle; } | |
1011 |
|
1012 | |||
1012 | .hascontextmenu { cursor: context-menu; } |
|
1013 | .hascontextmenu { cursor: context-menu; } | |
1013 |
|
1014 | |||
1014 | /************* CodeRay styles *************/ |
|
1015 | /************* CodeRay styles *************/ | |
1015 | .syntaxhl div {display: inline;} |
|
1016 | .syntaxhl div {display: inline;} | |
1016 | .syntaxhl .line-numbers {padding: 2px 4px 2px 4px; background-color: #eee; margin:0px 5px 0px 0px;} |
|
1017 | .syntaxhl .line-numbers {padding: 2px 4px 2px 4px; background-color: #eee; margin:0px 5px 0px 0px;} | |
1017 | .syntaxhl .code pre { overflow: auto } |
|
1018 | .syntaxhl .code pre { overflow: auto } | |
1018 | .syntaxhl .debug { color: white !important; background: blue !important; } |
|
1019 | .syntaxhl .debug { color: white !important; background: blue !important; } | |
1019 |
|
1020 | |||
1020 | .syntaxhl .annotation { color:#007 } |
|
1021 | .syntaxhl .annotation { color:#007 } | |
1021 | .syntaxhl .attribute-name { color:#b48 } |
|
1022 | .syntaxhl .attribute-name { color:#b48 } | |
1022 | .syntaxhl .attribute-value { color:#700 } |
|
1023 | .syntaxhl .attribute-value { color:#700 } | |
1023 | .syntaxhl .binary { color:#509 } |
|
1024 | .syntaxhl .binary { color:#509 } | |
1024 | .syntaxhl .char .content { color:#D20 } |
|
1025 | .syntaxhl .char .content { color:#D20 } | |
1025 | .syntaxhl .char .delimiter { color:#710 } |
|
1026 | .syntaxhl .char .delimiter { color:#710 } | |
1026 | .syntaxhl .char { color:#D20 } |
|
1027 | .syntaxhl .char { color:#D20 } | |
1027 | .syntaxhl .class { color:#258; font-weight:bold } |
|
1028 | .syntaxhl .class { color:#258; font-weight:bold } | |
1028 | .syntaxhl .class-variable { color:#369 } |
|
1029 | .syntaxhl .class-variable { color:#369 } | |
1029 | .syntaxhl .color { color:#0A0 } |
|
1030 | .syntaxhl .color { color:#0A0 } | |
1030 | .syntaxhl .comment { color:#385 } |
|
1031 | .syntaxhl .comment { color:#385 } | |
1031 | .syntaxhl .comment .char { color:#385 } |
|
1032 | .syntaxhl .comment .char { color:#385 } | |
1032 | .syntaxhl .comment .delimiter { color:#385 } |
|
1033 | .syntaxhl .comment .delimiter { color:#385 } | |
1033 | .syntaxhl .complex { color:#A08 } |
|
1034 | .syntaxhl .complex { color:#A08 } | |
1034 | .syntaxhl .constant { color:#258; font-weight:bold } |
|
1035 | .syntaxhl .constant { color:#258; font-weight:bold } | |
1035 | .syntaxhl .decorator { color:#B0B } |
|
1036 | .syntaxhl .decorator { color:#B0B } | |
1036 | .syntaxhl .definition { color:#099; font-weight:bold } |
|
1037 | .syntaxhl .definition { color:#099; font-weight:bold } | |
1037 | .syntaxhl .delimiter { color:black } |
|
1038 | .syntaxhl .delimiter { color:black } | |
1038 | .syntaxhl .directive { color:#088; font-weight:bold } |
|
1039 | .syntaxhl .directive { color:#088; font-weight:bold } | |
1039 | .syntaxhl .doc { color:#970 } |
|
1040 | .syntaxhl .doc { color:#970 } | |
1040 | .syntaxhl .doc-string { color:#D42; font-weight:bold } |
|
1041 | .syntaxhl .doc-string { color:#D42; font-weight:bold } | |
1041 | .syntaxhl .doctype { color:#34b } |
|
1042 | .syntaxhl .doctype { color:#34b } | |
1042 | .syntaxhl .entity { color:#800; font-weight:bold } |
|
1043 | .syntaxhl .entity { color:#800; font-weight:bold } | |
1043 | .syntaxhl .error { color:#F00; background-color:#FAA } |
|
1044 | .syntaxhl .error { color:#F00; background-color:#FAA } | |
1044 | .syntaxhl .escape { color:#666 } |
|
1045 | .syntaxhl .escape { color:#666 } | |
1045 | .syntaxhl .exception { color:#C00; font-weight:bold } |
|
1046 | .syntaxhl .exception { color:#C00; font-weight:bold } | |
1046 | .syntaxhl .float { color:#06D } |
|
1047 | .syntaxhl .float { color:#06D } | |
1047 | .syntaxhl .function { color:#06B; font-weight:bold } |
|
1048 | .syntaxhl .function { color:#06B; font-weight:bold } | |
1048 | .syntaxhl .global-variable { color:#d70 } |
|
1049 | .syntaxhl .global-variable { color:#d70 } | |
1049 | .syntaxhl .hex { color:#02b } |
|
1050 | .syntaxhl .hex { color:#02b } | |
1050 | .syntaxhl .imaginary { color:#f00 } |
|
1051 | .syntaxhl .imaginary { color:#f00 } | |
1051 | .syntaxhl .include { color:#B44; font-weight:bold } |
|
1052 | .syntaxhl .include { color:#B44; font-weight:bold } | |
1052 | .syntaxhl .inline { background-color: hsla(0,0%,0%,0.07); color: black } |
|
1053 | .syntaxhl .inline { background-color: hsla(0,0%,0%,0.07); color: black } | |
1053 | .syntaxhl .inline-delimiter { font-weight: bold; color: #666 } |
|
1054 | .syntaxhl .inline-delimiter { font-weight: bold; color: #666 } | |
1054 | .syntaxhl .instance-variable { color:#33B } |
|
1055 | .syntaxhl .instance-variable { color:#33B } | |
1055 | .syntaxhl .integer { color:#06D } |
|
1056 | .syntaxhl .integer { color:#06D } | |
1056 | .syntaxhl .key .char { color: #60f } |
|
1057 | .syntaxhl .key .char { color: #60f } | |
1057 | .syntaxhl .key .delimiter { color: #404 } |
|
1058 | .syntaxhl .key .delimiter { color: #404 } | |
1058 | .syntaxhl .key { color: #606 } |
|
1059 | .syntaxhl .key { color: #606 } | |
1059 | .syntaxhl .keyword { color:#939; font-weight:bold } |
|
1060 | .syntaxhl .keyword { color:#939; font-weight:bold } | |
1060 | .syntaxhl .label { color:#970; font-weight:bold } |
|
1061 | .syntaxhl .label { color:#970; font-weight:bold } | |
1061 | .syntaxhl .local-variable { color:#963 } |
|
1062 | .syntaxhl .local-variable { color:#963 } | |
1062 | .syntaxhl .namespace { color:#707; font-weight:bold } |
|
1063 | .syntaxhl .namespace { color:#707; font-weight:bold } | |
1063 | .syntaxhl .octal { color:#40E } |
|
1064 | .syntaxhl .octal { color:#40E } | |
1064 | .syntaxhl .operator { } |
|
1065 | .syntaxhl .operator { } | |
1065 | .syntaxhl .predefined { color:#369; font-weight:bold } |
|
1066 | .syntaxhl .predefined { color:#369; font-weight:bold } | |
1066 | .syntaxhl .predefined-constant { color:#069 } |
|
1067 | .syntaxhl .predefined-constant { color:#069 } | |
1067 | .syntaxhl .predefined-type { color:#0a5; font-weight:bold } |
|
1068 | .syntaxhl .predefined-type { color:#0a5; font-weight:bold } | |
1068 | .syntaxhl .preprocessor { color:#579 } |
|
1069 | .syntaxhl .preprocessor { color:#579 } | |
1069 | .syntaxhl .pseudo-class { color:#00C; font-weight:bold } |
|
1070 | .syntaxhl .pseudo-class { color:#00C; font-weight:bold } | |
1070 | .syntaxhl .regexp .content { color:#808 } |
|
1071 | .syntaxhl .regexp .content { color:#808 } | |
1071 | .syntaxhl .regexp .delimiter { color:#404 } |
|
1072 | .syntaxhl .regexp .delimiter { color:#404 } | |
1072 | .syntaxhl .regexp .modifier { color:#C2C } |
|
1073 | .syntaxhl .regexp .modifier { color:#C2C } | |
1073 | .syntaxhl .regexp { background-color:hsla(300,100%,50%,0.06); } |
|
1074 | .syntaxhl .regexp { background-color:hsla(300,100%,50%,0.06); } | |
1074 | .syntaxhl .reserved { color:#080; font-weight:bold } |
|
1075 | .syntaxhl .reserved { color:#080; font-weight:bold } | |
1075 | .syntaxhl .shell .content { color:#2B2 } |
|
1076 | .syntaxhl .shell .content { color:#2B2 } | |
1076 | .syntaxhl .shell .delimiter { color:#161 } |
|
1077 | .syntaxhl .shell .delimiter { color:#161 } | |
1077 | .syntaxhl .shell { background-color:hsla(120,100%,50%,0.06); } |
|
1078 | .syntaxhl .shell { background-color:hsla(120,100%,50%,0.06); } | |
1078 | .syntaxhl .string .char { color: #46a } |
|
1079 | .syntaxhl .string .char { color: #46a } | |
1079 | .syntaxhl .string .content { color: #46a } |
|
1080 | .syntaxhl .string .content { color: #46a } | |
1080 | .syntaxhl .string .delimiter { color: #46a } |
|
1081 | .syntaxhl .string .delimiter { color: #46a } | |
1081 | .syntaxhl .string .modifier { color: #46a } |
|
1082 | .syntaxhl .string .modifier { color: #46a } | |
1082 | .syntaxhl .symbol .content { color:#d33 } |
|
1083 | .syntaxhl .symbol .content { color:#d33 } | |
1083 | .syntaxhl .symbol .delimiter { color:#d33 } |
|
1084 | .syntaxhl .symbol .delimiter { color:#d33 } | |
1084 | .syntaxhl .symbol { color:#d33 } |
|
1085 | .syntaxhl .symbol { color:#d33 } | |
1085 | .syntaxhl .tag { color:#070 } |
|
1086 | .syntaxhl .tag { color:#070 } | |
1086 | .syntaxhl .type { color:#339; font-weight:bold } |
|
1087 | .syntaxhl .type { color:#339; font-weight:bold } | |
1087 | .syntaxhl .value { color: #088; } |
|
1088 | .syntaxhl .value { color: #088; } | |
1088 | .syntaxhl .variable { color:#037 } |
|
1089 | .syntaxhl .variable { color:#037 } | |
1089 |
|
1090 | |||
1090 | .syntaxhl .insert { background: hsla(120,100%,50%,0.12) } |
|
1091 | .syntaxhl .insert { background: hsla(120,100%,50%,0.12) } | |
1091 | .syntaxhl .delete { background: hsla(0,100%,50%,0.12) } |
|
1092 | .syntaxhl .delete { background: hsla(0,100%,50%,0.12) } | |
1092 | .syntaxhl .change { color: #bbf; background: #007; } |
|
1093 | .syntaxhl .change { color: #bbf; background: #007; } | |
1093 | .syntaxhl .head { color: #f8f; background: #505 } |
|
1094 | .syntaxhl .head { color: #f8f; background: #505 } | |
1094 | .syntaxhl .head .filename { color: white; } |
|
1095 | .syntaxhl .head .filename { color: white; } | |
1095 |
|
1096 | |||
1096 | .syntaxhl .delete .eyecatcher { background-color: hsla(0,100%,50%,0.2); border: 1px solid hsla(0,100%,45%,0.5); margin: -1px; border-bottom: none; border-top-left-radius: 5px; border-top-right-radius: 5px; } |
|
1097 | .syntaxhl .delete .eyecatcher { background-color: hsla(0,100%,50%,0.2); border: 1px solid hsla(0,100%,45%,0.5); margin: -1px; border-bottom: none; border-top-left-radius: 5px; border-top-right-radius: 5px; } | |
1097 | .syntaxhl .insert .eyecatcher { background-color: hsla(120,100%,50%,0.2); border: 1px solid hsla(120,100%,25%,0.5); margin: -1px; border-top: none; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; } |
|
1098 | .syntaxhl .insert .eyecatcher { background-color: hsla(120,100%,50%,0.2); border: 1px solid hsla(120,100%,25%,0.5); margin: -1px; border-top: none; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; } | |
1098 |
|
1099 | |||
1099 | .syntaxhl .insert .insert { color: #0c0; background:transparent; font-weight:bold } |
|
1100 | .syntaxhl .insert .insert { color: #0c0; background:transparent; font-weight:bold } | |
1100 | .syntaxhl .delete .delete { color: #c00; background:transparent; font-weight:bold } |
|
1101 | .syntaxhl .delete .delete { color: #c00; background:transparent; font-weight:bold } | |
1101 | .syntaxhl .change .change { color: #88f } |
|
1102 | .syntaxhl .change .change { color: #88f } | |
1102 | .syntaxhl .head .head { color: #f4f } |
|
1103 | .syntaxhl .head .head { color: #f4f } | |
1103 |
|
1104 | |||
1104 | /***** Media print specific styles *****/ |
|
1105 | /***** Media print specific styles *****/ | |
1105 | @media print { |
|
1106 | @media print { | |
1106 | #top-menu, #header, #main-menu, #sidebar, #footer, .contextual, .other-formats { display:none; } |
|
1107 | #top-menu, #header, #main-menu, #sidebar, #footer, .contextual, .other-formats { display:none; } | |
1107 | #main { background: #fff; } |
|
1108 | #main { background: #fff; } | |
1108 | #content { width: 99%; margin: 0; padding: 0; border: 0; background: #fff; overflow: visible !important;} |
|
1109 | #content { width: 99%; margin: 0; padding: 0; border: 0; background: #fff; overflow: visible !important;} | |
1109 | #wiki_add_attachment { display:none; } |
|
1110 | #wiki_add_attachment { display:none; } | |
1110 | .hide-when-print { display: none; } |
|
1111 | .hide-when-print { display: none; } | |
1111 | .autoscroll {overflow-x: visible;} |
|
1112 | .autoscroll {overflow-x: visible;} | |
1112 | table.list {margin-top:0.5em;} |
|
1113 | table.list {margin-top:0.5em;} | |
1113 | table.list th, table.list td {border: 1px solid #aaa;} |
|
1114 | table.list th, table.list td {border: 1px solid #aaa;} | |
1114 | } |
|
1115 | } | |
1115 |
|
1116 | |||
1116 | /* Accessibility specific styles */ |
|
1117 | /* Accessibility specific styles */ | |
1117 | .hidden-for-sighted { |
|
1118 | .hidden-for-sighted { | |
1118 | position:absolute; |
|
1119 | position:absolute; | |
1119 | left:-10000px; |
|
1120 | left:-10000px; | |
1120 | top:auto; |
|
1121 | top:auto; | |
1121 | width:1px; |
|
1122 | width:1px; | |
1122 | height:1px; |
|
1123 | height:1px; | |
1123 | overflow:hidden; |
|
1124 | overflow:hidden; | |
1124 | } |
|
1125 | } |
General Comments 0
You need to be logged in to leave comments.
Login now