# bivouac/helpers/view/form module BivouacHelpers module FormView # Adds AJAX autocomplete functionality to the text input field with the DOM ID specified by +field_id+. def auto_complete_field( field_id, options = nil ) if options.has_key?( :indicator ) data = options[:indicator] options[:indicator] = "indicator_#{field_id}" span( data, :id => options[:indicator], :style => "display: none" ) end choises_id = "choises_#{field_id}" div( :id => choises_id, :class => "autocomplete" ) do; end url = options.delete( :url ) javascript_tag "new Ajax.Autocompleter( '#{field_id}', '#{choises_id}', '#{url}', #{options_for_javascript(options)} );" end # Autocomplete options : # # +:url+: URL to call for autocompletion results # +:tokens+: # +:frequency+: # +:minChars+: # +:indicator+: When sending the Ajax request Autocompleter shows this # +:updateElement+: Hook for a custom function called after the element has been updated (i.e. when the user has selected an entry). # +:afterUpdateElement+: Hook for a custom function called after the element has been updated (i.e. when the user has selected an entry). # +:callback+: This function is called just before the Request is actually made, allowing you to modify the querystring that is sent to the server. # +:parameters+: If you need to send any additional parameters through your search form, add them here, in the usual {field: 'value',another: 'value'} or 'field=value&another=value' manner. def text_field(field_name, value = "", options = {}) autocomplete_options = nil if options.has_key?( :autocomplete ) unless ["on", "off"].include?( options[:autocomplete] ) autocomplete_options = Hash.new( ) autocomplete_options[:url] = options.delete( :autocomplete ) # options[:autocomplete] = "off" end end [:tokens, :frequency, :minChars, :indicator, :updateElement, :afterUpdateElement, :callback, :parameters].each do |op| if options.has_key?( op ) if autocomplete_options.nil? options.delete( op ) else autocomplete_options[op] = options.delete( op ) end end end options = { :id => "default_#{Time.now.to_i}", :type => "text", :name => field_name, :value => value }.merge( options ) input( options ) auto_complete_field( options[:id], autocomplete_options ) unless autocomplete_options.nil? end # Returns a button that'll trigger a JavaScript function using the onclick # handler. # # The function argument can be omitted in favor of an update_page block, # which evaluates to a string when the template is rendered (instead of # making an Ajax request first). def button_to_function(name, *args, &block) html_options = args.last.is_a?(Hash) ? args.pop : {} function = args[0] || '' function = update_page(&block) if block_given? input( html_options.merge({ :type => "button", :value => name, :onclick => (html_options[:onclick] ? "#{html_options[:onclick]}; " : "") + "#{function};" })) end # Returns a button input tag that will submit form using XMLHttpRequest # in the background instead of regular reloading POST arrangement. # options argument is the same as in form_remote_tag. def submit_to_remote(name, value, options = {}) options[:with] ||= 'Form.serialize(this.form)' options[:html] ||= {} options[:html][:type] = 'button' options[:html][:onclick] = "#{remote_function(options)}; return false;" options[:html][:name] = name options[:html][:value] = value input options[:html] end # Starts a form tag that points the action to an url. The method for the form defaults to POST. # # Examples: # * form_tag('/posts') => # * form_tag('/upload', :multipart => true) => # # Example: # form_tag R(Post) do # div do; input( :type => 'submit', :name => 'submit' :value => 'Save' ); end # end # # Will output: #
# # Options: # * :multipart - If set to true, the enctype is set to "multipart/form-data". # * :method - The method to use when submitting the form, usually either "get" or "post". # If "put", "delete", or another verb is used, a hidden input with name _method # is added to simulate the verb over post. def form_tag(url, options = {}, &block) options[:enctype] = "multipart/form-data" if options.delete(:multipart) options[:action] = url method_tag = false case method = options.delete(:method).to_s when /^get$/i # must be case-insentive, but can't use downcase as might be nil options[:method] = "get" when /^post$/i, "", nil options[:method] = "post" else options[:method] = "post" method_tag = true end if block_given? form( options ) do yield( ) input( :type => "hidden", :name => "_method", :value => method ) if method_tag end else form( options ) do; end end end # Returns a form tag that will submit using XMLHttpRequest in the # background instead of the regular reloading POST arrangement. Even # though it's using JavaScript to serialize the form elements, the form # submission will work just like a regular submission as viewed by the # receiving side. The options for specifying the target with :url and # defining callbacks is the same as # link_to_remote. # # A "fall-through" target for browsers that doesn't do JavaScript can be # specified with the :action/:method options on :html. # # Example: # form_remote_tag :html => { :url => R(SomePlace) } # # The Hash passed to the :html key is equivalent to the options (2nd) # argument in the form_tag method. # # By default the fall-through action is the same as the one specified in # the :url (and the default method is :post). # # form_remote_tag takes a block, like form_tag: # form_remote_tag :url => '/posts' do # div do; input( :type => 'submit', :name => 'submit' :value => 'Save' ); end # end def form_remote_tag(options = {}, &block) options[:form] = true options[:html] ||= {} options[:html][:onsubmit] = (options[:html][:onsubmit] ? options[:html][:onsubmit] + "; " : "") + "#{remote_function(options)}; return false;" form_tag( options[:html].delete(:url), options[:html], &block ) end end end