module DataMapper
module Is
##
# = dm-is-select
#
# A DataMapper plugin that makes getting the options from a Model easier.
#
#
#
module Select
##
# Defines the field to use for the select menu
#
# ==== Params
#
# * :field_name => the name of the field values shown in select
# * :options
# * :is_tree => whether if the current Model is an is :tree model
#
# ==== Examples
#
#
# is :select, :name
# => creates a options array on the :name attribute of the model
#
# is :select, :name, :is_tree => true
# => creates a options array with the results ordered in hierarchical order
# parent > child > grandchild for each parent
#
#
# @api public
def is_select(select_field = :name, options = {})
raise ArgumentError, "The :select_field, must be an existing attribute in the Model. Got [ #{select_field.inspect} ]" unless properties.any?{ |p| p.name == select_field.to_sym }
@select_options = {
# add specical features if we are working with Tree Model
:is_tree => false,
}.merge(options)
@select_field = select_field
# Add class & Instance methods
extend DataMapper::Is::Select::ClassMethods
# include DataMapper::Is::Select::InstanceMethods
end
module ClassMethods
attr_reader :select_field, :select_options
##
# Provides the Model content in a ready to use options array
#
# ==== Params
#
# * :options
# * :prompt [String/Boolean] => The text shown on the field in the browser. (Defaults to "Select NameOfYourModel")
# * :divider [Boolean] => Whether to add a divider/separator between the prompt and the main options. (Defaults to +true+)
# * :order [Array] => A normal DM order declaration. (Defaults to [:name] or the name of the select_field declared)
# * :show_root [Boolean] => Whether to add the Top Level Parent in the choices. (Defaults to +true+)
# * :root_text [String] => The text to show as the Parent item in select list. (Defaults to "Top Level NameOfYourModel")
#
# ==== Examples
#
# Category.items_for_select_menu
# => [ ['Select Category',nil], ['---', nil], ['Category 1',1] ,....]
#
# Category.items_for_select_menu(:prompt => "Custom Prompt")
# => [ ['Custom Prompt',nil],...]
#
# Category.items_for_select_menu(:prompt => false)
# => [ ['Category 1',1] ,...]
#
# Category.items_for_select_menu(:divider => false )
# => array without the ['---', nil] node
#
# Category.items_for_select_menu(:order => [ :id.desc ] )
# => array with the order reversed. (Prompts & divider always comes first)
#
# If your model is a Tree:
#
# Category.items_for_select_menu(:root_text => "Custom Root Text") # sets the text for the Top Level (root) Parent
# => [ ..., ['Custom Root Text', 0],...]
#
# Category.items_for_select_menu(:show_root => false) # removes the Top Level (root) Parent from the
#
#
# @api public
def items_for_select_menu(options={})
options = {
:prompt => "Select #{self.name}",
:divider => true,
:order => [self.select_field.to_sym],
:show_root => true,
:root_text => "Top Level #{self.name}",
}.merge(options)
mi = self.select_options[:is_tree] ?
all(:parent_id => 0, :order => options[:order] ) :
all(:order => options[:order])
res = []
if options[:prompt]
res << [options[:prompt],nil]
res << [" ------ ",'nil'] if options[:divider]
if self.select_options[:is_tree]
if options[:show_root]
res << [options[:root_text], 0]
res << [" ------ ",'nil'] if options[:divider]
end
end
end
if self.select_options[:is_tree]
mi.each do |x|
res << [x.send(self.select_field), x.id]
unless x.children.blank?
x.children.each do |child|
res << ["-- #{child.send(self.select_field)}", child.id]
child.children.each do |grand_child|
res << ["-- -- #{grand_child.send(self.select_field)}", grand_child.id]
end unless child.children.blank?
end
end
end
else
mi.each do |x|
res << [x.send(self.select_field), x.id]
end
end
res
end
end # ClassMethods
# module InstanceMethods
#
# end # InstanceMethods
end # Select
end # Is
Model.append_extensions(Is::Select)
end # DataMapper