sort_helper.rb
171 lines
| 5.4 KiB
| text/x-ruby
|
RubyLexer
|
r2 | # Helpers to sort tables using clickable column headers. | ||
# | ||||
# Author: Stuart Rackham <srackham@methods.co.nz>, March 2005. | ||||
# License: This source code is released under the MIT license. | ||||
# | ||||
# - Consecutive clicks toggle the column's sort order. | ||||
# - Sort state is maintained by a session hash entry. | ||||
# - Icon image identifies sort column and state. | ||||
# - Typically used in conjunction with the Pagination module. | ||||
# | ||||
# Example code snippets: | ||||
# | ||||
# Controller: | ||||
# | ||||
# helper :sort | ||||
# include SortHelper | ||||
# | ||||
# def list | ||||
# sort_init 'last_name' | ||||
# sort_update | ||||
# @items = Contact.find_all nil, sort_clause | ||||
# end | ||||
# | ||||
# Controller (using Pagination module): | ||||
# | ||||
# helper :sort | ||||
# include SortHelper | ||||
# | ||||
# def list | ||||
# sort_init 'last_name' | ||||
# sort_update | ||||
# @contact_pages, @items = paginate :contacts, | ||||
# :order_by => sort_clause, | ||||
# :per_page => 10 | ||||
# end | ||||
# | ||||
# View (table header in list.rhtml): | ||||
# | ||||
# <thead> | ||||
# <tr> | ||||
# <%= sort_header_tag('id', :title => 'Sort by contact ID') %> | ||||
# <%= sort_header_tag('last_name', :caption => 'Name') %> | ||||
# <%= sort_header_tag('phone') %> | ||||
# <%= sort_header_tag('address', :width => 200) %> | ||||
# </tr> | ||||
# </thead> | ||||
# | ||||
# - The ascending and descending sort icon images are sort_asc.png and | ||||
# sort_desc.png and reside in the application's images directory. | ||||
# - Introduces instance variables: @sort_name, @sort_default. | ||||
# - Introduces params :sort_key and :sort_order. | ||||
# | ||||
module SortHelper | ||||
# Initializes the default sort column (default_key) and sort order | ||||
# (default_order). | ||||
# | ||||
# - default_key is a column attribute name. | ||||
# - default_order is 'asc' or 'desc'. | ||||
# - name is the name of the session hash entry that stores the sort state, | ||||
# defaults to '<controller_name>_sort'. | ||||
# | ||||
def sort_init(default_key, default_order='asc', name=nil) | ||||
|
r124 | @sort_name = name || params[:controller] + params[:action] + '_sort' | ||
|
r2 | @sort_default = {:key => default_key, :order => default_order} | ||
end | ||||
# Updates the sort state. Call this in the controller prior to calling | ||||
# sort_clause. | ||||
|
r2169 | # sort_keys can be either an array or a hash of allowed keys | ||
def sort_update(sort_keys) | ||||
sort_key = params[:sort_key] | ||||
sort_key = nil unless (sort_keys.is_a?(Array) ? sort_keys.include?(sort_key) : sort_keys[sort_key]) | ||||
sort_order = (params[:sort_order] == 'desc' ? 'DESC' : 'ASC') | ||||
if sort_key | ||||
sort = {:key => sort_key, :order => sort_order} | ||||
|
r124 | elsif session[@sort_name] | ||
sort = session[@sort_name] # Previous sort. | ||||
|
r2 | else | ||
sort = @sort_default | ||||
end | ||||
|
r124 | session[@sort_name] = sort | ||
|
r2169 | |||
sort_column = (sort_keys.is_a?(Hash) ? sort_keys[sort[:key]] : sort[:key]) | ||||
|
r2349 | @sort_clause = (sort_column.blank? ? nil : [sort_column].flatten.collect {|s| "#{s} #{sort[:order]}"}.join(',')) | ||
|
r2 | end | ||
# Returns an SQL sort clause corresponding to the current sort state. | ||||
# Use this to sort the controller's table items collection. | ||||
# | ||||
def sort_clause() | ||||
|
r2181 | @sort_clause | ||
|
r2 | end | ||
# Returns a link which sorts by the named column. | ||||
# | ||||
# - column is the name of an attribute in the sorted record collection. | ||||
# - The optional caption explicitly specifies the displayed link text. | ||||
# - A sort icon image is positioned to the right of the sort link. | ||||
# | ||||
|
r1107 | def sort_link(column, caption, default_order) | ||
|
r124 | key, order = session[@sort_name][:key], session[@sort_name][:order] | ||
|
r2 | if key == column | ||
if order.downcase == 'asc' | ||||
|
r154 | icon = 'sort_asc.png' | ||
|
r2 | order = 'desc' | ||
else | ||||
|
r154 | icon = 'sort_desc.png' | ||
|
r2 | order = 'asc' | ||
end | ||||
else | ||||
icon = nil | ||||
|
r1107 | order = default_order | ||
|
r2 | end | ||
caption = titleize(Inflector::humanize(column)) unless caption | ||||
|
r403 | |||
|
r1159 | sort_options = { :sort_key => column, :sort_order => order } | ||
# don't reuse params if filters are present | ||||
url_options = params.has_key?(:set_filter) ? sort_options : params.merge(sort_options) | ||||
|
r403 | |||
|
r2322 | # Add project_id to url_options | ||
url_options = url_options.merge(:project_id => params[:project_id]) if params.has_key?(:project_id) | ||||
|
r31 | link_to_remote(caption, | ||
|
r2315 | {:update => "content", :url => url_options, :method => :get}, | ||
|
r1159 | {:href => url_for(url_options)}) + | ||
|
r31 | (icon ? nbsp(2) + image_tag(icon) : '') | ||
|
r2 | end | ||
# Returns a table header <th> tag with a sort link for the named column | ||||
# attribute. | ||||
# | ||||
# Options: | ||||
# :caption The displayed link name (defaults to titleized column name). | ||||
# :title The tag's 'title' attribute (defaults to 'Sort by :caption'). | ||||
# | ||||
# Other options hash entries generate additional table header tag attributes. | ||||
# | ||||
# Example: | ||||
# | ||||
# <%= sort_header_tag('id', :title => 'Sort by contact ID', :width => 40) %> | ||||
# | ||||
# Renders: | ||||
# | ||||
# <th title="Sort by contact ID" width="40"> | ||||
# <a href="/contact/list?sort_order=desc&sort_key=id">Id</a> | ||||
# <img alt="Sort_asc" src="/images/sort_asc.png" /> | ||||
# </th> | ||||
# | ||||
def sort_header_tag(column, options = {}) | ||||
|
r615 | caption = options.delete(:caption) || titleize(Inflector::humanize(column)) | ||
|
r1107 | default_order = options.delete(:default_order) || 'asc' | ||
|
r866 | options[:title]= l(:label_sort_by, "\"#{caption}\"") unless options[:title] | ||
|
r1107 | content_tag('th', sort_link(column, caption, default_order), options) | ||
|
r2 | end | ||
private | ||||
# Return n non-breaking spaces. | ||||
def nbsp(n) | ||||
' ' * n | ||||
end | ||||
# Return capitalized title. | ||||
def titleize(title) | ||||
title.split.map {|w| w.capitalize }.join(' ') | ||||
end | ||||
end | ||||