:list_status => [ "o", "=", "!", "c", "*" ],
:list_optional => [ "=", "!", "!*", "*" ],
:list_subprojects => [ "*", "!*", "=" ],
- :date => [ "<t+", ">t+", "t+", "t", "w", ">t-", "<t-", "t-" ],
- :date_past => [ ">t-", "<t-", "t-", "t", "w" ],
+ :date => [ "=", ">=", "<=", "><", "<t+", ">t+", "t+", "t", "w", ">t-", "<t-", "t-" ],
+ :date_past => [ "=", ">=", "<=", "><", ">t-", "<t-", "t-", "t", "w" ],
:string => [ "=", "~", "!", "!~" ],
:text => [ "~", "!~" ],
:integer => [ "=", ">=", "<=", "><", "!*", "*" ] }
def add_filter(field, operator, values)
# values must be an array
- return unless values and values.is_a? Array # and !values.first.empty?
+ return unless values.nil? || values.is_a?(Array)
# check if field is defined as an available filter
if available_filters.has_key? field
filter_options = available_filters[field]
# allowed_values = values & ([""] + (filter_options[:values] || []).collect {|val| val[1]})
# filters[field] = {:operator => operator, :values => allowed_values } if (allowed_values.first and !allowed_values.first.empty?) or ["o", "c", "!*", "*", "t"].include? operator
#end
- filters[field] = {:operator => operator, :values => values }
+ filters[field] = {:operator => operator, :values => (values || ['']) }
end
end
# Add multiple filters using +add_filter+
def add_filters(fields, operators, values)
- if fields.is_a?(Array) && operators.is_a?(Hash) && values.is_a?(Hash)
+ if fields.is_a?(Array) && operators.is_a?(Hash) && (values.nil? || values.is_a?(Hash))
fields.each do |field|
- add_filter(field, operators[field], values[field])
+ add_filter(field, operators[field], values && values[field])
end
end
end
def has_filter?(field)
filters and filters[field]
end
+
+ def type_for(field)
+ available_filters[field][:type] if available_filters.has_key?(field)
+ end
def operator_for(field)
has_filter?(field) ? filters[field][:operator] : nil
sql = ''
case operator
when "="
- if value.any?
- sql = "#{db_table}.#{db_field} IN (" + value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + ")"
+ if [:date, :date_past].include?(type_for(field))
+ sql = date_clause(db_table, db_field, (Date.parse(value.first) rescue nil), (Date.parse(value.first) rescue nil))
else
- # IN an empty set
- sql = "1=0"
+ if value.any?
+ sql = "#{db_table}.#{db_field} IN (" + value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + ")"
+ else
+ # IN an empty set
+ sql = "1=0"
+ end
end
when "!"
if value.any?
sql = "#{db_table}.#{db_field} IS NOT NULL"
sql << " AND #{db_table}.#{db_field} <> ''" if is_custom_filter
when ">="
- if is_custom_filter
- sql = "CAST(#{db_table}.#{db_field} AS decimal(60,3)) >= #{value.first.to_i}"
+ if [:date, :date_past].include?(type_for(field))
+ sql = date_clause(db_table, db_field, (Date.parse(value.first) rescue nil), nil)
else
- sql = "#{db_table}.#{db_field} >= #{value.first.to_i}"
+ if is_custom_filter
+ sql = "CAST(#{db_table}.#{db_field} AS decimal(60,3)) >= #{value.first.to_i}"
+ else
+ sql = "#{db_table}.#{db_field} >= #{value.first.to_i}"
+ end
end
when "<="
- if is_custom_filter
- sql = "CAST(#{db_table}.#{db_field} AS decimal(60,3)) <= #{value.first.to_i}"
+ if [:date, :date_past].include?(type_for(field))
+ sql = date_clause(db_table, db_field, nil, (Date.parse(value.first) rescue nil))
else
- sql = "#{db_table}.#{db_field} <= #{value.first.to_i}"
+ if is_custom_filter
+ sql = "CAST(#{db_table}.#{db_field} AS decimal(60,3)) <= #{value.first.to_i}"
+ else
+ sql = "#{db_table}.#{db_field} <= #{value.first.to_i}"
+ end
end
when "><"
- if is_custom_filter
- sql = "CAST(#{db_table}.#{db_field} AS decimal(60,3)) BETWEEN #{value[0].to_i} AND #{value[1].to_i}"
+ if [:date, :date_past].include?(type_for(field))
+ sql = date_clause(db_table, db_field, (Date.parse(value[0]) rescue nil), (Date.parse(value[1]) rescue nil))
else
- sql = "#{db_table}.#{db_field} BETWEEN #{value[0].to_i} AND #{value[1].to_i}"
+ if is_custom_filter
+ sql = "CAST(#{db_table}.#{db_field} AS decimal(60,3)) BETWEEN #{value[0].to_i} AND #{value[1].to_i}"
+ else
+ sql = "#{db_table}.#{db_field} BETWEEN #{value[0].to_i} AND #{value[1].to_i}"
+ end
end
when "o"
sql = "#{IssueStatus.table_name}.is_closed=#{connection.quoted_false}" if field == "status_id"
when "c"
sql = "#{IssueStatus.table_name}.is_closed=#{connection.quoted_true}" if field == "status_id"
when ">t-"
- sql = date_range_clause(db_table, db_field, - value.first.to_i, 0)
+ sql = relative_date_clause(db_table, db_field, - value.first.to_i, 0)
when "<t-"
- sql = date_range_clause(db_table, db_field, nil, - value.first.to_i)
+ sql = relative_date_clause(db_table, db_field, nil, - value.first.to_i)
when "t-"
- sql = date_range_clause(db_table, db_field, - value.first.to_i, - value.first.to_i)
+ sql = relative_date_clause(db_table, db_field, - value.first.to_i, - value.first.to_i)
when ">t+"
- sql = date_range_clause(db_table, db_field, value.first.to_i, nil)
+ sql = relative_date_clause(db_table, db_field, value.first.to_i, nil)
when "<t+"
- sql = date_range_clause(db_table, db_field, 0, value.first.to_i)
+ sql = relative_date_clause(db_table, db_field, 0, value.first.to_i)
when "t+"
- sql = date_range_clause(db_table, db_field, value.first.to_i, value.first.to_i)
+ sql = relative_date_clause(db_table, db_field, value.first.to_i, value.first.to_i)
when "t"
- sql = date_range_clause(db_table, db_field, 0, 0)
+ sql = relative_date_clause(db_table, db_field, 0, 0)
when "w"
first_day_of_week = l(:general_first_day_of_week).to_i
day_of_week = Date.today.cwday
days_ago = (day_of_week >= first_day_of_week ? day_of_week - first_day_of_week : day_of_week + 7 - first_day_of_week)
- sql = date_range_clause(db_table, db_field, - days_ago, - days_ago + 6)
+ sql = relative_date_clause(db_table, db_field, - days_ago, - days_ago + 6)
when "~"
sql = "LOWER(#{db_table}.#{db_field}) LIKE '%#{connection.quote_string(value.first.to_s.downcase)}%'"
when "!~"
@available_filters["cf_#{field.id}"] = options.merge({ :name => field.name })
end
end
-
+
# Returns a SQL clause for a date or datetime field.
- def date_range_clause(table, field, from, to)
+ def date_clause(table, field, from, to)
s = []
if from
- s << ("#{table}.#{field} > '%s'" % [connection.quoted_date((Date.yesterday + from).to_time.end_of_day)])
+ s << ("#{table}.#{field} > '%s'" % [connection.quoted_date((from - 1).to_time.end_of_day)])
end
if to
- s << ("#{table}.#{field} <= '%s'" % [connection.quoted_date((Date.today + to).to_time.end_of_day)])
+ s << ("#{table}.#{field} <= '%s'" % [connection.quoted_date(to.to_time.end_of_day)])
end
s.join(' AND ')
end
+
+ # Returns a SQL clause for a date or datetime field using relative dates.
+ def relative_date_clause(table, field, days_from, days_to)
+ date_clause(table, field, (days_from ? Date.today + days_from : nil), (days_to ? Date.today + days_to : nil))
+ end
end
<script type="text/javascript">
//<![CDATA[
function add_filter() {
- select = $('add_filter_select');
- field = select.value
- Element.show('tr_' + field);
- check_box = $('cb_' + field);
- check_box.checked = true;
- toggle_filter(field);
- select.selectedIndex = 0;
-
- for (i=0; i<select.options.length; i++) {
- if (select.options[i].value == field) {
- select.options[i].disabled = true;
- }
- }
+ select = $('add_filter_select');
+ field = select.value
+ Element.show('tr_' + field);
+ check_box = $('cb_' + field);
+ check_box.checked = true;
+ toggle_filter(field);
+ select.selectedIndex = 0;
+
+ for (i=0; i<select.options.length; i++) {
+ if (select.options[i].value == field) {
+ select.options[i].disabled = true;
+ }
+ }
}
function toggle_filter(field) {
- check_box = $('cb_' + field);
-
- if (check_box.checked) {
- Element.show("operators_" + field);
- Form.Element.enable("operators_" + field);
- $$(".values_" + field).each(function(el){ Form.Element.enable(el)});
- toggle_operator(field);
- } else {
- Element.hide("operators_" + field);
- Element.hide("div_values_" + field);
- Form.Element.disable("operators_" + field);
- $$(".values_" + field).each(function(el){ Form.Element.disable(el)});
+ check_box = $('cb_' + field);
+ if (check_box.checked) {
+ Element.show("operators_" + field);
+ Form.Element.enable("operators_" + field);
+ toggle_operator(field);
+ } else {
+ Element.hide("operators_" + field);
+ Form.Element.disable("operators_" + field);
+ enableValues(field, []);
}
}
+function enableValues(field, indexes) {
+ var f = $$(".values_" + field);
+ for(var i=0;i<f.length;i++) {
+ if (indexes.include(i)) {
+ Form.Element.enable(f[i]);
+ f[i].up('span').show();
+ } else {
+ f[i].value = '';
+ Form.Element.disable(f[i]);
+ f[i].up('span').hide();
+ }
+ }
+ if (indexes.length > 0) {
+ Element.show("div_values_" + field);
+ } else {
+ Element.hide("div_values_" + field);
+ }
+}
+
function toggle_operator(field) {
operator = $("operators_" + field);
switch (operator.value) {
case "w":
case "o":
case "c":
- Element.hide("div_values_" + field);
- var v = $$(".values_" + field);
- if (v.length > 1) {v[1].hide(); Form.Element.disable(v[1])}
+ enableValues(field, []);
break;
case "><":
- Element.show("div_values_" + field);
- var v = $$(".values_" + field);
- if (v.length > 1) {v[1].show(); Form.Element.enable(v[1])}
+ enableValues(field, [0,1]);
+ break;
+ case "<t+":
+ case ">t+":
+ case "t+":
+ case ">t-":
+ case "<t-":
+ case "t-":
+ enableValues(field, [2]);
break;
default:
- Element.show("div_values_" + field);
- var v = $$(".values_" + field);
- if (v.length > 1) {v[1].hide(); Form.Element.disable(v[1])}
+ enableValues(field, [0]);
break;
}
}
-function toggle_multi_select(field) {
- select = $('values_' + field);
- if (select.multiple == true) {
- select.multiple = false;
- } else {
- select.multiple = true;
- }
+function toggle_multi_select(el) {
+ var select = $(el);
+ if (select.multiple == true) {
+ select.multiple = false;
+ } else {
+ select.multiple = true;
+ }
}
function submit_query_form(id) {
<div id="div_values_<%= field %>" style="display:none;">
<% case options[:type]
when :list, :list_optional, :list_status, :list_subprojects %>
- <%= select_tag "v[#{field}][]", options_for_select(options[:values], query.values_for(field)), :class => "values_#{field}", :multiple => (query.values_for(field) && query.values_for(field).length > 1) %>
- <%= link_to_function image_tag('bullet_toggle_plus.png'), "toggle_multi_select('#{field}');", :style => "vertical-align: bottom;" %>
+ <span class="span_values_<%= field %>">
+ <%= 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) %>
+ <%= link_to_function image_tag('bullet_toggle_plus.png'), "toggle_multi_select('values_#{field}_1');", :style => "vertical-align: bottom;" %>
+ </span>
<% when :date, :date_past %>
- <%= text_field_tag "v[#{field}][]", query.value_for(field), :class => "values_#{field}", :size => 3 %> <%= l(:label_day_plural) %>
+ <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>
+ <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>
+ <span class="span_values_<%= field %>"><%= text_field_tag "v[#{field}][]", query.value_for(field), :size => 3, :class => "values_#{field}" %> <%= l(:label_day_plural) %></span>
<% when :string, :text %>
- <%= text_field_tag "v[#{field}][]", query.value_for(field), :class => "values_#{field}", :size => 30 %>
+ <span class="span_values_<%= field %>"><%= text_field_tag "v[#{field}][]", query.value_for(field), :class => "values_#{field}", :id => "values_#{field}", :size => 30 %></span>
<% when :integer %>
- <%= text_field_tag "v[#{field}][]", query.value_for(field), :class => "values_#{field}", :size => 3 %>
- <%= text_field_tag "v[#{field}][]", query.value_for(field, 1), :class => "values_#{field}", :size => 3 %>
+ <span class="span_values_<%= field %>"><%= text_field_tag "v[#{field}][]", query.value_for(field), :class => "values_#{field}", :id => "values_#{field}_1", :size => 3 %></span>
+ <span class="span_values_<%= field %>"><%= text_field_tag "v[#{field}][]", query.value_for(field, 1), :class => "values_#{field}", :id => "values_#{field}_2", :size => 3 %></span>
<% end %>
</div>
<script type="text/javascript">toggle_filter('<%= field %>');</script>