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: '
#{contents}
',
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 << '
'
if attachment = variable.send(method)
# Create first the remove link
remove_link = link_to_remote(tl(:remove), :url => "/backend/attachments/#{attachment.id}",
:method => :delete,
:success => "$('#{method}_#{attachment.id}').remove();")
if options[:image]
fstyle = "float:left;margin:5px;margin-left:0px;"
fclass = "box-image"
ftag = '
'
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 << '
'
for attachment in variable.send(method).all(:order => :position)
# Create first the remove link
remove_link = link_to_remote(tl(:remove), :url => "/backend/attachments/#{attachment.id}",
:method => :delete,
:success => "$('#{method}_#{attachment.id}').remove();")
if options[:image]
fstyle = "float:left;margin:5px;margin-left:0px;"
fstyle += "cursor:move;" if options[:order]
fclass = "box-image"
ftag = '
'
html << ' ' + link_to_function(tl(:add)) { |page| page.insert_html(:before, "add-#{method}", rowa) }
html << '
'
html << '
'
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:
# #
# #
# 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)}
#{"