searchlogic 1.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.rdoc +228 -0
- data/MIT-LICENSE +20 -0
- data/Manifest +123 -0
- data/README.rdoc +383 -0
- data/Rakefile +15 -0
- data/TODO.rdoc +6 -0
- data/examples/README.rdoc +4 -0
- data/init.rb +1 -0
- data/lib/searchlogic.rb +89 -0
- data/lib/searchlogic/active_record/associations.rb +52 -0
- data/lib/searchlogic/active_record/base.rb +218 -0
- data/lib/searchlogic/active_record/connection_adapters/mysql_adapter.rb +172 -0
- data/lib/searchlogic/active_record/connection_adapters/postgresql_adapter.rb +168 -0
- data/lib/searchlogic/active_record/connection_adapters/sqlite_adapter.rb +75 -0
- data/lib/searchlogic/condition/base.rb +159 -0
- data/lib/searchlogic/condition/begins_with.rb +17 -0
- data/lib/searchlogic/condition/blank.rb +21 -0
- data/lib/searchlogic/condition/child_of.rb +11 -0
- data/lib/searchlogic/condition/descendant_of.rb +24 -0
- data/lib/searchlogic/condition/ends_with.rb +17 -0
- data/lib/searchlogic/condition/equals.rb +27 -0
- data/lib/searchlogic/condition/greater_than.rb +15 -0
- data/lib/searchlogic/condition/greater_than_or_equal_to.rb +15 -0
- data/lib/searchlogic/condition/inclusive_descendant_of.rb +11 -0
- data/lib/searchlogic/condition/keywords.rb +47 -0
- data/lib/searchlogic/condition/less_than.rb +15 -0
- data/lib/searchlogic/condition/less_than_or_equal_to.rb +15 -0
- data/lib/searchlogic/condition/like.rb +15 -0
- data/lib/searchlogic/condition/nil.rb +21 -0
- data/lib/searchlogic/condition/not_begin_with.rb +20 -0
- data/lib/searchlogic/condition/not_blank.rb +19 -0
- data/lib/searchlogic/condition/not_end_with.rb +20 -0
- data/lib/searchlogic/condition/not_equal.rb +26 -0
- data/lib/searchlogic/condition/not_have_keywords.rb +20 -0
- data/lib/searchlogic/condition/not_like.rb +20 -0
- data/lib/searchlogic/condition/not_nil.rb +19 -0
- data/lib/searchlogic/condition/sibling_of.rb +14 -0
- data/lib/searchlogic/condition/tree.rb +17 -0
- data/lib/searchlogic/conditions/base.rb +484 -0
- data/lib/searchlogic/conditions/protection.rb +36 -0
- data/lib/searchlogic/config.rb +31 -0
- data/lib/searchlogic/config/helpers.rb +289 -0
- data/lib/searchlogic/config/search.rb +53 -0
- data/lib/searchlogic/core_ext/hash.rb +75 -0
- data/lib/searchlogic/helpers/control_types/link.rb +310 -0
- data/lib/searchlogic/helpers/control_types/links.rb +241 -0
- data/lib/searchlogic/helpers/control_types/remote_link.rb +87 -0
- data/lib/searchlogic/helpers/control_types/remote_links.rb +72 -0
- data/lib/searchlogic/helpers/control_types/remote_select.rb +36 -0
- data/lib/searchlogic/helpers/control_types/select.rb +82 -0
- data/lib/searchlogic/helpers/form.rb +208 -0
- data/lib/searchlogic/helpers/utilities.rb +197 -0
- data/lib/searchlogic/modifiers/absolute.rb +15 -0
- data/lib/searchlogic/modifiers/acos.rb +11 -0
- data/lib/searchlogic/modifiers/asin.rb +11 -0
- data/lib/searchlogic/modifiers/atan.rb +11 -0
- data/lib/searchlogic/modifiers/base.rb +27 -0
- data/lib/searchlogic/modifiers/ceil.rb +15 -0
- data/lib/searchlogic/modifiers/char_length.rb +15 -0
- data/lib/searchlogic/modifiers/cos.rb +15 -0
- data/lib/searchlogic/modifiers/cot.rb +15 -0
- data/lib/searchlogic/modifiers/day_of_month.rb +15 -0
- data/lib/searchlogic/modifiers/day_of_week.rb +15 -0
- data/lib/searchlogic/modifiers/day_of_year.rb +15 -0
- data/lib/searchlogic/modifiers/degrees.rb +11 -0
- data/lib/searchlogic/modifiers/exp.rb +15 -0
- data/lib/searchlogic/modifiers/floor.rb +15 -0
- data/lib/searchlogic/modifiers/hex.rb +11 -0
- data/lib/searchlogic/modifiers/hour.rb +11 -0
- data/lib/searchlogic/modifiers/log.rb +15 -0
- data/lib/searchlogic/modifiers/log10.rb +11 -0
- data/lib/searchlogic/modifiers/log2.rb +11 -0
- data/lib/searchlogic/modifiers/lower.rb +15 -0
- data/lib/searchlogic/modifiers/ltrim.rb +15 -0
- data/lib/searchlogic/modifiers/md5.rb +11 -0
- data/lib/searchlogic/modifiers/microseconds.rb +11 -0
- data/lib/searchlogic/modifiers/milliseconds.rb +11 -0
- data/lib/searchlogic/modifiers/minute.rb +15 -0
- data/lib/searchlogic/modifiers/month.rb +15 -0
- data/lib/searchlogic/modifiers/octal.rb +15 -0
- data/lib/searchlogic/modifiers/radians.rb +11 -0
- data/lib/searchlogic/modifiers/round.rb +11 -0
- data/lib/searchlogic/modifiers/rtrim.rb +15 -0
- data/lib/searchlogic/modifiers/second.rb +15 -0
- data/lib/searchlogic/modifiers/sign.rb +11 -0
- data/lib/searchlogic/modifiers/sin.rb +11 -0
- data/lib/searchlogic/modifiers/square_root.rb +15 -0
- data/lib/searchlogic/modifiers/tan.rb +15 -0
- data/lib/searchlogic/modifiers/trim.rb +15 -0
- data/lib/searchlogic/modifiers/upper.rb +15 -0
- data/lib/searchlogic/modifiers/week.rb +11 -0
- data/lib/searchlogic/modifiers/year.rb +11 -0
- data/lib/searchlogic/search/base.rb +148 -0
- data/lib/searchlogic/search/conditions.rb +53 -0
- data/lib/searchlogic/search/ordering.rb +244 -0
- data/lib/searchlogic/search/pagination.rb +121 -0
- data/lib/searchlogic/search/protection.rb +89 -0
- data/lib/searchlogic/search/searching.rb +31 -0
- data/lib/searchlogic/shared/utilities.rb +50 -0
- data/lib/searchlogic/shared/virtual_classes.rb +39 -0
- data/lib/searchlogic/version.rb +79 -0
- data/searchlogic.gemspec +39 -0
- data/test/fixtures/accounts.yml +15 -0
- data/test/fixtures/cats.yml +3 -0
- data/test/fixtures/dogs.yml +3 -0
- data/test/fixtures/orders.yml +14 -0
- data/test/fixtures/user_groups.yml +13 -0
- data/test/fixtures/users.yml +36 -0
- data/test/test_active_record_associations.rb +81 -0
- data/test/test_active_record_base.rb +93 -0
- data/test/test_condition_base.rb +52 -0
- data/test/test_condition_types.rb +143 -0
- data/test/test_conditions_base.rb +242 -0
- data/test/test_conditions_protection.rb +16 -0
- data/test/test_config.rb +23 -0
- data/test/test_helper.rb +134 -0
- data/test/test_search_base.rb +227 -0
- data/test/test_search_conditions.rb +19 -0
- data/test/test_search_ordering.rb +165 -0
- data/test/test_search_pagination.rb +72 -0
- data/test/test_search_protection.rb +24 -0
- data/test_libs/acts_as_tree.rb +98 -0
- data/test_libs/ordered_hash.rb +9 -0
- data/test_libs/rexml_fix.rb +14 -0
- metadata +317 -0
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
module Searchlogic
|
|
2
|
+
module Helpers
|
|
3
|
+
# = Control Type Helpers
|
|
4
|
+
#
|
|
5
|
+
# The purpose of these helpers is to make ordering and paginating data, in your view, a breeze. Everyone has their own flavor of displaying data, so I made these helpers extra flexible, just for you.
|
|
6
|
+
#
|
|
7
|
+
# === Tutorial
|
|
8
|
+
#
|
|
9
|
+
# Check out my tutorial on how to implement searchlogic into a rails app: http://www.binarylogic.com/2008/9/7/tutorial-pagination-ordering-and-searching-with-searchlogic
|
|
10
|
+
#
|
|
11
|
+
# === How it's organized
|
|
12
|
+
#
|
|
13
|
+
# If we break it down, you can do 4 different things with your data in your view:
|
|
14
|
+
#
|
|
15
|
+
# 1. Order your data by a single column or an array of columns
|
|
16
|
+
# 2. Descend or ascend your data
|
|
17
|
+
# 3. Change how many items are on each page
|
|
18
|
+
# 4. Paginate through your data
|
|
19
|
+
#
|
|
20
|
+
# Each one of these actions comes with 3 different types of helpers:
|
|
21
|
+
#
|
|
22
|
+
# 1. Link - A single link for a single value. Requires that you pass a value as the first parameter.
|
|
23
|
+
# 2. Links - A group of single links.
|
|
24
|
+
# 3. Select - A select with choices that perform an action once selected. Basically the same thing as a group of links, but just as a select form element
|
|
25
|
+
# 4. Remote - lets you prefix any of these helpers with "remote_" and it will use the built in rails ajax helpers. I highly recommend unobstrusive javascript though, using jQuery.
|
|
26
|
+
#
|
|
27
|
+
# === Examples
|
|
28
|
+
#
|
|
29
|
+
# Sometimes the best way to explain something is with some examples. Let's pretend we are performing these actions on a User model. Check it out:
|
|
30
|
+
#
|
|
31
|
+
# order_by_link(:name)
|
|
32
|
+
# => produces a single link that when clicked will order by the name column, and each time its clicked alternated between "ASC" and "DESC"
|
|
33
|
+
#
|
|
34
|
+
# order_by_links
|
|
35
|
+
# => produces a group of links for all of the columns in your users table, each link is basically order_by_link(column.name)
|
|
36
|
+
#
|
|
37
|
+
# order_by_select
|
|
38
|
+
# => produces a select form element with all of the user's columns as choices, when the value is change (onchange) it will act as if they clicked a link.
|
|
39
|
+
# => This is just order_by_links as a select form element, nothing fancy
|
|
40
|
+
#
|
|
41
|
+
# What about paginating? I got you covered:
|
|
42
|
+
#
|
|
43
|
+
# page_link(2)
|
|
44
|
+
# => creates a link to page 2
|
|
45
|
+
#
|
|
46
|
+
# page_links
|
|
47
|
+
# => creates a group of links for pages, similar to a flickr style of pagination
|
|
48
|
+
#
|
|
49
|
+
# page_select
|
|
50
|
+
# => creates a drop down instead of a group of links. The user can select the page in the drop down and it will be as if they clicked a link for that page.
|
|
51
|
+
#
|
|
52
|
+
# You can apply the _link, _links, or _select to any of the following: order_by, order_as, per_page, page. You have your choice on how you want to set up the interface. For more information and options on these individual
|
|
53
|
+
# helpers check out their source files. Look at the sub modules under this one (Ex: Searchlogic::Helpers::ControlTypes::Select)
|
|
54
|
+
module ControlTypes
|
|
55
|
+
# = Link Control Types
|
|
56
|
+
#
|
|
57
|
+
# These helpers make ordering and paginating your data a breeze in your view. They only produce links.
|
|
58
|
+
module Link
|
|
59
|
+
# Creates a link for ordering data by a column or columns
|
|
60
|
+
#
|
|
61
|
+
# === Example uses for a User class that has many orders
|
|
62
|
+
#
|
|
63
|
+
# order_by_link(:first_name)
|
|
64
|
+
# order_by_link([:first_name, :last_name])
|
|
65
|
+
# order_by_link({:orders => :total})
|
|
66
|
+
# order_by_link([{:orders => :total}, :first_name])
|
|
67
|
+
# order_by_link(:id, :text => "Order Number", :html => {:class => "order_number"})
|
|
68
|
+
#
|
|
69
|
+
# What's nifty about this is that the value gets "serialized", if it is not a string or a symbol, so that it can be passed via a param in the url. Searchlogic will automatically try to "unserializes" this value and use it. This allows you
|
|
70
|
+
# to pass complex objects besides strings and symbols, such as arrays and hashes. All of the hard work is done for you.
|
|
71
|
+
#
|
|
72
|
+
# Another thing to keep in mind is that this will alternate between "asc" and "desc" each time it is clicked.
|
|
73
|
+
#
|
|
74
|
+
# === Options
|
|
75
|
+
# * <tt>:text</tt> -- default: column_name.to_s.humanize, text for the link
|
|
76
|
+
# * <tt>:desc_indicator</tt> -- default: ▼, the indicator that this column is descending
|
|
77
|
+
# * <tt>:asc_indicator</tt> -- default: ▲, the indicator that this column is ascending
|
|
78
|
+
# * <tt>:html</tt> -- html arrtributes for the <a> tag.
|
|
79
|
+
#
|
|
80
|
+
# === Advanced Options
|
|
81
|
+
# * <tt>:params_scope</tt> -- default: :search, this is the scope in which your search params will be preserved (params[:search]). If you don't want a scope and want your options to be at base level in params such as params[:page], params[:per_page], etc, then set this to nil.
|
|
82
|
+
# * <tt>:search_obj</tt> -- default: @#{params_scope}, this is your search object, everything revolves around this. It will try to infer the name from your params_scope. If your params_scope is :search it will try to get @search, etc. If it can not be inferred by this, you need to pass the object itself.
|
|
83
|
+
# * <tt>:params</tt> -- default: nil, Additional params to add to the url, must be a hash
|
|
84
|
+
# * <tt>:exclude_params</tt> -- default: nil, params you want to exclude. This is nifty because it does a "deep delete". So you can pass {:param1 => {:param2 => :param3}} and it will make sure param3 does not get included. param1 and param2 will not be touched. This also accepts an array or just a symbol or string.
|
|
85
|
+
# * <tt>:search_params</tt> -- default: nil, Additional search params to add to the url, must be a hash. Adds the options into the :params_scope.
|
|
86
|
+
# * <tt>:exclude_search_params</tt> -- default: nil, Same as :exclude_params but for the :search_params.
|
|
87
|
+
def order_by_link(order_by, options = {})
|
|
88
|
+
add_order_by_link_defaults!(order_by, options)
|
|
89
|
+
html = searchlogic_state(options)
|
|
90
|
+
|
|
91
|
+
if !options[:is_remote]
|
|
92
|
+
html += link_to(options[:text], options[:url], options[:html])
|
|
93
|
+
else
|
|
94
|
+
html += link_to_remote(options[:text], options[:remote].merge(:url => options[:url]), options[:html])
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
html
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Creates a link for ascending or descending data.
|
|
101
|
+
#
|
|
102
|
+
# === Example uses
|
|
103
|
+
#
|
|
104
|
+
# order_as_link("asc")
|
|
105
|
+
# order_as_link("desc")
|
|
106
|
+
# order_as_link("asc", :text => "Ascending", :html => {:class => "ascending"})
|
|
107
|
+
#
|
|
108
|
+
# === Options
|
|
109
|
+
# * <tt>:text</tt> -- default: column_name.to_s.humanize, text for the link
|
|
110
|
+
# * <tt>:html</tt> -- html arrtributes for the <a> tag.
|
|
111
|
+
#
|
|
112
|
+
# === Advanced Options
|
|
113
|
+
# * <tt>:params_scope</tt> -- default: :search, this is the scope in which your search params will be preserved (params[:search]). If you don't want a scope and want your options to be at base level in params such as params[:page], params[:per_page], etc, then set this to nil.
|
|
114
|
+
# * <tt>:search_obj</tt> -- default: @#{params_scope}, this is your search object, everything revolves around this. It will try to infer the name from your params_scope. If your params_scope is :search it will try to get @search, etc. If it can not be inferred by this, you need to pass the object itself.
|
|
115
|
+
# * <tt>:params</tt> -- default: nil, Additional params to add to the url, must be a hash
|
|
116
|
+
# * <tt>:exclude_params</tt> -- default: nil, params you want to exclude. This is nifty because it does a "deep delete". So you can pass {:param1 => {:param2 => :param3}} and it will make sure param3 does not get included. param1 and param2 will not be touched. This also accepts an array or just a symbol or string.
|
|
117
|
+
# * <tt>:search_params</tt> -- default: nil, Additional search params to add to the url, must be a hash. Adds the options into the :params_scope.
|
|
118
|
+
# * <tt>:exclude_search_params</tt> -- default: nil, Same as :exclude_params but for the :search_params.
|
|
119
|
+
def order_as_link(order_as, options = {})
|
|
120
|
+
add_order_as_link_defaults!(order_as, options)
|
|
121
|
+
html = searchlogic_state(options)
|
|
122
|
+
|
|
123
|
+
if !options[:is_remote]
|
|
124
|
+
html += link_to(options[:text], options[:url], options[:html])
|
|
125
|
+
else
|
|
126
|
+
html += link_to_remote(options[:text], options[:remote].merge(:url => options[:url]), options[:html])
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
html
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# This is similar to order_by_link but with a small difference. The best way to explain priority ordering is with an example. Let's say you wanted to list products on a page. You have "featured" products
|
|
133
|
+
# that you want to show up first, no matter what. This is what this is all about. It makes ordering by featured products a priority, then searching by price, quantity, etc. is the same as it has always been.
|
|
134
|
+
#
|
|
135
|
+
# The difference between order_by_link and priority_order_by_link is that priority_order_by_link it just a switch. Turn it on or turn it off. You don't neccessarily want to flip between ASC and DESC. If you do
|
|
136
|
+
# then you should just incorporate this into your regular order_by, like: order_by_link [:featured, :price]
|
|
137
|
+
#
|
|
138
|
+
# === Example uses for a User class that has many orders
|
|
139
|
+
#
|
|
140
|
+
# priority_order_by_link(:featured, "DESC")
|
|
141
|
+
# order_by_link([:featured, :created_at], "ASC")
|
|
142
|
+
# order_by_link({:orders => :featured}, "ASC")
|
|
143
|
+
# order_by_link([{:orders => :featured}, :featured], "ASC")
|
|
144
|
+
# order_by_link(:featured, "ASC", :text => "Featured", :html => {:class => "featured_link"})
|
|
145
|
+
#
|
|
146
|
+
# === Options
|
|
147
|
+
# * <tt>:activate_text</tt> -- default: "Show #{column_name.to_s.humanize} first"
|
|
148
|
+
# * <tt>:deactivate_text</tt> -- default: "Don't show #{column_name.to_s.humanize} first", text for the link, text for the link
|
|
149
|
+
# * <tt>:column_name</tt> -- default: column_name.to_s.humanize, automatically inferred by what you are ordering by and is added into the active_text and deactive_text strings.
|
|
150
|
+
# * <tt>:text</tt> -- default: :activate_text or :deactivate_text depending on if its active or not, Overwriting this will make this text stay the same, no matter way. A good alternative would be "Toggle featured first"
|
|
151
|
+
# * <tt>:html</tt> -- html arrtributes for the <a> tag.
|
|
152
|
+
#
|
|
153
|
+
# === Advanced Options
|
|
154
|
+
# * <tt>:params_scope</tt> -- default: :search, this is the scope in which your search params will be preserved (params[:search]). If you don't want a scope and want your options to be at base level in params such as params[:page], params[:per_page], etc, then set this to nil.
|
|
155
|
+
# * <tt>:search_obj</tt> -- default: @#{params_scope}, this is your search object, everything revolves around this. It will try to infer the name from your params_scope. If your params_scope is :search it will try to get @search, etc. If it can not be inferred by this, you need to pass the object itself.
|
|
156
|
+
# * <tt>:params</tt> -- default: nil, Additional params to add to the url, must be a hash
|
|
157
|
+
# * <tt>:exclude_params</tt> -- default: nil, params you want to exclude. This is nifty because it does a "deep delete". So you can pass {:param1 => {:param2 => :param3}} and it will make sure param3 does not get included. param1 and param2 will not be touched. This also accepts an array or just a symbol or string.
|
|
158
|
+
# * <tt>:search_params</tt> -- default: nil, Additional search params to add to the url, must be a hash. Adds the options into the :params_scope.
|
|
159
|
+
# * <tt>:exclude_search_params</tt> -- default: nil, Same as :exclude_params but for the :search_params.
|
|
160
|
+
def priority_order_by_link(priority_order_by, priority_order_as, options = {})
|
|
161
|
+
add_priority_order_by_link_defaults!(priority_order_by, priority_order_as, options)
|
|
162
|
+
html = searchlogic_state(options)
|
|
163
|
+
|
|
164
|
+
if !options[:is_remote]
|
|
165
|
+
html += link_to(options[:text], options[:url], options[:html])
|
|
166
|
+
else
|
|
167
|
+
html += link_to_remote(options[:text], options[:remote].merge(:url => options[:url]), options[:html])
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
html
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# Creates a link for limiting how many items are on each page
|
|
174
|
+
#
|
|
175
|
+
# === Example uses
|
|
176
|
+
#
|
|
177
|
+
# per_page_link(200)
|
|
178
|
+
# per_page_link(nil) # => Show all
|
|
179
|
+
# per_page_link(nil, :text => "All", :html => {:class => "show_all"})
|
|
180
|
+
#
|
|
181
|
+
# As you can see above, passing nil means "show all" and the text will automatically revert to "show all"
|
|
182
|
+
#
|
|
183
|
+
# === Options
|
|
184
|
+
# * <tt>:html</tt> -- html arrtributes for the <a> tag.
|
|
185
|
+
#
|
|
186
|
+
# === Advanced Options
|
|
187
|
+
# * <tt>:params_scope</tt> -- default: :search, this is the scope in which your search params will be preserved (params[:search]). If you don't want a scope and want your options to be at base level in params such as params[:page], params[:per_page], etc, then set this to nil.
|
|
188
|
+
# * <tt>:search_obj</tt> -- default: @#{params_scope}, this is your search object, everything revolves around this. It will try to infer the name from your params_scope. If your params_scope is :search it will try to get @search, etc. If it can not be inferred by this, you need to pass the object itself.
|
|
189
|
+
# * <tt>:params</tt> -- default: nil, Additional params to add to the url, must be a hash
|
|
190
|
+
# * <tt>:exclude_params</tt> -- default: nil, params you want to exclude. This is nifty because it does a "deep delete". So you can pass {:param1 => {:param2 => :param3}} and it will make sure param3 does not get included. param1 and param2 will not be touched. This also accepts an array or just a symbol or string.
|
|
191
|
+
# * <tt>:search_params</tt> -- default: nil, Additional search params to add to the url, must be a hash. Adds the options into the :params_scope.
|
|
192
|
+
# * <tt>:exclude_search_params</tt> -- default: nil, Same as :exclude_params but for the :search_params.
|
|
193
|
+
def per_page_link(per_page, options = {})
|
|
194
|
+
add_per_page_link_defaults!(per_page, options)
|
|
195
|
+
html = searchlogic_state(options)
|
|
196
|
+
|
|
197
|
+
if !options[:is_remote]
|
|
198
|
+
html += link_to(options[:text], options[:url], options[:html])
|
|
199
|
+
else
|
|
200
|
+
html += link_to_remote(options[:text], options[:remote].merge(:url => options[:url]), options[:html])
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
html
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
# Creates a link for changing to a sepcific page of your data
|
|
207
|
+
#
|
|
208
|
+
# === Example uses
|
|
209
|
+
#
|
|
210
|
+
# page_link(2)
|
|
211
|
+
# page_link(1)
|
|
212
|
+
# page_link(5, :text => "Fifth page", :html => {:class => "fifth_page"})
|
|
213
|
+
#
|
|
214
|
+
# === Options
|
|
215
|
+
# * <tt>:text</tt> -- default: column_name.to_s.humanize, text for the link
|
|
216
|
+
# * <tt>:html</tt> -- html arrtributes for the <a> tag.
|
|
217
|
+
#
|
|
218
|
+
# === Advanced Options
|
|
219
|
+
# * <tt>:params_scope</tt> -- default: :search, this is the scope in which your search params will be preserved (params[:search]). If you don't want a scope and want your options to be at base level in params such as params[:page], params[:per_page], etc, then set this to nil.
|
|
220
|
+
# * <tt>:search_obj</tt> -- default: @#{params_scope}, this is your search object, everything revolves around this. It will try to infer the name from your params_scope. If your params_scope is :search it will try to get @search, etc. If it can not be inferred by this, you need to pass the object itself.
|
|
221
|
+
# * <tt>:params</tt> -- default: nil, Additional params to add to the url, must be a hash
|
|
222
|
+
# * <tt>:exclude_params</tt> -- default: nil, params you want to exclude. This is nifty because it does a "deep delete". So you can pass {:param1 => {:param2 => :param3}} and it will make sure param3 does not get included. param1 and param2 will not be touched. This also accepts an array or just a symbol or string.
|
|
223
|
+
# * <tt>:search_params</tt> -- default: nil, Additional search params to add to the url, must be a hash. Adds the options into the :params_scope.
|
|
224
|
+
# * <tt>:exclude_search_params</tt> -- default: nil, Same as :exclude_params but for the :search_params.
|
|
225
|
+
def page_link(page, options = {})
|
|
226
|
+
add_page_link_defaults!(page, options)
|
|
227
|
+
html = searchlogic_state(options)
|
|
228
|
+
|
|
229
|
+
if !options[:is_remote]
|
|
230
|
+
html += link_to(options[:text], options[:url], options[:html])
|
|
231
|
+
else
|
|
232
|
+
html += link_to_remote(options[:text], options[:remote].merge(:url => options[:url]), options[:html])
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
html
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
private
|
|
239
|
+
def add_order_by_link_defaults!(order_by, options = {})
|
|
240
|
+
add_searchlogic_control_defaults!(options)
|
|
241
|
+
searchlogic_add_class!(options[:html], Config.helpers.order_by_link_class_name)
|
|
242
|
+
ordering_by_this = searchlogic_ordering_by?(order_by, options)
|
|
243
|
+
searchlogic_add_class!(options[:html], "ordering") if ordering_by_this
|
|
244
|
+
options[:text] ||= determine_order_by_text(order_by)
|
|
245
|
+
options[:asc_indicator] ||= Config.helpers.order_by_link_asc_indicator
|
|
246
|
+
options[:desc_indicator] ||= Config.helpers.order_by_link_desc_indicator
|
|
247
|
+
options[:text] += options[:search_obj].desc? ? options[:desc_indicator] : options[:asc_indicator] if ordering_by_this
|
|
248
|
+
options[:url] = searchlogic_params(options.merge(:search_params => {:order_by => order_by}))
|
|
249
|
+
options
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
def add_order_as_link_defaults!(order_as, options = {})
|
|
253
|
+
add_searchlogic_control_defaults!(options)
|
|
254
|
+
searchlogic_add_class!(options[:html], Config.helpers.order_as_link_class_name)
|
|
255
|
+
options[:text] ||= order_as.to_s
|
|
256
|
+
options[:url] = searchlogic_params(options.merge(:search_params => {:order_as => order_as}))
|
|
257
|
+
options
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
def add_priority_order_by_link_defaults!(priority_order_by, priority_order_as, options = {})
|
|
261
|
+
add_searchlogic_control_defaults!(options)
|
|
262
|
+
searchlogic_add_class!(options[:html], Config.helpers.priority_order_by_link_class_name)
|
|
263
|
+
options[:column_name] ||= determine_order_by_text(priority_order_by).downcase
|
|
264
|
+
options[:activate_text] ||= Config.helpers.priority_order_by_link_activate_text % options[:column_name]
|
|
265
|
+
options[:deactivate_text] ||= Config.helpers.priority_order_by_link_deactivate_text % options[:column_name]
|
|
266
|
+
active = deep_stringify(options[:search_obj].priority_order_by) == deep_stringify(priority_order_by) && options[:search_obj].priority_order_as == priority_order_as
|
|
267
|
+
options[:text] ||= active ? options[:deactivate_text] : options[:activate_text]
|
|
268
|
+
if active
|
|
269
|
+
options.merge!(:search_params => {:priority_order_by => nil, :priority_order_as => nil})
|
|
270
|
+
else
|
|
271
|
+
options.merge!(:search_params => {:priority_order_by => priority_order_by, :priority_order_as => priority_order_as})
|
|
272
|
+
end
|
|
273
|
+
options[:url] = searchlogic_params(options)
|
|
274
|
+
options
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
def add_per_page_link_defaults!(per_page, options = {})
|
|
278
|
+
add_searchlogic_control_defaults!(options)
|
|
279
|
+
searchlogic_add_class!(options[:html], Config.helpers.per_page_link_class_name)
|
|
280
|
+
options[:text] ||= per_page.to_s
|
|
281
|
+
options[:url] = searchlogic_params(options.merge(:search_params => {:per_page => per_page}))
|
|
282
|
+
options
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
def add_page_link_defaults!(page, options = {})
|
|
286
|
+
add_searchlogic_control_defaults!(options)
|
|
287
|
+
searchlogic_add_class!(options[:html], Config.helpers.page_link_class_name)
|
|
288
|
+
options[:text] ||= page.to_s
|
|
289
|
+
options[:url] = searchlogic_params(options.merge(:search_params => {:page => page}))
|
|
290
|
+
options
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
def determine_order_by_text(column_name, relationship_name = nil)
|
|
294
|
+
case column_name
|
|
295
|
+
when String, Symbol
|
|
296
|
+
relationship_name.blank? ? column_name.to_s.titleize : "#{relationship_name.to_s.titleize} #{column_name.to_s.titleize}"
|
|
297
|
+
when Array
|
|
298
|
+
determine_order_by_text(column_name.first)
|
|
299
|
+
when Hash
|
|
300
|
+
k = column_name.keys.first
|
|
301
|
+
v = column_name.values.first
|
|
302
|
+
determine_order_by_text(v, k)
|
|
303
|
+
end
|
|
304
|
+
end
|
|
305
|
+
end
|
|
306
|
+
end
|
|
307
|
+
end
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
ActionController::Base.helper Searchlogic::Helpers::ControlTypes::Link if defined?(ActionController)
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
module Searchlogic
|
|
2
|
+
module Helpers
|
|
3
|
+
module ControlTypes
|
|
4
|
+
module Links
|
|
5
|
+
# Creates a group of links that order the data by a column or columns. All that this does is loop through the :choices option and call order_by_link and then glue it all together.
|
|
6
|
+
#
|
|
7
|
+
# === Examples
|
|
8
|
+
#
|
|
9
|
+
# order_by_links
|
|
10
|
+
# order_by_links(:choices => [:name, {:orders => {:line_items => :total}}, :email])
|
|
11
|
+
#
|
|
12
|
+
# === Options
|
|
13
|
+
#
|
|
14
|
+
# Please look at order_by_link. All options there are applicable here and are passed onto each option.
|
|
15
|
+
#
|
|
16
|
+
# * <tt>:choices</tt> -- default: the models column names, the choices to loop through when calling order_by_link
|
|
17
|
+
def order_by_links(options = {})
|
|
18
|
+
add_order_by_links_defaults!(options)
|
|
19
|
+
links_options = options.deep_dup
|
|
20
|
+
links_options.delete(:choices)
|
|
21
|
+
html = ""
|
|
22
|
+
options[:choices].each do |choice|
|
|
23
|
+
link_options = links_option.deep_dup
|
|
24
|
+
text, value = option_text_and_value(choice)
|
|
25
|
+
link_options[:text] ||= text
|
|
26
|
+
html += order_by_link(value, link_options)
|
|
27
|
+
end
|
|
28
|
+
html
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Creates a group of links that ascend or descend the data. All that this does is loop through the :choices option and call order_as_link and then glue it all together.
|
|
32
|
+
#
|
|
33
|
+
# === Examples
|
|
34
|
+
#
|
|
35
|
+
# order_as_links
|
|
36
|
+
# order_as_links(:choices => [:ascending, :descending])
|
|
37
|
+
#
|
|
38
|
+
# === Options
|
|
39
|
+
#
|
|
40
|
+
# Please look at order_as_link. All options there are applicable here and are passed onto each option.
|
|
41
|
+
#
|
|
42
|
+
# * <tt>:choices</tt> -- default: ["asc", "desc"], the choices to loop through when calling order_as_link
|
|
43
|
+
def order_as_links(options = {})
|
|
44
|
+
add_order_as_links_defaults!(options)
|
|
45
|
+
links_options = options.deep_dup
|
|
46
|
+
links_options.delete(:choices)
|
|
47
|
+
html = ""
|
|
48
|
+
options[:choices].each do |choice|
|
|
49
|
+
link_options = links_option.deep_dup
|
|
50
|
+
text, value = option_text_and_value(choice)
|
|
51
|
+
link_options[:text] ||= text
|
|
52
|
+
html += order_as_link(value, link_options)
|
|
53
|
+
end
|
|
54
|
+
html
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Creates a group of links that limit how many items are on each page. All that this does is loop through the :choices option and call per_page_link and then glue it all together.
|
|
58
|
+
#
|
|
59
|
+
# === Examples
|
|
60
|
+
#
|
|
61
|
+
# per_page_links
|
|
62
|
+
# per_page_links(:choices => [25, 50, nil])
|
|
63
|
+
#
|
|
64
|
+
# === Options
|
|
65
|
+
#
|
|
66
|
+
# Please look at per_page_link. All options there are applicable here and are passed onto each option.
|
|
67
|
+
#
|
|
68
|
+
# * <tt>:choices</tt> -- default: [["10 per page", 10], ["25 per page", 25], ["50 per page", 50], ["100 per page", 100], ["150 per page", 150], ["200 per page", 200], ["Show all", nil]]
|
|
69
|
+
def per_page_links(options = {})
|
|
70
|
+
add_per_page_links_defaults!(options)
|
|
71
|
+
links_options = options.deep_dup
|
|
72
|
+
links_options.delete(:choices)
|
|
73
|
+
html = ""
|
|
74
|
+
options[:choices].each do |choice|
|
|
75
|
+
link_options = links_options.deep_dup
|
|
76
|
+
text, value = option_text_and_value(choice)
|
|
77
|
+
link_options[:text] ||= text
|
|
78
|
+
searchlogic_add_class!(link_options[:html], Config.helpers.order_by_links_ordering_by_class_name) if link_options[:search_obj].per_page == value
|
|
79
|
+
html += per_page_link(value, link_options)
|
|
80
|
+
end
|
|
81
|
+
html
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Creates a group of links that paginate through the data. Kind of like a flickr page navigation. This one has some nifty options.
|
|
85
|
+
#
|
|
86
|
+
# === Examples
|
|
87
|
+
#
|
|
88
|
+
# page_links
|
|
89
|
+
# page_links(:first => "<< First", :last => "Last >>")
|
|
90
|
+
#
|
|
91
|
+
# === Classes and tags
|
|
92
|
+
#
|
|
93
|
+
# If the user is on the current page they will get a <span> tag, not an <a> tag. If they are on the first page the "first" and "prev" options will be a <span> also. The same goes
|
|
94
|
+
# for "next" and "last" if the user is on the last page. Other than that each element will come with a CSS class so you can style it to your liking. Somtimes the easiest way to understand this
|
|
95
|
+
# Is to either look at the example (linked in the README) or try it out and view the HTML source. It's pretty simple, but here are the explanations:
|
|
96
|
+
#
|
|
97
|
+
# * <tt>page</tt> - This is in *every* element, span or a.
|
|
98
|
+
# * <tt>first_page</tt> - This is for the "first page" element only.
|
|
99
|
+
# * <tt>prev_page</tt> - This is for the "prev page" element only.
|
|
100
|
+
# * <tt>current_page</tt> - This is for the current page element
|
|
101
|
+
# * <tt>next_page</tt> - This is for the "next page" element only.
|
|
102
|
+
# * <tt>last_page</tt> - This is for the "last page" element only.
|
|
103
|
+
# * <tt>disabled_page</tt> - Any element that is a span instead of an a tag.
|
|
104
|
+
#
|
|
105
|
+
# === Options
|
|
106
|
+
#
|
|
107
|
+
# Please look at per_page_link. All options there are applicable here and are passed onto each option.
|
|
108
|
+
#
|
|
109
|
+
# * <tt>:inner_spread</tt> -- default: 3, set to nil to show all pages, set 0 to show no page links. This represents how many choices available on each side of the current page
|
|
110
|
+
# * <tt>:outer_spread</tt> -- default: 1, set to nil to disable, set to 0 show no outer spread but the separator will still be present. This represents how many choices are in the "outer" spread.
|
|
111
|
+
# * <tt>:prev</tt> -- default: "< Prev", set to nil to omit. This is an extra link on the left side of the page links that will go to the previous page
|
|
112
|
+
# * <tt>:next</tt> -- default: "Next >", set to nil to omit. This is an extra link on the right side of the page links that will go to the next page
|
|
113
|
+
# * <tt>:first</tt> -- default: nil, set to nil to omit. This is an extra link on thefar left side of the page links that will go to the first page
|
|
114
|
+
# * <tt>:last</tt> -- default: nil, set to nil to omit. This is an extra link on the far right side of the page links that will go to the last page
|
|
115
|
+
def page_links(options = {})
|
|
116
|
+
add_page_links_defaults!(options)
|
|
117
|
+
return if options[:last_page] <= 1
|
|
118
|
+
|
|
119
|
+
inner_spread_start = inner_spread_end = lower_gap = lower_outer_spread_start = lower_outer_spread_end = upper_gap = upper_outer_spread_start = upper_outer_spread_end = 0
|
|
120
|
+
if !options[:inner_spread].blank?
|
|
121
|
+
inner_spread_start = options[:current_page] - options[:inner_spread]
|
|
122
|
+
inner_spread_start = options[:first_page] if inner_spread_start < options[:first_page]
|
|
123
|
+
inner_spread_end = options[:current_page] + options[:inner_spread]
|
|
124
|
+
inner_spread_end = options[:last_page] if inner_spread_end > options[:last_page]
|
|
125
|
+
|
|
126
|
+
if !options[:outer_spread].blank?
|
|
127
|
+
lower_gap = inner_spread_start - options[:first_page]
|
|
128
|
+
if lower_gap > 0
|
|
129
|
+
lower_outer_spread_start = options[:first_page]
|
|
130
|
+
lower_outer_spread_end = options[:outer_spread] > lower_gap ? lower_gap : options[:outer_spread]
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
upper_gap = options[:last_page] - inner_spread_end
|
|
134
|
+
if upper_gap > 0
|
|
135
|
+
upper_outer_spread_start = options[:last_page] - (options[:outer_spread] > upper_gap ? upper_gap : options[:outer_spread]) + 1
|
|
136
|
+
upper_outer_spread_end = options[:last_page]
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
else
|
|
140
|
+
inner_spread_start = options[:first_page]
|
|
141
|
+
inner_spread_end = options[:last_page]
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
html = ""
|
|
145
|
+
html += span_or_page_link(:first, options.deep_dup, options[:current_page] == options[:first_page]) if options[:first]
|
|
146
|
+
html += span_or_page_link(:prev, options.deep_dup, options[:current_page] == options[:first_page]) if options[:prev]
|
|
147
|
+
|
|
148
|
+
if lower_gap > 0
|
|
149
|
+
(lower_outer_spread_start..lower_outer_spread_end).each { |page| html += span_or_page_link(page, options.deep_dup, false) }
|
|
150
|
+
html += content_tag(:span, "…", options[:html]) if (inner_spread_start - lower_outer_spread_end) > 1
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
(inner_spread_start..inner_spread_end).each { |page| html += span_or_page_link(page, options.deep_dup, page == options[:current_page]) }
|
|
154
|
+
|
|
155
|
+
if upper_gap > 0
|
|
156
|
+
html += content_tag(:span, "…", options[:html]) if (upper_outer_spread_start - inner_spread_end) > 1
|
|
157
|
+
(upper_outer_spread_start..upper_outer_spread_end).each { |page| html += span_or_page_link(page, options.deep_dup, false) }
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
html += span_or_page_link(:next, options.deep_dup, options[:current_page] == options[:last_page]) if options[:next]
|
|
161
|
+
html += span_or_page_link(:last, options.deep_dup, options[:current_page] == options[:last_page]) if options[:last]
|
|
162
|
+
html
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
private
|
|
166
|
+
def add_order_by_links_defaults!(options)
|
|
167
|
+
add_searchlogic_control_defaults!(options)
|
|
168
|
+
options[:choices] ||= options[:search_obj].klass.column_names.map(&:humanize)
|
|
169
|
+
options
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def add_order_as_links_defaults!(options)
|
|
173
|
+
add_searchlogic_control_defaults!(options)
|
|
174
|
+
options[:choices] = [:asc, :desc]
|
|
175
|
+
options
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def add_per_page_links_defaults!(options)
|
|
179
|
+
add_searchlogic_control_defaults!(options)
|
|
180
|
+
options[:choices] ||= Config.helpers.per_page_links_choices.dup
|
|
181
|
+
if !options[:search_obj].per_page.blank? && !choices_include?(options[:choices], options[:search_obj].per_page)
|
|
182
|
+
options[:choices] << ["#{options[:search_obj].per_page} per page", options[:search_obj].per_page]
|
|
183
|
+
options[:choices].sort! do |a, b|
|
|
184
|
+
a_value = (a.is_a?(Array) ? a.last : a).to_i
|
|
185
|
+
return -1 if a_value == 0
|
|
186
|
+
b_value = (b.is_a?(Array) ? b.last : b).to_i
|
|
187
|
+
a_value <=> b_value
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
options
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def choices_include?(choices, includes)
|
|
194
|
+
choices.each do |choice|
|
|
195
|
+
value = choice.is_a?(Array) ? choice.last : choice
|
|
196
|
+
return true if value == includes
|
|
197
|
+
end
|
|
198
|
+
false
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
def add_page_links_defaults!(options)
|
|
202
|
+
add_searchlogic_control_defaults!(options)
|
|
203
|
+
options[:first_page] ||= 1
|
|
204
|
+
options[:last_page] ||= options[:search_obj].page_count
|
|
205
|
+
options[:current_page] ||= options[:search_obj].page
|
|
206
|
+
options[:inner_spread] = Config.helpers.page_links_inner_spread unless options.has_key?(:inner_spread)
|
|
207
|
+
options[:outer_spread] = Config.helpers.page_links_outer_spread unless options.has_key?(:outer_spread)
|
|
208
|
+
options[:prev] = Config.helpers.page_links_prev unless options.has_key?(:prev)
|
|
209
|
+
options[:next] = Config.helpers.page_links_next unless options.has_key?(:next)
|
|
210
|
+
options[:first] = Config.helpers.page_links_first unless options.has_key?(:first)
|
|
211
|
+
options[:last] = Config.helpers.page_links_last unless options.has_key?(:last)
|
|
212
|
+
options
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
def span_or_page_link(name, options, span)
|
|
216
|
+
text = ""
|
|
217
|
+
page = 0
|
|
218
|
+
case name
|
|
219
|
+
when Fixnum
|
|
220
|
+
text = name
|
|
221
|
+
page = name
|
|
222
|
+
searchlogic_add_class!(options[:html], Config.helpers.page_links_current_page_class_name) if span
|
|
223
|
+
else
|
|
224
|
+
text = options[name]
|
|
225
|
+
page = options[:search_obj].send("#{name}_page")
|
|
226
|
+
searchlogic_add_class!(options[:html], Config.helpers.send("page_links_#{name}_page_class_name"))
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
if span
|
|
230
|
+
searchlogic_add_class!(options[:html], Config.helpers.page_links_disabled_class_name)
|
|
231
|
+
searchlogic_add_class!(options[:html], Config.helpers.page_link_class_name)
|
|
232
|
+
end
|
|
233
|
+
options[:text] = text
|
|
234
|
+
span ? content_tag(:span, text, options[:html]) : page_link(page, options)
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
ActionController::Base.helper Searchlogic::Helpers::ControlTypes::Links if defined?(ActionController)
|