lib/country_select/tag_helper.rb
# frozen_string_literal: true
module CountrySelect
class CountryNotFoundError < StandardError; end
module TagHelper
def country_option_tags
# In Rails 5.2+, `value` accepts no arguments and must also be called
# with parens to avoid the local variable of the same name
# https://github.com/rails/rails/pull/29791
selected_option = @options.fetch(:selected) do
if self.method(:value).arity.zero?
value()
else
value(@object)
end
end
option_tags_options = {
selected: selected_option,
disabled: @options[:disabled]
}
if priority_countries.present?
options_for_select_with_priority_countries(country_options, option_tags_options)
else
options_for_select(country_options, option_tags_options)
end
end
private
def locale
@options.fetch(:locale, ::CountrySelect::DEFAULTS[:locale])
end
def priority_countries
@options.fetch(:priority_countries, ::CountrySelect::DEFAULTS[:priority_countries])
end
def priority_countries_divider
@options.fetch(:priority_countries_divider, ::CountrySelect::DEFAULTS[:priority_countries_divider])
end
def only_country_codes
@options.fetch(:only, ::CountrySelect::DEFAULTS[:only])
end
def except_country_codes
@options.fetch(:except, ::CountrySelect::DEFAULTS[:except])
end
def format
@options.fetch(:format, ::CountrySelect::DEFAULTS[:format])
end
def country_options
codes = ISO3166::Country.codes
if only_country_codes.present?
codes = only_country_codes & codes
sort = @options.fetch(:sort_provided, ::CountrySelect::DEFAULTS[:sort_provided])
else
codes -= except_country_codes if except_country_codes.present?
sort = true
end
country_options_for(codes, sorted: sort)
end
def country_options_for(country_codes, sorted: rue)
I18n.with_locale(locale) do
country_list = country_codes.map { |code_or_name| get_formatted_country(code_or_name) }
country_list.sort_by! { |name, _| [I18n.transliterate(name), name] } if sorted
country_list
end
end
def options_for_select_with_priority_countries(country_options, tags_options)
sorted = @options.fetch(:sort_provided, ::CountrySelect::DEFAULTS[:sort_provided])
priority_countries_options = country_options_for(priority_countries, sorted: sorted)
option_tags = priority_options_for_select(priority_countries_options, tags_options)
tags_options[:selected] = Array(tags_options[:selected]).delete_if do |selected|
priority_countries_options.map(&:second).include?(selected)
end
option_tags += "\n".html_safe + options_for_select(country_options, tags_options)
option_tags
end
def priority_options_for_select(priority_countries_options, tags_options)
option_tags = options_for_select(priority_countries_options, tags_options)
option_tags += "\n".html_safe +
options_for_select([priority_countries_divider], disabled: priority_countries_divider)
end
def get_formatted_country(code_or_name)
country = ISO3166::Country.new(code_or_name) ||
ISO3166::Country.find_country_by_any_name(code_or_name)
raise(CountryNotFoundError, "Could not find Country with string '#{code_or_name}'") unless country.present?
code = country.alpha2
formatted_country = ::CountrySelect::FORMATS[format].call(country)
if formatted_country.is_a?(Array)
formatted_country
else
[formatted_country, code]
end
end
end
end