diff --git a/assets/javascripts/reporting/filters.js b/assets/javascripts/reporting/filters.js index 265a23d92a..a12956f4b9 100644 --- a/assets/javascripts/reporting/filters.js +++ b/assets/javascripts/reporting/filters.js @@ -3,7 +3,7 @@ Reporting.Filters = { load_available_values_for_filter: function (filter_name, callback_func) { - var select; + var select, radio_options; select = $('' + filter_name + '_arg_1_val'); //TODO: the following code ist cost report specific, we should refactor that to be general useful if (select !== null && select.readAttribute('data-loading') === "ajax" && select.childElements().length === 0) { @@ -26,7 +26,15 @@ Reporting.Filters = { callback_func(); } // select first option by default - select.selectedIndex = 0; + if (select.tagName.toLowerCase() === "div") { + // check if we might have a radio-box + radio_options = $$('.' + filter_name + '_radio_option input'); + if (radio_options && radio_options.size() !== 0) { + radio_options.first().checked = true; + } + } else if (select.tagName.toLowerCase() === "select") { + select.selectedIndex = 0; + } }, show_filter: function (field, options) { @@ -58,7 +66,7 @@ Reporting.Filters = { (options.slowly ? Effect.Appear : Element.show)(field_el); Reporting.Filters.load_available_values_for_filter(field, options.callback_func); $('rm_' + field).value = field; // set the value, so the serialized form will return this filter - Reporting.Filters.value_changed(field) + Reporting.Filters.value_changed(field); Reporting.Filters.set_filter_value_widths(100); } else { (options.slowly ? Effect.Fade : Element.hide)(field_el); @@ -144,15 +152,13 @@ Reporting.Filters = { val = $(field + '_arg_1_val'); tr = $('tr_' + field); if (!val) { - return + return; + } + if (val.value === '<>') { + tr.addClassName('inactive-filter'); + } else { + tr.removeClassName('inactive-filter'); } - if (val.value == '<>') { - tr.addClassName('inactive-filter') - } - else - { - tr.removeClassName('inactive-filter') - } }, change_argument_visibility: function (field, arg_nr) { diff --git a/assets/javascripts/reporting/restore_query.js b/assets/javascripts/reporting/restore_query.js index 0bb06633d8..b48da12300 100644 --- a/assets/javascripts/reporting/restore_query.js +++ b/assets/javascripts/reporting/restore_query.js @@ -33,8 +33,8 @@ Reporting.RestoreQuery = { // (and possibly are dependents themselfes) initialize_load_dependent_filters: function(elements) { var filters_to_load, dependent_filters; - dependent_filters = elements.findAll(function (select) { return select.value == '<>' }); - filters_to_load = elements.reject( function (select) { return select.value == '<>' }); + dependent_filters = elements.findAll(function (select) { return select.getValue() == '<>' || select.select('option[selected]').size()==0 }); + filters_to_load = elements.reject( function (select) { return select.getValue() == '<>' }); // Filters which are <> are probably dependents themselfes, so remove and forget them for now. // This is OK as they get reloaded later dependent_filters.each(function(select) { diff --git a/assets/stylesheets/reporting.css b/assets/stylesheets/reporting.css index ab071f4e75..5c49b0b9ba 100644 --- a/assets/stylesheets/reporting.css +++ b/assets/stylesheets/reporting.css @@ -64,9 +64,9 @@ background-color: #e8e8e8 !important; } -.report tr:hover .inner, -.report tr:hover .bottom, -.report tr:hover .empty, +.report tr:hover .inner, +.report tr:hover .bottom, +.report tr:hover .empty, .report tr:hover .right { background-color: #f5f5c5 !important; } @@ -164,6 +164,11 @@ white-space: nowrap; } +.filter_radio_option { + padding-left: 5px; + padding-right: 5px; +} + #add_filter_block { margin-top: 6px; } @@ -495,3 +500,14 @@ html>body #ajax-indicator { position: fixed; } padding-left: 26px; vertical-align: bottom; } +<<<<<<< HEAD + +#content p, +#content label, +#content a, +#content div { + font-size: 11px; + line-height: 16px; +} +======= +>>>>>>> feature/widgets diff --git a/lib/report/filter/base.rb b/lib/report/filter/base.rb index 9a4b74a9e8..d77518dc68 100644 --- a/lib/report/filter/base.rb +++ b/lib/report/filter/base.rb @@ -23,6 +23,12 @@ class Report::Filter false end + # Indicates whether this Filter is a multiple choice filter, + # meaning that the user must select a value of a given set of choices. + def self.is_multiple_choice? + false + end + ## # A Filter may have depentent filters. See the following example: # Filter::Project.dependents --> [Filter::IssueId] diff --git a/lib/report/filter/multi_choice.rb b/lib/report/filter/multi_choice.rb new file mode 100644 index 0000000000..fd3f1db2f9 --- /dev/null +++ b/lib/report/filter/multi_choice.rb @@ -0,0 +1,11 @@ +class Report::Filter + class MultiChoice < Base + + dont_inherit :available_operators + use '=' + + def self.is_multiple_choice? + true + end + end +end \ No newline at end of file diff --git a/lib/report/operator.rb b/lib/report/operator.rb index e901c47bd4..37d2b83ccb 100644 --- a/lib/report/operator.rb +++ b/lib/report/operator.rb @@ -177,6 +177,16 @@ class Report::Operator end end + new "?=", :label => :label_null_or_equal do + def modify(query, field, *values) + where_clause = "(#{field} IS NULL" + where_clause += " OR #{field} IN #{collection(*values)}" unless values.compact.empty? + where_clause += ")" + query.where where_clause + query + end + end + end ############################################################################################# @@ -207,6 +217,10 @@ class Report::Operator all[name.to_s] or raise ArgumentError, "Operator #{name.inspect} not defined" end + def self.exists?(name) + all.has_key?(name.to_s) + end + def self.defaults(&block) class_eval &block end @@ -272,6 +286,17 @@ class Report::Operator self.name <=> other.name end + ## Creates an alias for a given operator. + def aka(alt_name, alt_label) + all = self.class.all + alt = alt_name.to_s + raise ArgumentError, "Can't alias operator with an existing one's name ( #{alt} )." if all.has_key?(alt) + op = all[name].clone + op.send(:rename_to, alt_name) + op.singleton_class.send(:define_method, 'label') { alt_label } + all[alt] = op + end + module DateRange def modify(query, field, from, to) query.where ["#{field} > '%s'", quoted_date((Date.yesterday + from).to_time.end_of_day)] if from @@ -280,6 +305,12 @@ class Report::Operator end end + private + + def rename_to(new_name) + @name = new_name + end + # Done with class method definition, let's initialize the operators load diff --git a/lib/widget/filters.rb b/lib/widget/filters.rb index 0d082eefd9..c924cdd107 100644 --- a/lib/widget/filters.rb +++ b/lib/widget/filters.rb @@ -64,8 +64,12 @@ class Widget::Filters < Widget::Base render_widget Filters::MultiValues, f, :to => html end else - render_widget Filters::MultiValues, f, :to => html + if f_cls.is_multiple_choice? + render_widget Filters::MultiChoice, f, :to => html + else + render_widget Filters::MultiValues, f, :to => html + end end render_widget Filters::RemoveButton, f, :to => html end -end +end \ No newline at end of file diff --git a/lib/widget/filters/multi_choice.rb b/lib/widget/filters/multi_choice.rb new file mode 100644 index 0000000000..365a982692 --- /dev/null +++ b/lib/widget/filters/multi_choice.rb @@ -0,0 +1,37 @@ +class Widget::Filters::MultiChoice < Widget::Filters::Base + + def render + filterName = filter_class.underscore_name + content_tag :td do + content_tag :div, :id => "#{filterName}_arg_1", :class => "filter_values" do + choices = filter_class.available_values.each_with_index.map do |(label, value), i| + opts = { + :type => "radio", + :name => "values[#{filterName}][]", + :id => "#{filterName}_radio_option_#{i}", + :value => value + } + opts[:checked] = "checked" if filter.values == value + radio_button = tag :input, opts + content_tag :label, radio_button + translate(label), + :for => "#{filterName}_radio_option_#{i}", + :'data-filter-name' => filter_class.underscore_name, + :class => "#{filterName}_radio_option filter_radio_option" + end + content_tag :div, choices.join.html_safe, + :id => "#{filter_class.underscore_name}_arg_1_val" + end + end + end + + private + + def translate(label) + if label.is_a?(Symbol) + ::I18n.t(label) + else + label + end + end + +end