diff --git a/assets/javascripts/reporting.js b/assets/javascripts/reporting.js index d8c7183714..1a4af66006 100644 --- a/assets/javascripts/reporting.js +++ b/assets/javascripts/reporting.js @@ -78,3 +78,4 @@ Reporting.require("table"); // } // // // defineElementGetter(); + diff --git a/assets/javascripts/reporting/filters.js b/assets/javascripts/reporting/filters.js index fc21c64044..3cb86059bb 100644 --- a/assets/javascripts/reporting/filters.js +++ b/assets/javascripts/reporting/filters.js @@ -44,15 +44,16 @@ Reporting.Filters = { var field_el = $('tr_' + field); if (field_el !== null) { // the following command might be included into the callback_function (which is called after the ajax request) later - $('rm_' + field).value = field; var display_functor; if (options.show_filter) { - display_functor = options.slowly ? Effect.Appear : Element.show; + (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 } else { - display_functor = options.slowly ? Effect.Fade : Element.hide; + (options.slowly ? Effect.Fade : Element.hide)(field_el); + field_el.removeAttribute('data-selected'); + $('rm_' + field).value = ""; // reset the value, so the serialized form will not return this filter } - display_functor(field_el); Reporting.Filters.operator_changed(field, $("operators_" + field)); Reporting.Filters.display_category($(field_el.getAttribute("data-label"))); } @@ -133,7 +134,7 @@ Reporting.Filters = { return $("filter_table").childElements().first().select('tr').select(function (tr) { return tr.visible() === true; }).collect(function (filter) { - return filter.className; + return filter.getAttribute("data-filter-name"); }); }, @@ -150,7 +151,7 @@ Reporting.onload(function () { }); $$(".filter_rem").each(function (e) { e.observe("click", function () { - var filter_name = this.getAttribute("data-filter-name"); + var filter_name = this.up('tr').getAttribute("data-filter-name"); Reporting.Filters.remove_filter(filter_name); }); }); diff --git a/assets/javascripts/reporting/restore_query.js b/assets/javascripts/reporting/restore_query.js index 2874874040..9107df74c6 100644 --- a/assets/javascripts/reporting/restore_query.js +++ b/assets/javascripts/reporting/restore_query.js @@ -60,9 +60,20 @@ Reporting.RestoreQuery = { var name = $(group_by).getAttribute("value"); Reporting.RestoreQuery.show_group_by(name, $('group_by_' + axis + 's')); }); + }, + + restore_filters: function () { + // FIXME: rm_xxx values for filters have to be set after re-displaying them + $$("tr[data-selected=true]").each(function (e) { + var rm_box = e.select("input[id^=rm]").first(); + var filter_name = e.getAttribute("data-filter-name"); + rm_box.value = filter_name; + Reporting.Filters.select_option_enabled($("add_filter_select"), filter_name, false); + }); } }; Reporting.onload(function () { Reporting.RestoreQuery.restore_group_bys(); + Reporting.RestoreQuery.restore_filters(); }); diff --git a/assets/stylesheets/reporting.css b/assets/stylesheets/reporting.css index 7125a8b01e..8d78b8ba39 100644 --- a/assets/stylesheets/reporting.css +++ b/assets/stylesheets/reporting.css @@ -100,21 +100,6 @@ vertical-align: top; } -/* Aligning filter elements at the top. */ -.new_report fieldset#filters table td { - vertical-align: top; - border-spacing: 5px 5px; - border-color: white; - border-style: solid; - border-width: 2px 0px 0px; -} - -.new_report fieldset#filters table td > label { - left: 3px; - top: 3px; - position: relative; -} - /* Overwriting styling for headlines within the query. */ /* TODO: Font-size seems to be a bit odd. Needs some love. */ .new_report fieldset h3 { @@ -183,11 +168,10 @@ } .filter_rem { + color: transparent; overflow: hidden; cursor: pointer; - background-repeat: no-repeat; - background-color: transparent; - background-position: 50%; + background: no-repeat center center transparent; height: 16px; width: 16px; border-style: none; @@ -208,11 +192,11 @@ margin-top: 6px; } -.new_report fieldset#filters table tr.filter:hover { +fieldset#filter-settings table tr.filter:hover { background: #aaa; } -.new_report fieldset#filters table tr.filter { +fieldset#filter-settings table tr.filter { color: #000; background: #ededed; -webkit-border-radius: 5px; @@ -220,6 +204,22 @@ border-radius: 5px; } +/* Aligning filter elements at the top. */ +fieldset#filter-settings table td { + vertical-align: top; + border-spacing: 5px 5px; + border-color: white; + border-style: solid; + border-width: 2px 0px 0px; + padding: 2px; + vertical-align: middle; +} + +fieldset#filter-settings table td > label { + left: 3px; + top: 3px; + position: relative; +} .drag_element { /*cursor: move;*/ @@ -356,7 +356,38 @@ td:hover .drill_down, th:hover .drill_down { margin: 2px; } -div#button_form { +.buttons .apply { + background-color: #9a9a9a; + border: none; + cursor: pointer; + margin: 0px; + overflow: visible; + text-align: center; + white-space: nowrap; + -moz-border-radius: 3px; + border-radius: 3px; + padding: 4px; +} + +.buttons .apply:hover { + background-color: #666666; +} + +.buttons .apply span em { + color: white; + display: block; + font-size: 11px; + font-style: normal; + font-weight: bold; + line-height: 17px; +} + +.buttons .apply span { + display: inline-block; + margin: 0px; +} + +div.button_form { /* TODO IE Compatibility! */ background-color: white; border: 1px solid grey; @@ -365,17 +396,20 @@ div#button_form { left: 100px; position: absolute; padding: 5px; - margin-top: -10px; } -div#button_form * input#name { +div.button_form * input#name { width: 200px } -div#button_form * input[type="button"] { +div.button_form * input[type="button"] { float: right; } br { clear: right; } +div.button_form p * { + margin: 2px; +} + /***** Ajax indicator ******/ #ajax-indicator { font-family: Verdana, sans-serif; diff --git a/lib/report/chainable.rb b/lib/report/chainable.rb index e5138225fe..0ce143c9c4 100644 --- a/lib/report/chainable.rb +++ b/lib/report/chainable.rb @@ -301,5 +301,21 @@ class Report < ActiveRecord::Base self.class.field end + def mapping + self.class.method(:mapping).to_proc + end + + def self.mapping(value) + value.to_s + end + + + def self.mapping_for(field) + @field_map ||= (engine::Filter.all + engine.GroupBy.all).inject(Hash.new {|h,k| h[k] = []}) do |hash,cbl| + hash[cbl.field] << cbl.mapping + end + @field_map[field] + end + end end diff --git a/lib/report/controller.rb b/lib/report/controller.rb index 899b0ec1ae..d8955a5275 100644 --- a/lib/report/controller.rb +++ b/lib/report/controller.rb @@ -9,7 +9,7 @@ module Report::Controller before_filter :determine_engine before_filter :prepare_query, :only => [:index, :create] - before_filter :find_optional_report, :only => [:index, :show, :update, :delete] + before_filter :find_optional_report, :only => [:index, :show, :update, :delete, :rename] end end @@ -187,14 +187,14 @@ module Report::Controller ## # Prepare the query from the request def prepare_query - determine_filter_settings + determine_settings @query = build_query(session[report_engine.name.underscore.to_sym][:filters], session[report_engine.name.underscore.to_sym][:groups]) end ## # Determine the query settings the current request and save it to # the session. - def determine_filter_settings + def determine_settings if force_default? filters = default_filter_parameters groups = default_group_parameters diff --git a/lib/report/filter.rb b/lib/report/filter.rb index f4687ea517..74ff36ba47 100644 --- a/lib/report/filter.rb +++ b/lib/report/filter.rb @@ -9,6 +9,10 @@ class Report::Filter @all ||= Set[] end + def self.reset! + @all = nil + end + def self.all_grouped all.group_by { |f| f.applies_for }.to_a.sort { |a,b| a.first.to_s <=> b.first.to_s } end diff --git a/lib/report/group_by.rb b/lib/report/group_by.rb index 171ef9de55..820203b138 100644 --- a/lib/report/group_by.rb +++ b/lib/report/group_by.rb @@ -12,6 +12,10 @@ class Report::GroupBy Set[engine::GroupBy::SingletonValue] end + def self.reset! + @all = nil + end + def self.all_grouped all.group_by { |f| f.applies_for }.to_a.sort { |a,b| a.first.to_s <=> b.first.to_s } end diff --git a/lib/report/operator.rb b/lib/report/operator.rb index 1a05c7f862..7bce779ee6 100644 --- a/lib/report/operator.rb +++ b/lib/report/operator.rb @@ -37,7 +37,7 @@ class Report::Operator new "w", :arity => 0, :label => :label_this_week do def modify(query, field, offset = nil) offset ||= 0 - from = Time.now.at_beginning_of_week - ((l(:general_first_day_of_week).to_i % 7) + 1).days + from = Time.now.at_beginning_of_week - ((I18n.t(:general_first_day_of_week).to_i % 7) + 1).days from -= offset.days '<>d'.to_operator.modify query, field, from, from + 7.days end diff --git a/lib/report/query_utils.rb b/lib/report/query_utils.rb index 6423feb351..d455f93a3f 100644 --- a/lib/report/query_utils.rb +++ b/lib/report/query_utils.rb @@ -46,6 +46,10 @@ module Report::QueryUtils ActiveRecord::Base.connection.quote_string(str) end + def current_language + ::I18n.locale + end + ## # Creates a SQL fragment representing a collection/array. # diff --git a/lib/report/walker.rb b/lib/report/walker.rb index cd72a7245c..cf11ffe196 100644 --- a/lib/report/walker.rb +++ b/lib/report/walker.rb @@ -17,12 +17,10 @@ class Report::Walker end def for_empty_cell(&block) - puts __method__ unless block_given? access_block(:empty_cell, &block) || access_block(:cell) end def access_block(name, &block) - puts method.center(80, '= '), caller[0..1] unless block_given? @blocks ||= {} @blocks[name] = block if block @blocks[name] diff --git a/lib/widget/controls/query_name.rb b/lib/widget/controls/query_name.rb index 1ad2829bc7..5cfe51f15e 100644 --- a/lib/widget/controls/query_name.rb +++ b/lib/widget/controls/query_name.rb @@ -2,7 +2,7 @@ class Widget::Controls::QueryName < Widget::Base def render options = { :id => "query_saved_name", "data-translations" => translations } if @query.new_record? - name = l(:label_save_this_query) + name = l(:label_new_report) icon = "" else name = @query.name diff --git a/lib/widget/controls/save_as.rb b/lib/widget/controls/save_as.rb index 1a440261d1..ca3a534c1d 100644 --- a/lib/widget/controls/save_as.rb +++ b/lib/widget/controls/save_as.rb @@ -2,19 +2,21 @@ class Widget::Controls::SaveAs < Widget::Base def render if @query.new_record? link_name = l(:button_save) + icon = "icon-save" else link_name = l(:button_save_as) + icon = "icon-save-as" end button = link_to link_name, "#", - :class => 'breadcrumb_icon icon-save-as', - :id => 'query-icon-save-as', :title => l(:button_save_as) + :class => "breadcrumb_icon #{icon}", + :id => 'query-icon-save-as', :title => link_name button + render_popup end def render_popup_form name = content_tag :p do label_tag(:query_name, l(:field_name)) + - text_field_tag(:query_name, @query.name || l(:label_default)) + text_field_tag(:query_name, @query.name) end box = content_tag :p do label_tag(:query_is_public, l(:field_is_public)) + @@ -27,7 +29,7 @@ class Widget::Controls::SaveAs < Widget::Base content_tag(:p) do save = link_to content_tag(:span, content_tag(:em, l(:button_save))), "#", :id => "query-icon-save-button", - :class => "button save", + :class => "button reporting_button save", :"data-target" => url_for(:action => 'create', :set_filter => '1') cancel = link_to l(:button_cancel), "#", :id => "query-icon-save-as-cancel", diff --git a/lib/widget/filters.rb b/lib/widget/filters.rb index eec8da0f9a..f55ebcc9f3 100644 --- a/lib/widget/filters.rb +++ b/lib/widget/filters.rb @@ -34,7 +34,9 @@ class Widget::Filters < Widget::Base def render_filters active_filters = @query.filters.select { |f| f.class.display? } engine::Filter.all.collect do |filter| - opts = {:id => "tr_#{filter.underscore_name}", :class => "#{filter.underscore_name}"} + opts = {:id => "tr_#{filter.underscore_name}", + :class => "#{filter.underscore_name} filter", + :"data-filter-name" => filter.underscore_name } active_instance = active_filters.detect { |f| f.class == filter } if active_instance opts[:"data-selected"] = true diff --git a/lib/widget/filters/remove_button.rb b/lib/widget/filters/remove_button.rb index 3ba76a5f6a..8820ce0c4d 100644 --- a/lib/widget/filters/remove_button.rb +++ b/lib/widget/filters/remove_button.rb @@ -3,8 +3,7 @@ class Widget::Filters::RemoveButton < Widget::Filters::Base content_tag :td, :width => "25px" do tag :input, :id => "rm_#{filter_class.underscore_name}", :name => "fields[]", :type => "button", :value => "", - :class => "icon filter_rem icon-filter-rem", - :"data-filter-name" => filter_class.underscore_name + :class => "icon filter_rem icon-filter-rem" end end end diff --git a/lib/widget/filters/text_box.rb b/lib/widget/filters/text_box.rb index 3125c7c1e3..ae25d29b67 100644 --- a/lib/widget/filters/text_box.rb +++ b/lib/widget/filters/text_box.rb @@ -3,7 +3,7 @@ class Widget::Filters::TextBox < Widget::Filters::Base content_tag :td do content_tag :div, :id => "#{filter_class.underscore_name}_arg_1", :class => "filter_values" do text_field_tag("values[#{filter_class.underscore_name}]", "", - :size => 150, + :size => "6", :class => "select-small", :id => "#{filter_class.underscore_name}_arg_1_val", :'data-filter-name' => filter_class.underscore_name) diff --git a/lib/widget/settings.rb b/lib/widget/settings.rb index 4a9e15f6a6..f134cef9c2 100644 --- a/lib/widget/settings.rb +++ b/lib/widget/settings.rb @@ -1,6 +1,6 @@ class Widget::Settings < Widget::Base def render - form_tag("#", {:id => 'query_form', :method => :post}) do |query_form| + form_tag("#", {:id => 'query_form', :method => :post}) do content_tag :div, :id => "query_form_content" do fieldsets = render_widget Widget::Settings::Fieldset, @query, { :type => "filter" } do diff --git a/lib/widget/table.rb b/lib/widget/table.rb index 48c9a5eeb9..b6c9322d44 100644 --- a/lib/widget/table.rb +++ b/lib/widget/table.rb @@ -1,24 +1,76 @@ class Widget::Table < Widget::Base extend Report::InheritedAttribute - include ReportingHelper # FIXME ugs in the ugly. have to think of something else for mapping stuff - inherited_attribute :debug, :default => false + attr_accessor :debug + attr_accessor :fields + attr_accessor :mapping - def initialize(query, options = {}) + def initialize(query) raise ArgumentError, "Tables only work on Reports!" unless query.is_a? Report - super(query) + super end def debug? !!debug end + def show_result(*args) + map :show_result, *args + end + + def show_row(*args) + map :show_row, *args + end + + def label_for(*args) + map :label, *args + end + + def entry_for(*args) + map :entry, *args + end + + def edit_content(*args) + map :edit, *args + end + + def debug_fields(*args) + map :debug_fields, *args + end + + def raw_result(result) + mapped = mapping[:raw_result] + if mapped + mapped.call self, result + else + show_result(result, 0) + end + end + + def show_field(field, *args) + mapped = mapping[:show_field] + if mapped + mapped.call self, field, *args + else + engine::Chainable.mapping_for(field).first.call field, *args + end + end + + def map(to_map, *args) + fail "Table Widget #{self.class} needs a mapping for :#{to_map}" unless mapping[to_map] + mapping[to_map.to_sym].call self, *args + end + def render_with_options(options = {}, &block) + @fields ||= (options[:fields] || @query.result.important_fields) + @debug ||= (options[:debug] || false) + @mapping ||= options[:mapping] + fail "mappings need to respond to #call" if mapping.values.any? { |val| not val.respond_to? :call } canvas = options[:to] ? options[:to] << "\n" : "" canvas << render(&block) end - def table_widget + def fancy_table if @query.depth_of(:row) == 0 @query.row(:singleton_value) elsif @query.depth_of(:column) == 0 @@ -27,14 +79,28 @@ class Widget::Table < Widget::Base Widget::Table::ReportTable end + def simple_table + Widget::Table::SimpleTable + end + + def entry_table + Widget::Table::EntryTable + end + def render content_tag :div, :id => "result-table" do - if @query.group_bys.empty? || @query.result.count <= 0 - content_tag :p, l(:label_no_data), :class => "nodata" + options = { :debug => debug?, :mapping => @mapping, :fields => @fields } + return content_tag :p, l(:label_no_data), :class => "nodata" if @query.result.count <= 0 + if @query.group_bys.empty? + render_widget entry_table, @query, options + elsif @query.group_bys.size == 1 + render_widget simple_table, @query, options else - render_widget table_widget, @query, { :debug => debug? } + render_widget fancy_table, @query, options end end end + + end diff --git a/lib/widget/table/report_table.rb b/lib/widget/table/report_table.rb index 3e3c8b64e9..dbad5d5d9a 100644 --- a/lib/widget/table/report_table.rb +++ b/lib/widget/table/report_table.rb @@ -2,9 +2,9 @@ class Widget::Table::ReportTable < Widget::Table attr_accessor :walker - def initialize(report, options = {}) + def initialize(query) super - @walker = @query.walker + @walker = query.walker end def render