jqgrid_rails 1.2.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.
@@ -0,0 +1,286 @@
1
+ module JqGridRails
2
+ module Controller
3
+
4
+ # These are the valid search operators jqgrid uses
5
+ # and the database translations for them. We use closures
6
+ # for the value so we can modify the string if we see fit
7
+ SEARCH_OPERS = {
8
+ 'eq' => ['= ?', lambda{|v|v}],
9
+ 'ne' => ['!= ?', lambda{|v|v}],
10
+ 'lt' => ['< ?', lambda{|v|v}],
11
+ 'le' => ['<= ?', lambda{|v|v}],
12
+ 'gt' => ['> ?', lambda{|v|v}],
13
+ 'ge' => ['>= ?', lambda{|v|v}],
14
+ 'bw' => ['ilike ?', lambda{|v| "#{v}%"}],
15
+ 'bn' => ['not ilike ?', lambda{|v| "#{v}%"}],
16
+ 'in' => ['in ?', lambda{|v| v.split(',').map(&:strip)}],
17
+ 'ni' => ['not in ?', lambda{|v| v.split(',').map(&:strip)}],
18
+ 'ew' => ['ilike ?', lambda{|v| "%#{v}"}],
19
+ 'en' => ['not ilike ?', lambda{|v| "%#{v}"}],
20
+ 'cn' => ['ilike ?', lambda{|v| "%#{v}%"}],
21
+ 'nc' => ['not ilike ?', lambda{|v| "%#{v}%"}]
22
+ }
23
+
24
+ # klass:: ActiveRecord::Base class or ActiveRecord::Relation
25
+ # params:: Request params
26
+ # fields:: Fields used within grid. Can be an array of attribute names or a Hash with keys of attributes and Hash values with options
27
+ # Array: [col1, col2, col3]
28
+ # Hash: {'col1' => {:fomatter => lambda{|v|v.to_s.upcase}, :order => 'other_table.col1'}}
29
+ # Provides generic JSON response for jqGrid requests (sorting/searching)
30
+ def grid_response(klass, params, fields)
31
+ raw_response(klass, params, fields).to_json
32
+ end
33
+
34
+ # klass:: ActiveRecord::Base class or ActiveRecord::Relation
35
+ # params:: Request params
36
+ # fields:: Fields used within grid. Can be an array of attribute names or a Hash with keys of attributes and Hash values with options
37
+ # Array: [col1, col2, col3]
38
+ # Hash: {'col1' => {:fomatter => lambda{|v|v.to_s.upcase}, :order => 'other_table.col1'}}
39
+ # Provides hash result for jqGrid requests (sorting/searching)
40
+ def raw_response(klass, params, fields)
41
+ allowed_consts = %w(ActiveRecord::Base ActiveRecord::Relation ActiveRecord::NamedScope::Scope)
42
+ unless(allowed_consts.detect{|const| klass.ancestors.detect{|c| c.to_s == const}})
43
+ raise TypeError.new "Unexpected type received. Allowed types are Class or ActiveRecord::Relation. Received: #{klass.class.name}"
44
+ end
45
+ clean_fields = scrub_fields(fields)
46
+ rel = apply_searching(klass, params, clean_fields)
47
+ unsorted = apply_filtering(rel, params, clean_fields)
48
+ rel = apply_sorting(unsorted, params, clean_fields)
49
+ create_result_hash(unsorted, rel, clean_fields)
50
+ end
51
+
52
+ # fields:: Fields used within grid
53
+ # Scrubs out fields to ensure in proper state
54
+ def scrub_fields(fields)
55
+ clean_fields = nil
56
+ if(fields.is_a?(Hash))
57
+ clean_fields = ActiveSupport::OrderedHash.new
58
+ fields.each_pair do |k,v|
59
+ clean_fields[k.to_s] = v.nil? ? {} : v
60
+ end
61
+ else
62
+ clean_fields = fields.map(&:to_s)
63
+ end
64
+ if(clean_fields.is_a?(Hash))
65
+ raise TypeError.new 'Hash values must be of Hash type or nil' if fields.values.detect{|v| !v.is_a?(Hash)}
66
+ end
67
+ clean_fields
68
+ end
69
+
70
+ # given:: Field for searching
71
+ # fields:: Array or Hash map of fields
72
+ # Returns proper field if mapped and ensures field is valid
73
+ def discover_field(given, fields)
74
+ given = JqGridRails.unescape(given)
75
+ col = nil
76
+ case fields
77
+ when Hash
78
+ col = fields.keys.detect{|key| key.to_s == given}
79
+ when Array
80
+ col = given if fields.map(&:to_s).include?(given)
81
+ else
82
+ raise TypeError.new "Expecting fields to be Array or Hash. Received: #{fields.class.name}"
83
+ end
84
+ raise NameError.new "Requested field was not found in provided fields list. Given: #{given}" unless col
85
+ col
86
+ end
87
+
88
+ # klass:: ActiveRecord::Base class or ActiveRecord::Relation
89
+ # col:: Sort column
90
+ # fields:: Aray or Hash map of fields
91
+ # Returns proper sorter based on inference or user defined
92
+ def discover_sorter(klass, col, fields)
93
+ col = JqGridRails.unescape(col)
94
+ if(fields.is_a?(Hash) && fields[col].try(:[], :order).present?)
95
+ fields[col][:order]
96
+ else
97
+ database_name_by_string(col, klass, fields)
98
+ end
99
+ end
100
+
101
+
102
+
103
+ # klass:: ActiveRecord::Base class or ActiveRecord::Relation
104
+ # params:: Request params
105
+ # fields:: Fields used within grid
106
+ # Applies any sorting to result set
107
+ def apply_sorting(klass, params, fields)
108
+ sort_col = params[[:sidx, :searchField].find{|sym| !params[sym].blank?}]
109
+ unless(sort_col)
110
+ begin
111
+ sort_col = discover_field(sort_col, fields)
112
+ rescue NameError
113
+ # continue on and let the sort_col be set to default below
114
+ end
115
+ end
116
+ unless(sort_col)
117
+ sort_col = (fields.is_a?(Hash) ? fields.keys : fields).first
118
+ end
119
+ sorter = discover_sorter(klass, sort_col, fields)
120
+ sort_ord = params[:sord] == 'asc' ? 'ASC' : 'DESC'
121
+ if(sorter.present?)
122
+ if(defined?(ActiveRecord::Relation) && klass.is_a?(ActiveRecord::Relation))
123
+ klass.order("#{sorter} #{sort_ord}")
124
+ else
125
+ klass.scoped(:order => "#{sorter} #{sort_ord}")
126
+ end
127
+ else
128
+ klass
129
+ end
130
+ end
131
+
132
+ # klass:: ActiveRecord::Base class or ActiveRecord::Relation
133
+ # params:: Request params
134
+ # fields:: Fields used within grid
135
+ # Applies any search restrictions to result set
136
+ # TODO: DRY out #apply_filtering and #apply_searching
137
+ def apply_searching(klass, params, fields)
138
+ unless(params[:searchField].blank?)
139
+ field = discover_field(params[:searchField], fields)
140
+ search_oper = params[:searchOper]
141
+ search_string = params[:searchString]
142
+ raise ArgumentError.new("Invalid search operator received: #{search_oper}") unless SEARCH_OPERS.keys.include?(search_oper)
143
+ if(defined?(ActiveRecord::Relation) && klass.is_a?(ActiveRecord::Relation))
144
+ if(fields.is_a?(Hash) && fields[field][:having])
145
+ rel = rel.having([
146
+ "#{fields[field][:having]} #{SEARCH_OPERS[oper].first}", SEARCH_OPERS[oper].last.call(data)
147
+ ])
148
+ end
149
+ if(!fields.is_a?(Hash) || fields[field][:having].blank? || fields[field][:where])
150
+ klass.where([
151
+ "#{database_name_by_string(field, klass, fields)} #{SEARCH_OPERS[search_oper].first}",
152
+ SEARCH_OPERS[search_oper].last.call(search_string)
153
+ ])
154
+ end
155
+ else
156
+ if(fields.is_a?(Hash) && fields[field][:having])
157
+ rel = rel.scoped(
158
+ :conditions => [
159
+ "#{fields[field][:having]} #{SEARCH_OPERS[oper].first}", SEARCH_OPERS[oper].last.call(data)
160
+ ]
161
+ )
162
+ end
163
+ if(!fields.is_a?(Hash) || fields[field][:having].blank? || fields[field][:where])
164
+ klass.scoped(
165
+ :conditions => [
166
+ "#{database_name_by_string(field, klass, fields)} #{SEARCH_OPERS[search_oper].first}",
167
+ SEARCH_OPERS[search_oper].last.call(search_string)
168
+ ]
169
+ )
170
+ end
171
+ end
172
+ else
173
+ klass
174
+ end
175
+ end
176
+
177
+ # klass:: ActiveRecord::Base class or ActiveRecord::Relation
178
+ # params:: Request params
179
+ # fields:: Fields used within grid
180
+ # Applies any filter restrictions to result set
181
+ #
182
+ # TODO: Currently this only supports AND'ing the filters. Need
183
+ # to add support for grabbing groupOp from parameters and using it for
184
+ # joining query parameters.
185
+ def apply_filtering(klass, params, fields)
186
+ rel = klass
187
+ havings = []
188
+ unless(params[:filters].blank?)
189
+ filters = JSON.load(params[:filters])
190
+ filters['rules'].each do |filter|
191
+ field = discover_field(filter['field'].gsub('___', '.'), fields)
192
+ oper = filter['op']
193
+ raise ArgumentError.new("Invalid search operator received: #{oper}") unless SEARCH_OPERS.keys.include?(oper)
194
+ data = filter['data']
195
+ if(fields.is_a?(Hash) && fields[field][:having])
196
+ havings << ["#{fields[field][:having]} #{SEARCH_OPERS[oper].first}", SEARCH_OPERS[oper].last.call(data)]
197
+ end
198
+ if(defined?(ActiveRecord::Relation) && rel.is_a?(ActiveRecord::Relation))
199
+ if(!fields.is_a?(Hash) || fields[field][:having].blank? || fields[field][:where])
200
+ rel = rel.where([
201
+ "#{database_name_by_string(field, klass, fields)} #{SEARCH_OPERS[oper].first}",
202
+ SEARCH_OPERS[oper].last.call(data)
203
+ ])
204
+ end
205
+ else
206
+ if(!fields.is_a?(Hash) || fields[field][:having].blank? || fields[field][:where])
207
+ rel = rel.scoped(
208
+ :conditions => [
209
+ "#{database_name_by_string(field, klass, fields)} #{SEARCH_OPERS[oper].first}",
210
+ SEARCH_OPERS[oper].last.call(data)
211
+ ]
212
+ )
213
+ end
214
+ end
215
+ end
216
+ end
217
+ unless(havings.blank?)
218
+ ary = ["(#{havings.map(&:first).join(') AND (')})", *havings.map(&:last)]
219
+ rel = defined?(ActiveRecord::Relation) && rel.is_a?(ActiveRecord::Relation) ? rel.having(ary) : rel.scoped(:having => ary)
220
+ end
221
+ rel
222
+ end
223
+
224
+ # klass:: ActiveRecord::Base class or ActiveRecord::Relation
225
+ # fields:: Fields used within grid
226
+ # Creates a result Hash in the structure the grid is expecting
227
+ # TODO: Calling #length is less than ideal on large datasets, but it is needed
228
+ # for cases where we are grouping items up for results. Perhaps set an optional
229
+ # flag to enable #length usage and use #count by default
230
+ def create_result_hash(unsorted, klass, fields)
231
+ if(defined?(ActiveRecord::Relation) && klass.is_a?(ActiveRecord::Relation))
232
+ dbres = klass.limit(params[:rows].to_i).offset(params[:rows].to_i * (params[:page].to_i - 1)).all
233
+ if(unsorted.respond_to?(:group_values) && unsorted.group_values.size > 0)
234
+ total = klass.connection.execute("SELECT COUNT(*) as count from (#{unsorted.to_sql}) AS countable_query").map.first['count'].to_i
235
+ end
236
+ else
237
+ dbres = klass.find(:all, :limit => params[:rows], :offset => (params[:rows].to_i * (params[:page].to_i - 1)))
238
+ if(unsorted.respond_to?(:proxy_options) && unsorted.proxy_options[:group].present?)
239
+ total = klass.connection.execute("SELECT COUNT(*) as count from (#{unsorted.send(:construct_finder_sql, {})}) AS countable_query").map.first['count'].to_i
240
+ end
241
+ end
242
+ total = unsorted.count unless total
243
+ rows = params[:rows].to_i
244
+ total_pages = rows > 0 ? (total.to_f / rows).ceil : 0
245
+ res = {'total' => total_pages, 'page' => params[:page], 'records' => total}
246
+ calls = fields.is_a?(Array) ? fields : fields.is_a?(Hash) ? fields.keys : nil
247
+ maps = fields.is_a?(Hash) ? fields : nil
248
+ res['rows'] = dbres.map do |row|
249
+ hsh = {}
250
+ calls.each do |method|
251
+ value = method.to_s.split('.').inject(row) do |result,meth|
252
+ if(result.try(:respond_to?, meth))
253
+ result.send(meth)
254
+ else
255
+ nil
256
+ end
257
+ end
258
+ if(fields.is_a?(Hash) && fields[method][:formatter].is_a?(Proc))
259
+ value = fields[method][:formatter].call(value, row)
260
+ end
261
+ hsh[method] = value
262
+ end
263
+ hsh
264
+ end
265
+ res
266
+ end
267
+
268
+ private
269
+
270
+ def database_name_by_string(string, klass, fields)
271
+ if(fields.is_a?(Hash) && fields[string].try(:[], :where))
272
+ fields[string][:where]
273
+ else
274
+ parts = string.split('.')
275
+ if(parts.size > 1)
276
+ parts = parts[-2,2]
277
+ "#{parts.first.pluralize}.#{parts.last}"
278
+ else
279
+ "#{klass.table_name}.#{parts.first}"
280
+ end
281
+ end
282
+ end
283
+ end
284
+ end
285
+
286
+ ActionController::Base.send :include, JqGridRails::Controller
@@ -0,0 +1,23 @@
1
+ module JqGridRails
2
+ module Generators
3
+
4
+ # grid:: JqGridRails::JqGrid instance
5
+ # Outputs javascript to build grid
6
+ def jq_grid(grid)
7
+ self << grid.build
8
+ end
9
+ alias_method :jqgrid, :jq_grid
10
+
11
+ # dom_id:: DOM ID of grid
12
+ # Instructs grid to reload itself
13
+ def reload_grid(dom_id)
14
+ dom_id = "##{dom_id}" unless dom_id.start_with?('#')
15
+ self << "jQuery('#{dom_id}').trigger('reloadGrid');"
16
+ end
17
+
18
+ end
19
+ end
20
+
21
+ if(defined?(ActionView::Helpers::PrototypeHelper::JavaScriptGenerator::GeneratorMethods))
22
+ ActionView::Helpers::PrototypeHelper::JavaScriptGenerator::GeneratorMethods.send :include, JqGridRails::Generators
23
+ end
@@ -0,0 +1,12 @@
1
+ require 'jqgrid_rails/jqgrid_rails_helpers'
2
+
3
+ module JqGridRails
4
+ class Helper
5
+ include ActionView::Helpers::JavaScriptHelper
6
+ include JqGridRails::Helpers
7
+ attr_accessor :table_id
8
+ def initialize(dom_id)
9
+ @table_id = dom_id
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,250 @@
1
+ #TODO: :with_row option is currently only applied to remote calls. Needs to be updated
2
+ # for non-ajax calls by adding dynamic form updates to include inputs for row data
3
+ require 'rails_javascript_helpers'
4
+ require 'action_view/helpers/form_tag_helper'
5
+
6
+ module JqGridRails
7
+ module Helpers
8
+ include RailsJavaScriptHelpers
9
+
10
+ # id:: String or RawJS object
11
+ # Ensures a DOM ID is returned from id. Does simple
12
+ # string replacement client side to force a # prefix.
13
+ # Client side conversion allows the id to be a RawJS
14
+ # instance for dynamic grid IDs
15
+ def convert_dom_id(id)
16
+ RawJS.new("#{format_type_to_js(id)}.replace(/^#*/, '#')")
17
+ end
18
+
19
+ # hash:: Argument hash for callback generation
20
+ # Generates a javascript callback from a Ruby hash. Important hash keys:
21
+ # :build_callback -> [false|:item|:selection] (false will stop callback from being created and simply return original hash)
22
+ # :url -> Symbol of route method name or string for actual url
23
+ # :args -> Arguments to be used when generating URL from :url value
24
+ # :method -> Request method (defaults to 'get')
25
+ # :ajax_args -> Arguments for jQuery.ajax options hash
26
+ # :remote -> [true|false] Request should be made via ajax
27
+ # :id_replacement -> Value used for dynamic ID replacement (generally not to be altered)
28
+ # :item_id -> Use for :item type callbacks to set URL generated ID if not the generic 'id' variable
29
+ def hash_to_callback(hash)
30
+ if(hash.is_a?(Hash) && hash[:build_callback] != false && hash[:url])
31
+ case hash[:build_callback]
32
+ when :item
33
+ build_single_callback(hash)
34
+ when :selection
35
+ build_selection_callback(hash)
36
+ else
37
+ build_default_callback(hash)
38
+ end
39
+ else
40
+ hash
41
+ end
42
+ end
43
+
44
+ # hash:: Argument hash
45
+ # Extracts and formats argument hash for callbacks
46
+ def extract_callback_variables(hash)
47
+ @url_gen ||= JqGridRails::UrlGenerator.new
48
+ args = hash.dup
49
+ args[:ajax_args] = hash.delete(:ajax) || {}
50
+ args[:method] = args[:ajax_args][:type] || args[:ajax_args].delete(:method) || hash.delete(:method) || 'get'
51
+ if(hash[:url].is_a?(Symbol))
52
+ url_args = hash[:args].is_a?(Array) ? hash[:args] : [hash[:args]]
53
+ args[:url] = @url_gen.send(hash[:url], *(url_args.sort_by{|x,y| if(x.is_a?(Hash) && y.is_a?(Hash)) then 0 elsif(x.is_a?(Hash)) then 1 else -1 end}))
54
+ else
55
+ args[:url] = hash[:url]
56
+ end
57
+ if(hash[:args_replacements].present?)
58
+ if(hash[:args_replacements].is_a?(Hash))
59
+ args[:args_replacements] = hash[:args_replacements].map{|fake_id, js_id| "replace(#{format_type_to_js(fake_id)}, #{format_type_to_js(js_id)})" }.join('.')
60
+ unless(args[:args_replacements].blank?)
61
+ args[:args_replacements] = ".#{args[:args_replacements]}"
62
+ end
63
+ else
64
+ args[:args_replacements] = hash[:args_replacements]
65
+ end
66
+ end
67
+ args[:ajax_args][:type] = args[:method] if hash[:remote]
68
+ args
69
+ end
70
+
71
+ # hash:: Argument hash
72
+ # Builds callback function for single selection
73
+ def build_single_callback(hash)
74
+ hash[:id_replacement] ||= '000'
75
+ hash[:args] = Array(hash[:args]) unless hash[:args].is_a?(Array)
76
+ hash[:args].push hash[:id_replacement]
77
+ args = extract_callback_variables(hash)
78
+ confirm = args.delete(:confirm)
79
+ item_id = args[:item_id].present? ? args[:item_id] : RawJS.new('id')
80
+ if(hash[:remote])
81
+ if(hash[:with_row])
82
+ args[:ajax_args] ||= {}
83
+ args[:ajax_args][:data] = {:row_data => RawJS.new("jQuery(#{convert_dom_id(@table_id)}).jqGrid('getRowData', id)")}
84
+ end
85
+ " function(id){
86
+ #{confirm_if_required(
87
+ confirm,
88
+ "jQuery.ajax(#{format_type_to_js(args[:url])}.replace(#{format_type_to_js(args[:id_replacement])}, #{format_type_to_js(item_id)})#{args[:args_replacements]}, #{format_type_to_js(args[:ajax_args])});"
89
+ )}
90
+ }
91
+ "
92
+ else
93
+ form_rand = rand(999)
94
+ " function(id){
95
+ #{csrf_token_discovery(args[:method])}
96
+ #{confirm_if_required(
97
+ confirm,
98
+ "jQuery('body').append('<form id=\"redirector_#{form_rand}\" action=\"#{args[:url]}\" method=\"#{args[:method]}\">'.replace(#{format_type_to_js(args[:id_replacement])}, #{format_type_to_js(item_id)})#{args[:args_replacements]} + csrf_token +'</form>');
99
+ jQuery('#redirector_#{form_rand}').submit();"
100
+ )}
101
+ }
102
+ "
103
+ end
104
+ end
105
+
106
+ # Returns callable function to get current selection in array form
107
+ def selection_array(error_when_empty=true, table_id=nil)
108
+ dom_id = convert_dom_id(table_id || @table_id)
109
+ " function(){
110
+ ary = jQuery(#{dom_id}).jqGrid('getGridParam', 'selarrrow');
111
+ if(!ary.length){ ary = []; }
112
+ ary.push(jQuery(#{dom_id}).jqGrid('getGridParam', 'selrow'));
113
+ ary = jQuery.grep(ary, function(value,key){ return value != null && value.length && jQuery.inArray(value, ary) === key; });
114
+ if(!ary.length && #{format_type_to_js(error_when_empty)}){
115
+ alert('Please select items from the table first.');
116
+ }
117
+ return ary;
118
+ }
119
+ "
120
+ end
121
+
122
+ # hash:: Argument has
123
+ # Builds callback function for full selection
124
+ # NOTE: In general you will want the URL to be auto generated within jqgrid_rails. The route
125
+ # should accept an ID which will be the first ID of the current selection. An extra parameter named
126
+ # 'ids' will be provided which will be an array of all selected values, included the ID given
127
+ # to the route
128
+ def build_selection_callback(hash, table_id=nil)
129
+ dom_id = table_id || @table_id
130
+ hash[:id_replacement] ||= '000'
131
+ hash[:args] = Array(hash[:args]) unless hash[:args].is_a?(Array)
132
+ hash[:args].push hash[:id_replacement]
133
+ args = extract_callback_variables(hash)
134
+ confirm = args.delete(:confirm)
135
+ item_id = args[:item_id].present? ? args[:item_id] : RawJS.new('id')
136
+ function = "function(){
137
+ rows_func = #{selection_array(true, table_id)}
138
+ ary = rows_func();
139
+ if(!ary.length){ return false; }
140
+ "
141
+ if(hash[:remote])
142
+ args[:ajax_args][:data] = {item_id.to_s.pluralize.to_sym => RawJS.new('ary')}
143
+ if(hash[:with_row])
144
+ args[:ajax_args][:data][:row_data] = RawJS.new("jQuery(#{convert_dom_id(dom_id)}).jqGrid('getRowData')")
145
+ end
146
+ function << confirm_if_required(confirm, "jQuery.ajax(#{format_type_to_js(args[:url])}.replace(#{format_type_to_js(args[:id_replacement])}, ary[0])#{args[:args_replacements]}, #{format_type_to_js(args[:ajax_args])}); }")
147
+ else
148
+ randomizer = rand(99999)
149
+ function << "parts = ary.map(
150
+ function(item){
151
+ return '<input type=\"hidden\" name=\"#{item_id.to_s.pluralize}[]\" value=\"'+item+'\"/>';
152
+ });
153
+ #{csrf_token_discovery(args[:method])}
154
+ var target_url = #{format_type_to_js(args[:url])}.replace(#{format_type_to_js(args[:id_replacement])}, ary[0])#{args[:args_replacements]};
155
+ jQuery('body').append('<form id=\"jqgrid_redirector_#{randomizer}\" action=\"'+ target_url +'\" method=\"#{args[:method]}\">' + parts + csrf_token + '</form>');
156
+ #{confirm_if_required(confirm, "jQuery(#{format_type_to_js(format_id("jqgrid_redirector_#{randomizer}"))}).submit();")}
157
+ }"
158
+ end
159
+ end
160
+
161
+ # hash:: Argument hash
162
+ # Builds a default callback based on argument hash. No interaction with
163
+ # grid is provided via this method
164
+ def build_default_callback(hash)
165
+ args = extract_callback_variables(hash)
166
+ confirm = args.delete(:confirm)
167
+ if(hash[:remote])
168
+ "function(){ #{confirm_if_required(confirm, "jQuery.ajax(#{format_type_to_js(args[:url])}#{args[:args_replacements]}, #{format_type_to_js(args[:ajax_args])});")} }"
169
+ else
170
+ randomizer = rand(99999)
171
+ output = " function(){
172
+ #{csrf_token_discovery(args[:method])}
173
+ jQuery('body').append('<form id=\"jqgrid_redirector_#{randomizer}\" action=\"#{args[:url]}#{args[:args_replacements]}\" method=\"#{args[:method]}\">' + csrf_token + '</form>');"
174
+ if(hash[:ajax_args] && hash[:ajax_args][:data])
175
+ output << "var args = #{format_type_to_js(hash[:ajax_args][:data])};
176
+ Object.keys(args).each(function(key){
177
+ jQuery('#{format_id("jqgrid_redirector_#{randomizer}")}').append(jQuery('<input/>')
178
+ .attr('type', 'hidden')
179
+ .attr('name', key)
180
+ .val(args[key])
181
+ );
182
+ });"
183
+ end
184
+ output << "#{confirm_if_required(confirm, "jQuery(#{format_type_to_js(format_id("jqgrid_redirector_#{randomizer}"))}).submit();")}
185
+ }"
186
+ end
187
+ end
188
+
189
+ # key:: ondbl_click_row/on_select_row
190
+ # Sets up click event functions based on hash values
191
+ def map_click(key, options)
192
+ if(options[key].is_a?(Hash))
193
+ options[key][:build_callback] = :item
194
+ options[key] = hash_to_callback(options[key])
195
+ end
196
+ end
197
+
198
+ # url_hash:: hash for url building
199
+ # Creates a toolbar button for the grid
200
+ # TODO: Put confirm in here
201
+ def build_toolbar_button(url_hash)
202
+ url_hash[:empty_selection] ||= url_hash[:single]
203
+ url_hash[:build_callback] ||= :selection unless url_hash[:empty_selection]
204
+ classes = ['grid_toolbar_item', 'button', 'ui-state-default', 'ui-corner-all']
205
+ s = <<-EOS
206
+ jQuery('<div class="#{(classes + Array(url_hash[:class])).compact.join(' ')}" />')
207
+ .text('#{escape_javascript(url_hash[:name])}')
208
+ .button()
209
+ .click(
210
+ #{hash_to_callback(url_hash)}
211
+ ).appendTo('#t_' + #{format_type_to_js(@table_id)});
212
+ EOS
213
+ end
214
+
215
+ # options_hash:: Hash of options
216
+ # Inserts callbacks in any applicable values
217
+ def scrub_options_hash(options_hash)
218
+ options_hash.each do |key,value|
219
+ options_hash[key] = hash_to_callback(value)
220
+ end
221
+ options_hash
222
+ end
223
+
224
+ # confirm:: Confirmation string
225
+ # contents:: JS contents for if block
226
+ # Wraps contents within if block using confirm() as conditional
227
+ def confirm_if_required(confirm, contents)
228
+ string = ''
229
+ if(confirm)
230
+ string << "if(confirm(#{format_type_to_js(confirm)})){"
231
+ string << contents
232
+ string << "}"
233
+ else
234
+ string << contents
235
+ end
236
+ string
237
+ end
238
+
239
+ def csrf_token_discovery(method)
240
+ output = "var csrf_token = '';"
241
+ if(method.to_s.downcase == 'get')
242
+ output
243
+ else
244
+ output << "if(jQuery('meta[name=\"csrf-param\"]').size() > 0){
245
+ csrf_token = '<input type=\"hidden\" name=\"'+jQuery('meta[name=\"csrf-param\"]').attr('content')+'\" value=\"'+jQuery('meta[name=\"csrf-token\"]').attr('content')+'\" />';
246
+ }"
247
+ end
248
+ end
249
+ end
250
+ end