peentar-smart_listing 1.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +279 -0
  4. data/Rakefile +34 -0
  5. data/app/assets/javascripts/smart_listing.coffee.erb +438 -0
  6. data/app/helpers/smart_listing/application_helper.rb +5 -0
  7. data/app/helpers/smart_listing/helper.rb +366 -0
  8. data/app/views/kaminari/smart_listing/_first_page.html.erb +13 -0
  9. data/app/views/kaminari/smart_listing/_gap.html.erb +8 -0
  10. data/app/views/kaminari/smart_listing/_last_page.html.erb +13 -0
  11. data/app/views/kaminari/smart_listing/_next_page.html.erb +13 -0
  12. data/app/views/kaminari/smart_listing/_page.html.erb +12 -0
  13. data/app/views/kaminari/smart_listing/_paginator.html.erb +25 -0
  14. data/app/views/kaminari/smart_listing/_prev_page.html.erb +13 -0
  15. data/app/views/smart_listing/_action_custom.html.erb +10 -0
  16. data/app/views/smart_listing/_action_delete.html.erb +12 -0
  17. data/app/views/smart_listing/_action_edit.html.erb +11 -0
  18. data/app/views/smart_listing/_action_show.html.erb +11 -0
  19. data/app/views/smart_listing/_item_new.html.erb +30 -0
  20. data/app/views/smart_listing/_pagination_per_page_link.html.erb +12 -0
  21. data/app/views/smart_listing/_pagination_per_page_links.html.erb +19 -0
  22. data/app/views/smart_listing/_sortable.html.erb +21 -0
  23. data/app/views/smart_listing/_update_list.js.erb +2 -0
  24. data/app/views/smart_listing/create.js.erb +2 -0
  25. data/app/views/smart_listing/destroy.js.erb +1 -0
  26. data/app/views/smart_listing/edit.js.erb +1 -0
  27. data/app/views/smart_listing/index.js.erb +1 -0
  28. data/app/views/smart_listing/item/_create.js.erb +3 -0
  29. data/app/views/smart_listing/item/_create_continue.js.erb +6 -0
  30. data/app/views/smart_listing/item/_destroy.js.erb +2 -0
  31. data/app/views/smart_listing/item/_edit.js.erb +2 -0
  32. data/app/views/smart_listing/item/_new.js.erb +2 -0
  33. data/app/views/smart_listing/item/_remove.js.erb +2 -0
  34. data/app/views/smart_listing/item/_update.js.erb +2 -0
  35. data/app/views/smart_listing/new.js.erb +1 -0
  36. data/app/views/smart_listing/update.js.erb +2 -0
  37. data/config/locales/en.yml +15 -0
  38. data/config/routes.rb +2 -0
  39. data/lib/generators/smart_listing/install_generator.rb +20 -0
  40. data/lib/generators/smart_listing/templates/initializer.rb +88 -0
  41. data/lib/generators/smart_listing/views_generator.rb +23 -0
  42. data/lib/smart_listing.rb +216 -0
  43. data/lib/smart_listing/config.rb +159 -0
  44. data/lib/smart_listing/engine.rb +5 -0
  45. data/lib/smart_listing/version.rb +3 -0
  46. data/lib/tasks/smart_list_tasks.rake +4 -0
  47. metadata +245 -0
@@ -0,0 +1,13 @@
1
+ <%# Link to the "Previous" page
2
+ - available local variables
3
+ url: url to the previous page
4
+ current_page: a page object for the currently displayed page
5
+ total_pages: total number of pages
6
+ per_page: number of items to fetch per page
7
+ remote: data-remote
8
+ -%>
9
+ <% unless current_page.first? %>
10
+ <li class="prev">
11
+ <%= link_to_unless current_page.first?, raw(t 'views.pagination.previous'), url, :rel => 'prev', :remote => remote %>
12
+ </li>
13
+ <% end %>
@@ -0,0 +1,10 @@
1
+ <%#
2
+ Custom action.
3
+
4
+ Available local variables:
5
+ url
6
+ icon
7
+ html_options: custom html options
8
+ -%>
9
+
10
+ <%= link_to_if(action_if, content_tag(:span, '', :class => icon, :title => title), url, html_options) %>
@@ -0,0 +1,12 @@
1
+ <%#
2
+ Delete action.
3
+
4
+ Available local variables:
5
+ action_if: false if action is disabled
6
+ url: destroy url
7
+ icon: icon css classes
8
+ confirmation: confrimation text
9
+ title
10
+ -%>
11
+
12
+ <%= link_to_if(action_if, content_tag(:i, "", :class => icon), url, :remote => true, :class => "destroy", :method => :delete, :title => title || t("smart_listing.actions.destroy"), :data => {:confirmation => confirmation || t("smart_listing.msgs.destroy_confirmation")} ) %>
@@ -0,0 +1,11 @@
1
+ <%#
2
+ Edit action.
3
+
4
+ Available local variables:
5
+ action_if: false if action is disabled
6
+ url: edit url
7
+ icon: icon css classes
8
+ title
9
+ -%>
10
+
11
+ <%= link_to_if(action_if, content_tag(:i, '', :class => icon), url, :remote => true, :class => "edit", :title => title || t("smart_listing.actions.edit") ) %>
@@ -0,0 +1,11 @@
1
+ <%#
2
+ Show action.
3
+
4
+ Available local variables:
5
+ action_if: false if action is disabled
6
+ url: show url
7
+ icon: icon clss classes
8
+ title
9
+ -%>
10
+
11
+ <%= link_to_if(action_if, content_tag(:i, '', :class => icon), url, :class => "show", :title => title || t("smart_listing.actions.show") ) %>
@@ -0,0 +1,30 @@
1
+ <%#
2
+ New list item element (contains new item placeholder and add button).
3
+
4
+ Available local variables:
5
+ placeholder_classes: classes for the main container
6
+ new_item_action_classes: new item action classes
7
+ colspan
8
+ no_items_classes: no items container classes
9
+ no_items_text: no items text displayed inside container
10
+ new_item_button_url: argument to link_to (new item button)
11
+ new_item_button_classes
12
+ new_item_button_text
13
+ new_item_autoshow automatically show new item placeholder
14
+ new_item_content new item placeholder content (usually some form)
15
+ -%>
16
+
17
+ <%= content_tag(:tr, '', :class => placeholder_classes + %w{info}, :data => {smart_listing_config.data_attributes(:autoshow) => new_item_autoshow}) do %>
18
+ <%= new_item_content %>
19
+ <% end %>
20
+ <%= content_tag(:tr, :class => new_item_action_classes + %w{info}) do %>
21
+ <%= content_tag(:td, :colspan => colspan) do %>
22
+ <%= content_tag(:p, :class => no_items_classes + %w{pull-left}) do %>
23
+ <%= no_items_text %>
24
+ <% end %>
25
+ <%= link_to(new_item_button_url, :remote => true, :class => new_item_button_classes + %w{btn pull-right}) do %>
26
+ <%= content_tag(:i, '', :class => smart_listing_config.classes(:icon_new)) %>
27
+ <%= new_item_button_text %>
28
+ <% end %>
29
+ <% end %>
30
+ <% end %>
@@ -0,0 +1,12 @@
1
+ <%#
2
+ Pagination single per-page link.
3
+
4
+ Available local variables:
5
+ page: page number
6
+ url: page url (if page is not selected)
7
+ smart_listing: current SmartListing instance
8
+ builder: current builder instance
9
+ -%>
10
+
11
+ <% name = page == 0 ? t('views.pagination.unlimited') : page %>
12
+ <%= url ? link_to(name, url, :remote => smart_listing.remote?) : content_tag(:span, name) %>
@@ -0,0 +1,19 @@
1
+ <%#
2
+ Pagination per-page links.
3
+
4
+ Available local variables:
5
+ container_classes: classes for the main container
6
+ per_page_sizes: array of available per-page sizes
7
+ smart_listing: current SmartListing instance
8
+ builder: current builder instance
9
+ -%>
10
+
11
+ <%= content_tag(:div, :class => container_classes ) do %>
12
+ <% if smart_listing.options[:paginate] && (smart_listing.count > smart_listing.page_sizes.first) %>
13
+ <%= t('views.pagination.per_page') %>
14
+ <% per_page_sizes.each do |p| %><%= builder.pagination_per_page_link p %><% break if p >= smart_listing.count %><% end %>
15
+ |
16
+ <% end %>
17
+ <%= t('views.pagination.total') %>
18
+ <%= content_tag(:span, smart_listing.count, :class => "count") %>
19
+ <% end %>
@@ -0,0 +1,21 @@
1
+ <%#
2
+ Sortable attribute listing header.
3
+
4
+ Available local variables:
5
+ container_classes: classes for the main container
6
+ url: sortable link url
7
+ attribute: current attribute name
8
+ title: current attribute title
9
+ order: defines column sort order
10
+ smart_listing: current SmartListing instance
11
+ builder: current builder instance
12
+ -%>
13
+
14
+ <%= link_to url, :class => container_classes, :data => {:attr => attribute}, :remote => true do %>
15
+ <%= title %>
16
+ <% if order %>
17
+ <span class="<%= order == "asc" ? smart_listing_config.classes(:icon_sort_up) : smart_listing_config.classes(:icon_sort_down) %>"></span>
18
+ <% else %>
19
+ <span class="<%= smart_listing_config.classes(:icon_sort_none) %>"></span>
20
+ <% end %>
21
+ <% end %>
@@ -0,0 +1,2 @@
1
+ var smart_listing = $('#<%= name %>').smart_listing();
2
+ smart_listing.update_list("<%= escape_javascript(render(:partial => part, :locals => {:smart_listing => smart_listing}.merge(locals))) %>", <%= smart_listing_data.to_json.html_safe %>);
@@ -0,0 +1,2 @@
1
+ <%= smart_listing_item :create, smart_listing_resource,
2
+ smart_listing_resource.valid? ? "item" : "form" %>
@@ -0,0 +1 @@
1
+ <%= smart_listing_item :destroy, smart_listing_resource %>
@@ -0,0 +1 @@
1
+ <%= smart_listing_item :edit, smart_listing_resource, "form" %>
@@ -0,0 +1 @@
1
+ <%= smart_listing_update %>
@@ -0,0 +1,3 @@
1
+ var smart_listing = $('#<%= name %>').smart_listing();
2
+ smart_listing.setAutoshow(false);
3
+ smart_listing.create(<%= id || 0 %>, <%= object.persisted? %>, "<%= escape_javascript(render(:partial => part, :locals => {object_key => object})) %>");
@@ -0,0 +1,6 @@
1
+ var smart_listing = $('#<%= name %>').smart_listing();
2
+ smart_listing.setAutoshow(true);
3
+ smart_listing.create(<%= id || 0 %>, <%= object.persisted? %>, "<%= escape_javascript(render(:partial => part, :locals => {object_key => object})) %>");
4
+ <% if object.persisted? %>
5
+ smart_listing.new_item("<%= escape_javascript(render(:partial => new.last, :locals => {object_key => new.first})) %>");
6
+ <% end %>
@@ -0,0 +1,2 @@
1
+ var smart_listing = $('#<%= name.to_s %>').smart_listing();
2
+ smart_listing.destroy(<%= id %>, <%= object.destroyed? %>);
@@ -0,0 +1,2 @@
1
+ var smart_listing = $('#<%= name %>').smart_listing();
2
+ smart_listing.edit(<%= id %>, "<%= escape_javascript(render(:partial => part, :locals => {object_key => object})) %>");
@@ -0,0 +1,2 @@
1
+ var smart_listing = $('#<%= name %>').smart_listing();
2
+ smart_listing.new_item("<%= escape_javascript(render(:partial => part, :locals => {object_key => object})) %>");
@@ -0,0 +1,2 @@
1
+ var smart_listing = $('#<%= name %>').smart_listing();
2
+ smart_listing.remove(<%= id %>);
@@ -0,0 +1,2 @@
1
+ var smart_listing = $('#<%= name %>').smart_listing();
2
+ smart_listing.update(<%= id %>, <%= valid.nil? ? object.valid? : valid %>, "<%= escape_javascript(render(:partial => part, :locals => {object_key => object})) %>");
@@ -0,0 +1 @@
1
+ <%= smart_listing_item :new, smart_listing_resource, "form" %>
@@ -0,0 +1,2 @@
1
+ <%= smart_listing_item :update, smart_listing_resource,
2
+ smart_listing_resource.valid? ? "item" : "form" %>
@@ -0,0 +1,15 @@
1
+ en:
2
+ smart_listing:
3
+ msgs:
4
+ destroy_confirmation: Destroy?
5
+ no_items: No items
6
+ actions:
7
+ destroy: Destroy
8
+ edit: Edit
9
+ show: Show
10
+ new: New item
11
+ views:
12
+ pagination:
13
+ per_page: Per page
14
+ unlimited: Unlimited
15
+ total: Total
@@ -0,0 +1,2 @@
1
+ SmartListing::Engine.routes.draw do
2
+ end
@@ -0,0 +1,20 @@
1
+ module SmartListing
2
+ module Generators
3
+ class InstallGenerator < Rails::Generators::Base
4
+ source_root File.expand_path('../templates', __FILE__)
5
+
6
+ def self.banner #:nodoc:
7
+ <<-BANNER.chomp
8
+ rails g smart_listing:install
9
+
10
+ Copies initializer file
11
+ BANNER
12
+ end
13
+
14
+ desc ''
15
+ def copy_views
16
+ template 'initializer.rb', 'config/initializers/smart_listing.rb'
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,88 @@
1
+ SmartListing.configure do |config|
2
+ config.global_options({
3
+ #:param_names => { # param names
4
+ #:page => :page,
5
+ #:per_page => :per_page,
6
+ #:sort => :sort,
7
+ #},
8
+ #:array => false, # controls whether smart list should be using arrays or AR collections
9
+ #:max_count => nil, # limit number of rows
10
+ #:unlimited_per_page => false, # allow infinite page size
11
+ #:paginate => true, # allow pagination
12
+ #:memorize_per_page => false, # save per page settings in the cookie
13
+ #:page_sizes => DEFAULT_PAGE_SIZES, # set available page sizes array
14
+ #:kaminari_options => {:theme => "smart_listing"}, # Kaminari's paginate helper options
15
+ #:sort_dirs => [nil, "asc", "desc"], # Default sorting directions cycle of sortables
16
+ })
17
+
18
+ config.constants :classes, {
19
+ #:main => "smart-listing",
20
+ #:editable => "editable",
21
+ #:content => "content",
22
+ #:loading => "loading",
23
+ #:status => "smart-listing-status",
24
+ #:item_actions => "actions",
25
+ #:new_item_placeholder => "new-item-placeholder",
26
+ #:new_item_action => "new-item-action",
27
+ #:new_item_button => "btn",
28
+ #:hidden => "hidden",
29
+ #:autoselect => "autoselect",
30
+ #:callback => "callback",
31
+ #:pagination_wrapper => "text-center",
32
+ #:pagination_container => "pagination",
33
+ #:pagination_per_page => "pagination-per-page text-center",
34
+ #:inline_editing => "info",
35
+ #:no_records => "no-records",
36
+ #:limit => "smart-listing-limit",
37
+ #:limit_alert => "smart-listing-limit-alert",
38
+ #:controls => "smart-listing-controls",
39
+ #:controls_reset => "reset",
40
+ #:filtering => "filter",
41
+ #:filtering_search => "glyphicon-search",
42
+ #:filtering_cancel => "glyphicon-remove",
43
+ #:filtering_disabled => "disabled",
44
+ #:sortable => "sortable",
45
+ #:icon_new => "glyphicon glyphicon-plus",
46
+ #:icon_edit => "glyphicon glyphicon-pencil",
47
+ #:icon_trash => "glyphicon glyphicon-trash",
48
+ #:icon_inactive => "glyphicon glyphicon-circle",
49
+ #:icon_show => "glyphicon glyphicon-share-alt",
50
+ #:icon_sort_none => "glyphicon glyphicon-resize-vertical",
51
+ #:icon_sort_up => "glyphicon glyphicon-chevron-up",
52
+ #:icon_sort_down => "glyphicon glyphicon-chevron-down",
53
+ #:muted => "text-muted",
54
+ }
55
+
56
+ config.constants :data_attributes, {
57
+ #:main => "smart-listing",
58
+ #:controls_initialized => "smart-listing-controls-initialized",
59
+ #:confirmation => "confirmation",
60
+ #:id => "id",
61
+ #:href => "href",
62
+ #:callback_href => "callback-href",
63
+ #:max_count => "max-count",
64
+ #:item_count => "item-count",
65
+ #:inline_edit_backup => "smart-listing-edit-backup",
66
+ #:params => "params",
67
+ #:observed => "observed",
68
+ #:href => "href",
69
+ #:autoshow => "autoshow",
70
+ #:popover => "slpopover",
71
+ }
72
+
73
+ config.constants :selectors, {
74
+ #:item_action_destroy => "a.destroy",
75
+ #:edit_cancel => "button.cancel",
76
+ #:row => "tr",
77
+ #:head => "thead",
78
+ #:filtering_icon => "i"
79
+ #:filtering_button => "button",
80
+ #:filtering_icon => "button span",
81
+ #:filtering_input => ".filter input",
82
+ #:pagination_count => ".pagination-per-page .count",
83
+ }
84
+
85
+ config.constants :element_templates, {
86
+ #:row => "<tr />",
87
+ }
88
+ end
@@ -0,0 +1,23 @@
1
+ module SmartListing
2
+ module Generators
3
+ class ViewsGenerator < Rails::Generators::Base
4
+ source_root File.expand_path('../../../../app/views/smart_listing', __FILE__)
5
+
6
+ def self.banner #:nodoc:
7
+ <<-BANNER.chomp
8
+ rails g smart_listing:views
9
+
10
+ Copies all smart listing partials templates to your application.
11
+ BANNER
12
+ end
13
+
14
+ desc ''
15
+ def copy_views
16
+ filename_pattern = File.join self.class.source_root, "*.html.erb"
17
+ Dir.glob(filename_pattern).map {|f| File.basename f}.each do |f|
18
+ copy_file f, "app/views/smart_listing/#{f}"
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,216 @@
1
+ require 'smart_listing/config'
2
+ require "smart_listing/engine"
3
+ require "kaminari"
4
+
5
+ # Fix parsing nested params
6
+ module Kaminari
7
+ module Helpers
8
+ class Tag
9
+ def page_url_for(page)
10
+ @template.url_for @params.deep_merge(page_param(page)).merge(:only_path => true)
11
+ end
12
+
13
+ private
14
+
15
+ def page_param(page)
16
+ Rack::Utils.parse_nested_query("#{@param_name}=#{page <= 1 ? nil : page}").symbolize_keys
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ module SmartListing
23
+ class Base
24
+ attr_reader :name, :collection, :options, :per_page, :sort, :page, :partial, :count
25
+
26
+ def initialize name, collection, options = {}
27
+ @name = name
28
+
29
+ config_profile = options.delete(:config_profile)
30
+
31
+ @options = {
32
+ :partial => @name, # SmartListing partial name
33
+ :sort_attributes => :implicit, # allow implicitly setting sort attributes
34
+ :default_sort => {}, # default sorting
35
+ :href => nil, # set SmartListing target url (in case when different than current url)
36
+ :remote => true, # SmartListing is remote by default
37
+ :callback_href => nil, # set SmartListing callback url (in case when different than current url)
38
+ }.merge(SmartListing.config(config_profile).global_options).merge(options)
39
+
40
+ if @options[:array]
41
+ @collection = collection.to_a
42
+ else
43
+ @collection = collection
44
+ end
45
+ end
46
+
47
+ def setup params, cookies
48
+ @params = params
49
+
50
+ @page = get_param :page
51
+ @per_page = !get_param(:per_page) || get_param(:per_page).empty? ? (@options[:memorize_per_page] && get_param(:per_page, cookies).to_i > 0 ? get_param(:per_page, cookies).to_i : page_sizes.first) : get_param(:per_page).to_i
52
+ @per_page = page_sizes.first unless page_sizes.include?(@per_page) || (unlimited_per_page? && @per_page == 0)
53
+
54
+ @sort = parse_sort(get_param(:sort)) || @options[:default_sort]
55
+ sort_keys = (@options[:sort_attributes] == :implicit ? @sort.keys.collect{|s| [s, s]} : @options[:sort_attributes])
56
+
57
+ set_param(:per_page, @per_page, cookies) if @options[:memorize_per_page]
58
+
59
+ @count = @collection.size
60
+ @count = @count.length if @count.is_a?(Hash)
61
+
62
+ # Reset @page if greater than total number of pages
63
+ if @per_page > 0
64
+ no_pages = (@count.to_f / @per_page.to_f).ceil.to_i
65
+ if @page.to_i > no_pages
66
+ @page = no_pages
67
+ end
68
+ end
69
+
70
+ if @options[:array]
71
+ if @sort && @sort.any? # when array we sort only by first attribute
72
+ i = sort_keys.index{|x| x[0] == @sort.first[0]}
73
+ @collection = @collection.sort do |x, y|
74
+ xval = x
75
+ yval = y
76
+ sort_keys[i][1].split(".").each do |m|
77
+ xval = xval.try(m)
78
+ yval = yval.try(m)
79
+ end
80
+ xval = xval.upcase if xval.is_a?(String)
81
+ yval = yval.upcase if yval.is_a?(String)
82
+
83
+ if xval.nil? || yval.nil?
84
+ xval.nil? ? 1 : -1
85
+ else
86
+ if @sort.first[1] == "asc"
87
+ (xval <=> yval) || (xval && !yval ? 1 : -1)
88
+ else
89
+ (yval <=> xval) || (yval && !xval ? 1 : -1)
90
+ end
91
+ end
92
+ end
93
+ end
94
+ if @options[:paginate] && @per_page > 0
95
+ @collection = ::Kaminari.paginate_array(@collection).page(@page).per(@per_page)
96
+ if @collection.length == 0
97
+ @collection = @collection.page(@collection.num_pages)
98
+ end
99
+ end
100
+ else
101
+ # let's sort by all attributes
102
+ #
103
+ @collection = @collection.order(sort_keys.collect{|s| "#{s[1]} #{@sort[s[0]]}" if @sort[s[0]]}.compact) if @sort && @sort.any?
104
+
105
+ if @options[:paginate] && @per_page > 0
106
+ @collection = @collection.page(@page).per(@per_page)
107
+ end
108
+ end
109
+ end
110
+
111
+ def partial
112
+ @options[:partial]
113
+ end
114
+
115
+ def param_names
116
+ @options[:param_names]
117
+ end
118
+
119
+ def param_name key
120
+ "#{base_param}[#{param_names[key]}]"
121
+ end
122
+
123
+ def unlimited_per_page?
124
+ !!@options[:unlimited_per_page]
125
+ end
126
+
127
+ def max_count
128
+ @options[:max_count]
129
+ end
130
+
131
+ def href
132
+ @options[:href]
133
+ end
134
+
135
+ def callback_href
136
+ @options[:callback_href]
137
+ end
138
+
139
+ def remote?
140
+ @options[:remote]
141
+ end
142
+
143
+ def page_sizes
144
+ @options[:page_sizes]
145
+ end
146
+
147
+ def kaminari_options
148
+ @options[:kaminari_options]
149
+ end
150
+
151
+ def sort_dirs
152
+ @options[:sort_dirs]
153
+ end
154
+
155
+ def all_params overrides = {}
156
+ ap = {base_param => {}}
157
+ @options[:param_names].each do |k, v|
158
+ if overrides[k]
159
+ ap[base_param][v] = overrides[k]
160
+ else
161
+ ap[base_param][v] = self.send(k)
162
+ end
163
+ end
164
+ ap
165
+ end
166
+
167
+ def sort_order attribute
168
+ @sort && @sort[attribute].present? ? @sort[attribute] : nil
169
+ end
170
+
171
+ def base_param
172
+ "#{name}_smart_listing"
173
+ end
174
+
175
+ private
176
+
177
+ def get_param key, store = @params
178
+ if store.is_a?(ActionDispatch::Cookies::CookieJar)
179
+ store["#{base_param}_#{param_names[key]}"]
180
+ else
181
+ store[base_param].try(:[], param_names[key])
182
+ end
183
+ end
184
+
185
+ def set_param key, value, store = @params
186
+ if store.is_a?(ActionDispatch::Cookies::CookieJar)
187
+ store["#{base_param}_#{param_names[key]}"] = value
188
+ else
189
+ store[base_param] ||= {}
190
+ store[base_param][param_names[key]] = value
191
+ end
192
+ end
193
+
194
+ def parse_sort sort_params
195
+ sort = nil
196
+
197
+ if @options[:sort_attributes] == :implicit
198
+ sort = sort_params.dup if sort_params.present?
199
+ elsif @options[:sort_attributes]
200
+ @options[:sort_attributes].each do |a|
201
+ k, v = a
202
+ if sort_params && sort_params[k.to_s]
203
+ dir = ["asc", "desc", ""].delete(sort_params[k.to_s])
204
+
205
+ if dir
206
+ sort ||= {}
207
+ sort[k] = dir
208
+ end
209
+ end
210
+ end
211
+ end
212
+
213
+ sort
214
+ end
215
+ end
216
+ end