module Lipsiadmin module View module Helpers module BackendHelper # This method work like builtin Rails error_message_for but use an Ext.Message.show({..}) def simple_error_messages_for(*params) options = params.extract_options!.symbolize_keys if object = options.delete(:object) objects = [object].flatten else objects = params.collect {|object_name| instance_variable_get("@#{object_name}") }.compact end count = objects.inject(0) {|sum, object| sum + object.errors.count } unless count.zero? html = {} [:id, :class].each do |key| if options.include?(key) value = options[key] html[key] = value unless value.blank? else html[key] = 'errorExplanation' end end options[:object_name] ||= params.first I18n.with_options :locale => options[:locale], :scope => [:activerecord, :errors, :template] do |locale| header_message = if options.include?(:header_message) escape_javascript(options[:header_message]) else object_name = options[:object_name].to_s.gsub('_', ' ') object_name = I18n.t(object_name, :default => object_name, :scope => [:activerecord, :models], :count => 1) escape_javascript(locale.t :header, :count => count, :model => object_name) end message = escape_javascript(options.include?(:message) ? options[:message] : locale.t(:body)) error_messages = objects.sum {|object| object.errors.full_messages.map {|msg| content_tag(:li, escape_javascript(msg)) } }.join contents = '' contents << content_tag(:p, message) unless message.blank? contents << content_tag(:ul, error_messages, :class => :list) content_tag(:script, "Ext.Msg.show({ title: '#{header_message}', msg: '', buttons: Ext.Msg.OK, minWidth: 400 });", :type => Mime::JS) end else '' end end # This method add tab for in your view. # # First argument is the name and title of the tab, an interesting thing wose that this helper # try to translate itself to your current locale ex: # # # Look for: I18n.t("backend.tabs.settings", :default => "Settings") # tab :settings do # ... # # The second argument specify if is necessary 10px of padding inside the tab, default is +true+ # # Third argument is an hash that accepts: # # :id:: The id of the tab # :style:: Custom style of the tab # def tab(name, padding=true, options={}, &block) options[:id] ||= name.to_s.downcase.gsub(/[^a-z0-9]+/, '_').gsub(/-+$/, '').gsub(/^-+$/, '') options[:style] ||= "padding:10px;#{options[:style]}" if padding options[:title] = I18n.t("backend.tabs.#{name.to_s.downcase}", :default => name.to_s.humanize) options[:tabbed] = true options[:class] = "x-hide-display" container = content_tag(:div, capture(&block), :class => :full) # Is necessary for IE6+ concat content_tag(:div, container, options) end # Set the title of the page. # # An interesting thing wose that this helper # try to translate itself to your current locale ex: # # # Look for: I18n.t("backend.titles.welcome_here", :default => "Welcome Here") # title :welcome_here # def title(title) title = I18n.t("backend.titles.#{title.gsub(/\./,"").to_s.downcase}", :default => title.to_s.humanize) content_tag(:script, "Backend.app.setTitle(#{title.to_json})", :type => Mime::JS) end # Get the title for grids of the specified model based on your # current locale. # # The locale file for this translation is located: config/locales/backend # # # Generate: List all Accounts # list_title_for(Account) # # # Generate: List all My Accounts # list_title_for("My Accounts") # def list_title_for(text) I18n.t("backend.general.list", :model => text.is_a?(String) ? text : text.send(:human_name)) end # Get the title for edit action of a form based on your current locale # # The locale file for this translation is located: config/locales/backend # # # Generate: Edit Account 18 # edit_title_for(Account, @account.id) # # # Generate: Edit My Account Foo Bar # edit_title_for("My Account", @account.full_name) # def edit_title_for(text, value) title I18n.t("backend.general.editForm", :model => text.is_a?(String) ? text : text.send(:human_name), :value => value) end # Get the title for new action of a form based on your current locale # # The locale file for this translation is located: config/locales/backend # # # Generate: New Account # new_title_for(Account) # # # Generate: New My Account # new_title_for("My Account") # def new_title_for(text) title I18n.t("backend.general.newForm", :model => text.is_a?(String) ? text : text.send(:human_name)) end # Try to translate the given word # # # Generate: I18n.t("backend.labels.add", :default => "Add") # tl("Add") # def translate_label(text) I18n.t("backend.labels.#{text.to_s.downcase.gsub(/\s/, "_")}", :default => text.to_s.humanize) end alias_method :tl, :translate_label # Try to translate the given pharse # # # Generate: I18n.t("backend.labels.lipsiadmin_is_beautifull", :default => "Lipsiadmin is beautifull") # tt("Lipsiadmin is beautifull") # def translate_text(text) I18n.t("backend.texts.#{text.to_s.downcase.gsub(/\s/, "_")}", :default => text.to_s.humanize) end alias_method :tt, :translate_text # Return the translated attribute based on your current locale # # # In config/locales/backend/models/en.yml # en: # activerecord: # attributes: # account: # name: "Account Name" # suranme: "Custom Title For Surname" # role: "Im a" # # # Generates: # # Account Name # # Custom Title For Surname # # Im a # # Attribute not translated # human_name_for :account, :name # human_name_for :account, :surname # human_name_for :account, :role # human_name_for :account, :attribute_not_translated # def human_name_for(instance, method) I18n.t("activerecord.attributes.#{instance}.#{method}", :default => method.to_s.humanize) end # Generate the menu from the Lispiadmin::AccessControl def backend_menu config = AccountAccess.maps_for(current_account).collect(&:project_modules).flatten.uniq.collect(&:config) config << { :text => I18n.t("backend.menus.help", :default => "Help"), :handler => "function() { Backend.app.openHelp() }".to_l } return config.to_json end # Returns html for upload one image or generic file. # # Options can be one of the following: # # :image:: Indicate if the attachments are ONLY images. # :only_upload:: Indicate that is not necessary manage the old attachments. # # Examples: # # class Category < ActiveRecord::Base # has_one_attachments :file, :dependent => :destroy # ... # # Then in our view we can simply add this: # # attachments_tag(:category, :file) # # Remember that al labels can be translated. See Locales for Backend. # def attachment_tag(object_name, method, options={}) variable = instance_variable_get("@#{object_name}") html = [] html << '' unless options[:only_upload] html << '' html << '
' end flbl = options[:image] ? :upload_image : :upload_file html << '
' + tl(flbl) + '
' html << '' rowa = ' ' rowa << ' ' rowa << ' ' rowa << ' ' html << rowa html << '
' + human_name_for(:attachment, :attached_file_name) + '' + file_field_tag("#{object_name}[#{method}_attributes][file]", :style => "width:250px") + '
' html.join("\n") end # Returns html for upload multiple images or generic files. # # Options can be one of the following: # # :image:: Indicate if the attachments are ONLY images. # :only_upload:: Indicate that is not necessary manage the old attachments. # :order:: Indicate if user can order files. # # Examples: # # class Category < ActiveRecord::Base # has_many_attachments :images, :dependent => :destroy # validates_attachment_content_type_for :images, /^image/ # ... # # Then in our view we can simply add this: # # attachments_tag(:category, :images, :image => true, :order => true) # # Remember that al labels can be translated. See Locales for Backend. # def attachments_tag(object_name, method, options={}) variable = instance_variable_get("@#{object_name}") html = [] html << '' unless options[:only_upload] html << '' html << '
' if options[:order] constraint = options[:image] ? "horizontal" : "vertical" html << '
 
' html << sortable_element("#{method}-order", :url => "/backend/attachments/order", :update => "#{method}-message", :constraint => constraint, :complete => visual_effect(:highlight, "#{method}-message", :duration => 0.5)) end end flbl = options[:image] ? :upload_images : :upload_files html << '
'+ tl(flbl) +'
' html << '' rowa = ' ' rowa << ' ' rowa << ' ' rowa << ' ' rowa << ' ' html << rowa html << ' ' html << ' ' html << ' ' html << ' ' html << '
' + human_name_for(:attachment, :attached_file_name) + '' + file_field_tag("#{object_name}[#{method}_attributes][][file]", :style => "width:250px") + '' + link_to_function(tl(:remove), "this.up('.attachment').remove()") + '
 ' html << ' ' + link_to_function(tl(:add)) { |page| page.insert_html(:before, "add-#{method}", rowa) } html << '
' html.join("\n") end # Build a new windows that can contain an existent grid # # The first argument name is used as the link text. # # The second argument is the url where js of grid are stored. # # The third argument is the name of the gird var usually gridPanel or editorGridPanel. # # The four argument are callbacks that may be specified: # # :before:: Called before request is initiated. # :update:: Called after user press +select+ button. # This call are performed in an handler where # you have access to two variables: # :win:: Backend.window # :selections:: Records selected in the grid # # # Generates: Select a Category # build_grid "Select a Category", "/backend/categories.js", "gridPanel", # :update => "$('post_category_ids').value = selections.collect(function(s) { return s.id }).join(',');" + # "$('category_names').innerHTML = selections.collect(function(s) { return s.data['categories.name'] }).join(', ');" # def build_grid(text, url, grid, options={}) options[:before] = options[:before] + ";" if options[:before] javascript = <<-JAVASCRIPT #{options[:before]} new Backend.window({ url: '#{url}', grid: '#{grid}', listeners: { selected: function(win, selections){ #{options[:update]} } } }).show() JAVASCRIPT link_to_function(text, javascript.gsub(/\n|\s+/, " ")) end alias_method :open_grid, :build_grid # Open a Standard window that can contain a standard existent grid # # Options can be one of the following: # # :grid:: The name of the grid var. Default "gridPanel" # :url:: The url where the grid is stored. Default is autogenerated. # :name:: The name of the link that open the window grid. Default a image. # # # Generates: # # New # # # open_standard_grid :warehouse, :supplier, :id, :name # def open_standard_grid(object_name, ext_object, value, display, options={}) current_value = instance_variable_get("@#{object_name}").send(ext_object).send(display) rescue "Nessuno" value_field = value.to_s.downcase == "id" ? "id" : "data['#{ext_object.to_s.pluralize}.#{value}']" options[:grid] ||= "gridPanel" options[:url] ||= "/backend/#{ext_object.to_s.pluralize}.js" options[:name] ||= image_tag("backend/new.gif", :style => "vertical-align:bottom") update_function = "$('#{object_name}_#{ext_object}_#{value}').value = selections.first().#{value_field}; " + "$('#{object_name}_#{ext_object}_#{display}').innerHTML = selections.first().data['#{ext_object.to_s.pluralize}.#{display}']" content_tag(:span, current_value, :id => "#{object_name}_#{ext_object}_#{display}" ) + ' ' + build_grid(options[:name], options[:url], options[:grid], :update => update_function) + hidden_field(object_name, "#{ext_object}_#{value}") end # Open a new windows that can contain a form that you can reuse # # The first argument name is used as the link text. # # The second argument is the url where html of form are stored. # # The third argument are callbacks that may be specified: # # :before:: Called before request is initiated. # :after:: Called after request is initiated. # :on_save:: Called after user press +save+ button. # This call are performed in an handler where # you have access to one variables: # :win:: Backend.window # # # Generates: Edit Post # open_form "Edit Post", "/backend/posts/'+$('comment_post_id').value+'/edit", :update => "someFn(win);" # def open_form(text, url, options={}) options[:before] = options[:before] + ";" if options[:before] javascript = <<-JAVASCRIPT #{options[:before]} new Backend.window({ url: '#{url}', form: true, listeners: { saved: function(win){ #{options[:on_save]} }, close: function(panel){ #{options[:after]} } } }).show(); JAVASCRIPT link_to_function(text, javascript.gsub(/\n/, " ")) end # This method call a remote_function and in the same time do a # # Backend.app.mask() # # and when the function is complete # # Backend.app.unmask() # def link_to_remote_with_wait(name, options={}, html_options={}) options[:complete] = "Backend.app.unmask();" options[:before] = "Backend.app.mask('#{I18n.t('backend.javascripts.messages.wait.message')}')"; link_to_function(name, remote_function(options), html_options || options.delete(:html)) end # This method generates a new ExtJs BoxComponent. # # Examples: # # -box "My Title", "My Subtitle", :submit => true, :collapsible => true, :style => "padding:none", :start => :close do # my content # # Defaults: # # * :submit => false # * :collapsible => false # * :start => :close # def box(title=nil, subtitle=nil, options={}, &block) options[:style] ||= "width:100%;" options[:start] ||= :open concat <<-HTML
 
#{"

"+title+"

" unless title.blank?} #{"
"+subtitle+"
" unless subtitle.blank?} #{"
" if !title.blank? || !subtitle.blank?} #{"
 
" if !title.blank? || !subtitle.blank?}
#{"
 
" if !title.blank? || !subtitle.blank?} #{capture(&block)} #{"
#{submit_tag(I18n.t("lipsiadmin.buttons.save"), :onclick=>"Backend.app.submitForm()")}
" if options[:submit]}
 
HTML end end end end end