2011-03-31 00:31:39 +00:00
|
|
|
module Ransack
|
|
|
|
module Helpers
|
|
|
|
module FormHelper
|
2011-08-13 20:36:40 +00:00
|
|
|
|
2014-12-07 19:38:51 +00:00
|
|
|
# +search_form_for+
|
|
|
|
#
|
|
|
|
# Example: <%= search_form_for(@q) do |f| %>
|
|
|
|
#
|
2011-03-31 00:31:39 +00:00
|
|
|
def search_form_for(record, options = {}, &proc)
|
2014-12-07 19:38:51 +00:00
|
|
|
if record.is_a? Ransack::Search
|
2011-03-31 00:31:39 +00:00
|
|
|
search = record
|
2014-04-18 08:49:38 +00:00
|
|
|
options[:url] ||= polymorphic_path(
|
|
|
|
search.klass, format: options.delete(:format)
|
|
|
|
)
|
2014-12-07 19:38:51 +00:00
|
|
|
elsif record.is_a? Array &&
|
|
|
|
(search = record.detect { |o| o.is_a? Ransack::Search })
|
2013-08-04 13:13:41 +00:00
|
|
|
options[:url] ||= polymorphic_path(
|
2014-12-07 19:38:51 +00:00
|
|
|
record.map { |o| o.is_a? Ransack::Search ? o.klass : o },
|
2014-04-18 08:49:38 +00:00
|
|
|
format: options.delete(:format)
|
2013-12-10 18:18:17 +00:00
|
|
|
)
|
2011-03-31 00:31:39 +00:00
|
|
|
else
|
2013-08-04 13:13:41 +00:00
|
|
|
raise ArgumentError,
|
2014-12-07 19:38:51 +00:00
|
|
|
'No Ransack::Search object was provided to search_form_for!'
|
2011-03-31 00:31:39 +00:00
|
|
|
end
|
|
|
|
options[:html] ||= {}
|
|
|
|
html_options = {
|
2014-05-01 13:55:39 +00:00
|
|
|
:class => options[:class].present? ?
|
2013-12-10 18:18:17 +00:00
|
|
|
"#{options[:class]}" :
|
|
|
|
"#{search.klass.to_s.underscore}_search",
|
2014-05-01 13:55:39 +00:00
|
|
|
:id => options[:id].present? ?
|
2013-12-10 18:18:17 +00:00
|
|
|
"#{options[:id]}" :
|
|
|
|
"#{search.klass.to_s.underscore}_search",
|
2014-05-01 13:55:39 +00:00
|
|
|
:method => :get
|
2011-03-31 00:31:39 +00:00
|
|
|
}
|
2014-11-15 19:56:19 +00:00
|
|
|
options[:as] ||= Ransack.options[:search_key]
|
2011-03-31 00:31:39 +00:00
|
|
|
options[:html].reverse_merge!(html_options)
|
|
|
|
options[:builder] ||= FormBuilder
|
|
|
|
|
|
|
|
form_for(record, options, &proc)
|
|
|
|
end
|
|
|
|
|
2014-12-07 19:38:51 +00:00
|
|
|
# +sort_link+
|
|
|
|
#
|
|
|
|
# Example: <%= sort_link(@q, :name, [:name, 'kind ASC'], 'Player Name') %>
|
|
|
|
#
|
2011-08-13 20:36:40 +00:00
|
|
|
def sort_link(search, attribute, *args)
|
2014-12-07 19:38:51 +00:00
|
|
|
@search_object, routing_proxy = extract_search_obj_and_routing(search)
|
|
|
|
raise TypeError, 'First argument must be a Ransack::Search!' unless
|
|
|
|
Search === @search_object
|
|
|
|
initialize!(search, attribute, args)
|
|
|
|
link_to(name, url(routing_proxy), html_options(args))
|
|
|
|
end
|
2012-03-28 19:00:19 +00:00
|
|
|
|
2014-12-07 19:38:51 +00:00
|
|
|
private
|
2011-08-13 20:36:40 +00:00
|
|
|
|
2014-12-07 19:38:51 +00:00
|
|
|
# All mutation and order-dependent code happens here.
|
|
|
|
# Ivars are not mutated outside of this method.
|
|
|
|
def initialize!(search, attribute, args)
|
|
|
|
@field_name = attribute.to_s
|
2014-12-07 20:58:29 +00:00
|
|
|
sort_fields, args = extract_sort_fields(args)
|
2014-12-07 19:38:51 +00:00
|
|
|
@label_text, args = extract_label_text(args)
|
|
|
|
@options, args = extract_options(args)
|
|
|
|
@hide_indicator = @options.delete :hide_indicator
|
|
|
|
@default_order = @options.delete :default_order
|
|
|
|
if Hash === @default_order
|
2014-12-07 19:48:57 +00:00
|
|
|
@default_order = @default_order.with_indifferent_access
|
2014-12-07 19:38:51 +00:00
|
|
|
end
|
2014-12-07 20:58:29 +00:00
|
|
|
@sort_params = initialize_sort_params(sort_fields)
|
2014-12-07 19:48:57 +00:00
|
|
|
@sort_params = @sort_params.first if @sort_params.size == 1
|
|
|
|
@current_dir = existing_sort_direction
|
2014-12-07 19:38:51 +00:00
|
|
|
end
|
Add multiple sort field support in sort_link
This patch allows users to sort on multiple fields with the sort_link
helper.
To specify sorting on multiple fields:
sort_link(:kind, [:kind, 'name asc'])
This will create a sort link that sorts first by kind, and then by
name. The first `:kind` parameter ensures that the link generated
shows the sort status of the `kind` field.
When you specify a sort direction in the sort fields array, the
direction is locked to that direction. In the above example, clicking
the resulting link would toggle sorting of the kind field, but the name
field would always sort ascending.
Also added was the ability to specify multiple default_order fields
with a hash:
sort_link(:kind, [:kind, :name],
:default_order => { :name => 'asc', :kind => 'desc' })
Clicking the resulting link will toggle the sort directions of both
`name` and `kind`, sorting the `name` field by default ascending, and
the `kind` field descending.
2014-09-30 22:58:33 +00:00
|
|
|
|
2014-12-07 19:38:51 +00:00
|
|
|
def name
|
|
|
|
[ERB::Util.h(@label_text), order_indicator]
|
|
|
|
.compact.join(Constants::NON_BREAKING_SPACE).html_safe
|
Add multiple sort field support in sort_link
This patch allows users to sort on multiple fields with the sort_link
helper.
To specify sorting on multiple fields:
sort_link(:kind, [:kind, 'name asc'])
This will create a sort link that sorts first by kind, and then by
name. The first `:kind` parameter ensures that the link generated
shows the sort status of the `kind` field.
When you specify a sort direction in the sort fields array, the
direction is locked to that direction. In the above example, clicking
the resulting link would toggle sorting of the kind field, but the name
field would always sort ascending.
Also added was the ability to specify multiple default_order fields
with a hash:
sort_link(:kind, [:kind, :name],
:default_order => { :name => 'asc', :kind => 'desc' })
Clicking the resulting link will toggle the sort directions of both
`name` and `kind`, sorting the `name` field by default ascending, and
the `kind` field descending.
2014-09-30 22:58:33 +00:00
|
|
|
end
|
|
|
|
|
2014-12-07 19:38:51 +00:00
|
|
|
def url(routing_proxy)
|
|
|
|
if routing_proxy && respond_to?(routing_proxy)
|
2014-12-07 19:49:53 +00:00
|
|
|
send(routing_proxy).url_for(options_for_url)
|
2014-10-07 03:25:21 +00:00
|
|
|
else
|
2014-12-07 19:49:53 +00:00
|
|
|
url_for(options_for_url)
|
2014-10-07 03:25:21 +00:00
|
|
|
end
|
2014-12-07 19:38:51 +00:00
|
|
|
end
|
Add multiple sort field support in sort_link
This patch allows users to sort on multiple fields with the sort_link
helper.
To specify sorting on multiple fields:
sort_link(:kind, [:kind, 'name asc'])
This will create a sort link that sorts first by kind, and then by
name. The first `:kind` parameter ensures that the link generated
shows the sort status of the `kind` field.
When you specify a sort direction in the sort fields array, the
direction is locked to that direction. In the above example, clicking
the resulting link would toggle sorting of the kind field, but the name
field would always sort ascending.
Also added was the ability to specify multiple default_order fields
with a hash:
sort_link(:kind, [:kind, :name],
:default_order => { :name => 'asc', :kind => 'desc' })
Clicking the resulting link will toggle the sort directions of both
`name` and `kind`, sorting the `name` field by default ascending, and
the `kind` field descending.
2014-09-30 22:58:33 +00:00
|
|
|
|
2014-12-07 19:49:53 +00:00
|
|
|
def options_for_url
|
|
|
|
@options[@search_object.context.search_key] = search_and_sort_params
|
|
|
|
params.merge(@options)
|
2014-12-07 19:38:51 +00:00
|
|
|
end
|
2014-10-03 18:54:20 +00:00
|
|
|
|
2014-12-07 19:38:51 +00:00
|
|
|
def search_and_sort_params
|
|
|
|
search_params.merge(:s => @sort_params)
|
2014-12-06 22:58:03 +00:00
|
|
|
end
|
Add multiple sort field support in sort_link
This patch allows users to sort on multiple fields with the sort_link
helper.
To specify sorting on multiple fields:
sort_link(:kind, [:kind, 'name asc'])
This will create a sort link that sorts first by kind, and then by
name. The first `:kind` parameter ensures that the link generated
shows the sort status of the `kind` field.
When you specify a sort direction in the sort fields array, the
direction is locked to that direction. In the above example, clicking
the resulting link would toggle sorting of the kind field, but the name
field would always sort ascending.
Also added was the ability to specify multiple default_order fields
with a hash:
sort_link(:kind, [:kind, :name],
:default_order => { :name => 'asc', :kind => 'desc' })
Clicking the resulting link will toggle the sort directions of both
`name` and `kind`, sorting the `name` field by default ascending, and
the `kind` field descending.
2014-09-30 22:58:33 +00:00
|
|
|
|
2014-12-07 19:38:51 +00:00
|
|
|
def search_params
|
|
|
|
params[@search_object.context.search_key].presence ||
|
2013-12-10 18:18:17 +00:00
|
|
|
{}.with_indifferent_access
|
Add multiple sort field support in sort_link
This patch allows users to sort on multiple fields with the sort_link
helper.
To specify sorting on multiple fields:
sort_link(:kind, [:kind, 'name asc'])
This will create a sort link that sorts first by kind, and then by
name. The first `:kind` parameter ensures that the link generated
shows the sort status of the `kind` field.
When you specify a sort direction in the sort fields array, the
direction is locked to that direction. In the above example, clicking
the resulting link would toggle sorting of the kind field, but the name
field would always sort ascending.
Also added was the ability to specify multiple default_order fields
with a hash:
sort_link(:kind, [:kind, :name],
:default_order => { :name => 'asc', :kind => 'desc' })
Clicking the resulting link will toggle the sort directions of both
`name` and `kind`, sorting the `name` field by default ascending, and
the `kind` field descending.
2014-09-30 22:58:33 +00:00
|
|
|
end
|
2011-08-13 20:36:40 +00:00
|
|
|
|
2014-12-07 19:38:51 +00:00
|
|
|
def html_options(args)
|
|
|
|
html_options = extract_options(args).first
|
|
|
|
html_options.merge(class: [css, html_options[:class]]
|
|
|
|
.compact.join(Constants::SPACE))
|
2014-12-06 22:58:03 +00:00
|
|
|
end
|
2011-08-13 20:36:40 +00:00
|
|
|
|
2014-12-07 19:38:51 +00:00
|
|
|
def css
|
|
|
|
[Constants::SORT_LINK, @current_dir].compact.join(Constants::SPACE)
|
|
|
|
end
|
2012-03-07 19:31:13 +00:00
|
|
|
|
2014-12-07 19:38:51 +00:00
|
|
|
def extract_search_obj_and_routing(search)
|
|
|
|
if search.is_a? Array
|
|
|
|
[search.second, search.first]
|
|
|
|
else
|
|
|
|
[search, nil]
|
|
|
|
end
|
|
|
|
end
|
2014-10-03 18:54:20 +00:00
|
|
|
|
2014-12-07 19:38:51 +00:00
|
|
|
def extract_sort_fields(args)
|
|
|
|
if Array === args.first
|
|
|
|
[args.shift, args]
|
|
|
|
else
|
|
|
|
[Array(@field_name), args]
|
|
|
|
end
|
|
|
|
end
|
2011-08-13 20:36:40 +00:00
|
|
|
|
2014-12-07 19:38:51 +00:00
|
|
|
def extract_label_text(args)
|
|
|
|
if String === args.first
|
|
|
|
[args.shift, args]
|
|
|
|
else
|
|
|
|
[Translate.attribute(@field_name, :context => @search_object.context), args]
|
|
|
|
end
|
|
|
|
end
|
2011-08-13 20:36:40 +00:00
|
|
|
|
2014-12-07 19:38:51 +00:00
|
|
|
def extract_options(args)
|
|
|
|
if args.first.is_a? Hash
|
|
|
|
[args.shift, args]
|
2014-12-06 22:58:03 +00:00
|
|
|
else
|
2014-12-07 19:38:51 +00:00
|
|
|
[{}, args]
|
2014-12-06 22:58:03 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2014-12-07 20:58:29 +00:00
|
|
|
def initialize_sort_params(sort_fields)
|
|
|
|
sort_fields.each_with_object([]) do |field, a|
|
2014-12-06 22:58:03 +00:00
|
|
|
attr_name, new_dir = field.to_s.split(/\s+/)
|
2014-12-07 19:38:51 +00:00
|
|
|
if no_sort_direction_specified?(new_dir)
|
|
|
|
new_dir = detect_previous_sort_direction_and_invert_it(attr_name)
|
2014-12-06 22:58:03 +00:00
|
|
|
end
|
2014-12-07 20:56:44 +00:00
|
|
|
a << "#{attr_name} #{new_dir}"
|
2014-12-06 22:58:03 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2014-12-07 19:38:51 +00:00
|
|
|
def detect_previous_sort_direction_and_invert_it(attr_name)
|
|
|
|
sort_dir = existing_sort_direction(attr_name)
|
|
|
|
if sort_dir
|
|
|
|
direction_text(sort_dir)
|
2014-12-06 22:58:03 +00:00
|
|
|
else
|
2014-12-07 20:56:44 +00:00
|
|
|
default_sort_order(attr_name) || Constants::ASC
|
2014-12-06 22:58:03 +00:00
|
|
|
end
|
|
|
|
end
|
2014-10-03 18:54:20 +00:00
|
|
|
|
2014-12-07 19:38:51 +00:00
|
|
|
def existing_sort_direction(attr_name = @field_name)
|
2014-12-07 20:56:44 +00:00
|
|
|
if sort = @search_object.sorts.detect { |s| s.name == attr_name }
|
|
|
|
sort.dir
|
2014-12-07 19:38:51 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2014-12-07 20:56:44 +00:00
|
|
|
def default_sort_order(attr_name)
|
2014-12-07 19:38:51 +00:00
|
|
|
Hash === @default_order ? @default_order[attr_name] : @default_order
|
2014-12-06 22:58:03 +00:00
|
|
|
end
|
|
|
|
|
2014-12-07 19:38:51 +00:00
|
|
|
def order_indicator
|
|
|
|
if @hide_indicator || no_sort_direction_specified?
|
2014-12-06 22:58:03 +00:00
|
|
|
nil
|
|
|
|
else
|
2014-12-07 19:38:51 +00:00
|
|
|
direction_arrow
|
2014-12-06 22:58:03 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2014-12-07 19:38:51 +00:00
|
|
|
def no_sort_direction_specified?(dir = @current_dir)
|
2014-12-06 22:58:03 +00:00
|
|
|
Constants::ASC_DESC.none? { |d| d == dir }
|
|
|
|
end
|
|
|
|
|
2014-12-07 19:38:51 +00:00
|
|
|
def direction_arrow
|
|
|
|
if @current_dir == Constants::DESC
|
2014-12-06 22:58:03 +00:00
|
|
|
Constants::DESC_ARROW
|
|
|
|
else
|
|
|
|
Constants::ASC_ARROW
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def direction_text(dir)
|
|
|
|
if dir == Constants::DESC
|
|
|
|
Constants::ASC
|
|
|
|
else
|
|
|
|
Constants::DESC
|
|
|
|
end
|
2011-08-13 20:36:40 +00:00
|
|
|
end
|
|
|
|
|
2011-03-31 00:31:39 +00:00
|
|
|
end
|
|
|
|
end
|
2012-04-11 15:58:27 +00:00
|
|
|
end
|