You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

sort_helper.rb 5.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. # Helpers to sort tables using clickable column headers.
  2. #
  3. # Author: Stuart Rackham <srackham@methods.co.nz>, March 2005.
  4. # License: This source code is released under the MIT license.
  5. #
  6. # - Consecutive clicks toggle the column's sort order.
  7. # - Sort state is maintained by a session hash entry.
  8. # - Icon image identifies sort column and state.
  9. # - Typically used in conjunction with the Pagination module.
  10. #
  11. # Example code snippets:
  12. #
  13. # Controller:
  14. #
  15. # helper :sort
  16. # include SortHelper
  17. #
  18. # def list
  19. # sort_init 'last_name'
  20. # sort_update
  21. # @items = Contact.find_all nil, sort_clause
  22. # end
  23. #
  24. # Controller (using Pagination module):
  25. #
  26. # helper :sort
  27. # include SortHelper
  28. #
  29. # def list
  30. # sort_init 'last_name'
  31. # sort_update
  32. # @contact_pages, @items = paginate :contacts,
  33. # :order_by => sort_clause,
  34. # :per_page => 10
  35. # end
  36. #
  37. # View (table header in list.rhtml):
  38. #
  39. # <thead>
  40. # <tr>
  41. # <%= sort_header_tag('id', :title => 'Sort by contact ID') %>
  42. # <%= sort_header_tag('last_name', :caption => 'Name') %>
  43. # <%= sort_header_tag('phone') %>
  44. # <%= sort_header_tag('address', :width => 200) %>
  45. # </tr>
  46. # </thead>
  47. #
  48. # - The ascending and descending sort icon images are sort_asc.png and
  49. # sort_desc.png and reside in the application's images directory.
  50. # - Introduces instance variables: @sort_name, @sort_default.
  51. # - Introduces params :sort_key and :sort_order.
  52. #
  53. module SortHelper
  54. # Initializes the default sort column (default_key) and sort order
  55. # (default_order).
  56. #
  57. # - default_key is a column attribute name.
  58. # - default_order is 'asc' or 'desc'.
  59. # - name is the name of the session hash entry that stores the sort state,
  60. # defaults to '<controller_name>_sort'.
  61. #
  62. def sort_init(default_key, default_order='asc', name=nil)
  63. @sort_name = name || params[:controller] + params[:action] + '_sort'
  64. @sort_default = {:key => default_key, :order => default_order}
  65. end
  66. # Updates the sort state. Call this in the controller prior to calling
  67. # sort_clause.
  68. # sort_keys can be either an array or a hash of allowed keys
  69. def sort_update(sort_keys)
  70. sort_key = params[:sort_key]
  71. sort_key = nil unless (sort_keys.is_a?(Array) ? sort_keys.include?(sort_key) : sort_keys[sort_key])
  72. sort_order = (params[:sort_order] == 'desc' ? 'DESC' : 'ASC')
  73. if sort_key
  74. sort = {:key => sort_key, :order => sort_order}
  75. elsif session[@sort_name]
  76. sort = session[@sort_name] # Previous sort.
  77. else
  78. sort = @sort_default
  79. end
  80. session[@sort_name] = sort
  81. sort_column = (sort_keys.is_a?(Hash) ? sort_keys[sort[:key]] : sort[:key])
  82. @sort_clause = (sort_column.blank? ? nil : "#{sort_column} #{sort[:order]}")
  83. end
  84. # Returns an SQL sort clause corresponding to the current sort state.
  85. # Use this to sort the controller's table items collection.
  86. #
  87. def sort_clause()
  88. @sort_clause
  89. end
  90. # Returns a link which sorts by the named column.
  91. #
  92. # - column is the name of an attribute in the sorted record collection.
  93. # - The optional caption explicitly specifies the displayed link text.
  94. # - A sort icon image is positioned to the right of the sort link.
  95. #
  96. def sort_link(column, caption, default_order)
  97. key, order = session[@sort_name][:key], session[@sort_name][:order]
  98. if key == column
  99. if order.downcase == 'asc'
  100. icon = 'sort_asc.png'
  101. order = 'desc'
  102. else
  103. icon = 'sort_desc.png'
  104. order = 'asc'
  105. end
  106. else
  107. icon = nil
  108. order = default_order
  109. end
  110. caption = titleize(Inflector::humanize(column)) unless caption
  111. sort_options = { :sort_key => column, :sort_order => order }
  112. # don't reuse params if filters are present
  113. url_options = params.has_key?(:set_filter) ? sort_options : params.merge(sort_options)
  114. link_to_remote(caption,
  115. {:update => "content", :url => url_options},
  116. {:href => url_for(url_options)}) +
  117. (icon ? nbsp(2) + image_tag(icon) : '')
  118. end
  119. # Returns a table header <th> tag with a sort link for the named column
  120. # attribute.
  121. #
  122. # Options:
  123. # :caption The displayed link name (defaults to titleized column name).
  124. # :title The tag's 'title' attribute (defaults to 'Sort by :caption').
  125. #
  126. # Other options hash entries generate additional table header tag attributes.
  127. #
  128. # Example:
  129. #
  130. # <%= sort_header_tag('id', :title => 'Sort by contact ID', :width => 40) %>
  131. #
  132. # Renders:
  133. #
  134. # <th title="Sort by contact ID" width="40">
  135. # <a href="/contact/list?sort_order=desc&amp;sort_key=id">Id</a>
  136. # &nbsp;&nbsp;<img alt="Sort_asc" src="/images/sort_asc.png" />
  137. # </th>
  138. #
  139. def sort_header_tag(column, options = {})
  140. caption = options.delete(:caption) || titleize(Inflector::humanize(column))
  141. default_order = options.delete(:default_order) || 'asc'
  142. options[:title]= l(:label_sort_by, "\"#{caption}\"") unless options[:title]
  143. content_tag('th', sort_link(column, caption, default_order), options)
  144. end
  145. private
  146. # Return n non-breaking spaces.
  147. def nbsp(n)
  148. '&nbsp;' * n
  149. end
  150. # Return capitalized title.
  151. def titleize(title)
  152. title.split.map {|w| w.capitalize }.join(' ')
  153. end
  154. end