pull/6827/head
jwollert 13 years ago
commit 7c623958b1
  1. 115
      assets/javascripts/reporting/filters.js
  2. 78
      assets/javascripts/reporting/restore_query.js
  3. 13
      lib/report/controller.rb
  4. 2
      lib/widget/filters/multi_choice.rb
  5. 6
      lib/widget/filters/multi_values.rb

@ -5,6 +5,12 @@ Reporting.Filters = {
load_available_values_for_filter: function (filter_name, callback_func) { load_available_values_for_filter: function (filter_name, callback_func) {
var select, radio_options, post_select_values; var select, radio_options, post_select_values;
select = $$('.filter-value[data-filter-name="' + filter_name + '"]').first(); select = $$('.filter-value[data-filter-name="' + filter_name + '"]').first();
// 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;
callback_func();
}
if (select === null || select === undefined) { if (select === null || select === undefined) {
return; return;
} }
@ -30,7 +36,6 @@ Reporting.Filters = {
}, },
onComplete: function (a, b) { onComplete: function (a, b) {
$$("select[data-filter-name='" + filter_name + "']").each(function (e) { e.enable(); }); $$("select[data-filter-name='" + filter_name + "']").each(function (e) { e.enable(); });
callback_func();
if (select.tagName.toLowerCase() === "select") { if (select.tagName.toLowerCase() === "select") {
if (post_select_values === undefined || post_select_values === null || post_select_values.size() === 0) { if (post_select_values === undefined || post_select_values === null || post_select_values.size() === 0) {
select.selectedIndex = 0; select.selectedIndex = 0;
@ -38,20 +43,13 @@ Reporting.Filters = {
Reporting.Filters.select_values(select, post_select_values); Reporting.Filters.select_values(select, post_select_values);
} }
} }
callback_func();
} }
}); });
Reporting.Filters.multi_select(select, false); Reporting.Filters.multi_select(select, false);
} else { } else {
callback_func(); callback_func();
} }
// select first option by default
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;
}
}
}, },
show_filter: function (field, options) { show_filter: function (field, options) {
@ -67,6 +65,9 @@ Reporting.Filters = {
if (options.show_filter === undefined) { if (options.show_filter === undefined) {
options.show_filter = true; options.show_filter = true;
} }
if (options.hide_only === undefined) {
options.hide_only = false;
}
var field_el = $('tr_' + field); var field_el = $('tr_' + field);
if (field_el !== null) { if (field_el !== null) {
if (options.insert_after === undefined) { if (options.insert_after === undefined) {
@ -74,8 +75,10 @@ Reporting.Filters = {
} }
if (options.insert_after !== undefined && options.show_filter) { if (options.insert_after !== undefined && options.show_filter) {
// Move the filter down to appear after the last currently visible filter // Move the filter down to appear after the last currently visible filter
field_el.remove(); if (field_el.id !== options.insert_after.id) {
options.insert_after.insert({after: field_el}); field_el.remove();
options.insert_after.insert({after: field_el});
}
} }
// the following command might be included into the callback_function (which is called after the ajax request) later // the following command might be included into the callback_function (which is called after the ajax request) later
var display_functor; var display_functor;
@ -87,7 +90,9 @@ Reporting.Filters = {
Reporting.Filters.set_filter_value_widths(100); Reporting.Filters.set_filter_value_widths(100);
} else { } else {
(options.slowly ? Effect.Fade : Element.hide)(field_el); (options.slowly ? Effect.Fade : Element.hide)(field_el);
field_el.removeAttribute('data-selected'); if (!options.hide_only) { // remember that this filter used to be selected
field_el.removeAttribute('data-selected');
}
$('rm_' + field).value = ""; // reset the value, so the serialized form will not return this filter $('rm_' + field).value = ""; // reset the value, so the serialized form will not return this filter
Reporting.Filters.set_filter_value_widths(5000); Reporting.Filters.set_filter_value_widths(5000);
} }
@ -96,6 +101,40 @@ Reporting.Filters = {
} }
}, },
/**
* Activates the filter with the given name and loads dependent filters if necessary.
*
* @param filter_name Name of the filter to be activated.
*/
add_filter: function (filter_name, activate_dependent, on_complete) {
var field = filter_name
if (activate_dependent === undefined) {
activate_dependent = true;
}
if (on_complete === undefined) {
on_complete = function() { };
}
Reporting.Filters.show_filter(field, { slowly: true, callback_func: function() {
if (activate_dependent) {
Reporting.Filters.activate_dependents($(field + "_arg_1_val"));
}
Reporting.Filters.select_option_enabled($("add_filter_select"), filter_name, false);
on_complete();
}
});
},
remove_filter: function (field, hide_only) {
Reporting.Filters.show_filter(field, { show_filter: false, hide_only: hide_only });
var dependent = Reporting.Filters.get_dependents($(field + '_arg_1_val'), false).find(function(d) {
return Reporting.Filters.visible_filters().include(d);
});
if (dependent !== undefined) {
Reporting.Filters.remove_filter(dependent);
}
Reporting.Filters.select_option_enabled($("add_filter_select"), field, true);
},
/* /*
Smoothly sets the width of currently displayed filters. Smoothly sets the width of currently displayed filters.
Params: Params:
@ -210,15 +249,6 @@ Reporting.Filters = {
} }
}, },
add_filter: function (select) {
var field;
field = select.value;
Reporting.Filters.show_filter(field, { slowly: true });
select.selectedIndex = 0;
Reporting.Filters.select_option_enabled(select, field, false);
Reporting.Filters.activate_dependents($(field + "_arg_1_val"))
},
select_option_enabled: function (box, value, state) { select_option_enabled: function (box, value, state) {
var option = box.select("[value='" + value + "']").first(); var option = box.select("[value='" + value + "']").first();
if (option !== undefined) { if (option !== undefined) {
@ -243,17 +273,6 @@ Reporting.Filters = {
Reporting.Filters.multi_select(select, !select.multiple); Reporting.Filters.multi_select(select, !select.multiple);
}, },
remove_filter: function (field) {
Reporting.Filters.show_filter(field, { show_filter: false });
var dependent = Reporting.Filters.get_dependents($(field + '_arg_1_val'), false).find(function(d) {
return Reporting.Filters.visible_filters().include(d);
});
if (dependent !== undefined) {
Reporting.Filters.remove_filter(dependent);
}
Reporting.Filters.select_option_enabled($("add_filter_select"), field, true);
},
visible_filters: function () { visible_filters: function () {
return $("filter_table").select("tr").select(function (tr) { return $("filter_table").select("tr").select(function (tr) {
return tr.visible() === true; return tr.visible() === true;
@ -289,11 +308,14 @@ Reporting.Filters = {
// Param: select [optional] - the select-box of the filter which should activate it's dependents // Param: select [optional] - the select-box of the filter which should activate it's dependents
activate_dependents: function (selectBox, callbackWhenFinished) { activate_dependents: function (selectBox, callbackWhenFinished) {
var all_dependents, next_dependents, dependent, active_filters, source; var all_dependents, next_dependents, dependent, active_filters, source;
if (selectBox === undefined || selectBox.type.toLowerCase() == 'change') { if (selectBox !== undefined && selectBox.tagName.toLowerCase() !== "select") {
return; // only multi_value filters have dependents
}
if (selectBox === undefined || selectBox.type.toLowerCase() == 'change') {
selectBox = this; selectBox = this;
} }
if (callbackWhenFinished === undefined) { if (callbackWhenFinished === undefined) {
callbackWhenFinished = function() {}; callbackWhenFinished = function(dependent) { };
} }
source = selectBox.getAttribute("data-filter-name"); source = selectBox.getAttribute("data-filter-name");
all_dependents = Reporting.Filters.get_dependents(selectBox); all_dependents = Reporting.Filters.get_dependents(selectBox);
@ -326,14 +348,18 @@ Reporting.Filters = {
var active_dependents = all_dependents.select(function (d) { var active_dependents = all_dependents.select(function (d) {
return active_filters.include(d); return active_filters.include(d);
}); });
Reporting.Filters.narrow_values(Reporting.Filters.dependent_for(source), active_dependents, callbackWhenFinished); Reporting.Filters.narrow_values(
Reporting.Filters.dependent_for(source),
active_dependents,
function() { callbackWhenFinished(dependent); }
);
}, 1); }, 1);
}, },
// return an array of all filters that depend on the given filter plus the given filter // return an array of all filters that depend on the given filter plus the given filter
dependent_for: function(field) { dependent_for: function(field) {
var deps = $$('.filters-select[data-all-dependents]').findAll(function(selectBox) { var deps = $$('.filters-select[data-all-dependents]').findAll(function(selectBox) {
return selectBox.up('tr').visible() && Reporting.Filters.get_dependents(selectBox).include(field) return (selectBox.up('tr').visible()) && Reporting.Filters.get_dependents(selectBox).include(field)
}).map(function(selectBox) { }).map(function(selectBox) {
return selectBox.getAttribute("data-filter-name"); return selectBox.getAttribute("data-filter-name");
}); });
@ -400,7 +426,9 @@ Reporting.Filters = {
// cannot use .innerhtml due to IE wierdness // cannot use .innerhtml due to IE wierdness
$(selectBox).insert(new Element('option', {value: value}).update(label.escapeHTML())); $(selectBox).insert(new Element('option', {value: value}).update(label.escapeHTML()));
}); });
Reporting.Filters.select_values(selectBox, selected); Reporting.Filters.select_values(selectBox, selected);
sources.push(currentDependent); // Add as last element sources.push(currentDependent); // Add as last element
dependents.splice(0, 1); // Delete first element dependents.splice(0, 1); // Delete first element
// if we got no values besides the <<inactive>> value, do not show this selectBox // if we got no values besides the <<inactive>> value, do not show this selectBox
@ -421,10 +449,13 @@ Reporting.Filters = {
if (continue_narrowing) { if (continue_narrowing) {
Reporting.Filters.narrow_values(sources, dependents); Reporting.Filters.narrow_values(sources, dependents);
} }
callbackWhenFinished();
} }
callbackWhenFinished();
}, },
onException: function (response, error) { onException: function (response, error) {
if (console) {
console.log(error);
}
Reporting.flash("Loading of filter values failed. Probably, the server is temporary offline for maintenance."); Reporting.flash("Loading of filter values failed. Probably, the server is temporary offline for maintenance.");
var selectBox = $(currentDependent + "_arg_1_val"); var selectBox = $(currentDependent + "_arg_1_val");
$(selectBox).insert(new Element('option', {value: '<<inactive>>'}).update('Failed to load values.')); $(selectBox).insert(new Element('option', {value: '<<inactive>>'}).update('Failed to load values.'));
@ -445,7 +476,8 @@ Reporting.onload(function () {
if ($("add_filter_select")) { if ($("add_filter_select")) {
$("add_filter_select").observe("change", function () { $("add_filter_select").observe("change", function () {
if (!(Reporting.Filters.exists(this.value))) { if (!(Reporting.Filters.exists(this.value))) {
Reporting.Filters.add_filter(this); Reporting.Filters.add_filter(this.value);
this.selectedIndex = 0;
}; };
}); });
} }
@ -474,15 +506,12 @@ Reporting.onload(function () {
}).size(); }).size();
s.multiple = (selected_size > 1); s.multiple = (selected_size > 1);
s.observe("change", function (evt) { s.observe("change", function (evt) {
var filter_name = this.up('tr').getAttribute("data-filter-name"); var filter_name = this.up('tr').getAttribute("data-filter-name");
Reporting.Filters.value_changed(filter_name); Reporting.Filters.value_changed(filter_name);
}); });
}); });
$$('.filters-select[data-all-dependents]').each(function (dependency) { $$('.filters-select[data-all-dependents]').each(function (dependency) {
dependency.observe("change", Reporting.Filters.activate_dependents); dependency.observe("change", Reporting.Filters.activate_dependents);
}); });
Reporting.Filters.visible_filters().each(function (filter) {
Reporting.Filters.load_available_values_for_filter(filter, function () {});
});
}); });

@ -27,58 +27,44 @@ Reporting.RestoreQuery = {
} }
}, },
// This is called the first time the report loads. restore_dependent_filters: function(filter_name) {
// Params: $$("tr.filter[data-filter-name=" + filter_name + "] select.filter-value").each(function(selectBox) {
// elements: Array of visible filter-select-boxes that have dependents var activateNext = function(dependent) {
// (and possibly are dependents themselfes) if (!dependent) return;
initialize_load_dependent_filters: function(elements) { Reporting.RestoreQuery.restore_dependent_filters(dependent);
var filters_to_load, dependent_filters; };
dependent_filters = elements.findAll(function (select) { return select.getValue() == '<<inactive>>' || select.select('option[selected]').size()==0 }); if (selectBox.hasAttribute('data-initially-selected')) {
filters_to_load = elements.reject( function (select) { return select.getValue() == '<<inactive>>' }); var selected_values = selectBox.readAttribute('data-initially-selected').replace(/'/g, '"').evalJSON(true);
// Filters which are <<inactive>> are probably dependents themselfes, so remove and forget them for now. Reporting.Filters.select_values(selectBox, selected_values);
// This is OK as they get reloaded later Reporting.Filters.value_changed(filter_name);
dependent_filters.each(function(select) { }
Reporting.Filters.remove_filter(select.up('tr').readAttribute("data-filter-name")); if (selectBox.getValue() !== '<<inactive>>') {
}); Reporting.Filters.activate_dependents(selectBox, activateNext);
// For each dependent filter we reload its dependent chain }
filters_to_load.each(function(selectBox) {
var sources, selected_values;
Reporting.Filters.activate_dependents(selectBox, function() {
sources = Reporting.Filters.get_dependents(selectBox).collect(function(field) {
return $('tr_' + field).select('.filter_values select').first();
});
sources.each(function(source) {
if (source.hasAttribute('data-initially-selected')) {
selected_values = source.readAttribute('data-initially-selected').replace(/'/g, '"').evalJSON(true);
Reporting.Filters.select_values(source, selected_values);
Reporting.Filters.value_changed(source.up('tr').readAttribute("data-filter-name"));
}
});
if (sources.reject( function (select) { return select.value == '<<inactive>>' }).size() == 0) {
Reporting.Filters.activate_dependents(selectBox);
}
else {
Reporting.RestoreQuery.initialize_load_dependent_filters(sources);
}
});
}); });
}, },
restore_filters: function () { restore_filters: function () {
// FIXME: rm_xxx values for filters have to be set after re-displaying them var deps = $$('.filters-select.filter-value').each(function(select) {
var tr = select.up('tr');
if (tr.visible()) {
var filter = tr.readAttribute('data-filter-name');
var dependent = select.readAttribute('data-dependent');
if (filter && dependent) {
Reporting.Filters.remove_filter(filter, false);
}
}
});
$$("tr[data-selected=true]").each(function (e) { $$("tr[data-selected=true]").each(function (e) {
var rm_box, filter_name; var select = e.down(".filter_values select");
rm_box = e.select("input[id^=rm]").first(); if (select && select.hasAttribute("data-dependent")) return;
filter_name = e.getAttribute("data-filter-name"); var filter_name = e.getAttribute("data-filter-name");
rm_box.value = filter_name; var on_complete = function() {
Reporting.Filters.select_option_enabled($("add_filter_select"), filter_name, false); Reporting.RestoreQuery.restore_dependent_filters(filter_name);
// correctly display number of arguments of filters depending on their arity };
Reporting.Filters.operator_changed(filter_name, $("operators[" + filter_name + "]")); Reporting.Filters.add_filter(filter_name, false, on_complete);
}); });
// restore values of dependent filters
Reporting.RestoreQuery.initialize_load_dependent_filters($$('.filters-select[data-all-dependents]').findAll(function(select) {
return select.up('tr').visible()
}));
}, },
restore_group_bys: function () { restore_group_bys: function () {

@ -340,15 +340,12 @@ module Report::Controller
# renders option tags for each available value for a single filter # renders option tags for each available value for a single filter
def available_values def available_values
if name = params[:filter_name] if name = params[:filter_name]
begin f_cls = report_engine::Filter.const_get(name.to_s.camelcase)
f_cls = report_engine::Filter.const_get(name.to_s.camelcase) filter = f_cls.new.tap do |f|
filter = f_cls.new.tap do |f| f.values = JSON.parse(params[:values].gsub("'", '"')) if params[:values].present? and params[:values]
f.values = JSON.parse(params[:values].gsub("'", '"')) if params[:values].present? and params[:values]
end
render_widget Widget::Filters::Option, filter, :to => canvas = ""
render :text => canvas, :layout => !request.xhr?
rescue NameError
end end
render_widget Widget::Filters::Option, filter, :to => canvas = ""
render :text => canvas, :layout => !request.xhr?
end end
end end

@ -12,7 +12,7 @@ class Widget::Filters::MultiChoice < Widget::Filters::Base
:id => "#{filterName}_radio_option_#{i}", :id => "#{filterName}_radio_option_#{i}",
:value => value :value => value
} }
opts[:checked] = "checked" if filter.values == value opts[:checked] = "checked" if filter.values == [value].flatten
radio_button = tag :input, opts radio_button = tag :input, opts
content_tag :label, radio_button + translate(label), content_tag :label, radio_button + translate(label),
:for => "#{filterName}_radio_option_#{i}", :for => "#{filterName}_radio_option_#{i}",

@ -23,9 +23,11 @@ class Widget::Filters::MultiValues < Widget::Filters::Base
# store selected value(s) in data-initially-selected if this filter is a dependent # store selected value(s) in data-initially-selected if this filter is a dependent
# of another filter, as we have to restore values manually in the client js # of another filter, as we have to restore values manually in the client js
if (filter_class.is_dependent? || @options[:lazy]) && !Array(filter.values).empty? if (filter_class.is_dependent? || @options[:lazy]) && !Array(filter.values).empty?
select_options.merge! :"data-initially-selected" => filter.values.to_json.gsub!('"', "'") select_options.merge! :"data-initially-selected" =>
filter.values.to_json.gsub!('"', "'") || "[" + filter.values.map { |v| "'#{v}'" }.join(',') + "]"
end end
box_content = "" select_options.merge! :"data-dependent" => true if filter_class.is_dependent?
box_content = "".html_safe
box = content_tag :select, select_options do box = content_tag :select, select_options do
render_widget Widget::Filters::Option, filter, :to => box_content unless @options[:lazy] render_widget Widget::Filters::Option, filter, :to => box_content unless @options[:lazy]
end end

Loading…
Cancel
Save