module ActionView
class Base
# Creates a link that alternates between acending and descending. It basically
# alternates between calling 2 named scopes: "ascend_by_*" and "descend_by_*"
#
# By default Searchlogic gives you these named scopes for all of your columns, but
# if you wanted to create your own, it will work with those too.
#
# Examples:
#
# order @search, :by => :username
# order @search, :by => :created_at, :as => "Created"
# order(@search, {:by => :last_login_at, :as => 'Login time', :arrow => true}, {:class => 'order'})
#
# This helper accepts the following options:
#
# * :by - the name of the named scope. This helper will prepend this value with "ascend_by_" and "descend_by_"
# * :as - the text used in the link, defaults to whatever is passed to :by
# * :ascend_scope - what scope to call for ascending the data, defaults to "ascend_by_:by"
# * :descend_scope - what scope to call for descending the data, defaults to "descend_by_:by"
# * :params - hash with additional params which will be added to generated url
# * :params_scope - the name of the params key to scope the order condition by, defaults to :search
# * :default_scope - either :asc or :desc, defaults to ascend_scope
# * :arrow - set to true if you want an ascii arrow showing the ordering
# * :css_classes - Array of what css classes you want to add, defaults to [:asc, :desc]. For old behaviour use [:ascending, :descending] here
def order(search, options = {}, html_options = {})
options[:params_scope] ||= :search
options[:as] ||= options[:by].to_s.humanize
options[:ascend_scope] ||= "ascend_by_#{options[:by]}"
options[:descend_scope] ||= "descend_by_#{options[:by]}"
options[:css_classes] ||= [:asc, :desc]
selected = [options[:ascend_scope], options[:descend_scope]].include?(search.order.to_s)
if selected
ascending = search.order.to_s == options[:ascend_scope]
new_scope = ascending ? options[:descend_scope] : options[:ascend_scope]
css_classes = html_options[:class] ? html_options[:class].split(" ") : []
if ascending
options[:as] = "▲ #{options[:as]}" if options[:arrow]
css_classes << options[:css_classes].first
else
options[:as] = "▼ #{options[:as]}" if options[:arrow]
css_classes << options[:css_classes].last
end
html_options[:class] = css_classes.join(" ")
else
new_scope = (options[:default_scope] == :desc) ? options[:descend_scope] : options[:ascend_scope]
end
url_options = {
options[:params_scope] => search.conditions.merge( { :order => new_scope } )
}.deep_merge(options[:params] || {})
link_to options[:as], url_for(url_options), html_options
end
# Automatically makes the form method :get if a Searchlogic::Search and sets
# the params scope to :search
def form_for_with_searchlogic(*args, &block)
if search_obj = args.find { |arg| arg.is_a?(Searchlogic::Search) }
options = args.extract_options!
options[:html] ||= {}
options[:html][:method] ||= :get
options[:url] ||= url_for
args.unshift(:search) if args.first == search_obj
args << options
end
form_for_without_searchlogic(*args, &block)
end
# Automatically adds an "order" hidden field in your form to preserve how the data
# is being ordered.
def fields_for_with_searchlogic(*args, &block)
if search_obj = args.find { |arg| arg.is_a?(Searchlogic::Search) }
args.unshift(:search) if args.first == search_obj
concat(content_tag("div", hidden_field_tag("#{args.first}[order]", search_obj.order)) + "\n")
end
fields_for_without_searchlogic(*args, &block)
end
end
end