mongoid_wice_grid 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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