padrino-helpers 0.10.7 → 0.11.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.
- checksums.yaml +7 -0
- data/lib/padrino-helpers.rb +2 -1
- data/lib/padrino-helpers/asset_tag_helpers.rb +57 -65
- data/lib/padrino-helpers/breadcrumb_helpers.rb +171 -0
- data/lib/padrino-helpers/form_builder/abstract_form_builder.rb +82 -24
- data/lib/padrino-helpers/form_helpers.rb +84 -17
- data/lib/padrino-helpers/format_helpers.rb +2 -1
- data/lib/padrino-helpers/locale/fr.yml +12 -12
- data/lib/padrino-helpers/locale/pt_br.yml +2 -2
- data/lib/padrino-helpers/output_helpers.rb +42 -2
- data/lib/padrino-helpers/output_helpers/erb_handler.rb +1 -1
- data/lib/padrino-helpers/output_helpers/slim_handler.rb +4 -5
- data/lib/padrino-helpers/render_helpers.rb +2 -2
- data/lib/padrino-helpers/tag_helpers.rb +33 -5
- data/padrino-helpers.gemspec +0 -0
- data/test/fixtures/markup_app/app.rb +13 -6
- data/test/fixtures/markup_app/views/capture_concat.erb +2 -2
- data/test/fixtures/markup_app/views/capture_concat.haml +2 -2
- data/test/fixtures/markup_app/views/capture_concat.slim +4 -5
- data/test/fixtures/markup_app/views/content_for.slim +4 -4
- data/test/fixtures/markup_app/views/content_tag.slim +5 -5
- data/test/fixtures/markup_app/views/current_engine.haml +1 -1
- data/test/fixtures/markup_app/views/fields_for.slim +13 -13
- data/test/fixtures/markup_app/views/form_for.slim +43 -43
- data/test/fixtures/markup_app/views/form_tag.slim +57 -57
- data/test/fixtures/markup_app/views/link_to.slim +2 -2
- data/test/fixtures/markup_app/views/mail_to.slim +2 -2
- data/test/fixtures/markup_app/views/meta_tag.slim +2 -2
- data/test/fixtures/markup_app/views/partials/_slim.slim +1 -1
- data/test/fixtures/markup_app/views/simple_partial.slim +1 -1
- data/test/fixtures/render_app/app.rb +3 -0
- data/test/test_asset_tag_helpers.rb +17 -4
- data/test/test_form_builder.rb +35 -1
- data/test/test_form_helpers.rb +29 -0
- data/test/test_format_helpers.rb +4 -0
- data/test/test_output_helpers.rb +5 -3
- data/test/test_tag_helpers.rb +11 -0
- metadata +10 -15
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f362f51264ab447da505f5bbaeb295b467cff819
|
4
|
+
data.tar.gz: c0a4370011a89876d15d3668a82e3451e5b9b6cb
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c3b645ff7c6bbdafc844465cb6f78fcdea389ee27ccff8b6dabd2f7eb352ebb1f256f0cea9c67914a6d56ba74609c678a2703b7b7451558c73ef1822877a511f
|
7
|
+
data.tar.gz: fafd39ce16c2639cbde4537a6b6530b2580e1c59ae9c397298dd16d8416bc9a241e7eeff8c4a91f4548609f64339162ec28ad597398a1c6a93839f11c6706652
|
data/lib/padrino-helpers.rb
CHANGED
@@ -4,7 +4,6 @@ require 'i18n'
|
|
4
4
|
require 'enumerator'
|
5
5
|
require 'active_support/time_with_zone' # next extension depends on this
|
6
6
|
require 'active_support/core_ext/string/conversions' # to_date
|
7
|
-
require 'active_support/core_ext/float/rounding' # round
|
8
7
|
require 'active_support/option_merger' # with_options
|
9
8
|
require 'active_support/core_ext/object/with_options' # with_options
|
10
9
|
require 'active_support/inflector' # humanize
|
@@ -32,6 +31,7 @@ module Padrino
|
|
32
31
|
# Padrino::Helpers::FormatHelpers
|
33
32
|
# Padrino::Helpers::RenderHelpers
|
34
33
|
# Padrino::Helpers::NumberHelpers
|
34
|
+
# Padrino::Helpers::Breadcrumbs
|
35
35
|
#
|
36
36
|
# @param [Sinatra::Application] app
|
37
37
|
# The specified padrino application
|
@@ -52,6 +52,7 @@ module Padrino
|
|
52
52
|
app.helpers Padrino::Helpers::RenderHelpers
|
53
53
|
app.helpers Padrino::Helpers::NumberHelpers
|
54
54
|
app.helpers Padrino::Helpers::TranslationHelpers
|
55
|
+
app.helpers Padrino::Helpers::Breadcrumbs
|
55
56
|
end
|
56
57
|
alias :included :registered
|
57
58
|
end
|
@@ -4,6 +4,10 @@ module Padrino
|
|
4
4
|
# Helpers related to producing assets (images,stylesheets,js,etc) within templates.
|
5
5
|
#
|
6
6
|
module AssetTagHelpers
|
7
|
+
FRAGMENT_HASH = "#".html_safe.freeze
|
8
|
+
# assets that require an appended extension
|
9
|
+
APPEND_ASSET_EXTENSIONS = ["js", "css"]
|
10
|
+
|
7
11
|
##
|
8
12
|
# Creates a div to display the flash of given type if it exists
|
9
13
|
#
|
@@ -11,6 +15,7 @@ module Padrino
|
|
11
15
|
# The type of flash to display in the tag.
|
12
16
|
# @param [Hash] options
|
13
17
|
# The html options for this section.
|
18
|
+
# use :bootstrap => true to support Twitter's bootstrap dismiss alert button
|
14
19
|
#
|
15
20
|
# @return [String] Flash tag html with specified +options+.
|
16
21
|
#
|
@@ -24,11 +29,13 @@ module Padrino
|
|
24
29
|
# @api public
|
25
30
|
def flash_tag(*args)
|
26
31
|
options = args.extract_options!
|
27
|
-
|
32
|
+
bootstrap = options.delete(:bootstrap) if options[:bootstrap]
|
33
|
+
args.inject(''.html_safe) do |html,kind|
|
28
34
|
flash_text = flash[kind]
|
29
35
|
next if flash_text.blank?
|
30
|
-
|
31
|
-
|
36
|
+
flash_text << safe_content_tag(:button, "×", {:type => :button, :class => :close, :'data-dismiss' => :alert}) if bootstrap
|
37
|
+
html << safe_content_tag(:div, flash_text, options.reverse_merge(:class => kind))
|
38
|
+
end
|
32
39
|
end
|
33
40
|
|
34
41
|
##
|
@@ -45,6 +52,8 @@ module Padrino
|
|
45
52
|
#
|
46
53
|
# @option options [String] :anchor
|
47
54
|
# The anchor for the link (i.e #something)
|
55
|
+
# @option options [String] :fragment
|
56
|
+
# Synonym for anchor
|
48
57
|
# @option options [Boolean] :if
|
49
58
|
# If true, the link will appear, otherwise not;
|
50
59
|
# @option options [Boolean] :unless
|
@@ -70,66 +79,38 @@ module Padrino
|
|
70
79
|
# @api public
|
71
80
|
def link_to(*args, &block)
|
72
81
|
options = args.extract_options!
|
73
|
-
|
82
|
+
fragment = options.delete(:anchor).to_s if options[:anchor]
|
83
|
+
fragment = options.delete(:fragment).to_s if options[:fragment]
|
74
84
|
|
85
|
+
url = ActiveSupport::SafeBuffer.new
|
75
86
|
if block_given?
|
76
|
-
|
87
|
+
if args[0]
|
88
|
+
url.concat(args[0])
|
89
|
+
url.concat(FRAGMENT_HASH).concat(fragment) if fragment
|
90
|
+
else
|
91
|
+
url.concat(FRAGMENT_HASH)
|
92
|
+
url.concat(fragment) if fragment
|
93
|
+
end
|
77
94
|
options.reverse_merge!(:href => url)
|
78
95
|
link_content = capture_html(&block)
|
79
96
|
return '' unless parse_conditions(url, options)
|
80
97
|
result_link = content_tag(:a, link_content, options)
|
81
98
|
block_is_template?(block) ? concat_content(result_link) : result_link
|
82
99
|
else
|
83
|
-
|
100
|
+
if args[1]
|
101
|
+
url.concat(args[1])
|
102
|
+
url.safe_concat(FRAGMENT_HASH).concat(fragment) if fragment
|
103
|
+
else
|
104
|
+
url = FRAGMENT_HASH
|
105
|
+
url.concat(fragment) if fragment
|
106
|
+
end
|
107
|
+
name = args[0]
|
84
108
|
return name unless parse_conditions(url, options)
|
85
109
|
options.reverse_merge!(:href => url)
|
86
110
|
content_tag(:a, name, options)
|
87
111
|
end
|
88
112
|
end
|
89
113
|
|
90
|
-
##
|
91
|
-
# Creates a form containing a single button that submits to the url.
|
92
|
-
#
|
93
|
-
# @overload button_to(name, url, options={})
|
94
|
-
# @param [String] caption The text caption.
|
95
|
-
# @param [String] url The url href.
|
96
|
-
# @param [Hash] options The html options.
|
97
|
-
# @overload button_to(name, options={}, &block)
|
98
|
-
# @param [String] url The url href.
|
99
|
-
# @param [Hash] options The html options.
|
100
|
-
# @param [Proc] block The button content.
|
101
|
-
#
|
102
|
-
# @option options [Boolean] :multipart
|
103
|
-
# If true, this form will support multipart encoding.
|
104
|
-
# @option options [String] :remote
|
105
|
-
# Instructs ujs handler to handle the submit as ajax.
|
106
|
-
# @option options [Symbol] :method
|
107
|
-
# Instructs ujs handler to use different http method (i.e :post, :delete).
|
108
|
-
#
|
109
|
-
# @return [String] Form and button html with specified +options+.
|
110
|
-
#
|
111
|
-
# @example
|
112
|
-
# button_to 'Delete', url(:accounts_destroy, :id => account), :method => :delete, :class => :form
|
113
|
-
# # Generates:
|
114
|
-
# # <form class="form" action="/admin/accounts/destroy/2" method="post">
|
115
|
-
# # <input type="hidden" value="delete" name="_method" />
|
116
|
-
# # <input type="submit" value="Delete" />
|
117
|
-
# # </form>
|
118
|
-
#
|
119
|
-
# @api public
|
120
|
-
def button_to(*args, &block)
|
121
|
-
name, url = args[0], args[1]
|
122
|
-
options = args.extract_options!
|
123
|
-
desired_method = options[:method]
|
124
|
-
options.delete(:method) if options[:method].to_s !~ /get|post/i
|
125
|
-
options.reverse_merge!(:method => 'post', :action => url)
|
126
|
-
options[:enctype] = 'multipart/form-data' if options.delete(:multipart)
|
127
|
-
options['data-remote'] = 'true' if options.delete(:remote)
|
128
|
-
inner_form_html = hidden_form_method_field(desired_method)
|
129
|
-
inner_form_html += block_given? ? capture_html(&block) : submit_tag(name)
|
130
|
-
content_tag('form', inner_form_html, options)
|
131
|
-
end
|
132
|
-
|
133
114
|
##
|
134
115
|
# Creates a link tag that browsers and news readers can use to auto-detect an RSS or ATOM feed.
|
135
116
|
#
|
@@ -185,7 +166,7 @@ module Padrino
|
|
185
166
|
# @api public
|
186
167
|
def mail_to(email, caption=nil, mail_options={})
|
187
168
|
html_options = mail_options.slice!(:cc, :bcc, :subject, :body)
|
188
|
-
mail_query = Rack::Utils.build_query(mail_options).gsub(/\+/, '%20').gsub('%40', '@')
|
169
|
+
mail_query = Rack::Utils.build_query(mail_options).gsub(/\+/, '%20').gsub('%40', '@').gsub('&', '&')
|
189
170
|
mail_href = "mailto:#{email}"; mail_href << "?#{mail_query}" if mail_query.present?
|
190
171
|
link_to((caption || email), mail_href, html_options)
|
191
172
|
end
|
@@ -275,7 +256,7 @@ module Padrino
|
|
275
256
|
options.reverse_merge!(:media => 'screen', :rel => 'stylesheet', :type => 'text/css')
|
276
257
|
sources.flatten.map { |source|
|
277
258
|
tag(:link, options.reverse_merge(:href => asset_path(:css, source)))
|
278
|
-
}.join("\n")
|
259
|
+
}.join("\n").html_safe
|
279
260
|
end
|
280
261
|
|
281
262
|
##
|
@@ -298,7 +279,7 @@ module Padrino
|
|
298
279
|
options.reverse_merge!(:type => 'text/javascript')
|
299
280
|
sources.flatten.map { |source|
|
300
281
|
content_tag(:script, nil, options.reverse_merge(:src => asset_path(:js, source)))
|
301
|
-
}.join("\n")
|
282
|
+
}.join("\n").html_safe
|
302
283
|
end
|
303
284
|
|
304
285
|
##
|
@@ -341,14 +322,11 @@ module Padrino
|
|
341
322
|
#
|
342
323
|
# @api semipublic
|
343
324
|
def asset_path(kind, source)
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
source << ".#{kind}" unless ignore_extension or source =~ /\.#{kind}/
|
350
|
-
result_path = is_absolute ? source : uri_root_path(asset_folder, source)
|
351
|
-
timestamp = asset_timestamp(result_path, is_absolute)
|
325
|
+
source = asset_normalize_extension(kind, URI.escape(source.to_s))
|
326
|
+
return source if source =~ %r{^(/|https?://)} # absolute source
|
327
|
+
source = File.join(asset_folder_name(kind), source)
|
328
|
+
timestamp = asset_timestamp(source)
|
329
|
+
result_path = uri_root_path(source)
|
352
330
|
"#{result_path}#{timestamp}"
|
353
331
|
end
|
354
332
|
|
@@ -370,14 +348,15 @@ module Padrino
|
|
370
348
|
#
|
371
349
|
# @example
|
372
350
|
# asset_timestamp("some/path/to/file.png") => "?154543678"
|
373
|
-
# asset_timestamp("/some/absolute/path.png", true) => nil
|
374
351
|
#
|
375
|
-
def asset_timestamp(file_path
|
352
|
+
def asset_timestamp(file_path)
|
376
353
|
return nil if file_path =~ /\?/ || (self.class.respond_to?(:asset_stamp) && !self.class.asset_stamp)
|
377
|
-
|
354
|
+
public_path = self.class.public_folder if self.class.respond_to?(:public_folder)
|
355
|
+
public_path ||= Padrino.root("public") if Padrino.respond_to?(:root)
|
356
|
+
public_file_path = File.join(public_path, file_path) if public_path
|
378
357
|
stamp = File.mtime(public_file_path).to_i if public_file_path && File.exist?(public_file_path)
|
379
|
-
stamp ||= Time.now.to_i
|
380
|
-
"?#{stamp}"
|
358
|
+
stamp ||= Time.now.to_i
|
359
|
+
"?#{stamp}"
|
381
360
|
end
|
382
361
|
|
383
362
|
###
|
@@ -396,6 +375,19 @@ module Padrino
|
|
396
375
|
end
|
397
376
|
end
|
398
377
|
|
378
|
+
# Normalizes the extension for a given asset
|
379
|
+
#
|
380
|
+
# @example
|
381
|
+
#
|
382
|
+
# asset_normalize_extension(:images, "/foo/bar/baz.png") => "/foo/bar/baz.png"
|
383
|
+
# asset_normalize_extension(:js, "/foo/bar/baz") => "/foo/bar/baz.js"
|
384
|
+
#
|
385
|
+
def asset_normalize_extension(kind, source)
|
386
|
+
ignore_extension = !APPEND_ASSET_EXTENSIONS.include?(kind.to_s)
|
387
|
+
source << ".#{kind}" unless ignore_extension or source =~ /\.#{kind}/
|
388
|
+
source
|
389
|
+
end
|
390
|
+
|
399
391
|
##
|
400
392
|
# Parses link_to options for given correct conditions
|
401
393
|
#
|
@@ -0,0 +1,171 @@
|
|
1
|
+
module Padrino
|
2
|
+
module Helpers
|
3
|
+
class Breadcrumb
|
4
|
+
|
5
|
+
attr_accessor :home
|
6
|
+
attr_accessor :items
|
7
|
+
|
8
|
+
DEFAULT_URL = "/"
|
9
|
+
DEFAULT_CAPTION ="Home Page"
|
10
|
+
|
11
|
+
##
|
12
|
+
# initialize breadcrumbs with default value
|
13
|
+
#
|
14
|
+
# @example
|
15
|
+
# before do
|
16
|
+
# @breadcrumbs = breadcrumbs.new
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# @api public
|
20
|
+
def initialize
|
21
|
+
self.home = { :url => DEFAULT_URL, :caption => DEFAULT_CAPTION, :name => :home }
|
22
|
+
reset
|
23
|
+
end
|
24
|
+
|
25
|
+
##
|
26
|
+
# Set the custom home (Parent) link
|
27
|
+
#
|
28
|
+
# @param [String] url
|
29
|
+
# The url href
|
30
|
+
#
|
31
|
+
# @param [String] caption
|
32
|
+
# The text caption.
|
33
|
+
#
|
34
|
+
# @example
|
35
|
+
# breadcrumbs.set_home "/HomeFoo", "Foo Home"
|
36
|
+
#
|
37
|
+
#
|
38
|
+
# @api public
|
39
|
+
def set_home(url, caption)
|
40
|
+
self.home = { :url => url, :caption => caption.to_s.humanize, :name => :home }
|
41
|
+
reset
|
42
|
+
end
|
43
|
+
|
44
|
+
##
|
45
|
+
# Reset breadcrumbs to default or personal home
|
46
|
+
#
|
47
|
+
# @example
|
48
|
+
# breadcrumbs.reset
|
49
|
+
#
|
50
|
+
# @api public
|
51
|
+
def reset
|
52
|
+
self.items=[]
|
53
|
+
self.items << home
|
54
|
+
end
|
55
|
+
|
56
|
+
##
|
57
|
+
# Reset breadcrumbs to default home
|
58
|
+
#
|
59
|
+
# @example
|
60
|
+
# breadcrumbs.reset!
|
61
|
+
#
|
62
|
+
# @api public
|
63
|
+
def reset!
|
64
|
+
self.home = { :url => DEFAULT_URL, :caption => DEFAULT_CAPTION, :name => :home }
|
65
|
+
reset
|
66
|
+
end
|
67
|
+
|
68
|
+
##
|
69
|
+
# Add a new breadcrumbs
|
70
|
+
#
|
71
|
+
# @param [String] name
|
72
|
+
# The name of resource
|
73
|
+
# @param [Symbol] name
|
74
|
+
# The name of resource
|
75
|
+
#
|
76
|
+
# @param [String] url
|
77
|
+
# The url href.
|
78
|
+
#
|
79
|
+
# @param [String] caption
|
80
|
+
# The text caption
|
81
|
+
#
|
82
|
+
# @example
|
83
|
+
# breadcrumbs.add "foo", "/foo", "Foo Link"
|
84
|
+
# breadcrumbs.add :foo, "/foo", "Foo Link"
|
85
|
+
#
|
86
|
+
# @api public
|
87
|
+
def add(name, url, caption)
|
88
|
+
items << { :name => name, :url => url.to_s, :caption => caption.to_s.humanize }
|
89
|
+
end
|
90
|
+
|
91
|
+
alias :<< :add
|
92
|
+
|
93
|
+
##
|
94
|
+
# Remove a Breadcrumbs
|
95
|
+
#
|
96
|
+
# @param [String] name
|
97
|
+
# The name of resource to delete from breadcrumbs list
|
98
|
+
#
|
99
|
+
# @param [Symbol] name
|
100
|
+
# The name of resource to delete from breadcrumbs list
|
101
|
+
#
|
102
|
+
# @example
|
103
|
+
# breadcrumbs.del "foo"
|
104
|
+
# breadcrumbs.del :foo
|
105
|
+
#
|
106
|
+
# @api public
|
107
|
+
def del(name)
|
108
|
+
items.delete_if { |item| item[:name] == name.to_sym }
|
109
|
+
end
|
110
|
+
|
111
|
+
end # Breadcrumb
|
112
|
+
|
113
|
+
|
114
|
+
module Breadcrumbs
|
115
|
+
|
116
|
+
# Render breadcrumbs to view
|
117
|
+
#
|
118
|
+
# @param [Breadcrumbs] breadcrumbs
|
119
|
+
# The breadcrumbs to render into view
|
120
|
+
#
|
121
|
+
# @param [Boolean] bootstrap
|
122
|
+
# If true, render separation (usefull with Twitter Bootstrap)
|
123
|
+
#
|
124
|
+
# @param [String] active
|
125
|
+
# Css class style set to active breadcrumb
|
126
|
+
#
|
127
|
+
# @return [String] Unordered list with breadcrumbs
|
128
|
+
#
|
129
|
+
# @example
|
130
|
+
# = breadcrumbs @breacrumbs
|
131
|
+
# # Generates:
|
132
|
+
# # <ul>
|
133
|
+
# # <li><a herf="/foo" >Foo Link</a></li>
|
134
|
+
# # <li class="active" ><a herf="/bar">Bar Link</a></li>
|
135
|
+
# # </ul>
|
136
|
+
#
|
137
|
+
#
|
138
|
+
# @api public
|
139
|
+
def breadcrumbs(breadcrumbs, bootstrap=false, active="active")
|
140
|
+
content=""
|
141
|
+
breadcrumbs.items[0..-2].each do |item|
|
142
|
+
content << render_item(item, bootstrap)
|
143
|
+
end
|
144
|
+
last = link_to(breadcrumbs.items.last[:caption], breadcrumbs.items.last[:url])
|
145
|
+
content << safe_content_tag(:li, last, :class => active)
|
146
|
+
safe_content_tag(:ul, content, :class => "breadcrumb" )
|
147
|
+
end
|
148
|
+
|
149
|
+
private
|
150
|
+
##
|
151
|
+
# Private method to return list item
|
152
|
+
#
|
153
|
+
# @param [Hash] item
|
154
|
+
# The breadcrumb item
|
155
|
+
#
|
156
|
+
# @param [Boolean] bootstrap
|
157
|
+
# If true, render separation (usefull with Twitter Bootstrap)
|
158
|
+
#
|
159
|
+
# @return [String] List item with breacrumb
|
160
|
+
#
|
161
|
+
# @api public
|
162
|
+
def render_item(item, bootstrap)
|
163
|
+
content = ""
|
164
|
+
content << link_to(item[:caption], item[:url])
|
165
|
+
content << safe_content_tag(:span, "/", :class => "divider") if bootstrap
|
166
|
+
safe_content_tag(:li, content )
|
167
|
+
end
|
168
|
+
|
169
|
+
end # Breadcrumb
|
170
|
+
end # Helpers
|
171
|
+
end # Padrino
|
@@ -95,12 +95,38 @@ module Padrino
|
|
95
95
|
@template.select_tag field_name(field), options
|
96
96
|
end
|
97
97
|
|
98
|
+
# f.check_box_group :color, :options => ['red', 'green', 'blue'], :selected => ['red', 'blue']
|
99
|
+
# f.check_box_group :color, :collection => @colors, :fields => [:name, :id]
|
100
|
+
def check_box_group(field, options={})
|
101
|
+
selected_values = Array(options[:selected] || field_value(field))
|
102
|
+
if options[:collection]
|
103
|
+
fields = options[:fields] || [:name, :id]
|
104
|
+
# don't use map!, it will break some orms
|
105
|
+
selected_values = selected_values.map{ |v| (v.respond_to?(fields[0]) ? v.send(fields[1]) : v).to_s }
|
106
|
+
end
|
107
|
+
labeled_group( field, options ) do |variant|
|
108
|
+
@template.check_box_tag( field_name(field)+'[]', :value => variant[1], :id => variant[2], :checked => selected_values.include?(variant[1]) )
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# f.radio_button_group :color, :options => ['red', 'green']
|
113
|
+
# f.radio_button_group :color, :collection => @colors, :fields => [:name, :id], :selected => @colors.first
|
114
|
+
def radio_button_group(field, options={})
|
115
|
+
fields = options[:fields] || [:name, :id]
|
116
|
+
selected_value = options[:selected] || field_value(field)
|
117
|
+
selected_value = selected_value.send(fields[1]) if selected_value.respond_to?(fields[0])
|
118
|
+
labeled_group( field, options ) do |variant|
|
119
|
+
@template.radio_button_tag( field_name(field), :value => variant[1], :id => variant[2], :checked => variant[1] == selected_value.to_s )
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
98
123
|
# f.check_box :remember_me, :value => 'true', :uncheck_value => '0'
|
99
124
|
def check_box(field, options={})
|
125
|
+
html = ActiveSupport::SafeBuffer.new
|
100
126
|
unchecked_value = options.delete(:uncheck_value) || '0'
|
101
127
|
options.reverse_merge!(:id => field_id(field), :value => '1')
|
102
128
|
options.reverse_merge!(:checked => true) if values_matches_field?(field, options[:value])
|
103
|
-
html
|
129
|
+
html << @template.hidden_field_tag(options[:name] || field_name(field), :value => unchecked_value, :id => nil)
|
104
130
|
html << @template.check_box_tag(field_name(field), options)
|
105
131
|
end
|
106
132
|
|
@@ -140,7 +166,11 @@ module Padrino
|
|
140
166
|
result = nested_objects.each_with_index.map do |child_instance, index|
|
141
167
|
nested_options[:index] = include_index ? index : nil
|
142
168
|
@template.fields_for(child_instance, { :nested => nested_options }, &block)
|
143
|
-
end.join("\n")
|
169
|
+
end.join("\n").html_safe
|
170
|
+
end
|
171
|
+
|
172
|
+
def csrf_token_field
|
173
|
+
@template.csrf_token_field
|
144
174
|
end
|
145
175
|
|
146
176
|
protected
|
@@ -171,17 +201,8 @@ module Padrino
|
|
171
201
|
# field_name(:number) => "user[telephone_attributes][number]"
|
172
202
|
# field_name(:street) => "user[addresses_attributes][0][street]"
|
173
203
|
def field_name(field=nil)
|
174
|
-
result =
|
175
|
-
if
|
176
|
-
result << object_model_name
|
177
|
-
elsif nested_form?
|
178
|
-
parent_form = @options[:nested][:parent]
|
179
|
-
attributes_name = "#{@options[:nested][:association]}_attributes"
|
180
|
-
nested_index = @options[:nested][:index]
|
181
|
-
fragment = [parent_form.field_name, "[#{attributes_name}", "]"]
|
182
|
-
fragment.insert(2, "][#{nested_index}") if nested_index
|
183
|
-
result << fragment
|
184
|
-
end
|
204
|
+
result = field_result
|
205
|
+
result << field_name_fragment if nested_form?
|
185
206
|
result << "[#{field}]" unless field.blank?
|
186
207
|
result.flatten.join
|
187
208
|
end
|
@@ -192,17 +213,8 @@ module Padrino
|
|
192
213
|
# field_name(:number) => "user_telephone_attributes_number"
|
193
214
|
# field_name(:street) => "user_addresses_attributes_0_street"
|
194
215
|
def field_id(field=nil, value=nil)
|
195
|
-
result =
|
196
|
-
if
|
197
|
-
result << object_model_name
|
198
|
-
elsif nested_form?
|
199
|
-
parent_form = @options[:nested][:parent]
|
200
|
-
attributes_name = "#{@options[:nested][:association]}_attributes"
|
201
|
-
nested_index = @options[:nested][:index]
|
202
|
-
fragment = [parent_form.field_id, "_#{attributes_name}"]
|
203
|
-
fragment.push("_#{nested_index}") if nested_index
|
204
|
-
result << fragment
|
205
|
-
end
|
216
|
+
result = field_result
|
217
|
+
result << field_id_fragment if nested_form?
|
206
218
|
result << "_#{field}" unless field.blank?
|
207
219
|
result << "_#{value}" unless value.blank?
|
208
220
|
result.flatten.join
|
@@ -245,6 +257,52 @@ module Padrino
|
|
245
257
|
def root_form?
|
246
258
|
!nested_form?
|
247
259
|
end
|
260
|
+
|
261
|
+
# Builds a group of labels for radios or checkboxes
|
262
|
+
def labeled_group(field, options={})
|
263
|
+
options.reverse_merge!(:id => field_id(field), :selected => field_value(field))
|
264
|
+
options.merge!(:class => field_error(field, options))
|
265
|
+
variants = case
|
266
|
+
when options[:options]
|
267
|
+
options[:options].map{ |caption, value| [caption.to_s, (value||caption).to_s] }
|
268
|
+
when options[:collection]
|
269
|
+
fields = options[:fields] || [:name, :id]
|
270
|
+
options[:collection].map{ |variant| [variant.send(fields.first).to_s, variant.send(fields.last).to_s] }
|
271
|
+
else
|
272
|
+
[]
|
273
|
+
end
|
274
|
+
variants.inject('') do |html, variant|
|
275
|
+
variant[2] = "#{field_id(field)}_#{variant[1]}"
|
276
|
+
html << @template.label_tag("#{field_name(field)}[]", :for => variant[2], :caption => "#{yield(variant)} #{variant[0]}")
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
private
|
281
|
+
def field_result
|
282
|
+
result = []
|
283
|
+
result << object_model_name if root_form?
|
284
|
+
result
|
285
|
+
end
|
286
|
+
|
287
|
+
def field_name_fragment
|
288
|
+
fragment = [result_options[:parent_form].field_name, "[#{result_options[:attributes_name]}", "]"]
|
289
|
+
fragment.insert(2, "][#{result_options[:nested_index]}") if result_options[:nested_index]
|
290
|
+
fragment
|
291
|
+
end
|
292
|
+
|
293
|
+
def field_id_fragment
|
294
|
+
fragment = [result_options[:parent_form].field_id, "_#{result_options[:attributes_name]}"]
|
295
|
+
fragment.push("_#{result_options[:nested_index]}") if result_options[:nested_index]
|
296
|
+
fragment
|
297
|
+
end
|
298
|
+
|
299
|
+
def result_options
|
300
|
+
{
|
301
|
+
:parent_form => @options[:nested][:parent],
|
302
|
+
:nested_index => @options[:nested][:index],
|
303
|
+
:attributes_name => "#{@options[:nested][:association]}_attributes"
|
304
|
+
}
|
305
|
+
end
|
248
306
|
end # AbstractFormBuilder
|
249
307
|
end # FormBuilder
|
250
308
|
end # Helpers
|