require 'nitro/helper/xhtml' module Nitro # :section: Property controls. # A Form control. class Control include Nitro::XhtmlHelper # Fetch the instance vars in a nice way use either rel # or prop. # # values/value contain the contents of the prop or rel, # (values reads better for relations) attr_reader :prop alias_method :rel, :prop attr_reader :obj attr_reader :value alias_method :values, :value # setup instance vars to use in methods def initialize(obj, key, value=nil) @obj = obj @prop = key @value = value || obj.send(key.name.to_sym) end # Main bulk of the control. Overide to customise def render "No view for this control" end # Label item. Override to customise def label %{} end # Custom callback to process the request information # posted back from the form # # When Property.populate_object (or fill) is called # with the :preprocess => true option then this # method will get called before the value is pushed # onto the object that is getting 'filled' # # Overide this on controls that require special mods # to the incoming values def on_populate(val) puts "PREPROCESSING !" return val end private def emit_style if prop.respond_to?(:control_style) style = prop.control_style elsif self.class.respond_to?(:style) style = self.class.style else style = nil end style ? %{ style="#{style}"} : '' end end # Fixnum class FixnumControl < Control setting :style, :default => 'width: 100px', :doc => 'The default style' def render style = prop.control_style ||self.class.style %{ + -} end end # Float class FloatControl < Control setting :style, :default => 'width: 100px', :doc => 'The default style' def render style = prop.control_style ||self.class.style %{ + -} end end # Text class TextControl < Control setting :style, :default => 'width: 250px', :doc => 'The default style' def render %{} end end # Textarea class TextareaControl < Control setting :style, :default => 'width: 500px; height: 100px', :doc => 'The default style' def render %{} end end # CheckboxControl < Control class CheckboxControl < Control setting :style, :default => '', :doc => 'The default style' def render checked = value == true ? ' checked="checked"':'' %{} end end # :section: Relation controls. # RefersTo. Also used for BelongsTo. class RefersToControl < Control def render objs = rel.target_class.all if selected = value selected = selected.pk end str = %{} return str end end # HasMany, ManyToMany and JoinsMany class HasManyControl < Control #pre :do_this, :on => :populate_object def render str = emit_container_start str << emit_js if selected_items.empty? str << emit_selector(all_items, :removable => false) else removable = selected_items.size != 1 ? true : false selected_items.each do |item| str << emit_selector(all_items, :selected => item.pk) end end str << emit_container_end end private # these parts are seperated from render to make it easier # to extend and customise the HasManyControl def all_items rel.target_class.all end def selected_items values end def emit_container_start %{
} end def emit_container_end %{
} end # :removable controls wether the minus button is active # :selected denotes the oid to flag as selected in the list def emit_selector(items, options={}) removable = options.fetch(:removable, true) %{
} end # Inline script: override this to change behavior def emit_js %{ } end end # The controls map. class Control # Setup the mapping of names => control classes setting :map, :doc => 'Mappings of control names => classes', :default => { :fixnum => FixnumControl, :float => FloatControl, :boolean => CheckboxControl, :checkbox => CheckboxControl, :string => TextControl, :textarea => TextareaControl, :true_class => CheckboxControl, :refers_to => RefersToControl, :belongs_to => RefersToControl, :has_many => HasManyControl, :many_to_many => HasManyControl, :joins_many => HasManyControl } # Fetch a control, setup for 'obj' for a property, or relation # or :symbol defaults to Control if not found def self.fetch(obj, key, missing=self) if key.kind_of? Og::Relation control_sym = key[:control] || key.class.to_s.demodulize.underscore.to_sym elsif key.kind_of? Property control_sym = key[:control] || key.klass.to_s.underscore.to_sym else control_sym = key.to_sym end self.map.fetch(control_sym, missing).new(obj, key) end end end # * George Moschovitis # * Chris Farmiloe