padrino-helpers 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. data/.document +5 -0
  2. data/.gitignore +21 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +7 -0
  5. data/Rakefile +58 -0
  6. data/VERSION +1 -0
  7. data/lib/padrino-helpers.rb +16 -0
  8. data/lib/padrino-helpers/asset_tag_helpers.rb +97 -0
  9. data/lib/padrino-helpers/form_builder/abstract_form_builder.rb +139 -0
  10. data/lib/padrino-helpers/form_builder/standard_form_builder.rb +37 -0
  11. data/lib/padrino-helpers/form_helpers.rb +194 -0
  12. data/lib/padrino-helpers/format_helpers.rb +74 -0
  13. data/lib/padrino-helpers/output_helpers.rb +98 -0
  14. data/lib/padrino-helpers/render_helpers.rb +63 -0
  15. data/lib/padrino-helpers/tag_helpers.rb +42 -0
  16. data/test/active_support_helpers.rb +7 -0
  17. data/test/fixtures/markup_app/app.rb +61 -0
  18. data/test/fixtures/markup_app/views/capture_concat.erb +14 -0
  19. data/test/fixtures/markup_app/views/capture_concat.haml +13 -0
  20. data/test/fixtures/markup_app/views/content_for.erb +11 -0
  21. data/test/fixtures/markup_app/views/content_for.haml +9 -0
  22. data/test/fixtures/markup_app/views/content_tag.erb +11 -0
  23. data/test/fixtures/markup_app/views/content_tag.haml +9 -0
  24. data/test/fixtures/markup_app/views/fields_for.erb +8 -0
  25. data/test/fixtures/markup_app/views/fields_for.haml +6 -0
  26. data/test/fixtures/markup_app/views/form_for.erb +56 -0
  27. data/test/fixtures/markup_app/views/form_for.haml +47 -0
  28. data/test/fixtures/markup_app/views/form_tag.erb +57 -0
  29. data/test/fixtures/markup_app/views/form_tag.haml +45 -0
  30. data/test/fixtures/markup_app/views/link_to.erb +5 -0
  31. data/test/fixtures/markup_app/views/link_to.haml +4 -0
  32. data/test/fixtures/markup_app/views/mail_to.erb +3 -0
  33. data/test/fixtures/markup_app/views/mail_to.haml +3 -0
  34. data/test/fixtures/render_app/app.rb +53 -0
  35. data/test/fixtures/render_app/views/erb/test.erb +1 -0
  36. data/test/fixtures/render_app/views/haml/test.haml +1 -0
  37. data/test/fixtures/render_app/views/template/_user.haml +7 -0
  38. data/test/fixtures/render_app/views/template/haml_template.haml +1 -0
  39. data/test/fixtures/render_app/views/template/some_template.haml +2 -0
  40. data/test/helper.rb +73 -0
  41. data/test/test_asset_tag_helpers.rb +127 -0
  42. data/test/test_form_builder.rb +611 -0
  43. data/test/test_form_helpers.rb +406 -0
  44. data/test/test_format_helpers.rb +96 -0
  45. data/test/test_output_helpers.rb +63 -0
  46. data/test/test_render_helpers.rb +78 -0
  47. data/test/test_tag_helpers.rb +73 -0
  48. metadata +174 -0
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,21 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Padrino
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,7 @@
1
+ = padrino-helpers
2
+
3
+ Description goes here.
4
+
5
+ == Copyright
6
+
7
+ Copyright (c) 2009 Padrino. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,58 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "padrino-helpers"
8
+ gem.summary = "Helpers for padrino"
9
+ gem.description = "Tag helpers, asset helpers, form helpers, form builders and many more helpers for padrino"
10
+ gem.email = "nesquena@gmail.com"
11
+ gem.homepage = "http://github.com/padrino/padrino-helpers"
12
+ gem.authors = ["Padrino Team", "Nathan Esquenazi", "Davide D'Agostino", "Arthur Chiu"]
13
+ gem.add_runtime_dependency "sinatra", ">= 0.9.2"
14
+ gem.add_development_dependency "haml", ">= 2.2.1"
15
+ gem.add_development_dependency "shoulda", ">= 0"
16
+ gem.add_development_dependency "mocha", ">= 0.9.7"
17
+ gem.add_development_dependency "rack-test", ">= 0.5.0"
18
+ gem.add_development_dependency "webrat", ">= 0.5.1"
19
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
20
+ end
21
+ Jeweler::GemcutterTasks.new
22
+ rescue LoadError
23
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
24
+ end
25
+
26
+ require 'rake/testtask'
27
+ Rake::TestTask.new(:test) do |test|
28
+ test.libs << 'lib' << 'test'
29
+ test.pattern = 'test/**/test_*.rb'
30
+ test.verbose = true
31
+ end
32
+
33
+ begin
34
+ require 'rcov/rcovtask'
35
+ Rcov::RcovTask.new do |test|
36
+ test.libs << 'test'
37
+ test.pattern = 'test/**/test_*.rb'
38
+ test.verbose = true
39
+ end
40
+ rescue LoadError
41
+ task :rcov do
42
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
43
+ end
44
+ end
45
+
46
+ task :test => :check_dependencies
47
+
48
+ task :default => :test
49
+
50
+ require 'rake/rdoctask'
51
+ Rake::RDocTask.new do |rdoc|
52
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
53
+
54
+ rdoc.rdoc_dir = 'rdoc'
55
+ rdoc.title = "padrino-helpers #{version}"
56
+ rdoc.rdoc_files.include('README*')
57
+ rdoc.rdoc_files.include('lib/**/*.rb')
58
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,16 @@
1
+ require File.dirname(__FILE__) + '/../../padrino-core/lib/padrino-core/support_lite'
2
+ Dir[File.dirname(__FILE__) + '/padrino-helpers/**/*.rb'].each {|file| require file }
3
+
4
+ module Padrino
5
+ module Helpers
6
+ def self.registered(app)
7
+ app.set :default_builder, 'StandardFormBuilder'
8
+ app.helpers Padrino::Helpers::OutputHelpers
9
+ app.helpers Padrino::Helpers::TagHelpers
10
+ app.helpers Padrino::Helpers::AssetTagHelpers
11
+ app.helpers Padrino::Helpers::FormHelpers
12
+ app.helpers Padrino::Helpers::FormatHelpers
13
+ app.helpers Padrino::Helpers::RenderHelpers
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,97 @@
1
+ module Padrino
2
+ module Helpers
3
+ module AssetTagHelpers
4
+
5
+ # Creates a div to display the flash of given type if it exists
6
+ # flash_tag(:notice, :class => 'flash', :id => 'flash-notice')
7
+ def flash_tag(kind, options={})
8
+ flash_text = flash[kind]
9
+ return '' if flash_text.blank?
10
+ options.reverse_merge!(:class => 'flash')
11
+ content_tag(:div, flash_text, options)
12
+ end
13
+
14
+ # Creates a link element with given name, url and options
15
+ # link_to 'click me', '/dashboard', :class => 'linky'
16
+ # link_to('/dashboard', :class => 'blocky') do ... end
17
+ # parameters: name, url='javascript:void(0)', options={}, &block
18
+ def link_to(*args, &block)
19
+ if block_given?
20
+ url, options = (args[0] || 'javascript:void(0);'), (args[1] || {})
21
+ options.reverse_merge!(:href => url)
22
+ link_content = capture_html(&block)
23
+ result_link = content_tag(:a, link_content, options)
24
+ block_is_template?(block) ? concat_content(result_link) : result_link
25
+ else
26
+ name, url, options = args.first, (args[1] || 'javascript:void(0);'), (args[2] || {})
27
+ options.reverse_merge!(:href => url)
28
+ content_tag(:a, name, options)
29
+ end
30
+ end
31
+
32
+ # Creates a mail link element with given name and caption
33
+ # mail_to "me@demo.com" => <a href="mailto:me@demo.com">me@demo.com</a>
34
+ # mail_to "me@demo.com", "My Email" => <a href="mailto:me@demo.com">My Email</a>
35
+ def mail_to(email, caption=nil, mail_options={})
36
+ html_options = mail_options.slice!(:cc, :bcc, :subject, :body)
37
+ mail_query = Rack::Utils.build_query(mail_options).gsub(/\+/, '%20').gsub('%40', '@')
38
+ mail_href = "mailto:#{email}"; mail_href << "?#{mail_query}" if mail_query.present?
39
+ link_to (caption || email), mail_href, html_options
40
+ end
41
+
42
+ # Creates an image element with given url and options
43
+ # image_tag('icons/avatar.png')
44
+ def image_tag(url, options={})
45
+ options.reverse_merge!(:src => image_path(url))
46
+ tag(:img, options)
47
+ end
48
+
49
+ # Returns a stylesheet link tag for the sources specified as arguments
50
+ # stylesheet_link_tag 'style', 'application', 'layout'
51
+ def stylesheet_link_tag(*sources)
52
+ options = sources.extract_options!.symbolize_keys
53
+ sources.collect { |sheet| stylesheet_tag(sheet, options) }.join("\n")
54
+ end
55
+
56
+ # javascript_include_tag 'application', 'special'
57
+ def javascript_include_tag(*sources)
58
+ options = sources.extract_options!.symbolize_keys
59
+ sources.collect { |script| javascript_tag(script, options) }.join("\n")
60
+ end
61
+
62
+ # Returns the path to the image, either relative or absolute
63
+ def image_path(src)
64
+ src.gsub!(/\s/, '')
65
+ src =~ %r{^\s*(/|http)} ? src : File.join('/images', src)
66
+ end
67
+
68
+ protected
69
+
70
+ # stylesheet_tag('style', :media => 'screen')
71
+ def stylesheet_tag(source, options={})
72
+ options = options.dup.reverse_merge!(:href => stylesheet_path(source), :media => 'screen', :rel => 'stylesheet', :type => 'text/css')
73
+ tag(:link, options)
74
+ end
75
+
76
+ # javascript_tag 'application', :src => '/javascripts/base/application.js'
77
+ def javascript_tag(source, options={})
78
+ options = options.dup.reverse_merge!(:src => javascript_path(source), :type => 'text/javascript', :content => "")
79
+ tag(:script, options)
80
+ end
81
+
82
+ def javascript_path(source)
83
+ return source if source =~ /^http/
84
+ result_path = "/javascripts/#{File.basename(source, '.js')}.js"
85
+ stamp = File.exist?(result_path) ? File.mtime(result_path) : Time.now.to_i
86
+ "#{result_path}?#{stamp}"
87
+ end
88
+
89
+ def stylesheet_path(source)
90
+ return source if source =~ /^http/
91
+ result_path = "/stylesheets/#{File.basename(source, '.css')}.css"
92
+ stamp = File.exist?(result_path) ? File.mtime(result_path) : Time.now.to_i
93
+ "#{result_path}?#{stamp}"
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,139 @@
1
+ module Padrino
2
+ module Helpers
3
+ module FormBuilder
4
+ class AbstractFormBuilder
5
+ attr_accessor :template, :object
6
+
7
+ def initialize(template, object)
8
+ @template = template
9
+ @object = build_object(object)
10
+ raise "FormBuilder template must be initialized!" unless template
11
+ raise "FormBuilder object must be not be nil value. If there's no object, use a symbol instead! (i.e :user)" unless object
12
+ end
13
+
14
+ # f.error_messages
15
+ def error_messages(options={})
16
+ @template.error_messages_for(@object, options)
17
+ end
18
+
19
+ # f.label :username, :caption => "Nickname"
20
+ def label(field, options={})
21
+ options.reverse_merge!(:caption => field.to_s.titleize)
22
+ @template.label_tag(field_id(field), options)
23
+ end
24
+
25
+ # f.hidden_field :session_id, :value => "45"
26
+ def hidden_field(field, options={})
27
+ options.reverse_merge!(:value => field_value(field), :id => field_id(field))
28
+ @template.hidden_field_tag field_name(field), options
29
+ end
30
+
31
+ # f.text_field :username, :value => "(blank)", :id => 'username'
32
+ def text_field(field, options={})
33
+ options.reverse_merge!(:value => field_value(field), :id => field_id(field))
34
+ @template.text_field_tag field_name(field), options
35
+ end
36
+
37
+ # f.text_area :summary, :value => "(enter summary)", :id => 'summary'
38
+ def text_area(field, options={})
39
+ options.reverse_merge!(:value => field_value(field), :id => field_id(field))
40
+ @template.text_area_tag field_name(field), options
41
+ end
42
+
43
+ # f.password_field :password, :id => 'password'
44
+ def password_field(field, options={})
45
+ options.reverse_merge!(:value => field_value(field), :id => field_id(field))
46
+ @template.password_field_tag field_name(field), options
47
+ end
48
+
49
+ # f.select :color, :options => ['red', 'green'], :include_blank => true
50
+ # f.select :color, :collection => @colors, :fields => [:name, :id]
51
+ def select(field, options={})
52
+ options.reverse_merge!(:id => field_id(field), :selected => field_value(field))
53
+ @template.select_tag field_name(field), options
54
+ end
55
+
56
+ # f.check_box :remember_me, :value => 'true', :uncheck_value => '0'
57
+ def check_box(field, options={})
58
+ unchecked_value = options.delete(:uncheck_value) || '0'
59
+ options.reverse_merge!(:id => field_id(field), :value => '1')
60
+ options.merge!(:checked => true) if values_matches_field?(field, options[:value])
61
+ html = @template.check_box_tag field_name(field), options
62
+ html << hidden_field(field, :value => unchecked_value, :id => nil)
63
+ end
64
+
65
+ # f.radio_button :gender, :value => 'male'
66
+ def radio_button(field, options={})
67
+ options.reverse_merge!(:id => field_id(field, options[:value]))
68
+ options.merge!(:checked => true) if values_matches_field?(field, options[:value])
69
+ @template.radio_button_tag field_name(field), options
70
+ end
71
+
72
+ # f.file_field :photo, :class => 'avatar'
73
+ def file_field(field, options={})
74
+ options.reverse_merge!(:id => field_id(field))
75
+ @template.file_field_tag field_name(field), options
76
+ end
77
+
78
+ # f.submit "Update", :class => 'large'
79
+ def submit(caption="Submit", options={})
80
+ @template.submit_tag caption, options
81
+ end
82
+
83
+ # f.simage_submitubmit "buttons/submit.png", :class => 'large'
84
+ def image_submit(source, options={})
85
+ @template.image_submit_tag source, options
86
+ end
87
+
88
+ protected
89
+
90
+ # Returns the known field types for a formbuilder
91
+ def self.field_types
92
+ [:hidden_field, :text_field, :text_area, :password_field, :file_field, :radio_button, :check_box, :select]
93
+ end
94
+
95
+ # Returns the object's models name
96
+ # => user_assignment
97
+ def object_name
98
+ object.is_a?(Symbol) ? object : object.class.to_s.underscore
99
+ end
100
+
101
+ # Returns true if the value matches the value in the field
102
+ # field_has_value?(:gender, 'male')
103
+ def values_matches_field?(field, value)
104
+ value.present? && (field_value(field).to_s == value.to_s || field_value(field).to_s == 'true')
105
+ end
106
+
107
+ # Returns the value for the object's field
108
+ # field_value(:username) => "Joey"
109
+ def field_value(field)
110
+ @object && @object.respond_to?(field) ? @object.send(field) : ""
111
+ end
112
+
113
+ # Returns the name for the given field
114
+ # field_name(:username) => "user[username]"
115
+ def field_name(field)
116
+ "#{object_name}[#{field}]"
117
+ end
118
+
119
+ # Returns the id for the given field
120
+ # field_id(:username) => "user_username"
121
+ # field_id(:gender, :male) => "user_gender_male"
122
+ def field_id(field, value=nil)
123
+ value.blank? ? "#{object_name}_#{field}" : "#{object_name}_#{field}_#{value}"
124
+ end
125
+
126
+ # explicit_object is either a symbol or a record
127
+ # Returns a new record of the type specified in the object
128
+ def build_object(object_or_symbol)
129
+ object_or_symbol.is_a?(Symbol) ? object_class(object_or_symbol).new : object_or_symbol
130
+ end
131
+
132
+ # Returns the class type for the given object
133
+ def object_class(explicit_object)
134
+ explicit_object.is_a?(Symbol) ? explicit_object.to_s.classify.constantize : explicit_object.class
135
+ end
136
+ end
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,37 @@
1
+ module Padrino
2
+ module Helpers
3
+ module FormBuilder
4
+ class StandardFormBuilder < AbstractFormBuilder
5
+
6
+ # text_field_block(:username, { :class => 'long' }, { :class => 'wide-label' })
7
+ # text_area_block(:summary, { :class => 'long' }, { :class => 'wide-label' })
8
+ # password_field_block(:password, { :class => 'long' }, { :class => 'wide-label' })
9
+ # file_field_block(:photo, { :class => 'long' }, { :class => 'wide-label' })
10
+ # check_box_block(:remember_me, { :class => 'long' }, { :class => 'wide-label' })
11
+ # select_block(:color, :options => ['green', 'black'])
12
+ (self.field_types - [ :hidden_field, :radio_button ]).each do |field_type|
13
+ class_eval <<-EOF
14
+ def #{field_type}_block(field, options={}, label_options={})
15
+ label_options.reverse_merge!(:caption => options.delete(:caption)) if options[:caption]
16
+ field_html = label(field, label_options)
17
+ field_html << #{field_type}(field, options)
18
+ @template.content_tag(:p, field_html)
19
+ end
20
+ EOF
21
+ end
22
+
23
+ # submit_block("Update")
24
+ def submit_block(caption, options={})
25
+ submit_html = self.submit(caption, options)
26
+ @template.content_tag(:p, submit_html)
27
+ end
28
+
29
+ # image_submit_block("submit.png")
30
+ def image_submit_block(source, options={})
31
+ submit_html = self.image_submit(source, options)
32
+ @template.content_tag(:p, submit_html)
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,194 @@
1
+ module Padrino
2
+ module Helpers
3
+ module FormHelpers
4
+ # Constructs a form for object using given or default form_builder
5
+ # form_for :user, '/register' do |f| ... end
6
+ # form_for @user, '/register', :id => 'register' do |f| ... end
7
+ def form_for(object, url, settings={}, &block)
8
+ builder_class = configured_form_builder_class(settings[:builder])
9
+ form_html = capture_html(builder_class.new(self, object), &block)
10
+ form_tag(url, settings) { form_html }
11
+ end
12
+
13
+ # Constructs form fields for an object using given or default form_builder
14
+ # Used within an existing form to allow alternate objects within one form
15
+ # fields_for @user.assignment do |assignment| ... end
16
+ # fields_for :assignment do |assigment| ... end
17
+ def fields_for(object, settings={}, &block)
18
+ builder_class = configured_form_builder_class(settings[:builder])
19
+ fields_html = capture_html(builder_class.new(self, object), &block)
20
+ concat_content fields_html
21
+ end
22
+
23
+ # Constructs a form without object based on options
24
+ # form_tag '/register' do ... end
25
+ def form_tag(url, options={}, &block)
26
+ options.reverse_merge!(:method => 'post', :action => url)
27
+ options[:enctype] = "multipart/form-data" if options.delete(:multipart)
28
+ inner_form_html = hidden_form_method_field(options[:method]) + capture_html(&block)
29
+ concat_content content_tag('form', inner_form_html, options)
30
+ end
31
+
32
+ # Constructs a field_set to group fields with given options
33
+ # field_set_tag("Office", :class => 'office-set')
34
+ # parameters: legend_text=nil, options={}
35
+ def field_set_tag(*args, &block)
36
+ options = args.extract_options!
37
+ legend_text = args[0].is_a?(String) ? args.first : nil
38
+ legend_html = legend_text.blank? ? '' : content_tag(:legend, legend_text)
39
+ field_set_content = legend_html + capture_html(&block)
40
+ concat_content content_tag('fieldset', field_set_content, options)
41
+ end
42
+
43
+ # Constructs list html for the errors for a given object
44
+ # error_messages_for @user
45
+ def error_messages_for(record, options={})
46
+ return "" if record.blank? or record.errors.none?
47
+ options.reverse_merge!(:header_message => "The #{record.class.to_s.downcase} could not be saved!")
48
+ error_messages = record.errors.full_messages
49
+ error_items = error_messages.collect { |er| content_tag(:li, er) }.join("\n")
50
+ error_html = content_tag(:p, options.delete(:header_message))
51
+ error_html << content_tag(:ul, error_items, :class => 'errors-list')
52
+ content_tag(:div, error_html, :class => 'field-errors')
53
+ end
54
+
55
+ # Constructs a label tag from the given options
56
+ # label_tag :username, :class => 'long-label'
57
+ # label_tag :username, :class => 'long-label' do ... end
58
+ def label_tag(name, options={}, &block)
59
+ options.reverse_merge!(:caption => name.to_s.titleize, :for => name)
60
+ caption_text = options.delete(:caption) + ": "
61
+ if block_given? # label with inner content
62
+ label_content = caption_text + capture_html(&block)
63
+ concat_content(content_tag(:label, label_content, options))
64
+ else # regular label
65
+ content_tag(:label, caption_text, options)
66
+ end
67
+ end
68
+
69
+ # Constructs a hidden field input from the given options
70
+ # hidden_field_tag :session_key, :value => "__secret__"
71
+ def hidden_field_tag(name, options={})
72
+ options.reverse_merge!(:name => name)
73
+ input_tag(:hidden, options)
74
+ end
75
+
76
+ # Constructs a text field input from the given options
77
+ # text_field_tag :username, :class => 'long'
78
+ def text_field_tag(name, options={})
79
+ options.reverse_merge!(:name => name)
80
+ input_tag(:text, options)
81
+ end
82
+
83
+ # Constructs a text area input from the given options
84
+ # text_area_tag :username, :class => 'long'
85
+ def text_area_tag(name, options={})
86
+ options.reverse_merge!(:name => name)
87
+ content_tag(:textarea, '', options)
88
+ end
89
+
90
+ # Constructs a password field input from the given options
91
+ # password_field_tag :password, :class => 'long'
92
+ def password_field_tag(name, options={})
93
+ options.reverse_merge!(:name => name)
94
+ input_tag(:password, options)
95
+ end
96
+
97
+ # Constructs a check_box from the given options
98
+ # options = [['caption', 'value'], ['Green', 'green1'], ['Blue', 'blue1'], ['Black', "black1"]]
99
+ # options = ['option', 'red', 'yellow' ]
100
+ # select_tag(:favorite_color, :options => ['red', 'yellow'], :selected => 'green1')
101
+ # select_tag(:country, :collection => @countries, :fields => [:name, :code])
102
+ def select_tag(name, options={})
103
+ options.reverse_merge!(:name => name)
104
+ collection, fields = options.delete(:collection), options.delete(:fields)
105
+ options[:options] = options_from_collection(collection, fields) if collection
106
+ options[:options].unshift('') if options.delete(:include_blank)
107
+ select_options_html = options_for_select(options.delete(:options), options.delete(:selected))
108
+ options.merge!(:name => "#{options[:name]}[]") if options[:multiple]
109
+ content_tag(:select, select_options_html, options)
110
+ end
111
+
112
+ # Constructs a check_box from the given options
113
+ # check_box_tag :remember_me, :value => 'Yes'
114
+ def check_box_tag(name, options={})
115
+ options.reverse_merge!(:name => name, :value => '1')
116
+ input_tag(:checkbox, options)
117
+ end
118
+
119
+ # Constructs a radio_button from the given options
120
+ # radio_button_tag :remember_me, :value => 'true'
121
+ def radio_button_tag(name, options={})
122
+ options.reverse_merge!(:name => name)
123
+ input_tag(:radio, options)
124
+ end
125
+
126
+ # Constructs a file field input from the given options
127
+ # file_field_tag :photo, :class => 'long'
128
+ def file_field_tag(name, options={})
129
+ options.reverse_merge!(:name => name)
130
+ input_tag(:file, options)
131
+ end
132
+
133
+ # Constructs a submit button from the given options
134
+ # submit_tag "Create", :class => 'success'
135
+ def submit_tag(caption="Submit", options={})
136
+ options.reverse_merge!(:value => caption)
137
+ input_tag(:submit, options)
138
+ end
139
+
140
+ # Constructs a button input from the given options
141
+ # button_tag "Cancel", :class => 'clear'
142
+ def button_tag(caption, options = {})
143
+ options.reverse_merge!(:value => caption)
144
+ input_tag(:button, options)
145
+ end
146
+
147
+ # Constructs a submit button from the given options
148
+ # submit_tag "Create", :class => 'success'
149
+ def image_submit_tag(source, options={})
150
+ options.reverse_merge!(:src => image_path(source))
151
+ input_tag(:image, options)
152
+ end
153
+
154
+ protected
155
+
156
+ # Returns an array of option items for a select field based on the given collection
157
+ # fields is an array containing the fields to display from each item in the collection
158
+ def options_from_collection(collection, fields)
159
+ return '' if collection.blank?
160
+ collection.collect { |item| [ item.send(fields.first), item.send(fields.last) ] }
161
+ end
162
+
163
+ # Returns the options tags for a select based on the given option items
164
+ def options_for_select(option_items, selected_value=nil)
165
+ return '' if option_items.blank?
166
+ option_items.collect do |caption, value|
167
+ value ||= caption
168
+ content_tag(:option, caption, :value => value, :selected => selected_value.to_s =~ /#{value}|#{caption}/)
169
+ end
170
+ end
171
+
172
+ # returns the hidden method field for 'put' and 'delete' forms
173
+ # Only 'get' and 'post' are allowed within browsers;
174
+ # 'put' and 'delete' are just specified using hidden fields with form action still 'put'.
175
+ # hidden_form_method_field('delete') => <input name="_method" value="delete" />
176
+ def hidden_form_method_field(desired_method)
177
+ return '' if (desired_method =~ /get|post/)
178
+ original_method = desired_method.dup
179
+ desired_method.replace('post')
180
+ hidden_field_tag(:_method, :value => original_method)
181
+ end
182
+
183
+ # Returns the FormBuilder class to use based on all available setting sources
184
+ # If explicitly defined, returns that, otherwise returns defaults
185
+ # configured_form_builder_class(nil) => StandardFormBuilder
186
+ def configured_form_builder_class(explicit_builder=nil)
187
+ default_builder = self.respond_to?(:options) && self.options.default_builder
188
+ configured_builder = explicit_builder || default_builder || 'StandardFormBuilder'
189
+ configured_builder = "Padrino::Helpers::FormBuilder::#{configured_builder}".constantize if configured_builder.is_a?(String)
190
+ configured_builder
191
+ end
192
+ end
193
+ end
194
+ end