Kiss A simpler, smarter web application framework for Ruby

Kiss::Form Subclass of Object

Attributes

actionwritable

Not documented

cancelwritable

Not documented

controllerwritable

Not documented

enctypewritable

Not documented

error_classwritable

Not documented

errorswritable

Not documented

field_error_classwritable

Not documented

fieldswritable

Not documented

fields_hashwritable

Not documented

has_field_errorswritable

Not documented

htmlwritable

Not documented

idwritable

Not documented

mark_requiredwritable

Not documented

methodwritable

Not documented

namewritable

Not documented

objectwritable

Not documented

objectwritable

Not documented

paramswritable

Not documented

requestwritable

Not documented

stylewritable

Not documented

submitwritable

Not documented

submittedwritable

Not documented

urlwritable

Not documented

Public Class Methods

new(attrs) source

Creates a new form object with specified attributes.

    # File lib/kiss/form.rb, line 50
    def initialize(attrs)
      set_attributes(attrs,[:name,:action])
    
      raise "Missing required option 'name'" unless @name && (@name != '')
    
      @method ||= 'post'
    
      # move field definitions to different var
      # want to use @fields for array of Field objects
      @fields_specs = @fields || []
    
      @fields = []
      @fields_hash = {}
      @default_values ||= {}
      @params = {}
    
      @fields_specs.each do |field|
        # create field here
        add_field(field)
      end
      
        @errors = []
        @field_errors = {}
    end
    

Public Instance Methods

accepted() source

Returns true if user submitted form with non-cancel submit button (non-nil submit param, not equal to cancel submit button value).

    # File lib/kiss/form.rb, line 228
    def accepted
      raise 'form missing submit field' unless @submit
      return params[@submit.name] != @submit.cancel
    end
    
add_error(*args) source

Add error message to be rendered with form. If multiple args given, first arg is field name, and second arg (error message) will render next to specified field.

    # File lib/kiss/form.rb, line 151
    def add_error(*args)
      if args.size > 2
        raise 'too many args'
      elsif args.size == 0
        raise 'at least one arg required'
      end
      
      # args.size == 1 or 2
      if args.size == 1
        if args[0].is_a?(String)
          @errors << args[0]
          return
        else
          field_name = args[0].field_name.to_s
          message = args[0].message
        end
      else # args.size == 2
        # args == [field_name, message]
        field_name = args[0].to_s
        message = args[1]
      end
      return @fields_hash[field_name].add_error(message)
    end
    
add_field(attrs) source

Creates and adds a field to the form, according to specified attributes.

    # File lib/kiss/form.rb, line 108
    def add_field(attrs)
      # create field
      field = create_field(attrs)
      
      # used with mark_required to display required fields legend
      @has_required_fields ||= attrs[:required]
      
      # add field to form array/hash
      @fields << field
      
      field
    end
    
add_section_break() source

Adds a section break, which causes form’s table to close and new table to open when form is rendered.

    # File lib/kiss/form.rb, line 76
    def add_section_break
      @fields << :section_break
    end
    
add_submit(attrs) source

Creates and adds set of submit buttons to the form, per specified attributes.

    # File lib/kiss/form.rb, line 122
    def add_submit(attrs)
      @submit = create_field({
        :type => :submit,
        :name => 'submit',
        :save => false
      }.merge(attrs) )
    end
    
create_field(attrs) source

Not documented

    # File lib/kiss/form.rb, line 80
    def create_field(attrs)
      raise "form already has field named '#{attrs[:name]}'" if @fields_hash[attrs[:name]]
      
      attrs[:type] ||= :text
      type = attrs[:type].to_sym
      type = attrs[:type] = :text unless @@field_types.has_key?(type)
      
      field_class = @@field_types[type]
      field = field_class.new(self,attrs)
      
      field_name = field.name.to_s
      field.form = self
      
      while true
        other_field = field.other_field
        break unless other_field
        other_field.form = self
        @other_field = @form.create_field( { :name => @name + '.other' }.merge(@other) )
      end
      
      @fields_hash[field_name] = field
      
      @enctype = 'multipart/form-data' if field.type == :file
      
      field
    end
    
errors_html() source

Renders error HTML block for top of form, and returns as string.

    # File lib/kiss/form.rb, line 234
    def errors_html
      return nil unless has_errors
      
      @errors << "Please correct the errors highlighted below." if @has_field_errors
      
      if @errors.size == 1
        content = @errors[0]
      else
        content = "<ul>" + @errors.map {|e| "<li>#{e}</li>"}.join + "</ul>"
      end
      
      @errors.pop if @has_field_errors
      
      plural = @errors.size > 1 || @has_field_errors ? 's' : nil
      %Q(<div class="kiss_error">#{content}</div><br clear="all" />)
    end
    
field_html(field) source

Renders HTML for specified form field.

    # File lib/kiss/form.rb, line 412
    def field_html(field)
      type = field.type
      prompt = field.prompt
      label = field.label
      errors = field.errors_html
      required = field.required ? %Q(<span class="kiss_required">#{@mark_required}</span> ) : ''
      
      ([
          prompt ? %Q(<tr class="kiss_prompt"><td class="kiss_label">#{required}</td><td>#{prompt.to_s}</td></tr>) : '',
          
        %Q(<tr class="kiss_#{type}"><td class="kiss_label#{errors ? ' error' : ''}">),
        !prompt ? (required + (label ? label.to_s + ':' : '' )) : '',
          %Q(</td><td class="kiss_#{type}">),
                field.element_html, "</td></tr>"
        ] + (errors ? [
          '<tr class="kiss_form_error_row"><td class="kiss_required"></td><td>',
          errors,
          '</td></tr>'
        ] : [])).join
    end
    
fields_html() source

Renders form fields HTML.

    # File lib/kiss/form.rb, line 375
    def fields_html
      @fields.map do |field|
        field == :section_break ? begin
          table_html_close + table_html_open
        end : field_html(field)
      end.join
    end
    
has_errors() source

Returns true if form has errors.

    # File lib/kiss/form.rb, line 205
    def has_errors
      (@errors.size > 0 || @has_field_errors)
    end
    
html() source

Renders complete form HTML.

    # File lib/kiss/form.rb, line 400
    def html
      return [
        html_open,
        table_html_open,
        fields_html,
        submit_html,
        table_html_close,
        html_close
      ].flatten.join
    end
    
html_close() source

Renders end of form (form close tag).

    # File lib/kiss/form.rb, line 370
    def html_close
      '</div></form>'
    end
    
html_open() source

Renders beginning of form (form open tag and form/field/error styles).

    # File lib/kiss/form.rb, line 257
    def html_open
      @error_class ||= 'kiss_form_error_message'
      @field_error_class ||= @error_class
      
      # form tag
      form_attrs = ['method','enctype','class','style'].map do |attr|
        "#{attr}=\"#{send attr}\""
      end.join(' ')
      form_tag = %Q(<form action="#{@action}" #{form_attrs}><input type=hidden name="form" value="#{@name}">)
      
      # style tag
      styles = []
      styles.push( "table.kiss_form {\nmargin-bottom: 6px;\n}\n.kiss_form td {\npadding: 2px 4px;\nvertical-align: middle;\n}\n.kiss_form .kiss_error {\nbackground-color: #ff8;\npadding: 2px 4px;\nline-height: 135%;\nfloat: left;\ncolor: #900;\nborder: 1px solid #ea4;\nmargin-bottom: 4px;\n}\n.kiss_form .kiss_error ul {\npadding-left: 16px;\nmargin: 0;\n}\n.kiss_form .kiss_help {\npadding: 0px 3px 0 6px;\nfont-size: 90%;\ncolor: #555;\n}\n.kiss_required {\ncolor: #a21;\nfont-size: 150%;\nline-height: 50%;\nposition: relative;\ntop: 4px;\n}\n.kiss_form td.kiss_label {\ntext-align: right;\nwhite-space: nowrap;\n}\n.kiss_form td.kiss_label.error {\ncolor: #b10;\n}\n.kiss_form tr.kiss_prompt td {\npadding: 8px 3px 0px 4px;\n}\n.kiss_form tr.kiss_submit td.kiss_submit {\npadding: 6px 3px;\n}\n.kiss_form input[type=\"text\"],.kiss_form input[type=password],.kiss_form textarea {\nwidth: 250px;\nmargin-left: 0;\nmargin-right: 0;\n}\n"
      )
      styles.push( ".kiss_form_error_message {\npadding: 1px 4px;\nborder: 1px solid #edc;\nborder-top: 0;\nborder-bottom: 1px solid #db4;\nbackground-color: #ff8;\ncolor: #900;\nfont-size: 90%;\nline-height: 135%;\ndisplay: block;\nfloat: left;\nmargin-bottom: 2px;\n}\n.kiss_form_error_message div {\ncolor: #c00;\nfont-weight: bold;\n}\n.kiss_form_error_message ul {\npadding-left: 16px;\nmargin: 0;\n}\ntr.kiss_form_error_row td {\npadding-top: 0;\n}\ntr.kiss_form_error_row .kiss_form_error_message {\nposition: relative;\ntop: -2px;\nmargin-bottom: 0;\n}\n.kiss_form table.kiss_field_columns {\nborder-spacing: 0;\nborder-collapse: collapse;\n}\n.kiss_form table.kiss_field_columns td {\npadding: 0 0 2px 0;\n}\n"
      ) if @error_class == 'kiss_form_error_message'
      style_tag = styles.size == 0 ? '' : "<style>" + styles.join('') + "</style>"
      
      # combine
      return %Q(#{form_tag}#{style_tag}<div class="kiss_form">#{errors_html})
    end
    
process(object = @object) source

Checks whether form was submitted and accepted by user and, if so, whether form validates. If form validates, saves form values to form’s Sequel::Model object and returns true. Otherwise, returns false.

    # File lib/kiss/form.rb, line 213
    def process(object = @object)
      return false unless submitted
      
      if accepted
        validate
        return false if has_errors
      
        save(object)
      end
          
        return true
    end
    
render(options = {}) source

Renders current action using form’s HTML as action render content.

    # File lib/kiss/form.rb, line 252
    def render(options = {})
      @request.render options.merge(:content => html)
    end
    
save(object = @object) source

Saves form values to Sequel::Model object.

    # File lib/kiss/form.rb, line 186
    def save(object = @object)
      @fields.each do |field|
        next if field == :section_break
                # ignore fields whose name starts with underscore
        next if field.name =~ /\A\_/
                # don't save 'ignore' fields to the database
        next if field.ignore || !field.save
        
        value = (field.value != nil || object.class.db_schema[field.name.to_sym].allow_null) ?
          field.value : (object.class.db_schema[field.name.to_sym][:default] ||= field.format.default)
        
        object[field.name.to_sym] = field.save == true ? value :
          (digest_class = Kiss.digest_class(field.save)) ? digest_class.hexdigest(value) : value
      end
      
      object.save
    end
    
submit_html() source

Renders form submit buttons.

    # File lib/kiss/form.rb, line 395
    def submit_html
      @submit ? field_html(@submit) : ''
    end
    
table_html_close() source

Renders close of form table.

    # File lib/kiss/form.rb, line 390
    def table_html_close
      '</table>'
    end
    
table_html_open() source

Renders open of form table.

    # File lib/kiss/form.rb, line 384
    def table_html_open
      %Q(<table class="kiss_form" border=0 cellspacing=0>) +
        (@has_required_fields && @mark_required ? %Q( <tr><td></td><td class="kiss_help">Required fields marked by <span class="kiss_required">*</span></td></tr> ) : '')
    end
    
validate() source

Validates form values against fields’ format and required attributes, and returns values unless form has errors.

    # File lib/kiss/form.rb, line 177
    def validate
      return nil unless submitted
      
        @fields.each {|field| field.validate unless field == :section_break }
          
          has_errors ? nil : values
    end
    
values() source

Gets hash of form values.

    # File lib/kiss/form.rb, line 140
    def values
      @values ||= begin
        hash = {}
        @fields.each {|field| hash[field.name] = field.value unless field == :section_break}
        hash
      end
    end
    

Disabled; run with $DEBUG to generate this.