module ActiveScaffold
module Helpers
# All extra helpers that should be included in the View.
# Also a dumping ground for uncategorized helpers.
module ViewHelpers
include ActiveScaffold::Helpers::IdHelpers
include ActiveScaffold::Helpers::AssociationHelpers
include ActiveScaffold::Helpers::PaginationHelpers
include ActiveScaffold::Helpers::ListColumnHelpers
include ActiveScaffold::Helpers::ShowColumnHelpers
include ActiveScaffold::Helpers::FormColumnHelpers
include ActiveScaffold::Helpers::SearchColumnHelpers
include ActiveScaffold::Helpers::HumanConditionHelpers
##
## Delegates
##
# access to the configuration variable
def active_scaffold_config
controller.class.active_scaffold_config
end
def active_scaffold_config_for(*args)
controller.class.active_scaffold_config_for(*args)
end
def active_scaffold_controller_for(*args)
controller.class.active_scaffold_controller_for(*args)
end
##
## Uncategorized
##
def controller_path_for_activerecord(klass)
begin
controller = active_scaffold_controller_for(klass)
controller.controller_path
rescue ActiveScaffold::ControllerNotFound
controller = nil
end
end
# This is the template finder logic, keep it updated with however we find stuff in rails
# currently this very similar to the logic in ActionBase::Base.render for options file
def template_exists?(template_name, partial = false)
lookup_context.exists? template_name, '', partial
end
def generate_temporary_id
(Time.now.to_f*1000).to_i.to_s
end
# Turns [[label, value]] into " : ""
end
end
# Should this column be displayed in the subform?
def in_subform?(column, parent_record)
# A column shouldn't be in the subform if it's the reverse association to the parent
not (column.association and column.association.associated_class == parent_record.class)
end
def form_remote_upload_tag(url_for_options = {}, options = {})
options[:target] = action_iframe_id(url_for_options)
options[:multipart] ||= true
options[:class] = "#{options[:class]} as_remote_upload".strip
output=""
output << form_tag(url_for_options, options)
(output << "").html_safe
end
# a general-use loading indicator (the "stuff is happening, please wait" feedback)
def loading_indicator_tag(options)
image_tag "active_scaffold/indicator.gif", :style => "visibility:hidden;", :id => loading_indicator_id(options), :alt => "loading indicator", :class => "loading-indicator"
end
# Creates a javascript-based link that toggles the visibility of some element on the page.
# By default, it toggles the visibility of the sibling after the one it's nested in. You may pass custom javascript logic in options[:of] to change that, though. For example, you could say :of => '$("my_div_id")'.
# You may also flag whether the other element is visible by default or not, and the initial text will adjust accordingly.
def link_to_visibility_toggle(id, options = {})
options[:default_visible] = true if options[:default_visible].nil?
options[:hide_label] = as_(:hide)
options[:show_label] = as_(:show)
javascript_tag("ActiveScaffold.create_visibility_toggle('#{id}', #{options.to_json});")
end
def skip_action_link(link, *args)
(!link.ignore_method.nil? && controller.respond_to?(link.ignore_method) && controller.send(link.ignore_method, *args)) || ((link.security_method_set? or controller.respond_to? link.security_method) and !controller.send(link.security_method, *args))
end
def render_action_link(link, url_options, record = nil, html_options = {})
url_options = action_link_url_options(link, url_options, record)
html_options = action_link_html_options(link, url_options, record, html_options)
action_link_html(link, url_options, html_options, record)
end
def render_group_action_link(link, url_options, options, record = nil)
if link.type == :member && !options[:authorized]
action_link_html(link, nil, {:class => "disabled #{link.action}#{link.html_options[:class].blank? ? '' : (' ' + link.html_options[:class])}"}, record)
else
render_action_link(link, url_options, record)
end
end
def action_link_url_options(link, url_options, record, options = {})
url_options = url_options.clone
url_options[:action] = link.action
url_options[:controller] = link.controller.to_s if link.controller
url_options.delete(:search) if link.controller and link.controller.to_s != params[:controller]
url_options.merge! link.parameters if link.parameters
@link_record = record
url_options.merge! self.instance_eval(&(link.dynamic_parameters)) if link.dynamic_parameters.is_a?(Proc)
@link_record = nil
url_options_for_nested_link(link.column, record, link, url_options, options) if link.column
url_options_for_sti_link(link.column, record, link, url_options, options) unless record.nil? || active_scaffold_config.sti_children.nil?
url_options[:_method] = link.method if !link.confirm? && link.inline? && link.method != :get
url_options
end
def action_link_html_options(link, url_options, record, html_options)
link_id = get_action_link_id(url_options, record, link.column)
html_options.reverse_merge! link.html_options.merge(:class => link.action.to_s)
# Needs to be in html_options to as the adding _method to the url is no longer supported by Rails
html_options[:method] = link.method if link.method != :get
html_options[:class] += ' as_action' if link.inline?
html_options[:data] = {}
html_options[:data][:confirm] = link.confirm(record.try(:to_label)) if link.confirm?
html_options[:data][:position] = link.position if link.position and link.inline?
html_options[:data][:action] = link.action if link.inline?
if link.popup?
html_options[:data][:popup] = true
html_options[:target] = '_blank'
end
html_options[:id] = link_id
html_options[:remote] = true unless link.page? || link.popup?
if link.dhtml_confirm?
html_options[:class] += ' as_action' if !link.inline?
html_options[:page_link] = 'true' if !link.inline?
html_options[:dhtml_confirm] = link.dhtml_confirm.value
html_options[:onclick] = link.dhtml_confirm.onclick_function(controller, link_id)
end
html_options[:class] += " #{link.html_options[:class]}" unless link.html_options[:class].blank?
html_options
end
def get_action_link_id(url_options, record = nil, column = nil)
id = url_options[:id] || url_options[:parent_id]
id = "#{column.association[:name]}-#{record.id}" if column && column.plural_association?
if record.try(column.association[:name]).present?
id = "#{column.association[:name]}-#{record.send(column.association[:name]).id}-#{record.id}"
else
id = "#{column.association[:name]}-#{record.id}" unless record.nil?
end if column && column.singular_association?
id = "#{id}-#{url_options[:batch_scope].downcase}" if url_options[:batch_scope]
action_id = "#{id_from_controller(url_options[:controller]) + '-' if url_options[:parent_controller]}#{url_options[:action].to_s}"
action_link_id(action_id, id)
end
def action_link_html(link, url, html_options, record)
# issue 260, use url_options[:link] if it exists. This prevents DB data from being localized.
label = url.delete(:link) if url.is_a?(Hash)
label ||= link.label
if link.image.nil?
html = link_to(label, url, html_options)
else
html = link_to(image_tag(link.image[:name] , :size => link.image[:size], :alt => label), url, html_options)
end
# if url is nil we would like to generate an anchor without href attribute
url.nil? ? html.sub(/href=".*?"/, '').html_safe : html.html_safe
end
def url_options_for_nested_link(column, record, link, url_options, options = {})
if column && column.association
url_options[column.association[:model].name.foreign_key.to_sym] = url_options.delete(:id)
url_options[:id] = record.send(column.association[:name]).id if column.singular_association? && record.send(column.association[:name]).present?
end
end
def url_options_for_sti_link(column, record, link, url_options, options = {})
#need to find out controller of current record type
#and set parameters
# its quite difficult to detect an sti link
# if link.column.nil? we are sure that it is nt an singular association inline autolink
# howver that will not work if a sti parent is an singular association inline autolink
if link.column.nil?
sti_controller_path = controller_path_for_activerecord(record.class)
if sti_controller_path
url_options[:controller] = sti_controller_path
url_options[:parent_sti] = controller_path
end
end
end
def column_class(column, column_value, record)
classes = []
classes << "#{column.name}-column"
if column.css_class.is_a?(Proc)
css_class = column.css_class.call(column_value, record)
classes << css_class unless css_class.nil?
else
classes << column.css_class
end unless column.css_class.nil?
classes << 'empty' if column_empty? column_value
classes << 'sorted' if active_scaffold_config.list.user.sorting.sorts_on?(column)
classes << 'numeric' if column.number?
classes.join(' ').rstrip
end
def column_heading_class(column, sorting)
classes = []
classes << "#{column.name}-column_heading"
classes << "sorted #{sorting.direction_of(column).downcase}" if sorting.sorts_on? column
classes << column.css_class unless column.css_class.nil? || column.css_class.is_a?(Proc)
classes.join(' ')
end
def as_main_div_class
classes = ["active-scaffold", "active-scaffold-#{controller_id}", "#{id_from_controller params[:controller]}-view", "#{active_scaffold_config.theme}-theme"]
classes << "as_touch" if touch_device?
classes.join(' ')
end
def column_empty?(column_value)
empty = column_value.nil?
empty ||= column_value.blank? if column_value.respond_to? :blank?
empty ||= [' ', active_scaffold_config.list.empty_field_text].include? column_value if String === column_value
return empty
end
def column_calculation(column)
if column.calculate.instance_of? Proc
column.calculate.call(@records)
else
conditions = controller.send(:all_conditions)
includes = active_scaffold_config.list.count_includes
includes ||= controller.send(:active_scaffold_includes) unless conditions.nil?
controller.send(:append_to_query, beginning_of_chain.dataset, :where => conditions, :includes => includes,
:joins => controller.send(:joins_for_collection)).get(column.calculate.sql_function(column.name))
end
end
def render_column_calculation(column)
calculation = column_calculation(column)
override_formatter = "render_#{column.name}_#{column.calculate.is_a?(Proc) ? :calculate : column.calculate}"
calculation = send(override_formatter, calculation) if respond_to? override_formatter
"#{"#{as_(column.calculate)}: " unless column.calculate.is_a? Proc}#{format_column_value nil, column, calculation}"
end
def column_show_add_existing(column)
(column.allow_add_existing and options_for_association_count(column.association) > 0)
end
def column_show_add_new(column, associated, record)
value = column.plural_association? || (column.singular_association? and associated.empty?)
value = false unless column.association.associated_class.respond_to?(:authorized_for?) and column.association.associated_class.authorized_for?(:crud_type => :create)
value
end
def clean_column_name(name)
name.to_s.gsub('?', '')
end
def clean_class_name(name)
name.underscore.gsub('/', '_')
end
def active_scaffold_error_messages_for(*params)
options = params.extract_options!.symbolize_keys
options.reverse_merge!(:container_tag => :div, :list_type => :ul)
objects = Array.wrap(options.delete(:object) || params).map do |object|
object = instance_variable_get("@#{object}") unless object.respond_to?(:to_model)
object = convert_to_model(object)
if object.class.respond_to?(:model_name)
options[:object_name] ||= object.class.model_name.human.downcase
end
object
end
objects.compact!
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
header_message = if options.include?(:header_message)
options[:header_message]
else
as_('errors.template.header', :count => count, :model => options[:object_name].to_s.gsub('_', ' '))
end
message = options.include?(:message) ? options[:message] : as_('errors.template.body')
error_messages = objects.sum do |object|
object.errors.full_messages.map do |msg|
options[:list_type] != :br ? content_tag(:li, msg) : msg
end
end
error_messages = if options[:list_type] == :br
error_messages.join(' ').html_safe
else
content_tag(options[:list_type], error_messages.join.html_safe)
end
contents = []
contents << content_tag(options[:header_tag] || :h2, header_message) unless header_message.blank?
contents << content_tag(:p, message) unless message.blank?
contents << error_messages
contents = contents.join.html_safe
options[:container_tag] ? content_tag(options[:container_tag], contents, html) : contents
else
''
end
end
end
end
end