jqgrid_rails 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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