wice_grid 3.0.0.pre1

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 (64) hide show
  1. data/.gitignore +1 -0
  2. data/CHANGELOG +412 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +1179 -0
  5. data/Rakefile +42 -0
  6. data/SAVED_QUERIES_HOWTO.rdoc +123 -0
  7. data/VERSION +1 -0
  8. data/lib/generators/wice_grid/templates/calendarview.css +107 -0
  9. data/lib/generators/wice_grid/templates/calendarview.js +1168 -0
  10. data/lib/generators/wice_grid/templates/icons/arrow_down.gif +0 -0
  11. data/lib/generators/wice_grid/templates/icons/arrow_up.gif +0 -0
  12. data/lib/generators/wice_grid/templates/icons/calendar_view_month.png +0 -0
  13. data/lib/generators/wice_grid/templates/icons/delete.png +0 -0
  14. data/lib/generators/wice_grid/templates/icons/expand.png +0 -0
  15. data/lib/generators/wice_grid/templates/icons/page_white_excel.png +0 -0
  16. data/lib/generators/wice_grid/templates/icons/page_white_find.png +0 -0
  17. data/lib/generators/wice_grid/templates/icons/table.png +0 -0
  18. data/lib/generators/wice_grid/templates/icons/table_refresh.png +0 -0
  19. data/lib/generators/wice_grid/templates/icons/tick_all.png +0 -0
  20. data/lib/generators/wice_grid/templates/icons/untick_all.png +0 -0
  21. data/lib/generators/wice_grid/templates/wice_grid.css +173 -0
  22. data/lib/generators/wice_grid/templates/wice_grid.yml +279 -0
  23. data/lib/generators/wice_grid/templates/wice_grid_config.rb +154 -0
  24. data/lib/generators/wice_grid/templates/wice_grid_jquery.js +161 -0
  25. data/lib/generators/wice_grid/templates/wice_grid_prototype.js +153 -0
  26. data/lib/generators/wice_grid/wice_grid_assets_jquery_generator.rb +32 -0
  27. data/lib/generators/wice_grid/wice_grid_assets_prototype_generator.rb +34 -0
  28. data/lib/grid_output_buffer.rb +52 -0
  29. data/lib/grid_renderer.rb +535 -0
  30. data/lib/helpers/js_calendar_helpers.rb +183 -0
  31. data/lib/helpers/wice_grid_misc_view_helpers.rb +113 -0
  32. data/lib/helpers/wice_grid_serialized_queries_view_helpers.rb +91 -0
  33. data/lib/helpers/wice_grid_view_helpers.rb +781 -0
  34. data/lib/js_adaptors/jquery_adaptor.rb +145 -0
  35. data/lib/js_adaptors/js_adaptor.rb +12 -0
  36. data/lib/js_adaptors/prototype_adaptor.rb +168 -0
  37. data/lib/table_column_matrix.rb +51 -0
  38. data/lib/tasks/wice_grid_tasks.rake +28 -0
  39. data/lib/view_columns.rb +486 -0
  40. data/lib/views/create.rjs +13 -0
  41. data/lib/views/create_jq.rjs +31 -0
  42. data/lib/views/delete.rjs +12 -0
  43. data/lib/views/delete_jq.rjs +26 -0
  44. data/lib/wice_grid.rb +827 -0
  45. data/lib/wice_grid_controller.rb +165 -0
  46. data/lib/wice_grid_core_ext.rb +179 -0
  47. data/lib/wice_grid_misc.rb +98 -0
  48. data/lib/wice_grid_serialized_queries_controller.rb +86 -0
  49. data/lib/wice_grid_serialized_query.rb +15 -0
  50. data/lib/wice_grid_spreadsheet.rb +33 -0
  51. data/test/.gitignore +2 -0
  52. data/test/database.yml +21 -0
  53. data/test/schema.rb +33 -0
  54. data/test/test_helper.rb +89 -0
  55. data/test/views/projects_and_people_grid.html.erb +12 -0
  56. data/test/views/projects_and_people_grid_invalid.html.erb +12 -0
  57. data/test/views/simple_projects_grid.html.erb +9 -0
  58. data/test/wice_grid_core_ext_test.rb +183 -0
  59. data/test/wice_grid_functional_test.rb +68 -0
  60. data/test/wice_grid_misc_test.rb +41 -0
  61. data/test/wice_grid_test.rb +42 -0
  62. data/test/wice_grid_view_helper_test.rb +12 -0
  63. data/wice_grid.gemspec +111 -0
  64. metadata +153 -0
@@ -0,0 +1,183 @@
1
+ module Wice #:nodoc:
2
+ module JsCalendarHelpers #:nodoc:
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) #:nodoc:
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) #:nodoc:
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,91 @@
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
+ notification_messages_id = "#{grid_name}_notification_messages"
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="#{notification_messages_id}" onmouseover="#{Wice::JsAdaptor.fade_this(notification_messages_id)}"></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
+ ).html_safe
45
+ end
46
+ ).html_safe
47
+ end
48
+
49
+ def saved_queries_list(grid_name, saved_query = nil, extra_parameters = {}) #: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(
65
+ image_tag(Defaults::DELETE_QUERY_ICON),
66
+ delete_serialized_query_path(
67
+ :grid_name => grid_name,
68
+ :id => sq.id,
69
+ :current => currently_loaded_query_id,
70
+ :extra => extra_parameters
71
+ ),
72
+ :remote => true,
73
+ :confirm => deletion_confirmation,
74
+ :title => "#{deletion_link_title} #{sq.name}",
75
+ :with => 'with'
76
+ ) + ' &nbsp; ' +
77
+ link_to_function(h(sq.name),
78
+ %/ if (typeof(#{grid_name}) != "undefined") #{grid_name}.load_query(#{sq.id}) /,
79
+ link_opts) +
80
+ if sq.respond_to? :description
81
+ desc = sq.description
82
+ desc.blank? ? '' : " <i>#{desc}</i>"
83
+ else
84
+ ''
85
+ end +
86
+ '</li>'
87
+ end.join('') + '</ul>'
88
+ end
89
+
90
+ end
91
+ end
@@ -0,0 +1,781 @@
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(
299
+ column_name,
300
+ rendering.column_link(column, direction, params, options[:extra_request_parameters]),
301
+ :class => link_style)
302
+ content << content_tag(:th, col_link, Hash.make_hash(:class, css_class))
303
+ column.css_class = css_class
304
+ else
305
+ if reuse_last_column_for_filter_buttons && last
306
+ content << content_tag(:th,
307
+ hide_show_icon(filter_row_id, grid, filter_shown, no_filter_row, options[:show_filters], rendering),
308
+ :class => 'hide_show_icon'
309
+ )
310
+ else
311
+ content << content_tag(:th, column_name)
312
+ end
313
+ end
314
+ end
315
+
316
+ content << content_tag(:th,
317
+ hide_show_icon(filter_row_id, grid, filter_shown, no_filter_row, options[:show_filters], rendering),
318
+ :class => 'hide_show_icon'
319
+ ) unless no_rightmost_column
320
+
321
+ content << '</tr>'
322
+ # rendering first row end
323
+
324
+
325
+ unless no_filters_at_all # there are filters, we don't know where, in the table or detached
326
+ if no_filter_row # they are all detached
327
+ content.stubborn_output_mode = true
328
+ rendering.each_column(:in_html) do |column|
329
+ if column.filter_shown?
330
+ filter_html_code, filter_js_code = column.render_filter
331
+ filter_html_code = filter_html_code.html_safe_if_necessary
332
+ cached_javascript << filter_js_code
333
+ content.add_filter(column.detach_with_id, filter_html_code)
334
+ end
335
+ end
336
+
337
+ else # some filters are present in the table
338
+
339
+ filter_row_attrs = header_tr_html_attrs.clone
340
+ filter_row_attrs.add_or_append_class_value!('wice_grid_filter_row', true)
341
+ filter_row_attrs['id'] = filter_row_id
342
+
343
+ content << %!<tr #{tag_options(filter_row_attrs, true)} !
344
+ content << 'style="display:none"' unless filter_shown
345
+ content << '>'
346
+
347
+ rendering.each_column_aware_of_one_last_one(:in_html) do |column, last|
348
+ if column.filter_shown?
349
+
350
+ filter_html_code, filter_js_code = column.render_filter
351
+ filter_html_code = filter_html_code.html_safe_if_necessary
352
+ cached_javascript << filter_js_code
353
+ if column.detach_with_id
354
+ content.stubborn_output_mode = true
355
+ content << content_tag(:th, '', Hash.make_hash(:class, column.css_class))
356
+ content.add_filter(column.detach_with_id, filter_html_code)
357
+ else
358
+ content << content_tag(:th, filter_html_code, Hash.make_hash(:class, column.css_class))
359
+ end
360
+ else
361
+ if reuse_last_column_for_filter_buttons && last
362
+ content << content_tag(:th,
363
+ reset_submit_buttons(options, grid, rendering),
364
+ Hash.make_hash(:class, column.css_class).add_or_append_class_value!('filter_icons')
365
+ )
366
+ else
367
+ content << content_tag(:th, '', Hash.make_hash(:class, column.css_class))
368
+ end
369
+ end
370
+ end
371
+ unless no_rightmost_column
372
+ content << content_tag(:th, reset_submit_buttons(options, grid, rendering), :class => 'filter_icons' )
373
+ end
374
+ content << '</tr>'
375
+ end
376
+ end
377
+
378
+ rendering.each_column(:in_html) do |column|
379
+ unless column.css_class.blank?
380
+ column.td_html_attrs.add_or_append_class_value!(column.css_class)
381
+ end
382
+ end
383
+
384
+ content << '</thead><tfoot>'
385
+ content << rendering.pagination_panel(no_rightmost_column, options[:hide_csv_button]) do
386
+ if pagination_panel_content_html
387
+ pagination_panel_content_html
388
+ else
389
+ pagination_panel_content_html, pagination_panel_content_js =
390
+ pagination_panel_content(grid, options[:extra_request_parameters], options[:allow_showing_all_records])
391
+ pagination_panel_content_html
392
+ end
393
+ end
394
+
395
+ content << '</tfoot><tbody>'
396
+ cached_javascript << pagination_panel_content_js
397
+
398
+ # rendering rows
399
+ cell_value_of_the_ordered_column = nil
400
+ previous_cell_value_of_the_ordered_column = nil
401
+
402
+ grid.each do |ar| # rows
403
+
404
+ before_row_output = if rendering.before_row_handler
405
+ call_block_as_erb_or_ruby(rendering, rendering.before_row_handler, ar)
406
+ else
407
+ nil
408
+ end
409
+
410
+ after_row_output = if rendering.after_row_handler
411
+ call_block_as_erb_or_ruby(rendering, rendering.after_row_handler, ar)
412
+ else
413
+ nil
414
+ end
415
+
416
+ row_content = ''
417
+ rendering.each_column(:in_html) do |column|
418
+ cell_block = column.cell_rendering_block
419
+
420
+ opts = column.td_html_attrs.clone
421
+
422
+ column_block_output = if column.class == Wice::ActionViewColumn
423
+ cell_block.call(ar, params)
424
+ else
425
+ call_block_as_erb_or_ruby(rendering, cell_block, ar)
426
+ end
427
+
428
+ if column_block_output.kind_of?(Array)
429
+
430
+ unless column_block_output.size == 2
431
+ raise WiceGridArgumentError.new('When WiceGrid column block returns an array it is expected to contain 2 elements only - '+
432
+ 'the first is the contents of the table cell and the second is a hash containing HTML attributes for the <td> tag.')
433
+ end
434
+
435
+ column_block_output, additional_opts = column_block_output
436
+
437
+ unless additional_opts.is_a?(Hash)
438
+ raise WiceGridArgumentError.new('When WiceGrid column block returns an array its second element is expected to be a ' +
439
+ "hash containing HTML attributes for the <td> tag. The returned value is #{additional_opts.inspect}. Read documentation.")
440
+ end
441
+
442
+ additional_css_class = nil
443
+ if additional_opts.has_key?(:class)
444
+ additional_css_class = additional_opts[:class]
445
+ additional_opts.delete(:class)
446
+ elsif additional_opts.has_key?('class')
447
+ additional_css_class = additional_opts['class']
448
+ additional_opts.delete('class')
449
+ end
450
+ opts.merge!(additional_opts)
451
+ opts.add_or_append_class_value!(additional_css_class) unless additional_css_class.blank?
452
+ end
453
+
454
+ if sorting_dependant_row_cycling && column.attribute_name && grid.ordered_by?(column)
455
+ cell_value_of_the_ordered_column = column_block_output
456
+ end
457
+ row_content += content_tag(:td, column_block_output, opts)
458
+ end
459
+
460
+ row_attributes = rendering.get_row_attributes(ar)
461
+
462
+ if sorting_dependant_row_cycling
463
+ cycle_class = cycle('odd', 'even', :name => grid.name) if cell_value_of_the_ordered_column != previous_cell_value_of_the_ordered_column
464
+ previous_cell_value_of_the_ordered_column = cell_value_of_the_ordered_column
465
+ else
466
+ cycle_class = cycle('odd', 'even', :name => grid.name)
467
+ end
468
+
469
+ row_attributes.add_or_append_class_value!(cycle_class)
470
+
471
+ content << before_row_output if before_row_output
472
+ content << "<tr #{tag_options(row_attributes)}>#{row_content}"
473
+ content << content_tag(:td, '') unless no_rightmost_column
474
+ content << '</tr>'
475
+ content << after_row_output if after_row_output
476
+ end
477
+
478
+ content << '</tbody></table></div>'
479
+
480
+ base_link_for_filter, base_link_for_show_all_records = rendering.base_link_for_filter(controller, options[:extra_request_parameters])
481
+
482
+ link_for_export = rendering.link_for_export(controller, 'csv', options[:extra_request_parameters])
483
+
484
+ parameter_name_for_query_loading = {grid.name => {:q => ''}}.to_query
485
+ parameter_name_for_focus = {grid.name => {:foc => ''}}.to_query
486
+
487
+ prototype_and_js_version_check = if Rails.env == 'development'
488
+ %$ if (typeof(WiceGridProcessor) == "undefined"){\n$ +
489
+ %$ alert('wice_grid.js not loaded, WiceGrid cannot proceed! ' +\n$ +
490
+ %$ 'Please make sure that you include WiceGrid javascript in your page. ' +\n$ +
491
+ %$ 'Use <%= include_wice_grid_assets %> or <%= include_wice_grid_assets(:include_calendar => true) %> ' +\n$ +
492
+ %$ 'for WiceGrid javascripts and assets.')\n$ +
493
+ %$ } else if ((typeof(WiceGridProcessor._version) == "undefined") || ( WiceGridProcessor._version != "0.4.3")) {\n$ +
494
+ %$ alert("wice_grid.js in your /public is outdated, please run\\n ./script/generate wice_grid_assets_jquery\\n$ +
495
+ %$ or\\n ./script/generate wice_grid_assets_prototype\\nto update it.");\n$ +
496
+ %$ }\n$
497
+ else
498
+ ''
499
+ end
500
+
501
+ if rendering.show_hide_button_present
502
+ cached_javascript << JsAdaptor.show_hide_button_initialization(grid.name, filter_row_id)
503
+ end
504
+
505
+ if rendering.reset_button_present
506
+ cached_javascript << JsAdaptor.reset_button_initialization(grid.name, reset_grid_javascript(grid))
507
+ end
508
+
509
+ if rendering.submit_button_present
510
+ cached_javascript << JsAdaptor.submit_button_initialization(grid.name, submit_grid_javascript(grid))
511
+ end
512
+
513
+ if rendering.contains_a_text_input?
514
+ cached_javascript << JsAdaptor.enter_key_event_registration(grid.name)
515
+ end
516
+
517
+ if rendering.csv_export_icon_present
518
+ cached_javascript << JsAdaptor.csv_export_icon_initialization(grid.name)
519
+ end
520
+
521
+ if rendering.contains_auto_reloading_selects
522
+ cached_javascript << JsAdaptor.auto_reloading_selects_event_initialization(grid.name)
523
+ end
524
+
525
+ if rendering.contains_auto_reloading_inputs
526
+ cached_javascript << JsAdaptor.auto_reloading_inputs_event_initialization(grid.name)
527
+ end
528
+
529
+ if rendering.contains_auto_reloading_inputs_with_negation_checkboxes
530
+ cached_javascript << JsAdaptor.auto_reloading_inputs_with_negation_checkboxes_event_initialization(grid.name)
531
+ end
532
+
533
+ if rendering.contains_auto_reloading_calendars
534
+ cached_javascript << JsAdaptor.auto_reloading_calendar_event_initialization(grid.name)
535
+ end
536
+
537
+ if rendering.element_to_focus
538
+ cached_javascript << JsAdaptor.focus_element(rendering.element_to_focus)
539
+ end
540
+
541
+ content << javascript_tag(
542
+ JsAdaptor.dom_loaded +
543
+ %/ #{prototype_and_js_version_check}\n/ +
544
+ %/ window['#{grid.name}'] = new WiceGridProcessor('#{grid.name}', '#{base_link_for_filter}',\n/ +
545
+ %/ '#{base_link_for_show_all_records}', '#{link_for_export}', '#{parameter_name_for_query_loading}',\n/ +
546
+ %/ '#{parameter_name_for_focus}', '#{Rails.env}');\n/ +
547
+ if no_filters_at_all
548
+ ''
549
+ else
550
+ rendering.select_for(:in_html) do |vc|
551
+ vc.attribute_name and not vc.no_filter
552
+ end.collect{|column| column.yield_javascript}.join("\n")
553
+ end +
554
+ "\n" + cached_javascript.compact.join('') +
555
+ '})'
556
+ )
557
+
558
+ if content.stubborn_output_mode
559
+ grid.output_buffer = content
560
+ else
561
+ # this will serve as a flag that the grid helper has already processed the grid but in a normal mode,
562
+ # not in the mode with detached filters.
563
+ grid.output_buffer = true
564
+ end
565
+ return content
566
+ end
567
+
568
+ def hide_show_icon(filter_row_id, grid, filter_shown, no_filter_row, show_filters, rendering) #:nodoc:
569
+ grid_name = grid.name
570
+ no_filter_opening_closing_icon = (show_filters == :always) || no_filter_row
571
+
572
+ styles = ["display: block;", "display: none;"]
573
+ styles.reverse! unless filter_shown
574
+
575
+
576
+ if no_filter_opening_closing_icon
577
+ hide_icon = show_icon = ''
578
+ else
579
+
580
+
581
+ rendering.show_hide_button_present = true
582
+ filter_tooltip = WiceGridNlMessageProvider.get_message(:HIDE_FILTER_TOOLTIP)
583
+
584
+ hide_icon = content_tag(:span,
585
+ image_tag(Defaults::SHOW_HIDE_FILTER_ICON,
586
+ :title => filter_tooltip,
587
+ :alt => filter_tooltip),
588
+ :id => grid_name + '_hide_icon',
589
+ :style => styles[0],
590
+ :class => 'clickable'
591
+ )
592
+
593
+
594
+ filter_tooltip = WiceGridNlMessageProvider.get_message(:SHOW_FILTER_TOOLTIP)
595
+
596
+ show_icon = content_tag(:span,
597
+ image_tag(Defaults::SHOW_HIDE_FILTER_ICON,
598
+ :title => filter_tooltip,
599
+ :alt => filter_tooltip),
600
+ :id => grid_name + '_show_icon',
601
+ :style => styles[1],
602
+ :class => 'clickable'
603
+ )
604
+
605
+ hide_icon + show_icon
606
+ end
607
+ end
608
+
609
+ def reset_submit_buttons(options, grid, rendering) #:nodoc:
610
+ (if options[:hide_submit_button]
611
+ ''
612
+ else
613
+ rendering.submit_button_present = true
614
+ filter_tooltip = WiceGridNlMessageProvider.get_message(:FILTER_TOOLTIP)
615
+ image_tag(Defaults::FILTER_ICON, :title => filter_tooltip, :alt => filter_tooltip, :class => 'submit clickable')
616
+ end + ' ' +
617
+ if options[:hide_reset_button]
618
+ ''
619
+ else
620
+ rendering.reset_button_present = true
621
+ filter_tooltip = WiceGridNlMessageProvider.get_message(:RESET_FILTER_TOOLTIP)
622
+ image_tag(Defaults::RESET_ICON, :title => filter_tooltip, :alt => filter_tooltip, :class => 'reset clickable')
623
+ end).html_safe_if_necessary
624
+ end
625
+
626
+ # Renders a detached filter. The parameters are:
627
+ # * +grid+ the WiceGrid object
628
+ # * +filter_key+ an identifier of the filter specified in the column declaration by parameter +:detach_with_id+
629
+ def grid_filter(grid, filter_key)
630
+ unless grid.kind_of? WiceGrid
631
+ raise WiceGridArgumentError.new("submit_grid_javascript: the parameter must be a WiceGrid instance.")
632
+ end
633
+ if grid.output_buffer.nil?
634
+ raise WiceGridArgumentError.new("grid_filter: You have attempted to run 'grid_filter' before 'grid'. Read about detached filters in the documentation.")
635
+ end
636
+ if grid.output_buffer == true
637
+ raise WiceGridArgumentError.new("grid_filter: You have defined no detached filters, or you try use detached filters with" +
638
+ ":show_filters => :no (set :show_filters to :always in this case). Read about detached filters in the documentation.")
639
+ end
640
+
641
+ content_tag :span, grid.output_buffer.filter_for(filter_key), :class => "#{grid.name}_detached_filter"
642
+ end
643
+
644
+ # Returns javascript which applies current filters. The parameter is a WiceGrid instance. Use it with +button_to_function+ to create
645
+ # your Submit button.
646
+ def submit_grid_javascript(grid)
647
+ unless grid.kind_of? WiceGrid
648
+ raise WiceGridArgumentError.new("submit_grid_javascript: the parameter must be a WiceGrid instance.")
649
+ end
650
+ "#{grid.name}.process()"
651
+ end
652
+
653
+ # Returns javascript which resets the grid, clearing the state of filters.
654
+ # The parameter is a WiceGrid instance. Use it with +button_to_function+ to create
655
+ # your Reset button.
656
+ def reset_grid_javascript(grid)
657
+ unless grid.kind_of? WiceGrid
658
+ raise WiceGridArgumentError.new("reset_grid_javascript: the parameter must be a WiceGrid instance.")
659
+ end
660
+ "#{grid.name}.reset()"
661
+ end
662
+
663
+ # Returns javascript which triggers export to CSV.
664
+ # The parameter is a WiceGrid instance. Use it with +button_to_function+ to create
665
+ # your own Export To CSV button.
666
+ def export_to_csv_javascript(grid)
667
+ unless grid.kind_of? WiceGrid
668
+ raise WiceGridArgumentError.new("export_csv_javascript: the parameter must be a WiceGrid instance.")
669
+ end
670
+ "#{grid.name}.export_to_csv()"
671
+ end
672
+
673
+
674
+ def grid_csv(grid, rendering) #:nodoc:
675
+
676
+
677
+ field_separator = (grid.export_to_csv_enabled && grid.export_to_csv_enabled.is_a?(String)) ? grid.export_to_csv_enabled : ','
678
+ spreadsheet = ::Wice::Spreadsheet.new(grid.name, field_separator)
679
+
680
+ # columns
681
+ spreadsheet << rendering.column_labels(:in_csv)
682
+
683
+ # rendering rows
684
+ grid.each do |ar| # rows
685
+ row = []
686
+
687
+ rendering.each_column(:in_csv) do |column|
688
+ cell_block = column.cell_rendering_block
689
+
690
+ column_block_output = call_block_as_erb_or_ruby(rendering, cell_block, ar)
691
+
692
+ if column_block_output.kind_of?(Array)
693
+ column_block_output, additional_opts = column_block_output
694
+ end
695
+
696
+ row << column_block_output
697
+ end
698
+ spreadsheet << row
699
+ end
700
+ grid.csv_tempfile = spreadsheet.tempfile
701
+ return grid.csv_tempfile.path
702
+ end
703
+
704
+ def pagination_panel_content(grid, extra_request_parameters, allow_showing_all_records) #:nodoc:
705
+ extra_request_parameters = extra_request_parameters.clone
706
+ if grid.saved_query
707
+ extra_request_parameters["#{grid.name}[q]"] = grid.saved_query.id
708
+ end
709
+
710
+ html, js = pagination_info(grid, allow_showing_all_records)
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
+ collection = grid.resultset
751
+
752
+ collection_total_entries = collection.total_entries
753
+ collection_total_entries_str = collection_total_entries.to_s
754
+ parameters = grid.get_state_as_parameter_value_pairs
755
+
756
+ js = ''
757
+ html = if (collection.total_pages < 2 && collection.length == 0)
758
+ '0'
759
+ else
760
+ parameters << ["#{grid.name}[pp]", collection_total_entries_str]
761
+
762
+ "#{collection.offset + 1}-#{collection.offset + collection.length} / #{collection_total_entries_str} " +
763
+ if (! allow_showing_all_records) || collection_total_entries <= collection.length
764
+ ''
765
+ else
766
+ res, js = show_all_link(collection_total_entries, parameters, grid.name)
767
+ res
768
+ end
769
+ end +
770
+ if grid.all_record_mode?
771
+ res, js = back_to_pagination_link(parameters, grid.name)
772
+ res
773
+ else
774
+ ''
775
+ end
776
+
777
+ [html, js]
778
+ end
779
+
780
+ end
781
+ end