@@ -18,9 +18,12 | |||
|
18 | 18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
19 | 19 | |
|
20 | 20 | module QueriesHelper |
|
21 | ||
|
22 | def operators_for_select(filter_type) | |
|
23 | Query.operators_by_filter_type[filter_type].collect {|o| [l(Query.operators[o]), o]} | |
|
21 | def filters_options_for_select(query) | |
|
22 | options = [[]] | |
|
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 | 27 | end |
|
25 | 28 | |
|
26 | 29 | def column_header(column) |
@@ -214,6 +214,11 class Query < ActiveRecord::Base | |||
|
214 | 214 | @trackers ||= project.nil? ? Tracker.find(:all, :order => 'position') : project.rolled_up_trackers |
|
215 | 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 | 222 | def available_filters |
|
218 | 223 | return @available_filters if @available_filters |
|
219 | 224 | |
@@ -309,9 +314,22 class Query < ActiveRecord::Base | |||
|
309 | 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 | 321 | @available_filters |
|
313 | 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 | 333 | def add_filter(field, operator, values) |
|
316 | 334 | # values must be an array |
|
317 | 335 | return unless values.nil? || values.is_a?(Array) |
@@ -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 | 14 | <table style="width:100%"> |
|
2 | 15 | <tr> |
|
3 | 16 | <td> |
|
4 | <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 %> | |
|
17 | <table id="filters-table"> | |
|
42 | 18 | </table> |
|
43 | 19 | </td> |
|
44 | 20 | <td class="add-filter"> |
|
45 | 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), | |
|
47 | :onchange => "add_filter();", | |
|
48 | :name => nil %> | |
|
22 | <%= select_tag 'add_filter_select', filters_options_for_select(query), :name => nil %> | |
|
49 | 23 | </td> |
|
50 | 24 | </tr> |
|
51 | 25 | </table> |
|
52 | 26 | <%= hidden_field_tag 'f[]', '' %> |
|
53 | <%= javascript_tag '$(document).ready(function(){observeIssueFilters();});' %> | |
|
27 | <% include_calendar_headers_tags %> |
@@ -23,7 +23,7 | |||
|
23 | 23 | <%= select 'query', 'group_by', @query.groupable_columns.collect {|c| [c.caption, c.name.to_s]}, :include_blank => true %></p> |
|
24 | 24 | </div> |
|
25 | 25 | |
|
26 | <fieldset><legend><%= l(:label_filter_plural) %></legend> | |
|
26 | <fieldset id="filters"><legend><%= l(:label_filter_plural) %></legend> | |
|
27 | 27 | <%= render :partial => 'queries/filters', :locals => {:query => query}%> |
|
28 | 28 | </fieldset> |
|
29 | 29 |
@@ -78,35 +78,131 function hideFieldset(el) { | |||
|
78 | 78 | fieldset.children('div').hide(); |
|
79 | 79 | } |
|
80 | 80 | |
|
81 |
function |
|
|
82 |
|
|
|
83 | var field = select.val(); | |
|
84 | $('#tr_'+field).show(); | |
|
85 | var check_box = $('#cb_' + field); | |
|
86 | check_box.attr('checked', true); | |
|
87 | toggle_filter(field); | |
|
88 | select.val(''); | |
|
89 | ||
|
90 | select.children('option').each(function(index) { | |
|
81 | function initFilters(){ | |
|
82 | $('#add_filter_select').change(function(){ | |
|
83 | addFilter($(this).val(), '', []); | |
|
84 | }); | |
|
85 | $('#filters-table td.field input[type=checkbox]').each(function(){ | |
|
86 | toggleFilter($(this).val()); | |
|
87 | }); | |
|
88 | $('#filters-table td.field input[type=checkbox]').live('click',function(){ | |
|
89 | toggleFilter($(this).val()); | |
|
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 | 110 | if ($(this).attr('value') == field) { |
|
92 | 111 | $(this).attr('disabled', true); |
|
93 | 112 | } |
|
94 | 113 | }); |
|
95 | 114 | } |
|
96 | 115 | |
|
97 | function toggle_filter(field) { | |
|
98 | check_box = $('#cb_' + field); | |
|
99 | if (check_box.is(':checked')) { | |
|
100 | $("#operators_" + field).show().removeAttr('disabled'); | |
|
101 | toggle_operator(field); | |
|
116 | function buildFilterRow(field, operator, values) { | |
|
117 | var fieldId = field.replace('.', '_'); | |
|
118 | var filterTable = $("#filters-table"); | |
|
119 | var filterOptions = availableFilters[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]); | |
|
102 | 155 | } else { |
|
103 | $("#operators_" + field).hide().attr('disabled', true); | |
|
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); | |
|
197 | } else { | |
|
198 | $("#operators_" + fieldId).hide().attr('disabled', true); | |
|
104 | 199 | enableValues(field, []); |
|
105 | 200 | } |
|
106 | 201 | } |
|
107 | 202 | |
|
108 | 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 | 206 | if (indexes.indexOf(index) >= 0) { |
|
111 | 207 | $(this).removeAttr('disabled'); |
|
112 | 208 | $(this).parents('span').first().show(); |
@@ -122,16 +218,11 function enableValues(field, indexes) { | |||
|
122 | 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 |
|
|
134 | operator = $("#operators_" + field); | |
|
223 | function toggleOperator(field) { | |
|
224 | var fieldId = field.replace('.', '_'); | |
|
225 | var operator = $("#operators_" + fieldId); | |
|
135 | 226 | switch (operator.val()) { |
|
136 | 227 | case "!*": |
|
137 | 228 | case "*": |
@@ -158,12 +249,11 function toggle_operator(field) { | |||
|
158 | 249 | } |
|
159 | 250 | } |
|
160 | 251 | |
|
161 |
function toggle |
|
|
162 | var select = $('#'+id); | |
|
163 |
|
|
|
164 | select.removeAttr('multiple'); | |
|
252 | function toggleMultiSelect(el) { | |
|
253 | if (el.attr('multiple')) { | |
|
254 | el.removeAttr('multiple'); | |
|
165 | 255 | } else { |
|
166 |
|
|
|
256 | el.attr('multiple', true); | |
|
167 | 257 | } |
|
168 | 258 | } |
|
169 | 259 | |
@@ -172,12 +262,6 function submit_query_form(id) { | |||
|
172 | 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 | 265 | var fileFieldCount = 1; |
|
182 | 266 | function addFileField() { |
|
183 | 267 | var fields = $('#attachments_fields'); |
@@ -338,13 +338,14 fieldset.collapsible.collapsed legend { background-image: url(../images/arrow_co | |||
|
338 | 338 | fieldset#date-range p { margin: 2px 0 2px 0; } |
|
339 | 339 | fieldset#filters table { border-collapse: collapse; } |
|
340 | 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 | 342 | fieldset#filters td.field { width:200px; } |
|
343 | 343 | fieldset#filters td.operator { width:170px; } |
|
344 | 344 | fieldset#filters td.values { white-space:nowrap; } |
|
345 | 345 | fieldset#filters td.values select {min-width:130px;} |
|
346 |
fieldset#filters td.values i |
|
|
346 | fieldset#filters td.values input {height:1em;} | |
|
347 | 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 | 349 | .buttons { font-size: 0.9em; margin-bottom: 1.4em; margin-top: 1em; } |
|
349 | 350 | |
|
350 | 351 | div#issue-changesets {float:right; width:45%; margin-left: 1em; margin-bottom: 1em; background: #fff; padding-left: 1em; font-size: 90%;} |
General Comments 0
You need to be logged in to leave comments.
Login now