mongoid_wice_grid 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. data/.gitignore +9 -0
  2. data/CHANGELOG +409 -0
  3. data/Gemfile +17 -0
  4. data/Gemfile.lock +140 -0
  5. data/MIT-LICENSE +20 -0
  6. data/README.rdoc +1188 -0
  7. data/Rakefile +40 -0
  8. data/SAVED_QUERIES_HOWTO.rdoc +123 -0
  9. data/VERSION +1 -0
  10. data/lib/filter_conditions_generators.rb +126 -0
  11. data/lib/generators/wice_grid/templates/calendarview.css +107 -0
  12. data/lib/generators/wice_grid/templates/calendarview.js +1168 -0
  13. data/lib/generators/wice_grid/templates/icons/arrow_down.gif +0 -0
  14. data/lib/generators/wice_grid/templates/icons/arrow_up.gif +0 -0
  15. data/lib/generators/wice_grid/templates/icons/calendar_view_month.png +0 -0
  16. data/lib/generators/wice_grid/templates/icons/delete.png +0 -0
  17. data/lib/generators/wice_grid/templates/icons/expand.png +0 -0
  18. data/lib/generators/wice_grid/templates/icons/page_white_excel.png +0 -0
  19. data/lib/generators/wice_grid/templates/icons/page_white_find.png +0 -0
  20. data/lib/generators/wice_grid/templates/icons/table.png +0 -0
  21. data/lib/generators/wice_grid/templates/icons/table_refresh.png +0 -0
  22. data/lib/generators/wice_grid/templates/icons/tick_all.png +0 -0
  23. data/lib/generators/wice_grid/templates/icons/untick_all.png +0 -0
  24. data/lib/generators/wice_grid/templates/wice_grid.css +173 -0
  25. data/lib/generators/wice_grid/templates/wice_grid.yml +269 -0
  26. data/lib/generators/wice_grid/templates/wice_grid_config.rb +215 -0
  27. data/lib/generators/wice_grid/templates/wice_grid_jquery.js +161 -0
  28. data/lib/generators/wice_grid/templates/wice_grid_prototype.js +153 -0
  29. data/lib/generators/wice_grid/wice_grid_assets_jquery_generator.rb +32 -0
  30. data/lib/generators/wice_grid/wice_grid_assets_prototype_generator.rb +34 -0
  31. data/lib/grid_output_buffer.rb +52 -0
  32. data/lib/grid_renderer.rb +547 -0
  33. data/lib/helpers/js_calendar_helpers.rb +183 -0
  34. data/lib/helpers/wice_grid_misc_view_helpers.rb +113 -0
  35. data/lib/helpers/wice_grid_serialized_queries_view_helpers.rb +82 -0
  36. data/lib/helpers/wice_grid_view_helpers.rb +761 -0
  37. data/lib/js_adaptors/jquery_adaptor.rb +145 -0
  38. data/lib/js_adaptors/js_adaptor.rb +12 -0
  39. data/lib/js_adaptors/prototype_adaptor.rb +168 -0
  40. data/lib/mongoid_field.rb +50 -0
  41. data/lib/tasks/wice_grid_tasks.rake +28 -0
  42. data/lib/view_columns.rb +464 -0
  43. data/lib/views/create.rjs +13 -0
  44. data/lib/views/delete.rjs +12 -0
  45. data/lib/wice_grid.rb +521 -0
  46. data/lib/wice_grid_controller.rb +165 -0
  47. data/lib/wice_grid_core_ext.rb +179 -0
  48. data/lib/wice_grid_misc.rb +99 -0
  49. data/lib/wice_grid_serialized_queries_controller.rb +77 -0
  50. data/lib/wice_grid_serialized_query.rb +14 -0
  51. data/lib/wice_grid_spreadsheet.rb +33 -0
  52. data/test/.gitignore +2 -0
  53. data/test/blueprint.rb +17 -0
  54. data/test/database.yml +21 -0
  55. data/test/public/javascripts/jquery-1.4.2.min.js +154 -0
  56. data/test/public/javascripts/wice_grid.js +163 -0
  57. data/test/rails_mongoid_test.rb +104 -0
  58. data/test/rails_test_app.rb +71 -0
  59. data/test/require_gems.rb +19 -0
  60. data/test/schema.rb +33 -0
  61. data/test/spec_helper.rb +22 -0
  62. data/test/test_helper.rb +89 -0
  63. data/test/views/projects_and_people_grid.html.erb +12 -0
  64. data/test/views/projects_and_people_grid_invalid.html.erb +12 -0
  65. data/test/views/simple_projects_grid.html.erb +9 -0
  66. data/test/wice_grid_core_ext_test.rb +183 -0
  67. data/test/wice_grid_functional_test.rb +68 -0
  68. data/test/wice_grid_initializer.rb +215 -0
  69. data/test/wice_grid_misc_test.rb +41 -0
  70. data/test/wice_grid_test.rb +42 -0
  71. data/test/wice_grid_view_helper_test.rb +12 -0
  72. metadata +150 -0
@@ -0,0 +1,183 @@
1
+ module Wice
2
+ module JsCalendarHelpers
3
+
4
+ # Jquery
5
+
6
+ def date_calendar_jquery(initial_date, view, opts = {}, html_opts = {}) #:nodoc:
7
+ date_format = Wice::Defaults::DATE_FORMAT
8
+
9
+ options, name, date_string, dom_id, datepicker_placeholder_id, date_span_id =
10
+ prepare_data_for_calendar(opts, date_format, initial_date)
11
+
12
+ remove_date_function = %! $('##{date_span_id}').html(''); $('##{dom_id}')[0].value = ''; !
13
+
14
+ date_picker =
15
+
16
+ hidden_field_tag(name, date_string, :id => dom_id) + ' ' +
17
+
18
+ link_to_function(
19
+ content_tag(:span, date_string, :id => date_span_id),
20
+ remove_date_function,
21
+ :class => 'date_label',
22
+ :title => ::Wice::WiceGridNlMessageProvider.get_message(:DATE_STRING_TOOLTIP))
23
+
24
+ html = "<span id=\"#{datepicker_placeholder_id}\">#{date_picker}</span>"
25
+
26
+ javascript = calendar_constructor_jquery(dom_id, view, Wice::Defaults::DATE_FORMAT_JQUERY,
27
+ date_span_id, opts[:fire_event], html_opts[:title], datepicker_placeholder_id)
28
+
29
+ [html, javascript]
30
+ end
31
+
32
+ # Prototype
33
+ def date_calendar_prototype(initial_date, view, opts = {}, html_opts = {}) #:nodoc:
34
+ select_date_datetime_common_prototype(initial_date, view, opts, html_opts, false, Wice::Defaults::DATE_FORMAT)
35
+ end
36
+
37
+ def datetime_calendar_prototype(initial_date, view, opts = {}, html_opts = {}) #:nodoc:
38
+ select_date_datetime_common_prototype(initial_date, view, opts, html_opts, true, Wice::Defaults::DATETIME_FORMAT)
39
+ end
40
+
41
+ protected
42
+
43
+ # common
44
+
45
+ def prepare_data_for_calendar(opts, date_format, initial_date) #:nodoc:
46
+ options = {:prefix => 'date'}
47
+ options.merge!(opts)
48
+ name = options[:prefix]
49
+ date_string = initial_date.nil? ? '' : initial_date.strftime(date_format)
50
+ dom_id = options[:id] || name.gsub(/([\[\(])|(\]\[)/, '_').gsub(/[\]\)]/, '').gsub(/\./, '_').gsub(/_+/, '_')
51
+ datepicker_placeholder_id = dom_id + '_date_placeholder'
52
+ date_span_id = dom_id + '_date_view'
53
+
54
+ return options, name, date_string, dom_id, datepicker_placeholder_id, date_span_id
55
+ end
56
+
57
+ # jquery
58
+
59
+ def calendar_constructor_jquery(dom_id, view, date_format, date_span_id, fireEvent, title, datepicker_placeholder_id)
60
+
61
+ javascript = %| $( "##{dom_id}" ).datepicker({\n|
62
+ javascript << %| firstDay: 1,\n|
63
+ javascript << %| showOn: "button",\n|
64
+ javascript << %| dateFormat: "#{date_format}",\n|
65
+ javascript << %| buttonImage: "#{::Wice::Defaults::CALENDAR_ICON}",\n|
66
+ javascript << %| buttonImageOnly: true,\n|
67
+ javascript << %| buttonText: "#{title}",\n|
68
+ javascript << %| changeMonth: true,\n|
69
+ javascript << %| changeYear: true,\n|
70
+ javascript << %| onSelect: function(dateText, inst) {\n|
71
+ javascript << %| $("##{date_span_id}").html(dateText);\n|
72
+ if fireEvent
73
+ javascript << %| $("##{dom_id}").trigger('wg:calendarChanged');\n|
74
+ end
75
+ javascript << %| }\n|
76
+ javascript << %| });\n|
77
+
78
+ lang = Object.const_defined?(:I18n) ? I18n.locale : nil
79
+
80
+ if Rails.env == 'development'
81
+ unless view.respond_to? :datepicker_check_done
82
+
83
+ javascript << %| if (! $.datepicker ){\n|
84
+ javascript << %| alert("Seems like you do not have jQuery datepicker (http://jqueryui.com/demos/datepicker/)|
85
+ javascript << %| installed. Either install it or set Wice::Defaults::HELPER_STYLE to :standard in |
86
+ javascript << %| wice_grid_config.rb in order to use standard Rails date helpers")\n|
87
+ javascript << %| }\n|
88
+
89
+ def view.datepicker_check_done
90
+ end
91
+ end
92
+ end
93
+
94
+ if lang
95
+ unless view.respond_to? :wg_calendar_lang_set
96
+
97
+ javascript << %| wgCalendarLangRegionalOptions = $.datepicker.regional['#{lang}'];\n|
98
+ javascript << %| if (wgCalendarLangRegionalOptions){\n|
99
+ javascript << %| delete wgCalendarLangRegionalOptions.dateFormat ;\n|
100
+ javascript << %| delete wgCalendarLangRegionalOptions.firstDate ;\n|
101
+ javascript << %| }\n|
102
+
103
+ def view.wg_calendar_lang_set
104
+ end
105
+ end
106
+ javascript << %| if (wgCalendarLangRegionalOptions){\n|
107
+ javascript << %| $( "##{dom_id}" ).datepicker("option", wgCalendarLangRegionalOptions);\n|
108
+ javascript << %| }\n|
109
+ end
110
+
111
+ javascript += %| $('##{datepicker_placeholder_id} .ui-datepicker-trigger').addClass('clickable');\n|
112
+
113
+ javascript
114
+ end
115
+
116
+ # prortotype
117
+
118
+ def calendar_constructor_prototype(popup_trigger_icon_id, view, dom_id, date_format,
119
+ date_span_id, with_time, fireEvent)
120
+ javascript = ''
121
+
122
+ unless view.respond_to? :wg_calendar_lang_set
123
+ lang = Object.const_defined?(:I18n) ? I18n.locale : nil
124
+ javascript << %| Calendar.language = '#{lang}';\n| unless lang.blank?
125
+
126
+ def view.wg_calendar_lang_set
127
+ end
128
+ end
129
+
130
+
131
+ javascript << %| new Calendar({\n |
132
+ javascript << %| popupTriggerElement : "#{popup_trigger_icon_id}",\n |
133
+ javascript << %| initialDate : $('#{dom_id}').value,\n |
134
+ if fireEvent
135
+ javascript << %| onHideCallback : function(){Event.fire($(#{dom_id}), 'wg:calendarChanged')},\n |
136
+ end
137
+ javascript << %| dateFormat : "#{date_format}",\n|
138
+ unless Wice::Defaults::POPUP_PLACEMENT_STRATEGY == :trigger
139
+ javascript << %| popupPositioningStrategy : "#{Wice::Defaults::POPUP_PLACEMENT_STRATEGY}",\n|
140
+ end
141
+ if with_time
142
+ javascript << %| withTime : true,\n|
143
+ end
144
+ javascript << %| outputFields : $A(['#{date_span_id}', '#{dom_id}'])\n |
145
+ javascript << %| });\n|
146
+
147
+ javascript
148
+ end
149
+
150
+ def select_date_datetime_common_prototype(initial_date, view, opts, html_opts, with_time, date_format) #:nodoc:
151
+
152
+ options, name, date_string, dom_id, datepicker_placeholder_id, date_span_id =
153
+ prepare_data_for_calendar(opts, date_format, initial_date)
154
+
155
+ popup_trigger_icon_id = dom_id + '_trigger'
156
+
157
+ function = %! $('#{date_span_id}').innerHTML = ''; $('#{dom_id}').value = ''; !
158
+ if opts[:fire_event]
159
+ function += "Event.fire($(#{dom_id}), 'wg:calendarChanged')"
160
+ end
161
+
162
+ date_picker = image_tag(Defaults::CALENDAR_ICON,
163
+ :id => popup_trigger_icon_id,
164
+ :class => 'clickable',
165
+ :title => html_opts[:title]) +
166
+
167
+ link_to_function(
168
+ content_tag(:span, date_string, :id => date_span_id),
169
+ function,
170
+ :class => 'date_label',
171
+ :title => WiceGridNlMessageProvider.get_message(:DATE_STRING_TOOLTIP)) + ' ' +
172
+
173
+ hidden_field_tag(name, date_string, :class => 'text-input', :id => dom_id)
174
+
175
+ html = "<span id=\"#{datepicker_placeholder_id}\">#{date_picker}</span>"
176
+
177
+ javascript = calendar_constructor_prototype(popup_trigger_icon_id, view, dom_id, date_format, date_span_id, with_time, opts[:fire_event])
178
+
179
+ [html, javascript]
180
+ end
181
+
182
+ end
183
+ end
@@ -0,0 +1,113 @@
1
+ # encoding: UTF-8
2
+ module Wice
3
+ module GridViewHelper
4
+
5
+
6
+ # This method dumps all HTTP parameters related to filtering and ordering of a certain grid as hidden form fields.
7
+ # This might be required if you want to keep the state of a grid while reloading the page using other forms.
8
+ #
9
+ # The only parameter is a grid object returned by +initialize_grid+ in the controller.
10
+ def dump_filter_parameters_as_hidden_fields(grid)
11
+ unless grid.kind_of? WiceGrid
12
+ raise WiceGridArgumentError.new("dump_filter_parameters_as_hidden_fields: the parameter must be a WiceGrid instance.")
13
+ end
14
+
15
+ grid.get_state_as_parameter_value_pairs(true).collect{|param_name, value|
16
+ hidden_field_tag(param_name, value)
17
+ }.join("\n").html_safe_if_necessary
18
+ end
19
+
20
+ def dump_state(grid) #:nodoc:
21
+ debug(grid.get_state_as_parameter_value_pairs)
22
+ end
23
+
24
+
25
+ # secret but stupid weapon - takes an ActiveRecord and using reflection tries to build all the column clauses by itself.
26
+ # WiceGrid is not a scaffolding solution, I hate scaffolding and how certain idiots associate scaffolding with Rails,
27
+ # so I do not document this method to avoid contributing to this misunderstanding.
28
+ def scaffolded_grid(grid_obj, opts = {}) #:nodoc:
29
+ unless grid_obj.kind_of? WiceGrid
30
+ raise WiceGridArgumentError.new("scaffolded_grid: the parameter must be a WiceGrid instance.")
31
+ end
32
+
33
+ # debug grid.klass.column_names
34
+ columns = grid_obj.klass.column_names
35
+ if opts[:reject_attributes].is_a? Proc
36
+ columns = columns.reject{|c| opts[:reject_attributes].call(c)}
37
+ opts.delete(:reject_attributes)
38
+ elsif
39
+ columns = columns.reject{|c| c =~ opts[:reject_attributes]}
40
+ opts.delete(:reject_attributes)
41
+ end
42
+ grid(grid_obj, opts) do |g|
43
+ columns.each do |column_name|
44
+ g.column :column_name => column_name.humanize, :attribute_name => column_name do |ar|
45
+ ar.send(column_name)
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+ # View helper to include all stylesheets and javascript files needed for WiceGrid to function. Add it to template/layout in the
52
+ # page header section.
53
+ #
54
+ # By default the helper returns WiceGrid javascripts and stylesheets include statements only on demand, that is, only if at least one initialize_grid has been
55
+ # called in the controller. Otherwise the helper returns an empty string. However, you can force the old unconditioned behavior if you need by submitting
56
+ # parameter <tt>:load_on_demand</tt> set to +false+:
57
+ # <%= include_wice_grid_assets(:load_on_demand => false) %>
58
+ #
59
+ # By default +include_wice_grid_assets+ adds include statements for the javascript calendar widget used for date/datetime filters,
60
+ # but it's possible not to include them setting parameter +include_calendar+ to false:
61
+ # <%= include_wice_grid_assets(:include_calendar => false) %>
62
+ def include_wice_grid_assets(options = {})
63
+ opts = {:include_calendar => true, :load_on_demand => true}
64
+ options.assert_valid_keys(opts.keys)
65
+ opts.merge!(options)
66
+
67
+ if @__wice_grid_on_page || ! opts[:load_on_demand]
68
+ javascript_include_tag('wice_grid') +
69
+ stylesheet_link_tag('wice_grid') +
70
+ if opts[:include_calendar]
71
+ JsAdaptor.js_framework_specific_calendar_assets(self)
72
+ else
73
+ ''
74
+ end
75
+ end
76
+ end
77
+
78
+ # Returns a list of names of javascript files for WiceGrid thus providing compatibility with Rails asset caching.
79
+ # Mind the parameters, and the fact that Prototype has to be loaded before WiceGrid javascripts:
80
+ #
81
+ # <%= javascript_include_tag *([:defaults] + names_of_wice_grid_javascripts + [ 'ui', 'swfobject', {:cache => true}]) %>
82
+ #
83
+ # By default +names_of_wice_grid_javascripts+ returns all javascripts, but it's possible not to include calendar widget javascripts by
84
+ # setting parameter <tt>:include_calendar</tt> to +false+.
85
+ def names_of_wice_grid_javascripts(options = {})
86
+ opts = {:include_calendar => true}
87
+ options.assert_valid_keys(opts.keys)
88
+ opts.merge!(options)
89
+ res = ['wice_grid']
90
+ n = js_framework_specific_calendar_js_name
91
+ res << n if n && opts[:include_calendar]
92
+ res
93
+ end
94
+
95
+ # Returns a list of names of stylesheet files for WiceGrid thus providing compatibility with Rails asset caching.
96
+ # Mind the parameters, for example:
97
+ #
98
+ # <%= stylesheet_link_tag *(['core', 'modalbox'] + names_of_wice_grid_stylesheets + [ {:cache => true}]) %>
99
+ #
100
+ # By default +names_of_wice_grid_stylesheets+ returns all javascripts, but it's possible not to include calendar widget javascripts by
101
+ # setting parameter <tt>:include_calendar</tt> to +false+.
102
+ def names_of_wice_grid_stylesheets(options = {})
103
+ opts = {:include_calendar => true}
104
+ options.assert_valid_keys(opts.keys)
105
+ opts.merge!(options)
106
+ res = ['wice_grid']
107
+ n = js_framework_specific_calendar_css_name
108
+ res << n if n && opts[:include_calendar]
109
+ res
110
+ end
111
+
112
+ end
113
+ end
@@ -0,0 +1,82 @@
1
+ # encoding: UTF-8
2
+ module Wice
3
+ module GridViewHelper
4
+
5
+ # View helper to render the list of saved queries and the form to create a new query.
6
+ # Parameters:
7
+ # * <tt>:extra_parameters</tt> - a hash of additional parameters to use when creating a new query object.
8
+ # Read section "Adding Application Specific Logic to Saving/Restoring Queries" in README for more details.
9
+ def saved_queries_panel(grid, opts = {})
10
+ unless grid.kind_of? WiceGrid
11
+ raise WiceGridArgumentError.new("saved_queries_panel: the parameter must be a WiceGrid instance.")
12
+ end
13
+
14
+ options = {:extra_parameters => {}}
15
+ opts.assert_valid_keys(options.keys)
16
+ options.merge!(opts)
17
+
18
+ grid_name = grid.name
19
+ id_and_name = "#{grid_name}_saved_query_name"
20
+ base_path_to_query_controller = create_serialized_query_url(:grid_name => grid_name)
21
+
22
+ parameters = grid.get_state_as_parameter_value_pairs
23
+
24
+ options[:extra_parameters].each do |k, v|
25
+ parameters << [ CGI.unescape({:extra => {k => ''}}.to_query.sub(/=$/,'')) , v.to_s ]
26
+ end
27
+ parameters << ['authenticity_token', form_authenticity_token]
28
+
29
+ (%! <div class="wice_grid_query_panel"><h3>#{WiceGridNlMessageProvider.get_message(:SAVED_QUERY_PANEL_TITLE)}</h3>! +
30
+ saved_queries_list(grid_name, grid.saved_query, options[:extra_parameters]) +
31
+ %!<div id="#{grid_name}_notification_messages" onmouseover="#{Wice::JsAdaptor.fade_this}"></div>! +
32
+ if block_given?
33
+ view, ids = yield
34
+ view
35
+ else
36
+ ''
37
+ end +
38
+ text_field_tag(id_and_name, '', :size => 20, :onkeydown=>'', :id => id_and_name) +
39
+ button_to_function(WiceGridNlMessageProvider.get_message(:SAVE_QUERY_BUTTON_LABEL), "#{grid_name}_save_query()" ) +
40
+ '</div>' +
41
+ javascript_tag do
42
+ JsAdaptor.call_to_save_query_and_key_event_initialization_for_saving_queries(
43
+ id_and_name, grid_name, base_path_to_query_controller, parameters.to_json, ids.to_json
44
+ )
45
+ end
46
+ ).html_safe
47
+ end
48
+
49
+ def saved_queries_list(grid_name, saved_query = nil, extra_parameters = nil) #:nodoc:
50
+
51
+ link_title = WiceGridNlMessageProvider.get_message(:SAVED_QUERY_LINK_TITLE)
52
+ deletion_confirmation = WiceGridNlMessageProvider.get_message(:SAVED_QUERY_DELETION_CONFIRMATION)
53
+ deletion_link_title = WiceGridNlMessageProvider.get_message(:SAVED_QUERY_DELETION_LINK_TITLE)
54
+
55
+ query_store_model = ::Wice::get_query_store_model
56
+ currently_loaded_query_id = saved_query ? saved_query.id : nil
57
+ with = extra_parameters.nil? ? nil : "'" + {:extra => extra_parameters}.to_query + "'"
58
+
59
+ %!<ul id="#{grid_name}_query_list" class="query_list"> ! +
60
+ query_store_model.list(grid_name, controller).collect do |sq|
61
+ link_opts = {:class => 'query_load_link', :title => "#{link_title} #{sq.name}"}
62
+ link_opts[:class] += ' current' if saved_query == sq
63
+ "<li>"+
64
+ link_to_remote(image_tag(Defaults::DELETE_QUERY_ICON),
65
+ {:url => delete_serialized_query_path(:grid_name => grid_name, :id => sq.id, :current => currently_loaded_query_id ),
66
+ :confirm => deletion_confirmation, :with => with},
67
+ {:title => "#{deletion_link_title} #{sq.name}"} ) + ' &nbsp; ' +
68
+ link_to_function(h(sq.name),
69
+ %/ if (typeof(#{grid_name}) != "undefined") #{grid_name}.load_query(#{sq.id}) /,
70
+ link_opts) +
71
+ if sq.respond_to? :description
72
+ desc = sq.description
73
+ desc.blank? ? '' : " <i>#{desc}</i>"
74
+ else
75
+ ''
76
+ end +
77
+ '</li>'
78
+ end.join('') + '</ul>'
79
+ end
80
+
81
+ end
82
+ end
@@ -0,0 +1,761 @@
1
+ # encoding: UTF-8
2
+ module Wice
3
+ module GridViewHelper
4
+
5
+ # View helper for rendering the grid.
6
+ #
7
+ # The first parameter is a grid object returned by +initialize_grid+ in the controller.
8
+ #
9
+ # The second parameter is a hash of options:
10
+ # * <tt>:table_html_attrs</tt> - a hash of HTML attributes to be included into the <tt>table</tt> tag.
11
+ # * <tt>:class</tt> - a shortcut for <tt>:table_html_attrs => {:class => 'css_class'}</tt>
12
+ # * <tt>:header_tr_html_attrs</tt> - a hash of HTML attributes to be included into the first <tt>tr</tt> tag
13
+ # (or two first <tt>tr</tt>'s if the filter row is present).
14
+ # * <tt>:show_filters</tt> - defines when the filter is shown. Possible values are:
15
+ # * <tt>:when_filtered</tt> - the filter is shown when the current table is the result of filtering
16
+ # * <tt>:always</tt> or <tt>true</tt> - show the filter always
17
+ # * <tt>:no</tt> or <tt>false</tt> - never show the filter
18
+ # * <tt>:upper_pagination_panel</tt> - a boolean value which defines whether there is an additional pagination
19
+ # panel on top of the table. By default it is false.
20
+ # * <tt>:extra_request_parameters</tt> - a hash which will be added as additional HTTP request parameters to all
21
+ # links generated by the grid, be it sorting links, filters, or the 'Reset Filter' icon.
22
+ # Please note that WiceGrid respects and retains all request parameters already present in the URL which
23
+ # formed the page, so there is no need to enumerate them in <tt>:extra_request_parameters</tt>. A typical
24
+ # usage of <tt>:extra_request_parameters</tt> is a page with javascript tabs - changing the active tab
25
+ # does not reload the page, but if one such tab contains a WiceGrid, it could be required that if the user
26
+ # orders or filters the grid, the result page should have the tab with the grid activated. For this we
27
+ # need to send an additional parameter specifying from which tab the request was generated.
28
+ # * <tt>:sorting_dependant_row_cycling</tt> - When set to true (by default it is false) the row styles +odd+
29
+ # and +even+ will be changed only when the content of the cell belonging to the sorted column changes.
30
+ # In other words, rows with identical values in the ordered column will have the same style (color).
31
+ # * <tt>:erb_mode</tt> - can be <tt>true</tt> or <tt>false</tt>. Defines the style of the helper method
32
+ # in the view. The default is <tt>false</tt>.
33
+ # * <tt>:allow_showing_all_records</tt> - allow or prohibit the "All Records" mode.
34
+ # * <tt>:hide_reset_button</tt> - Do not show the default Filter Reset button.
35
+ # Useful when using a custom reset button (helper +reset_grid_javascript+).
36
+ # By default it is false.
37
+ # * <tt>:hide_submit_button</tt> - Do not show the default Filter Submit button.
38
+ # Useful when using a custom submit button (helper +submit_grid_javascript+).
39
+ # By default it is false.
40
+ # * <tt>:hide_csv_button</tt> - a boolean value which defines whether the default Export To CSV button
41
+ # should be rendered. Useful when using a custom Export To CSV button (helper +export_to_csv_javascript+).
42
+ # By default it is false.
43
+ # Please read README for more insights.
44
+ #
45
+ # The block contains definitions of grid columns using the +column+ method sent to the object yielded into
46
+ # the block. In other words, the value returned by each of the blocks defines the content of a cell, the
47
+ # first block is called for cells of the first column for each row (each ActiveRecord instance), the
48
+ # second block is called for cells of the second column, and so on. See the example:
49
+ #
50
+ # <%= grid(@accounts_grid, :table_html_attrs => {:class => 'grid_style', :id => 'accounts_grid'}, :header_tr_html_attrs => {:class => 'grid_headers'}) do |g|
51
+ #
52
+ # g.column :column_name => 'Username', :attribute_name => 'username' do |account|
53
+ # account.username
54
+ # end
55
+ #
56
+ # g.column :column_name => 'application_account.field.identity_id'._, :attribute_name => 'firstname', :model_class => Person do |account|
57
+ # link_to(account.identity.name, identity_path(account.identity))
58
+ # end
59
+ #
60
+ # g.column do |account|
61
+ # link_to('Edit', edit_account_path(account))
62
+ # end
63
+ #
64
+ # end -%>
65
+ #
66
+ # The helper may have two styles defined by the +erb_mode+ parameter to the +initialize_grid+ in the contoller.
67
+ # By default (<tt>erb_mode = false</tt>) this is a simple helper surrounded by <tt><%=</tt> and <tt>%></tt>:
68
+ #
69
+ # <%= grid(@countries_grid) do |g|
70
+ #
71
+ # g.column :column_name => 'Name', :attribute_name => 'name' do |country|
72
+ # link_to(country.name, country_path(country))
73
+ # end
74
+ #
75
+ # g.column :column_name => 'Numeric Code', :attribute_name => 'numeric_code' do |country|
76
+ # country.numeric_code
77
+ # end
78
+ #
79
+ # end -%>
80
+ #
81
+ #
82
+ #
83
+ # The second style (<tt>erb_mode = true</tt>) is called <em>ERB mode</em> and it allows to embed any ERB content inside blocks,
84
+ # which is basically the style of the
85
+ # <tt>form_for</tt> helper, only <tt>form_for</tt> takes one block, while inside the <tt>grid</tt> block there are other method calls taking
86
+ # blocks as parameters:
87
+ #
88
+ # <% grid(@countries_grid) do |g|
89
+ #
90
+ # <% g.column :column_name => 'Name', :attribute_name => 'name' do |country| %>
91
+ # <b>Name: <%= link_to(country.name, country_path(country)) %></b>
92
+ # <% end %>
93
+ #
94
+ # <% g.column :column_name => 'Numeric Code', :attribute_name => 'numeric_code' do |country| %>
95
+ # <i>Numeric Code: <%= country.numeric_code %></i>
96
+ # <% end %>
97
+ #
98
+ # <% end -%>
99
+ #
100
+ # This mode can be usable if you like to have much HTML code inside cells.
101
+ #
102
+ # Please remember that in this mode the helper opens with <tt><%</tt> instead of <tt><%=</tt>, similar to <tt>form_for</tt>.
103
+ #
104
+ # Defaults for parameters <tt>:show_filters</tt> and <tt>:upper_pagination_panel</tt>
105
+ # can be changed in <tt>lib/wice_grid_config.rb</tt> using constants <tt>Wice::Defaults::SHOW_FILTER</tt> and
106
+ # <tt>WiceGrid::Defaults::SHOW_UPPER_PAGINATION_PANEL</tt>, this is convenient if you want to set a project wide setting
107
+ # without having to repeat it for every grid instance.
108
+ #
109
+ # Pease read documentation about the +column+ method to achieve the enlightenment.
110
+
111
+ def grid(grid, opts = {}, &block)
112
+ unless grid.class == WiceGrid
113
+ raise WiceGridArgumentError.new("The first argument for the grid helper must be an instance of the WiceGrid class")
114
+ end
115
+
116
+ if grid.output_buffer
117
+ if grid.output_buffer == true
118
+ raise WiceGridException.new("Second occurence of grid helper with the same grid object. " +
119
+ "Did you intend to use detached filters and forget to define them?")
120
+ else
121
+ return grid.output_buffer
122
+ end
123
+ end
124
+
125
+ options = {
126
+ :allow_showing_all_records => Defaults::ALLOW_SHOWING_ALL_QUERIES,
127
+ :class => nil,
128
+ :erb_mode => Defaults::ERB_MODE,
129
+ :extra_request_parameters => {},
130
+ :header_tr_html_attrs => {},
131
+ :hide_reset_button => false,
132
+ :hide_submit_button => false,
133
+ :hide_csv_button => false,
134
+ :show_filters => Defaults::SHOW_FILTER,
135
+ :sorting_dependant_row_cycling => false,
136
+ :table_html_attrs => {},
137
+ :upper_pagination_panel => Defaults::SHOW_UPPER_PAGINATION_PANEL
138
+ }
139
+
140
+ opts.assert_valid_keys(options.keys)
141
+
142
+ options.merge!(opts)
143
+
144
+ options[:show_filters] = :no if options[:show_filters] == false
145
+ options[:show_filters] = :always if options[:show_filters] == true
146
+
147
+ options[:table_html_attrs].add_or_append_class_value!('wice_grid', true)
148
+
149
+ if options[:class]
150
+ options[:table_html_attrs].add_or_append_class_value!(options[:class])
151
+ options.delete(:class)
152
+ end
153
+
154
+ rendering = GridRenderer.new(grid, self)
155
+ rendering.erb_mode = options[:erb_mode]
156
+
157
+ block.call(rendering) # calling block containing column() calls
158
+
159
+ reuse_last_column_for_filter_buttons =
160
+ Defaults::REUSE_LAST_COLUMN_FOR_FILTER_ICONS && rendering.last_column_for_html.capable_of_hosting_filter_related_icons?
161
+
162
+ if grid.output_csv?
163
+ content = grid_csv(grid, rendering)
164
+ else
165
+ # If blank_slate is defined we don't show any grid at all
166
+ if rendering.blank_slate_handler && grid.resultset.size == 0 && ! grid.filtering_on?
167
+ content = generate_blank_slate(grid, rendering)
168
+ return prepare_result(rendering, grid, content, block)
169
+ end
170
+
171
+ content = grid_html(grid, options, rendering, reuse_last_column_for_filter_buttons)
172
+ end
173
+
174
+ grid.view_helper_finished = true
175
+ prepare_result(rendering, grid, content, block)
176
+ end
177
+
178
+ def prepare_result(rendering, grid, content, block) #:nodoc:
179
+ if rendering.erb_mode
180
+ # true in this case is a sign that grid_html has run in a normal mode, i.e. without detached filters
181
+ if grid.output_buffer.nil? || grid.output_buffer == true
182
+ content = content.to_s
183
+ if Rails.respond_to?(:version) && Rails.version.to_f >= 2.2
184
+ return concat(content)
185
+ else
186
+ return concat(content, block.binding)
187
+ end
188
+ else
189
+ # this way we're sending an empty string and setting flag stubborn_output_mode of GridOutputBuffer to false
190
+ return grid.output_buffer.to_s
191
+ end
192
+ else
193
+ return content
194
+ end
195
+ end
196
+
197
+
198
+ def generate_blank_slate(grid, rendering) #:nodoc:
199
+ buff = GridOutputBuffer.new
200
+
201
+ buff << if rendering.blank_slate_handler.is_a?(Proc)
202
+ call_block_as_erb_or_ruby(rendering, rendering.blank_slate_handler, nil)
203
+ elsif rendering.blank_slate_handler.is_a?(Hash)
204
+ render(rendering.blank_slate_handler)
205
+ else
206
+ rendering.blank_slate_handler
207
+ end
208
+
209
+ if rendering.find_one_for(:in_html){|column| column.detach_with_id}
210
+ buff.stubborn_output_mode = true
211
+ buff.return_empty_strings_for_nonexistent_filters = true
212
+ grid.output_buffer = buff
213
+ end
214
+ buff
215
+ end
216
+
217
+ def call_block_as_erb_or_ruby(rendering, block, ar) #:nodoc:
218
+ if rendering.erb_mode
219
+ capture(ar, &block)
220
+ else
221
+ block.call(ar)
222
+ end
223
+ end
224
+
225
+ # the longest method? :(
226
+ def grid_html(grid, options, rendering, reuse_last_column_for_filter_buttons) #:nodoc:
227
+
228
+ table_html_attrs, header_tr_html_attrs = options[:table_html_attrs], options[:header_tr_html_attrs]
229
+
230
+ cycle_class = nil
231
+ sorting_dependant_row_cycling = options[:sorting_dependant_row_cycling]
232
+
233
+ content = GridOutputBuffer.new
234
+ # Ruby 1.9.1
235
+ content.force_encoding('UTF-8') if content.respond_to?(:force_encoding)
236
+
237
+ content << %!<div class="wice_grid_container" id="#{grid.name}"><div id="#{grid.name}_title">!
238
+ content << content_tag(:h3, grid.saved_query.name) if grid.saved_query
239
+ content << "</div><table #{tag_options(table_html_attrs, true)}>"
240
+ content << "<thead>"
241
+
242
+ no_filters_at_all = (options[:show_filters] == :no || rendering.no_filter_needed?) ? true: false
243
+
244
+ if no_filters_at_all
245
+ no_rightmost_column = no_filter_row = no_filters_at_all
246
+ else
247
+ no_rightmost_column = no_filter_row = (options[:show_filters] == :no || rendering.no_filter_needed_in_main_table?) ? true: false
248
+ end
249
+
250
+ no_rightmost_column = true if reuse_last_column_for_filter_buttons
251
+
252
+ pagination_panel_content_html, pagination_panel_content_js = nil, nil
253
+ if options[:upper_pagination_panel]
254
+ content << rendering.pagination_panel(no_rightmost_column, options[:hide_csv_button]) do
255
+ pagination_panel_content_html, pagination_panel_content_js =
256
+ pagination_panel_content(grid, options[:extra_request_parameters], options[:allow_showing_all_records])
257
+ pagination_panel_content_html
258
+ end
259
+ end
260
+
261
+ title_row_attrs = header_tr_html_attrs.clone
262
+ title_row_attrs.add_or_append_class_value!('wice_grid_title_row', true)
263
+
264
+ content << %!<tr #{tag_options(title_row_attrs, true)}>!
265
+
266
+ filter_row_id = grid.name + '_filter_row'
267
+
268
+ # first row of column labels with sorting links
269
+
270
+ filter_shown = if options[:show_filters] == :when_filtered
271
+ grid.filtering_on?
272
+ elsif options[:show_filters] == :always
273
+ true
274
+ end
275
+
276
+ cached_javascript = []
277
+
278
+ rendering.each_column_aware_of_one_last_one(:in_html) do |column, last|
279
+
280
+ column_name = column.column_name
281
+ if column_name.is_a? Array
282
+ column_name, js = column_name
283
+ cached_javascript << js
284
+ end
285
+
286
+ if column.attribute_name && column.allow_ordering
287
+
288
+ css_class = grid.filtered_by?(column) ? 'active_filter' : nil
289
+
290
+ direction = 'asc'
291
+ link_style = nil
292
+ if grid.ordered_by?(column)
293
+ css_class = css_class.nil? ? 'sorted' : css_class + ' sorted'
294
+ link_style = grid.order_direction
295
+ direction = 'desc' if grid.order_direction == 'asc'
296
+ end
297
+
298
+ col_link = link_to(column_name,
299
+ rendering.column_link(column, direction, params, options[:extra_request_parameters]),
300
+ :class => link_style)
301
+ content << content_tag(:th, col_link, Hash.make_hash(:class, css_class))
302
+ column.css_class = css_class
303
+ else
304
+ if reuse_last_column_for_filter_buttons && last
305
+ content << content_tag(:th,
306
+ hide_show_icon(filter_row_id, grid, filter_shown, no_filter_row, options[:show_filters], rendering),
307
+ :class => 'hide_show_icon'
308
+ )
309
+ else
310
+ content << content_tag(:th, (column.icon ? image_tag("/images/icons/grid/#{column.icon}", :alt => column_name, :border => 0) : column_name))
311
+ end
312
+ end
313
+ end
314
+
315
+ content << content_tag(:th,
316
+ hide_show_icon(filter_row_id, grid, filter_shown, no_filter_row, options[:show_filters], rendering),
317
+ :class => 'hide_show_icon'
318
+ ) unless no_rightmost_column
319
+
320
+ content << '</tr>'
321
+ # rendering first row end
322
+
323
+
324
+ unless no_filters_at_all # there are filters, we don't know where, in the table or detached
325
+ if no_filter_row # they are all detached
326
+ content.stubborn_output_mode = true
327
+ rendering.each_column(:in_html) do |column|
328
+ if column.filter_shown?
329
+ filter_html_code, filter_js_code = column.render_filter
330
+ filter_html_code = filter_html_code.html_safe_if_necessary
331
+ cached_javascript << filter_js_code
332
+ content.add_filter(column.detach_with_id, filter_html_code)
333
+ end
334
+ end
335
+
336
+ else # some filters are present in the table
337
+
338
+ filter_row_attrs = header_tr_html_attrs.clone
339
+ filter_row_attrs.add_or_append_class_value!('wice_grid_filter_row', true)
340
+ filter_row_attrs['id'] = filter_row_id
341
+
342
+ content << %!<tr #{tag_options(filter_row_attrs, true)} !
343
+ content << 'style="display:none"' unless filter_shown
344
+ content << '>'
345
+
346
+ rendering.each_column_aware_of_one_last_one(:in_html) do |column, last|
347
+ if column.filter_shown?
348
+ filter_html_code, filter_js_code = column.render_filter
349
+ filter_html_code = filter_html_code.html_safe_if_necessary
350
+ cached_javascript << filter_js_code
351
+ if column.detach_with_id
352
+ content.stubborn_output_mode = true
353
+ content << content_tag(:th, '', Hash.make_hash(:class, column.css_class))
354
+ content.add_filter(column.detach_with_id, filter_html_code)
355
+ else
356
+ content << content_tag(:th, filter_html_code, Hash.make_hash(:class, column.css_class))
357
+ end
358
+ else
359
+ if reuse_last_column_for_filter_buttons && last
360
+ content << content_tag(:th,
361
+ reset_submit_buttons(options, grid, rendering),
362
+ Hash.make_hash(:class, column.css_class).add_or_append_class_value!('filter_icons')
363
+ )
364
+ else
365
+ content << content_tag(:th, '', Hash.make_hash(:class, column.css_class))
366
+ end
367
+ end
368
+ end
369
+ unless no_rightmost_column
370
+ content << content_tag(:th, reset_submit_buttons(options, grid, rendering), :class => 'filter_icons' )
371
+ end
372
+ content << '</tr>'
373
+ end
374
+ end
375
+
376
+ rendering.each_column(:in_html) do |column|
377
+ unless column.css_class.blank?
378
+ column.td_html_attrs.add_or_append_class_value!(column.css_class)
379
+ end
380
+ end
381
+
382
+ content << '</thead><tfoot>'
383
+
384
+ content << rendering.pagination_panel(no_rightmost_column, options[:hide_csv_button]) do
385
+ if pagination_panel_content_html
386
+ pagination_panel_content_html
387
+ else
388
+ pagination_panel_content_html, pagination_panel_content_js =
389
+ pagination_panel_content(grid, options[:extra_request_parameters], options[:allow_showing_all_records])
390
+ pagination_panel_content_html
391
+ end
392
+ end
393
+
394
+ content << '</tfoot><tbody>'
395
+ cached_javascript << pagination_panel_content_js
396
+
397
+ # rendering rows
398
+ cell_value_of_the_ordered_column = nil
399
+ previous_cell_value_of_the_ordered_column = nil
400
+
401
+ grid.each do |ar| # rows
402
+
403
+ before_row_output = if rendering.before_row_handler
404
+ call_block_as_erb_or_ruby(rendering, rendering.before_row_handler, ar)
405
+ else
406
+ nil
407
+ end
408
+
409
+ after_row_output = if rendering.after_row_handler
410
+ call_block_as_erb_or_ruby(rendering, rendering.after_row_handler, ar)
411
+ else
412
+ nil
413
+ end
414
+
415
+ row_content = ''
416
+ rendering.each_column(:in_html) do |column|
417
+ cell_block = column.cell_rendering_block
418
+
419
+ opts = column.td_html_attrs.clone
420
+
421
+ column_block_output = if column.class == Wice::ActionViewColumn
422
+ cell_block.call(ar, params)
423
+ else
424
+ call_block_as_erb_or_ruby(rendering, cell_block, ar)
425
+ end
426
+
427
+ if column_block_output.kind_of?(Array)
428
+
429
+ unless column_block_output.size == 2
430
+ raise WiceGridArgumentError.new('When WiceGrid column block returns an array it is expected to contain 2 elements only - '+
431
+ 'the first is the contents of the table cell and the second is a hash containing HTML attributes for the <td> tag.')
432
+ end
433
+
434
+ column_block_output, additional_opts = column_block_output
435
+
436
+ unless additional_opts.is_a?(Hash)
437
+ raise WiceGridArgumentError.new('When WiceGrid column block returns an array its second element is expected to be a ' +
438
+ "hash containing HTML attributes for the <td> tag. The returned value is #{additional_opts.inspect}. Read documentation.")
439
+ end
440
+
441
+ additional_css_class = nil
442
+ if additional_opts.has_key?(:class)
443
+ additional_css_class = additional_opts[:class]
444
+ additional_opts.delete(:class)
445
+ elsif additional_opts.has_key?('class')
446
+ additional_css_class = additional_opts['class']
447
+ additional_opts.delete('class')
448
+ end
449
+ opts.merge!(additional_opts)
450
+ opts.add_or_append_class_value!(additional_css_class) unless additional_css_class.blank?
451
+ end
452
+
453
+ if sorting_dependant_row_cycling && column.attribute_name && grid.ordered_by?(column)
454
+ cell_value_of_the_ordered_column = column_block_output
455
+ end
456
+ row_content += content_tag(:td, column_block_output, opts)
457
+ end
458
+
459
+ row_attributes = rendering.get_row_attributes(ar)
460
+
461
+ if sorting_dependant_row_cycling
462
+ cycle_class = cycle('odd', 'even', :name => grid.name) if cell_value_of_the_ordered_column != previous_cell_value_of_the_ordered_column
463
+ previous_cell_value_of_the_ordered_column = cell_value_of_the_ordered_column
464
+ else
465
+ cycle_class = cycle('odd', 'even', :name => grid.name)
466
+ end
467
+
468
+ row_attributes.add_or_append_class_value!(cycle_class)
469
+
470
+ content << before_row_output if before_row_output
471
+ content << "<tr #{tag_options(row_attributes)}>#{row_content}"
472
+ content << content_tag(:td, '') unless no_rightmost_column
473
+ content << '</tr>'
474
+ content << after_row_output if after_row_output
475
+ end
476
+
477
+ content << '</tbody></table></div>'
478
+
479
+ content << link_to( "More &#x25BC;".html_safe, rendering.more_link(controller, options[:extra_request_parameters]), :id => 'more') if grid.has_more_to_show?
480
+
481
+ base_link_for_filter, base_link_for_show_all_records = rendering.base_link_for_filter(controller, options[:extra_request_parameters])
482
+
483
+ link_for_export = rendering.link_for_export(controller, 'csv', options[:extra_request_parameters])
484
+
485
+ parameter_name_for_query_loading = {grid.name => {:q => ''}}.to_query
486
+ parameter_name_for_focus = {grid.name => {:foc => ''}}.to_query
487
+
488
+ prototype_and_js_version_check = if ENV['RAILS_ENV'] == 'development'
489
+ %$ if (typeof(WiceGridProcessor) == "undefined"){\n$ +
490
+ %$ alert('wice_grid.js not loaded, WiceGrid cannot proceed! ' +\n$ +
491
+ %$ 'Please make sure that you include WiceGrid javascript in your page. ' +\n$ +
492
+ %$ 'Use <%= include_wice_grid_assets %> or <%= include_wice_grid_assets(:include_calendar => true) %> ' +\n$ +
493
+ %$ 'for WiceGrid javascripts and assets.')\n$ +
494
+ %$ } else if ((typeof(WiceGridProcessor._version) == "undefined") || ( WiceGridProcessor._version != "0.4.3")) {\n$ +
495
+ %$ alert("wice_grid.js in your /public is outdated, please run\\n ./script/generate wice_grid_assets_jquery\\n$ +
496
+ %$ or\\n ./script/generate wice_grid_assets_prototype\\nto update it.");\n$ +
497
+ %$ }\n$
498
+ else
499
+ ''
500
+ end
501
+
502
+ if rendering.show_hide_button_present
503
+ cached_javascript << JsAdaptor.show_hide_button_initialization(grid.name, filter_row_id)
504
+ end
505
+
506
+ if rendering.reset_button_present
507
+ cached_javascript << JsAdaptor.reset_button_initialization(grid.name, reset_grid_javascript(grid))
508
+ end
509
+
510
+ if rendering.submit_button_present
511
+ cached_javascript << JsAdaptor.submit_button_initialization(grid.name, submit_grid_javascript(grid))
512
+ end
513
+
514
+ if rendering.contains_a_text_input?
515
+ cached_javascript << JsAdaptor.enter_key_event_registration(grid.name)
516
+ end
517
+
518
+ if rendering.csv_export_icon_present
519
+ cached_javascript << JsAdaptor.csv_export_icon_initialization(grid.name)
520
+ end
521
+
522
+ if rendering.contains_auto_reloading_selects
523
+ cached_javascript << JsAdaptor.auto_reloading_selects_event_initialization(grid.name)
524
+ end
525
+
526
+ if rendering.contains_auto_reloading_inputs
527
+ cached_javascript << JsAdaptor.auto_reloading_inputs_event_initialization(grid.name)
528
+ end
529
+
530
+ if rendering.contains_auto_reloading_inputs_with_negation_checkboxes
531
+ cached_javascript << JsAdaptor.auto_reloading_inputs_with_negation_checkboxes_event_initialization(grid.name)
532
+ end
533
+
534
+ if rendering.contains_auto_reloading_calendars
535
+ cached_javascript << JsAdaptor.auto_reloading_calendar_event_initialization(grid.name)
536
+ end
537
+
538
+ if rendering.element_to_focus
539
+ cached_javascript << JsAdaptor.focus_element(rendering.element_to_focus)
540
+ end
541
+
542
+ content << javascript_tag(
543
+ JsAdaptor.dom_loaded +
544
+ %/ #{prototype_and_js_version_check}\n/ +
545
+ %/ window['#{grid.name}'] = new WiceGridProcessor('#{grid.name}', '#{base_link_for_filter}',\n/ +
546
+ %/ '#{base_link_for_show_all_records}', '#{link_for_export}', '#{parameter_name_for_query_loading}',\n/ +
547
+ %/ '#{parameter_name_for_focus}', '#{ENV['RAILS_ENV']}');\n/ +
548
+ if no_filters_at_all
549
+ ''
550
+ else
551
+ rendering.select_for(:in_html) do |vc|
552
+ vc.attribute_name and not vc.no_filter
553
+ end.collect{|column| column.yield_javascript}.join("\n")
554
+ end +
555
+ "\n" + cached_javascript.compact.join('') +
556
+ '})'
557
+ )
558
+
559
+ if content.stubborn_output_mode
560
+ grid.output_buffer = content
561
+ else
562
+ # this will serve as a flag that the grid helper has already processed the grid but in a normal mode,
563
+ # not in the mode with detached filters.
564
+ grid.output_buffer = true
565
+ end
566
+ return content
567
+ end
568
+
569
+ def hide_show_icon(filter_row_id, grid, filter_shown, no_filter_row, show_filters, rendering) #:nodoc:
570
+ grid_name = grid.name
571
+ no_filter_opening_closing_icon = (show_filters == :always) || no_filter_row
572
+
573
+ styles = ["display: block;", "display: none;"]
574
+ styles.reverse! unless filter_shown
575
+
576
+
577
+ if no_filter_opening_closing_icon
578
+ hide_icon = show_icon = ''
579
+ else
580
+
581
+
582
+ rendering.show_hide_button_present = true
583
+ filter_tooltip = WiceGridNlMessageProvider.get_message(:HIDE_FILTER_TOOLTIP)
584
+
585
+ hide_icon = content_tag(:span,
586
+ image_tag(Defaults::SHOW_HIDE_FILTER_ICON,
587
+ :title => filter_tooltip,
588
+ :alt => filter_tooltip),
589
+ :id => grid_name + '_hide_icon',
590
+ :style => styles[0],
591
+ :class => 'clickable'
592
+ )
593
+
594
+
595
+ filter_tooltip = WiceGridNlMessageProvider.get_message(:SHOW_FILTER_TOOLTIP)
596
+
597
+ show_icon = content_tag(:span,
598
+ image_tag(Defaults::SHOW_HIDE_FILTER_ICON,
599
+ :title => filter_tooltip,
600
+ :alt => filter_tooltip),
601
+ :id => grid_name + '_show_icon',
602
+ :style => styles[1],
603
+ :class => 'clickable'
604
+ )
605
+
606
+ hide_icon + show_icon
607
+ end
608
+ end
609
+
610
+ def reset_submit_buttons(options, grid, rendering) #:nodoc:
611
+ (if options[:hide_submit_button]
612
+ ''
613
+ else
614
+ rendering.submit_button_present = true
615
+ filter_tooltip = WiceGridNlMessageProvider.get_message(:FILTER_TOOLTIP)
616
+ image_tag(Defaults::FILTER_ICON, :title => filter_tooltip, :alt => filter_tooltip, :class => 'submit clickable')
617
+ end + ' ' +
618
+ if options[:hide_reset_button]
619
+ ''
620
+ else
621
+ rendering.reset_button_present = true
622
+ filter_tooltip = WiceGridNlMessageProvider.get_message(:RESET_FILTER_TOOLTIP)
623
+ image_tag(Defaults::RESET_ICON, :title => filter_tooltip, :alt => filter_tooltip, :class => 'reset clickable')
624
+ end).html_safe_if_necessary
625
+ end
626
+
627
+ # Renders a detached filter. The parameters are:
628
+ # * +grid+ the WiceGrid object
629
+ # * +filter_key+ an identifier of the filter specified in the column declaration by parameter +:detach_with_id+
630
+ def grid_filter(grid, filter_key)
631
+ unless grid.kind_of? WiceGrid
632
+ raise WiceGridArgumentError.new("submit_grid_javascript: the parameter must be a WiceGrid instance.")
633
+ end
634
+ if grid.output_buffer.nil?
635
+ raise WiceGridArgumentError.new("grid_filter: You have attempted to run 'grid_filter' before 'grid'. Read about detached filters in the documentation.")
636
+ end
637
+ if grid.output_buffer == true
638
+ raise WiceGridArgumentError.new("grid_filter: You have defined no detached filters, or you try use detached filters with" +
639
+ ":show_filters => :no (set :show_filters to :always in this case). Read about detached filters in the documentation.")
640
+ end
641
+
642
+ content_tag :span, grid.output_buffer.filter_for(filter_key), :class => "#{grid.name}_detached_filter"
643
+ end
644
+
645
+ # Returns javascript which applies current filters. The parameter is a WiceGrid instance. Use it with +button_to_function+ to create
646
+ # your Submit button.
647
+ def submit_grid_javascript(grid)
648
+ unless grid.kind_of? WiceGrid
649
+ raise WiceGridArgumentError.new("submit_grid_javascript: the parameter must be a WiceGrid instance.")
650
+ end
651
+ "#{grid.name}.process()"
652
+ end
653
+
654
+ # Returns javascript which resets the grid, clearing the state of filters.
655
+ # The parameter is a WiceGrid instance. Use it with +button_to_function+ to create
656
+ # your Reset button.
657
+ def reset_grid_javascript(grid)
658
+ unless grid.kind_of? WiceGrid
659
+ raise WiceGridArgumentError.new("reset_grid_javascript: the parameter must be a WiceGrid instance.")
660
+ end
661
+ "#{grid.name}.reset()"
662
+ end
663
+
664
+ # Returns javascript which triggers export to CSV.
665
+ # The parameter is a WiceGrid instance. Use it with +button_to_function+ to create
666
+ # your own Export To CSV button.
667
+ def export_to_csv_javascript(grid)
668
+ unless grid.kind_of? WiceGrid
669
+ raise WiceGridArgumentError.new("export_csv_javascript: the parameter must be a WiceGrid instance.")
670
+ end
671
+ "#{grid.name}.export_to_csv()"
672
+ end
673
+
674
+
675
+ def grid_csv(grid, rendering) #:nodoc:
676
+ field_separator = (grid.export_to_csv_enabled && grid.export_to_csv_enabled.is_a?(String)) ? grid.export_to_csv_enabled : ','
677
+ spreadsheet = ::Wice::Spreadsheet.new(grid.name, field_separator)
678
+
679
+ # columns
680
+ spreadsheet << rendering.column_labels(:in_csv)
681
+
682
+ # rendering rows
683
+ grid.each do |ar| # rows
684
+ row = []
685
+
686
+ rendering.each_column(:in_csv) do |column|
687
+ cell_block = column.cell_rendering_block
688
+
689
+ column_block_output = call_block_as_erb_or_ruby(rendering, cell_block, ar)
690
+
691
+ if column_block_output.kind_of?(Array)
692
+ column_block_output, additional_opts = column_block_output
693
+ end
694
+
695
+ row << column_block_output
696
+ end
697
+ spreadsheet << row
698
+ end
699
+ grid.csv_tempfile = spreadsheet.tempfile
700
+ return grid.csv_tempfile.path
701
+ end
702
+
703
+ def pagination_panel_content(grid, extra_request_parameters, allow_showing_all_records) #:nodoc:
704
+ extra_request_parameters = extra_request_parameters.clone
705
+ if grid.saved_query
706
+ extra_request_parameters["#{grid.name}[q]"] = grid.saved_query.id
707
+ end
708
+
709
+ html, js = pagination_info(grid, allow_showing_all_records)
710
+ '<div class="pagination_status">' + html + '</div>'
711
+
712
+ # [will_paginate(grid.resultset,
713
+ # :previous_label => WiceGridNlMessageProvider.get_message(:PREVIOUS_LABEL),
714
+ # :next_label => WiceGridNlMessageProvider.get_message(:NEXT_LABEL),
715
+ # :param_name => "#{grid.name}[page]",
716
+ # :params => extra_request_parameters).to_s +
717
+ # (' <div class="pagination_status">' + html + '</div>').html_safe_if_necessary, js]
718
+ end
719
+
720
+
721
+ def show_all_link(collection_total_entries, parameters, grid_name) #:nodoc:
722
+
723
+ message = WiceGridNlMessageProvider.get_message(:ALL_QUERIES_WARNING)
724
+ confirmation = collection_total_entries > Defaults::START_SHOWING_WARNING_FROM ? "if (confirm('#{message}'))" : ''
725
+
726
+ js = JsAdaptor.show_all_link_initialization(grid_name, confirmation, parameters.to_json)
727
+
728
+ tooltip = WiceGridNlMessageProvider.get_message(:SHOW_ALL_RECORDS_TOOLTIP)
729
+ html = %/<span class="show_all_link"><a href="#" title="#{tooltip}">/ +
730
+ WiceGridNlMessageProvider.get_message(:SHOW_ALL_RECORDS_LABEL) +
731
+ '</a></span>'
732
+
733
+ [html, js]
734
+ end
735
+
736
+ def back_to_pagination_link(parameters, grid_name) #:nodoc:
737
+ pagination_override_parameter_name = "#{grid_name}[pp]"
738
+ parameters = parameters.reject{|k, v| k == pagination_override_parameter_name}
739
+
740
+ js = JsAdaptor.back_to_pagination_link_initialization(grid_name, parameters.to_json)
741
+
742
+ tooltip = WiceGridNlMessageProvider.get_message(:SWITCH_BACK_TO_PAGINATED_MODE_TOOLTIP)
743
+ html = %/ <span class="show_all_link"><a href="#" title="#{tooltip}">/ +
744
+ WiceGridNlMessageProvider.get_message(:SWITCH_BACK_TO_PAGINATED_MODE_LABEL) +
745
+ '</a></span>'
746
+ [html, js]
747
+ end
748
+
749
+ def pagination_info(grid, allow_showing_all_records) #:nodoc:
750
+ found = grid.resultset.count
751
+ total = grid.klass.count
752
+ shown = [found, grid.status[:per_page].to_i].min
753
+ summary = ""
754
+ summary << "Shown: #{shown}"
755
+ summary << ", Found: #{found}" if grid.has_any_filter_criteria?
756
+ summary << ", Total: #{total}"
757
+ [summary, ""]
758
+ end
759
+
760
+ end
761
+ end