module ActionView
module Helpers
def jqgrid_javascripts(locale)
js = capture { javascript_include_tag "i18n/jqgrid/locale-#{locale}.min" }
js << capture {javascript_tag "jQuery.jgrid.no_legacy_api = true;" }
js << capture { javascript_include_tag 'jquery.jqGrid.min' }
end
def jqgrid_from_xml(name, opts={})
@@grid_name = name.to_s
grid_data = YAML::load_file("#{RAILS_ROOT}/config/jquery/jqGrid/#{name}.yml")
before = grid_data[:before]
params = grid_data[:params]
def param_body(value)
value.scan(/^\((.+?)\)(.+)/).flatten
end
jquery_grid_code = <<-CODE
CODE
::ERB.new(jquery_grid_code, nil, '>').result(binding).gsub("_n_", "\n").
gsub(/[ \t]{2,}/,' ').
gsub(/,\s+\}\);/, "\n });").
gsub(/\n\s*\n/m, "\n").
gsub("_ss_", " ").
gsub("", @@grid_name)
end
def jqgrid(title, id, action, columns = {},
options = {}, edit_options = "", add_options = "", del_options = "", search_options = "",
custom1_button = nil, custom2_button = nil, custom3_button = nil, custom4_button = nil, custom5_button = nil )
# Default options
options =
{
:rows_per_page => '10',
:sort_column => '',
:sort_order => '',
:height => '150',
:gridview => 'false',
:error_handler => 'null',
:inline_edit_handler => 'null',
:add => 'false',
:delete => 'false',
:search => 'true',
:edit => 'false',
:inline_edit => 'false',
:autowidth => 'false',
:hidegrid => 'false',
:rownumbers => 'false'
}.merge(options)
# Stringify options values
options.inject({}) do |options, (key, value)|
options[key] = (key != :subgrid) ? value.to_s : value
options
end
options[:error_handler_return_value] = (options[:error_handler] == 'null') ? 'true;' : options[:error_handler]
edit_button = (options[:edit] == 'true' && options[:inline_edit] == 'false').to_s
# Generate columns data
col_names, col_model = gen_columns(columns)
# Enable multi-selection (checkboxes)
multiselect = "multiselect: false,"
if options[:multi_selection]
multiselect = "multiselect: true,"
multihandler = %Q/
jQuery("##{id}_select_button").click( function() {
var s; s = jQuery("##{id}").jqGrid('getGridParam', 'selarrrow');
#{options[:selection_handler]}(s);
return false;
});/
end
# Enable master-details
masterdetails = ""
if options[:master_details]
masterdetails = %Q/
onSelectRow: function(ids) {
if(ids == null) {
ids=0;
if(jQuery("##{id}_details").jqGrid('getGridParam', 'records') >0 )
{
jQuery("##{id}_details").jqGrid('setGridParam', {url:"#{options[:details_url]}?q=1&id="+ids,page:1})
jQuery("##{id}_details").jqGrid('setCaption', "#{options[:details_caption]}: "+ids)
jQuery("##{id}_details").trigger('reloadGrid');
}
}
else
{
jQuery("##{id}_details").jqGrid('setGridParam', {url:"#{options[:details_url]}?q=1&id="+ids,page:1})
jQuery("##{id}_details").jqGrid('setCaption', "#{options[:details_caption]} : "+ids)
jQuery("##{id}_details").trigger('reloadGrid');
}
},/
end
# Enable selection link, button
# The javascript function created by the user (options[:selection_handler]) will be called with the selected row id as a parameter
selection_link = ""
if options[:direct_selection].blank? && options[:selection_handler].present? && options[:multi_selection].blank?
selection_link = %Q/
jQuery("##{id}_select_button").click( function(){
var id = jQuery("##{id}").jqGrid('getGridParam', 'selrow');
if (id) {
#{options[:selection_handler]}(id);
} else {
alert("Please select a row");
}
return false;
});/
end
# Enable direct selection (when a row in the table is clicked)
# The javascript function created by the user (options[:selection_handler]) will be called with the selected row id as a parameter
direct_link = ""
if options[:direct_selection] && options[:selection_handler].present? && options[:multi_selection].blank?
direct_link = %Q/
onSelectRow: function(id){
if(id){
#{options[:selection_handler]}(id);
}
},/
end
# Enable grid_loaded callback
# When data are loaded into the grid, call the Javascript function options[:grid_loaded] (defined by the user)
grid_loaded = ""
if options[:grid_loaded].present?
grid_loaded = %Q/
loadComplete: function(){
#{options[:grid_loaded]}();
},
/
end
# Enable inline editing
# When a row is selected, all fields are transformed to input types
editable = ""
if options[:edit] && options[:inline_edit] == 'true'
editable = %Q/
onSelectRow: function(id){
if(id && id!==lastsel){
jQuery('##{id}').jqGrid('restoreRow', lastsel);
jQuery('##{id}').jqGrid('editRow', id, true, #{options[:inline_edit_handler]}, #{options[:error_handler]});
lastsel=id;
}
},/
end
# Enable subgrids
subgrid = ""
subgrid_enabled = "subGrid:false,"
if options[:subgrid].present?
subgrid_enabled = "subGrid:true,"
options[:subgrid] =
{
:rows_per_page => '10',
:sort_column => 'id',
:sort_order => 'asc',
:add => 'false',
:edit => 'false',
:delete => 'false',
:search => 'false'
}.merge(options[:subgrid])
# Stringify options values
options[:subgrid].inject({}) do |suboptions, (key, value)|
suboptions[key] = value.to_s
suboptions
end
subgrid_inline_edit = ""
if options[:subgrid][:inline_edit] == true
options[:subgrid][:edit] = 'false'
subgrid_inline_edit = %Q/
onSelectRow: function(id){
if(id && id!==lastsel){
jQuery('#'+subgrid_table_id).jqGrid('restoreRow', lastsel);
jQuery('#'+subgrid_table_id).jqGrid('editRow', id,true);
lastsel=id;
}
},
/
end
if options[:subgrid][:direct_selection] && options[:subgrid][:selection_handler].present?
subgrid_direct_link = %Q/
onSelectRow: function(id){
if(id){
#{options[:subgrid][:selection_handler]}(id);
}
},
/
end
sub_col_names, sub_col_model = gen_columns(options[:subgrid][:columns])
subgrid = %Q(
subGridRowExpanded: function(subgrid_id, row_id) {
var subgrid_table_id, pager_id;
subgrid_table_id = subgrid_id+"_t";
pager_id = "p_"+subgrid_table_id;
$("#"+subgrid_id).html("");
jQuery("#"+subgrid_table_id).jqGrid({
url:"#{options[:subgrid][:url]}?q=2&id="+row_id,
editurl:'#{options[:subgrid][:edit_url]}?parent_id='+row_id,
datatype: "json",
colNames: #{sub_col_names},
colModel: #{sub_col_model},
rowNum:#{options[:subgrid][:rows_per_page]},
pager: pager_id,
imgpath: '/images/jqgrid',
sortname: '#{options[:subgrid][:sort_column]}',
sortorder: '#{options[:subgrid][:sort_order]}',
viewrecords: true,
toolbar : [true,"top"],
#{subgrid_inline_edit}
#{subgrid_direct_link}
height: '100%'
});
jQuery("#"+subgrid_table_id).jqGrid('navGrid', "#"+pager_id,{edit:#{options[:subgrid][:edit]},add:#{options[:subgrid][:add]},del:#{options[:subgrid][:delete]},search:false})
jQuery("#"+subgrid_table_id).jqGrid('navButtonAdd', "#"+pager_id,{caption:"Search",title:"Toggle Search",buttonimg:'/images/jqgrid/search.png',
onClickButton:function(){
if(jQuery("#t_"+subgrid_table_id).css("display")=="none") {
jQuery("#t_"+subgrid_table_id).css("display","");
} else {
jQuery("#t_"+subgrid_table_id).css("display","none");
}
}
});
jQuery("#t_"+subgrid_table_id).height(25).hide().jqGrid('filterGrid', ""+subgrid_table_id,{gridModel:true,gridToolbar:true});
},
subGridRowColapsed: function(subgrid_id, row_id) {
},
)
end
# Generate required Javascript & html to create the jqgrid
%Q(
)
end
private
def gen_columns(columns)
# Generate columns data
col_names = "[" # Labels
col_model = "[" # Options
columns.each do |c|
col_names << "'#{c[:label]}',"
col_model << "{name:'#{c[:field]}', index:'#{c[:field]}'#{get_attributes(c)}},"
end
col_names.chop! << "]"
col_model.chop! << "]"
[col_names, col_model]
end
# Generate a list of attributes for related column (align:'right', sortable:true, resizable:false, ...)
def get_attributes(column)
options = ","
column.except(:field, :label).each do |couple|
if couple[0] == :editoptions
options << "editoptions:#{get_sub_options(couple[1])},"
elsif couple[0] == :formoptions
options << "formoptions:#{get_sub_options(couple[1])},"
elsif couple[0] == :searchoptions
options << "searchoptions:#{get_sub_options(couple[1])},"
elsif couple[0] == :editrules
options << "editrules:#{get_sub_options(couple[1])},"
else
if couple[1].class == String
options << "#{couple[0]}:'#{couple[1]}',"
else
options << "#{couple[0]}:#{couple[1]},"
end
end
end
options.chop!
end
# Generate options for editable fields (value, data, width, maxvalue, cols, rows, ...)
def get_sub_options(editoptions)
options = "{"
editoptions.each do |couple|
if couple[0] == :value # :value => [[1, "Rails"], [2, "Ruby"], [3, "jQuery"]]
options << %Q/value:"/
couple[1].each do |v|
options << "#{v[0]}:#{v[1]};"
end
options.chop! << %Q/",/
elsif couple[0] == :data # :data => [Category.all, :id, :title])
options << %Q/value:"/
couple[1].first.each do |obj|
options << "%s:%s;" % [obj.send(couple[1].second), obj.send(couple[1].third)]
end
options.chop! << %Q/",/
else # :size => 30, :rows => 5, :maxlength => 20, ...
if couple[1].instance_of?(Fixnum) || couple[1] == 'true' || couple[1] == 'false' || couple[1] == true || couple[1] == false
options << %Q/#{couple[0]}:#{couple[1]},/
else
options << %Q/#{couple[0]}:"#{couple[1]}",/
end
end
end
options.chop! << "}"
end
end
end
module JqgridJson
include ActionView::Helpers::JavaScriptHelper
def to_jqgrid_json(attributes, current_page, per_page, total)
json = %Q({"page":"#{current_page}","total":#{total/per_page.to_i+1},"records":"#{total}")
if total > 0
json << %Q(,"rows":[)
each do |elem|
elem.id ||= index(elem)
json << %Q({"id":"#{elem.id}","cell":[)
couples = elem.attributes.symbolize_keys
attributes.each do |atr|
value = get_atr_value(elem, atr, couples)
value = escape_javascript(value) if value and value.is_a? String
json << %Q("#{value}",)
end
json.chop! << "]},"
end
json.chop! << "]}"
else
json << "}"
end
end
private
def get_atr_value(elem, atr, couples)
if atr.to_s.include?('.')
value = get_nested_atr_value(elem, atr.to_s.split('.').reverse)
else
value = couples[atr]
value = elem.send(atr.to_sym) if value.blank? && elem.respond_to?(atr) # Required for virtual attributes
end
value
end
def get_nested_atr_value(elem, hierarchy)
return nil if hierarchy.size == 0
atr = hierarchy.pop
raise ArgumentError, "#{atr} doesn't exist on #{elem.inspect}" unless elem.respond_to?(atr)
nested_elem = elem.send(atr)
return "" if nested_elem.nil?
value = get_nested_atr_value(nested_elem, hierarchy)
value.nil? ? nested_elem : value
end
end
class Array
include JqgridJson
end