From 5b17ca25eafbd13f91e55d0479e91946d39dc42d Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Wed, 6 Apr 2011 10:44:52 +0200 Subject: [PATCH 01/17] Monkeypatch String to have a #write method, to mimic canvas behaviour --- lib/widget.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/widget.rb b/lib/widget.rb index 9314ee1c08..b59a8ed230 100644 --- a/lib/widget.rb +++ b/lib/widget.rb @@ -17,6 +17,8 @@ if Rails.version.start_with? "2" class ::String; def html_safe; self; end; end end +class ::String; def write(s); concat(s); end; end + class Widget < ActionView::Base include ActionView::Helpers::TagHelper include ActionView::Helpers::AssetTagHelper From 390e4d8b00123b7500e3357c0449645fe91746ea Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Wed, 6 Apr 2011 10:45:18 +0200 Subject: [PATCH 02/17] All widgets now have a default @output canvas they can write to with #write --- lib/widget/base.rb | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/lib/widget/base.rb b/lib/widget/base.rb index b44567b4d6..97d6c940d7 100644 --- a/lib/widget/base.rb +++ b/lib/widget/base.rb @@ -1,9 +1,14 @@ class Widget::Base < Widget - attr_reader :engine + attr_reader :engine, :output def initialize(query) @query = query @engine = query.class + @output = "".html_safe + end + + def write(str) + @output.write str end def render @@ -12,9 +17,12 @@ class Widget::Base < Widget def render_with_options(options = {}, &block) if canvas = options[:to] - canvas << "\n" << render(&block) - else - render(&block) + @output = canvas + end + result = render(&block) + if @output.respond_to? :to_str and @output.empty? # FIXME: Transitional support + @output += "\n#{result}".html_safe end + @output end end From 1f4bbc32b68d78ba0bd2ff21b8ba5ab96460bcb1 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Wed, 6 Apr 2011 10:45:45 +0200 Subject: [PATCH 03/17] Transitional: Include ReportingHelper in the Widget::Table class --- lib/widget/table.rb | 119 ++++++++++++++++++++++---------------------- 1 file changed, 60 insertions(+), 59 deletions(-) diff --git a/lib/widget/table.rb b/lib/widget/table.rb index b6c9322d44..d37bf4b657 100644 --- a/lib/widget/table.rb +++ b/lib/widget/table.rb @@ -1,5 +1,6 @@ class Widget::Table < Widget::Base extend Report::InheritedAttribute + include ReportingHelper attr_accessor :debug attr_accessor :fields @@ -10,65 +11,65 @@ class Widget::Table < Widget::Base 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 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 fancy_table if @query.depth_of(:row) == 0 From 0dd5b378b622722edcf928f3e87afbb1a16a8c3f Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Wed, 6 Apr 2011 10:46:02 +0200 Subject: [PATCH 04/17] Get Widget::ReportTable to render --- lib/widget/table/report_table.rb | 148 ++++++++++++++----------------- 1 file changed, 66 insertions(+), 82 deletions(-) diff --git a/lib/widget/table/report_table.rb b/lib/widget/table/report_table.rb index dbad5d5d9a..e3ff1c3628 100644 --- a/lib/widget/table/report_table.rb +++ b/lib/widget/table/report_table.rb @@ -7,129 +7,113 @@ class Widget::Table::ReportTable < Widget::Table @walker = query.walker end - def render - configure_walker - content = content_tag :table, :class => 'list report' do - header + footer + body + def configure_query + if @query.depth_of(:row) == 0 + @query.row(:singleton_value) + elsif @query.depth_of(:column) == 0 + @query.column(:singleton_value) end - content += (debug_content if debug?) end def configure_walker - walker.for_final_row do |row, cells| - final_row_html = content_tag :th, :class => 'normal inner left' do - "#{show_row(row)}#{debug_fields(row)}" - end - final_row_html += cells.join.html_safe - final_row_html += content_tag :th, :class => 'normal inner right' do - "#{show_result(row)}#{debug_fields(row)}" - end - final_row_html + @walker.for_final_row do |row, cells| + html = "#{show_row row}#{debug_fields(row)}" + html << cells.join + html << "#{show_result(row)}#{debug_fields(row)}" + html.html_safe end - walker.for_row do |row, subrows| + @walker.for_row do |row, subrows| subrows.flatten! unless row.fields.empty? - subrows[0] = '' - subrows[0] += content_tag(:th, :class => 'top left', :rowspan => subrows.size) do - "#{show_row(row)}#{debug_fields(row)}" - end - subrows[0].gsub("class='normal'", "class='top'") - subrows[0] += content_tag(:th, :class => 'top right', :rowspan => subrows.size) do - "#{show_result(row)}#{debug_fields(row)}" - end + subrows[0] = %Q{ + #{show_row row}#{debug_fields(row)} + #{subrows[0].gsub("class='normal", "class='top")} + #{show_result(row)}#{debug_fields(row )} + }.html_safe end subrows.last.gsub!("class='normal", "class='bottom") subrows.last.gsub!("class='top", "class='bottom top") subrows end - walker.for_empty_cell do - content_tag(:td, :class =>'normal empty') do - " " - end - end + @walker.for_empty_cell { " ".html_safe } - walker.for_cell do |result| - content_tag :td, :class => 'normal right' do - "#{show_result(result)}#{debug_fields(result)}" - end + @walker.for_cell do |result| + "#{show_result result}#{debug_fields(result)}".html_safe end end - def header - header_content = "" + def render + configure_query + configure_walker + write "" + render_thead + render_tfoot + render_tbody + write "
" + end + + def render_thead + write "" walker.headers do |list, first, first_in_col, last_in_col| - header_content += '' if first_in_col - if first - header_content += content_tag :th, :rowspan => @query.depth_of(:column), :colspan => @query.depth_of(:row) do - "" - end - end + write '' if first_in_col + write "" if first list.each do |column| - opts = { :colspan => column.final_number(:column) } - opts.merge!(:class => "inner") if column.final?(:column) - header_content += content_tag :th, opts do - show_row column - end - end - if first - header_content += content_tag :th, :rowspan => @query.depth_of(:column), :colspan => @query.depth_of(:row) do - "" - end - end - header_content += '' if last_in_col + write "" + write show_row(column) + write "" + end + write "" if first + write '' if last_in_col end - content_tag :thead, header_content.html_safe + write "" end - def footer - reverse_headers = "" + def render_tfoot + write "" walker.reverse_headers do |list, first, first_in_col, last_in_col| - if first_in_col - reverse_headers += '' - if first - reverse_headers += content_tag :th, :rowspan => @query.depth_of(:column), :colspan => @query.depth_of(:row), :class => 'top' do - " " - end - end + write "" if first_in_col + if first + write " " end - list.each do |column| - opts = { :colspan => column.final_number(:column) } - opts.merge!(:class => "inner") if first - reverse_headers += content_tag :th, opts do - "#{show_result(column)}#{debug_fields(column)}" - end + write "' + write show_result(column) + # FIXME: write debug_fields(column) + write "" end if last_in_col if first - reverse_headers += content_tag :th, - :rowspan => @query.depth_of(:column), - :colspan => @query.depth_of(:row), - :class => 'top result' do - show_result @query - end + write "" + write show_result(@query) + write "" end - reverse_headers += '' + write "" end end - content_tag :tfoot, reverse_headers.html_safe + write "" end - def body + def render_tbody + write "" first = true - walker_body = "" + odd = true walker.body do |line| if first line.gsub!("class='normal", "class='top") first = false end - walker_body += content_tag :tr, :class => cycle("odd", "even") do - line.html_safe - end + write "#{line}" + odd = !odd end - content_tag :tbody, walker_body.html_safe + write "" end def debug_content From 4adf1f98e9aa71b292533e4d11b6ccee0b7f36e5 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Wed, 6 Apr 2011 11:06:48 +0200 Subject: [PATCH 05/17] Cleanup render_widget availability --- lib/widget.rb | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/lib/widget.rb b/lib/widget.rb index b59a8ed230..22a3ebe956 100644 --- a/lib/widget.rb +++ b/lib/widget.rb @@ -40,4 +40,26 @@ class Widget < ActionView::Base def protect_against_forgery? false end + + module RenderWidgetInstanceMethods + def render_widget(widget, subject, options = {}, &block) + i = widget.new(subject) + if Rails.version.start_with? "3" + i.config = config + i._routes = _routes + else + i.output_buffer = "" + end + i._content_for = @_content_for + i.controller = respond_to? :controller ? controller : self + i.render_with_options(options, &block).html_safe + end + end +end + +ActionView::Base.send(:include, Widget::RenderWidgetInstanceMethods) +ActionController::Base.send(:include, Widget::RenderWidgetInstanceMethods) +if Rails.version.start_with? "2" + class ::String; def html_safe; self; end; end end +class ::String; def write(s); concat(s); end; end From 5d243d1f754637f919ab944f3b9e44f3efe8d853 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Wed, 6 Apr 2011 11:07:08 +0200 Subject: [PATCH 06/17] Add missing code --- lib/widget.rb | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/lib/widget.rb b/lib/widget.rb index 22a3ebe956..828cd1315b 100644 --- a/lib/widget.rb +++ b/lib/widget.rb @@ -1,24 +1,3 @@ -class ActionView::Base - def render_widget(widget, subject, options = {}, &block) - i = widget.new(subject) - if Rails.version.start_with? "3" - i.config = config - i._routes = _routes - else - i.output_buffer = "" - end - i._content_for = @_content_for - i.controller = controller - i.render_with_options(options, &block).html_safe - end -end - -if Rails.version.start_with? "2" - class ::String; def html_safe; self; end; end -end - -class ::String; def write(s); concat(s); end; end - class Widget < ActionView::Base include ActionView::Helpers::TagHelper include ActionView::Helpers::AssetTagHelper From 2e13bf810f5e3fa4197ebebb0392f11c2ab3d2d2 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Wed, 6 Apr 2011 11:13:35 +0200 Subject: [PATCH 07/17] Fix render_widget for controllers --- lib/widget.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/widget.rb b/lib/widget.rb index 828cd1315b..d605e03d3a 100644 --- a/lib/widget.rb +++ b/lib/widget.rb @@ -30,8 +30,8 @@ class Widget < ActionView::Base i.output_buffer = "" end i._content_for = @_content_for - i.controller = respond_to? :controller ? controller : self - i.render_with_options(options, &block).html_safe + i.controller = respond_to?(:controller) ? controller : self + i.render_with_options(options, &block) end end end From bb3f9f0faa0a8bfc58b0cc3ff85f7558d844cbfb Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Wed, 6 Apr 2011 11:56:29 +0200 Subject: [PATCH 08/17] add FIXME --- lib/widget.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/widget.rb b/lib/widget.rb index d605e03d3a..d37c6f634e 100644 --- a/lib/widget.rb +++ b/lib/widget.rb @@ -8,6 +8,7 @@ class Widget < ActionView::Base extend ProactiveAutoloader + # FIXME: There's a better one in ReportingHelper, remove this one def l(s) ::I18n.t(s.to_sym, :default => s.to_s.humanize) end From d740f5f6e068b1bb4af8cd077863c6ad717976d1 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Wed, 6 Apr 2011 11:56:46 +0200 Subject: [PATCH 09/17] create output canvas on demand --- lib/widget/base.rb | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/lib/widget/base.rb b/lib/widget/base.rb index 97d6c940d7..6886b5f1d4 100644 --- a/lib/widget/base.rb +++ b/lib/widget/base.rb @@ -4,10 +4,10 @@ class Widget::Base < Widget def initialize(query) @query = query @engine = query.class - @output = "".html_safe end def write(str) + @output ||= "".html_safe @output.write str end @@ -16,13 +16,8 @@ class Widget::Base < Widget end def render_with_options(options = {}, &block) - if canvas = options[:to] - @output = canvas - end - result = render(&block) - if @output.respond_to? :to_str and @output.empty? # FIXME: Transitional support - @output += "\n#{result}".html_safe - end + @output = options[:to] if options.has_key? :to + render(&block) @output end end From 753843fd33112ed6d09a1b0b6c275753ba932d73 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Wed, 6 Apr 2011 11:57:28 +0200 Subject: [PATCH 10/17] transition all widgets to canvas api --- lib/widget/controls/apply.rb | 3 ++- lib/widget/controls/clear.rb | 4 +++- lib/widget/controls/delete.rb | 2 +- lib/widget/controls/query_name.rb | 2 +- lib/widget/controls/save.rb | 2 +- lib/widget/controls/save_as.rb | 2 +- lib/widget/filters.rb | 4 ++-- lib/widget/filters/date.rb | 4 ++-- lib/widget/filters/label.rb | 5 +++-- lib/widget/filters/multi_choice.rb | 11 ++++++----- lib/widget/filters/multi_values.rb | 5 +++-- lib/widget/filters/operators.rb | 5 +++-- lib/widget/filters/remove_button.rb | 4 ++-- lib/widget/filters/text_box.rb | 4 ++-- lib/widget/group_bys.rb | 4 ++-- lib/widget/settings.rb | 2 +- lib/widget/settings/fieldset.rb | 4 ++-- 17 files changed, 37 insertions(+), 30 deletions(-) diff --git a/lib/widget/controls/apply.rb b/lib/widget/controls/apply.rb index 4851a452c8..d8bcecbde0 100644 --- a/lib/widget/controls/apply.rb +++ b/lib/widget/controls/apply.rb @@ -1,6 +1,7 @@ + class Widget::Controls::Apply < Widget::Base def render - link_to content_tag(:span, content_tag(:em, l(:button_apply))), {}, + write link_to content_tag(:span, content_tag(:em, l(:button_apply))), {}, :href => "#", :id => "query-icon-apply-button", :class => "button apply reporting_button", :"data-target" => url_for(:action => 'index', :set_filter => '1') diff --git a/lib/widget/controls/clear.rb b/lib/widget/controls/clear.rb index f460105a8d..35c0a7bef5 100644 --- a/lib/widget/controls/clear.rb +++ b/lib/widget/controls/clear.rb @@ -1,5 +1,7 @@ + class Widget::Controls::Clear < Widget::Base def render - link_to content_tag(:span, content_tag(:em, l(:"button_clear"), :class => "button-icon icon-clear")), '#', :id => 'query-link-clear', :class => 'button secondary' + write link_to(content_tag(:span, content_tag(:em, l(:"button_clear"), :class => "button-icon icon-clear")), + '#', :id => 'query-link-clear', :class => 'button secondary') end end diff --git a/lib/widget/controls/delete.rb b/lib/widget/controls/delete.rb index b60d6ad07a..cb8859c171 100644 --- a/lib/widget/controls/delete.rb +++ b/lib/widget/controls/delete.rb @@ -19,6 +19,6 @@ class Widget::Controls::Delete < Widget::Base end question + options end - button + popup + write(button + popup) end end diff --git a/lib/widget/controls/query_name.rb b/lib/widget/controls/query_name.rb index 5cfe51f15e..7fb9ca2b52 100644 --- a/lib/widget/controls/query_name.rb +++ b/lib/widget/controls/query_name.rb @@ -14,7 +14,7 @@ class Widget::Controls::QueryName < Widget::Base options["data-update-url"] = url_for(:action => "rename", :id => @query.id) options["data-is_new"] = @query.new_record? end - content_tag(:span, name, options) + icon + write(content_tag(:span, name, options) + icon) end def translations diff --git a/lib/widget/controls/save.rb b/lib/widget/controls/save.rb index 900d3491dc..68891ba656 100644 --- a/lib/widget/controls/save.rb +++ b/lib/widget/controls/save.rb @@ -1,7 +1,7 @@ class Widget::Controls::Save < Widget::Base def render return "" if @query.new_record? - link_to content_tag(:span, content_tag(:em, l(:button_save)), :class => "button-icon icon-save"), {}, + write link_to content_tag(:span, content_tag(:em, l(:button_save)), :class => "button-icon icon-save"), {}, :href => "#", :id => "query-breadcrumb-save", :class => "button secondary", :title => l(:button_save), diff --git a/lib/widget/controls/save_as.rb b/lib/widget/controls/save_as.rb index 5ae48ed33e..93f05d7fc6 100644 --- a/lib/widget/controls/save_as.rb +++ b/lib/widget/controls/save_as.rb @@ -10,7 +10,7 @@ class Widget::Controls::SaveAs < Widget::Base button = link_to content_tag(:span, content_tag(:em, link_name, :class => "button-icon icon-save-as")), "#", :class => "button secondary", :id => 'query-icon-save-as', :title => link_name - button + render_popup + write(button + render_popup) end def render_popup_form diff --git a/lib/widget/filters.rb b/lib/widget/filters.rb index c924cdd107..1730d6a469 100644 --- a/lib/widget/filters.rb +++ b/lib/widget/filters.rb @@ -17,7 +17,7 @@ class Widget::Filters < Widget::Base :class => "select-small", :name => nil end - content_tag(:div, table + select) + write content_tag(:div, table + select) end def selectables @@ -72,4 +72,4 @@ class Widget::Filters < Widget::Base end render_widget Filters::RemoveButton, f, :to => html end -end \ No newline at end of file +end diff --git a/lib/widget/filters/date.rb b/lib/widget/filters/date.rb index dafcf4c3a6..8ea167e5f0 100644 --- a/lib/widget/filters/date.rb +++ b/lib/widget/filters/date.rb @@ -23,7 +23,7 @@ class Widget::Filters::Date < Widget::Filters::Base name = "values[#{filter_class.underscore_name}][]" id_prefix = "#{filter_class.underscore_name}_" - content_tag :td do + write(content_tag :td do arg1 = content_tag :span, :id => "#{id_prefix}arg_1", :class => "filter_values" do text1 = text_field_tag name, @filter.values.first.to_s, :size => 10, :class => "select-small", :id => "#{id_prefix}arg_1_val" cal1 = calendar_for("#{id_prefix}arg_1_val") @@ -35,6 +35,6 @@ class Widget::Filters::Date < Widget::Filters::Base text2 + cal2 end arg1 + arg2 - end + end) end end diff --git a/lib/widget/filters/label.rb b/lib/widget/filters/label.rb index bc520d6e93..a43cf28794 100644 --- a/lib/widget/filters/label.rb +++ b/lib/widget/filters/label.rb @@ -1,6 +1,7 @@ + class Widget::Filters::Label < Widget::Filters::Base def render - content_tag :td, :width => 150 do + write(content_tag :td, :width => 150 do options = { :id => filter_class.underscore_name } if (engine::Filter.all.any? {|f| f.dependent == filter_class}) options.merge! :class => 'dependent-filter-label' @@ -8,6 +9,6 @@ class Widget::Filters::Label < Widget::Filters::Base content_tag :label, options do l(filter_class.label) end - end + end) end end diff --git a/lib/widget/filters/multi_choice.rb b/lib/widget/filters/multi_choice.rb index 365a982692..a7864120b2 100644 --- a/lib/widget/filters/multi_choice.rb +++ b/lib/widget/filters/multi_choice.rb @@ -1,8 +1,9 @@ + class Widget::Filters::MultiChoice < Widget::Filters::Base def render filterName = filter_class.underscore_name - content_tag :td do + write(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 = { @@ -21,11 +22,11 @@ class Widget::Filters::MultiChoice < Widget::Filters::Base content_tag :div, choices.join.html_safe, :id => "#{filter_class.underscore_name}_arg_1_val" end - end + end) end - + private - + def translate(label) if label.is_a?(Symbol) ::I18n.t(label) @@ -33,5 +34,5 @@ class Widget::Filters::MultiChoice < Widget::Filters::Base label end end - + end diff --git a/lib/widget/filters/multi_values.rb b/lib/widget/filters/multi_values.rb index 5872d540c5..f1015fef91 100644 --- a/lib/widget/filters/multi_values.rb +++ b/lib/widget/filters/multi_values.rb @@ -1,7 +1,8 @@ + class Widget::Filters::MultiValues < Widget::Filters::Base def render - content_tag :td do + write(content_tag :td do content_tag :div, :id => "#{filter_class.underscore_name}_arg_1", :class => "filter_values" do select_options = { :style => "vertical-align: top;", # FIXME: Do CSS :name => "values[#{filter_class.underscore_name}][]", @@ -52,6 +53,6 @@ class Widget::Filters::MultiValues < Widget::Filters::Base :"data-filter-name" => filter_class.underscore_name box + plus end - end + end) end end diff --git a/lib/widget/filters/operators.rb b/lib/widget/filters/operators.rb index 3b5f7e908e..fcacd92a42 100644 --- a/lib/widget/filters/operators.rb +++ b/lib/widget/filters/operators.rb @@ -1,6 +1,7 @@ + class Widget::Filters::Operators < Widget::Filters::Base def render - content_tag :td, :width => 100 do + write(content_tag :td, :width => 100 do hide_select_box = filter_class.available_operators.count == 1 options = {:class => "select-small filters-select filter_operator", :style => "vertical-align: top", # FIXME: put into CSS @@ -19,6 +20,6 @@ class Widget::Filters::Operators < Widget::Filters::Base l(filter_class.available_operators.first.label) end hide_select_box ? select_box + label : select_box - end + end) end end diff --git a/lib/widget/filters/remove_button.rb b/lib/widget/filters/remove_button.rb index a8c6bbde40..3cdbd16664 100644 --- a/lib/widget/filters/remove_button.rb +++ b/lib/widget/filters/remove_button.rb @@ -1,11 +1,11 @@ class Widget::Filters::RemoveButton < Widget::Filters::Base def render - content_tag :td, :width => "25px" do + write( content_tag :td, :width => "25px" do hidden_field = tag :input, :id => "rm_#{filter_class.underscore_name}", :name => "fields[]", :type => "hidden", :value => "" button = tag :input, :type => "button", :value => "", :class => "icon filter_rem icon-filter-rem" content_tag(:div, hidden_field + button, :id => "rm_box_#{filter_class.underscore_name}", :class => "remove-box") - end + end) end end diff --git a/lib/widget/filters/text_box.rb b/lib/widget/filters/text_box.rb index ae25d29b67..d32dec5c96 100644 --- a/lib/widget/filters/text_box.rb +++ b/lib/widget/filters/text_box.rb @@ -1,6 +1,6 @@ class Widget::Filters::TextBox < Widget::Filters::Base def render - content_tag :td do + write(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 => "6", @@ -8,6 +8,6 @@ class Widget::Filters::TextBox < Widget::Filters::Base :id => "#{filter_class.underscore_name}_arg_1_val", :'data-filter-name' => filter_class.underscore_name) end - end + end) end end diff --git a/lib/widget/group_bys.rb b/lib/widget/group_bys.rb index 5265204d6a..5639990ebe 100644 --- a/lib/widget/group_bys.rb +++ b/lib/widget/group_bys.rb @@ -51,10 +51,10 @@ class Widget::GroupBys < Widget::Base end def render - content_tag :div, :id => 'group_by_area' do + write(content_tag :div, :id => 'group_by_area' do out = render_group 'columns', @query.group_bys(:column) out += render_group 'rows', @query.group_bys(:row) out.html_safe - end + end) end end diff --git a/lib/widget/settings.rb b/lib/widget/settings.rb index f134cef9c2..4ee7161d90 100644 --- a/lib/widget/settings.rb +++ b/lib/widget/settings.rb @@ -19,7 +19,7 @@ class Widget::Settings < Widget::Base render_widget(Widget::Controls::Delete, @query, :to => widgets) end - fieldsets + controls + write(fieldsets + controls) end end end diff --git a/lib/widget/settings/fieldset.rb b/lib/widget/settings/fieldset.rb index c4f71d2d22..4f4b7db289 100644 --- a/lib/widget/settings/fieldset.rb +++ b/lib/widget/settings/fieldset.rb @@ -7,9 +7,9 @@ class Widget::Settings::Fieldset < Widget::Base end def render - content_tag :fieldset, :id => @id, :class => "collapsible collapsed" do + write(content_tag :fieldset, :id => @id, :class => "collapsible collapsed" do html = content_tag :legend, l(@label), :onclick => "toggleFieldset(this);" #FIXME: onclick html + yield - end + end) end end From 043a3a8f54825bb05de0def5ad42fcc75a105b93 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Wed, 6 Apr 2011 12:15:34 +0200 Subject: [PATCH 11/17] finish transition to canvas --- lib/widget/base.rb | 2 +- lib/widget/settings.rb | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/widget/base.rb b/lib/widget/base.rb index 6886b5f1d4..ee1cc374d4 100644 --- a/lib/widget/base.rb +++ b/lib/widget/base.rb @@ -8,7 +8,7 @@ class Widget::Base < Widget def write(str) @output ||= "".html_safe - @output.write str + @output.write str.html_safe end def render diff --git a/lib/widget/settings.rb b/lib/widget/settings.rb index 4ee7161d90..5634eff8a1 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 + write(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 @@ -19,8 +19,8 @@ class Widget::Settings < Widget::Base render_widget(Widget::Controls::Delete, @query, :to => widgets) end - write(fieldsets + controls) + fieldsets + controls end - end + end) end end From 9ce19f499c0000a66e74247beae548f8107aa4c4 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Wed, 6 Apr 2011 12:33:23 +0200 Subject: [PATCH 12/17] enable caching of widgets --- lib/widget/base.rb | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/lib/widget/base.rb b/lib/widget/base.rb index ee1cc374d4..99427c5f37 100644 --- a/lib/widget/base.rb +++ b/lib/widget/base.rb @@ -17,7 +17,20 @@ class Widget::Base < Widget def render_with_options(options = {}, &block) @output = options[:to] if options.has_key? :to - render(&block) + render_with_cache(options, &block) @output end + + def render_with_cache(options = {}, &block) + if Rails.cache.exist? cache_key + Rails.cache.fetch(cache_key) + else + render(&block) + Rails.cache.write(cache_key, @output) + end + end + + def cache_key + "#{self.class.name}/#{subject.hash}" + end end From bb219265735d7d9a83eedc1774f11f5f990cd5df Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Wed, 6 Apr 2011 12:47:47 +0200 Subject: [PATCH 13/17] make sure to set @subject in all widgets --- lib/widget.rb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/widget.rb b/lib/widget.rb index d37c6f634e..1a77d36894 100644 --- a/lib/widget.rb +++ b/lib/widget.rb @@ -4,10 +4,16 @@ class Widget < ActionView::Base include ActionView::Helpers::FormTagHelper include ActionView::Helpers::JavaScriptHelper - attr_accessor :output_buffer, :controller, :config, :_content_for, :_routes + attr_accessor :output_buffer, :controller, :config, :_content_for, :_routes, :subject extend ProactiveAutoloader + def self.new(subject) + super(subject).tap do |o| + o.subject = subject + end + end + # FIXME: There's a better one in ReportingHelper, remove this one def l(s) ::I18n.t(s.to_sym, :default => s.to_s.humanize) From 1d6abbae2f060f074a9bce19bf840ddac80f4b16 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Wed, 6 Apr 2011 12:49:03 +0200 Subject: [PATCH 14/17] Provide a @cache_output for cases, where the canvas cannot be marshalled --- lib/widget/base.rb | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/lib/widget/base.rb b/lib/widget/base.rb index 99427c5f37..2c00b82b99 100644 --- a/lib/widget/base.rb +++ b/lib/widget/base.rb @@ -9,6 +9,7 @@ class Widget::Base < Widget def write(str) @output ||= "".html_safe @output.write str.html_safe + @cache_output.write(str.html_safe) if @cache_output end def render @@ -16,21 +17,31 @@ class Widget::Base < Widget end def render_with_options(options = {}, &block) - @output = options[:to] if options.has_key? :to + set_canvas(options[:to]) if options.has_key? :to render_with_cache(options, &block) @output end + def cache_key + "#{self.class.name}/#{subject.hash}" + end + def render_with_cache(options = {}, &block) if Rails.cache.exist? cache_key Rails.cache.fetch(cache_key) else render(&block) - Rails.cache.write(cache_key, @output) + Rails.cache.write(cache_key, @cache_output || @output) end end - def cache_key - "#{self.class.name}/#{subject.hash}" + ## + # Set the canvas. If the canvas object isn't a string (e.g. cannot be cached easily), + # a @cache_output String is created, that will mirror what is being written to the canvas. + def set_canvas(canvas) + unless canvas.respond_to? :to_str + @cache_output = @output || "".html_safe + end + @output = canvas end end From 3838a86a2aabc61d3746a9f2591cd172fe093864 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Wed, 6 Apr 2011 12:49:12 +0200 Subject: [PATCH 15/17] Code documentation --- lib/widget/base.rb | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/lib/widget/base.rb b/lib/widget/base.rb index 2c00b82b99..0211720c9f 100644 --- a/lib/widget/base.rb +++ b/lib/widget/base.rb @@ -6,16 +6,25 @@ class Widget::Base < Widget @engine = query.class end + ## + # Write a string to the canvas. The string is marked as html_safe. + # This will write twice, if @cache_output is set. def write(str) @output ||= "".html_safe @output.write str.html_safe @cache_output.write(str.html_safe) if @cache_output end + ## + # Render this widget. Abstract method. Needs to call #write at least once def render raise NotImplementedError, "#render is missing in my subclass" end + ## + # Render this widget, passing options. + # Available options: + # :to => canvas - The canvas (streaming or otherwise) to render to. Has to respond to #write def render_with_options(options = {}, &block) set_canvas(options[:to]) if options.has_key? :to render_with_cache(options, &block) @@ -26,6 +35,10 @@ class Widget::Base < Widget "#{self.class.name}/#{subject.hash}" end + private + + ## + # Render this widget or serve it from cache def render_with_cache(options = {}, &block) if Rails.cache.exist? cache_key Rails.cache.fetch(cache_key) From 91e0fe7487915997312cf7650e3e558903ae9259 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Wed, 6 Apr 2011 13:01:24 +0200 Subject: [PATCH 16/17] Allow widgets to deactivate caching. Use this for the fieldset widget --- lib/widget/base.rb | 14 +++++++++++++- lib/widget/settings/fieldset.rb | 2 ++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/widget/base.rb b/lib/widget/base.rb index 0211720c9f..3b04fb8aab 100644 --- a/lib/widget/base.rb +++ b/lib/widget/base.rb @@ -1,6 +1,14 @@ class Widget::Base < Widget attr_reader :engine, :output + def self.dont_cache! + @dont_cache = true + end + + def self.dont_cache? + @dont_cache + end + def initialize(query) @query = query @engine = query.class @@ -37,10 +45,14 @@ class Widget::Base < Widget private + def cache? + !self.class.dont_cache? + end + ## # Render this widget or serve it from cache def render_with_cache(options = {}, &block) - if Rails.cache.exist? cache_key + if Rails.cache.exist? cache_key and cache? Rails.cache.fetch(cache_key) else render(&block) diff --git a/lib/widget/settings/fieldset.rb b/lib/widget/settings/fieldset.rb index 4f4b7db289..affe251548 100644 --- a/lib/widget/settings/fieldset.rb +++ b/lib/widget/settings/fieldset.rb @@ -1,4 +1,6 @@ class Widget::Settings::Fieldset < Widget::Base + dont_cache! + def render_with_options(options, &block) @type = options.delete(:type) || "filter" @id = "#{@type}-settings" From 237805db5fbabc7cda04ac13c1dbeced5440b6f2 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Wed, 6 Apr 2011 13:05:08 +0200 Subject: [PATCH 17/17] Actually render the cache hits to the canvas, too --- lib/widget/base.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/widget/base.rb b/lib/widget/base.rb index 3b04fb8aab..970a554332 100644 --- a/lib/widget/base.rb +++ b/lib/widget/base.rb @@ -53,7 +53,7 @@ class Widget::Base < Widget # Render this widget or serve it from cache def render_with_cache(options = {}, &block) if Rails.cache.exist? cache_key and cache? - Rails.cache.fetch(cache_key) + write Rails.cache.fetch(cache_key) else render(&block) Rails.cache.write(cache_key, @cache_output || @output)