merb_helpers 0.5 → 0.9.2
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.
- data/Rakefile +4 -5
- data/lib/merb_helpers.rb +3 -3
- data/lib/merb_helpers/date_time_helpers.rb +269 -0
- data/lib/merb_helpers/form_helpers.rb +99 -74
- data/lib/merb_helpers/tag_helpers.rb +61 -0
- metadata +53 -47
- data/lib/tasks/merb_tasks.rb +0 -6
data/Rakefile
CHANGED
@@ -5,7 +5,7 @@ require 'spec/rake/spectask'
|
|
5
5
|
|
6
6
|
PLUGIN = "merb_helpers"
|
7
7
|
NAME = "merb_helpers"
|
8
|
-
|
8
|
+
VERSION = "0.9.2"
|
9
9
|
AUTHOR = "Yehuda Katz"
|
10
10
|
EMAIL = "wycats@gmail.com"
|
11
11
|
HOMEPAGE = "http://merb.rubyforge.org/"
|
@@ -17,7 +17,7 @@ SUDO = windows ? "" : "sudo"
|
|
17
17
|
|
18
18
|
spec = Gem::Specification.new do |s|
|
19
19
|
s.name = NAME
|
20
|
-
s.version =
|
20
|
+
s.version = VERSION
|
21
21
|
s.platform = Gem::Platform::RUBY
|
22
22
|
s.has_rdoc = true
|
23
23
|
s.extra_rdoc_files = ["README", "LICENSE", 'TODO']
|
@@ -26,7 +26,7 @@ spec = Gem::Specification.new do |s|
|
|
26
26
|
s.author = AUTHOR
|
27
27
|
s.email = EMAIL
|
28
28
|
s.homepage = HOMEPAGE
|
29
|
-
s.add_dependency("merb", ">=0.
|
29
|
+
s.add_dependency("merb-core", ">=0.9.2")
|
30
30
|
s.require_path = 'lib'
|
31
31
|
s.autorequire = PLUGIN
|
32
32
|
s.files = %w(LICENSE README Rakefile TODO) + Dir.glob("{lib,specs}/**/*")
|
@@ -39,7 +39,7 @@ end
|
|
39
39
|
|
40
40
|
desc "Run :package and install resulting .gem"
|
41
41
|
task :install => [:package] do
|
42
|
-
sh %{#{SUDO} gem install pkg/#{NAME}-#{
|
42
|
+
sh %{#{SUDO} gem install pkg/#{NAME}-#{VERSION} --no-rdoc --no-ri --no-update-sources}
|
43
43
|
end
|
44
44
|
|
45
45
|
Rake::RDocTask.new do |rdoc|
|
@@ -54,7 +54,6 @@ end
|
|
54
54
|
|
55
55
|
|
56
56
|
Spec::Rake::SpecTask.new do |t|
|
57
|
-
t.warning = true
|
58
57
|
t.spec_opts = ["--format", "specdoc", "--colour"]
|
59
58
|
t.spec_files = Dir['spec/**/*_spec.rb'].sort
|
60
59
|
end
|
data/lib/merb_helpers.rb
CHANGED
@@ -24,12 +24,12 @@ module Merb
|
|
24
24
|
else
|
25
25
|
load_helpers
|
26
26
|
end
|
27
|
-
|
28
|
-
Merb::Plugins.add_rakefiles "tasks/merb_tasks"
|
29
27
|
end
|
30
28
|
|
31
29
|
end
|
32
30
|
|
33
31
|
end
|
34
32
|
|
35
|
-
Merb::
|
33
|
+
Merb::BootLoader.before_app_loads do
|
34
|
+
Merb::Helpers.load if defined?(Merb::Plugins)
|
35
|
+
end
|
@@ -1,7 +1,276 @@
|
|
1
|
+
module TimeDSL
|
2
|
+
{:second => 1,
|
3
|
+
:minute => 60,
|
4
|
+
:hour => 3600,
|
5
|
+
:day => [24,:hours],
|
6
|
+
:week => [7,:days],
|
7
|
+
:month => [30,:days],
|
8
|
+
:year => [364.25, :days]}.each do |meth, amount|
|
9
|
+
define_method meth do
|
10
|
+
amount = amount.is_a?(Array) ? amount[0].send(amount[1]) : amount
|
11
|
+
self * amount
|
12
|
+
end
|
13
|
+
alias_method "#{meth}s".intern, meth
|
14
|
+
end
|
15
|
+
|
16
|
+
# Reads best without arguments: 10.minutes.ago
|
17
|
+
def ago(time = ::Time.now)
|
18
|
+
time - self
|
19
|
+
end
|
20
|
+
alias :until :ago
|
21
|
+
|
22
|
+
# Reads best with argument: 10.minutes.since(time)
|
23
|
+
def since(time = ::Time.now)
|
24
|
+
time + self
|
25
|
+
end
|
26
|
+
alias :from_now :since
|
27
|
+
end
|
28
|
+
|
29
|
+
class Integer
|
30
|
+
# Ordinalize turns a number into an ordinal string used to denote the
|
31
|
+
# position in an ordered sequence such as 1st, 2nd, 3rd, 4th.
|
32
|
+
#
|
33
|
+
# Examples
|
34
|
+
# 1.ordinalize # => "1st"
|
35
|
+
# 2.ordinalize # => "2nd"
|
36
|
+
# 1002.ordinalize # => "1002nd"
|
37
|
+
# 1003.ordinalize # => "1003rd"
|
38
|
+
def ordinalize
|
39
|
+
if (11..13).include?(self % 100)
|
40
|
+
"#{self}th"
|
41
|
+
else
|
42
|
+
case self % 10
|
43
|
+
when 1; "#{self}st"
|
44
|
+
when 2; "#{self}nd"
|
45
|
+
when 3; "#{self}rd"
|
46
|
+
else "#{self}th"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
Numeric.send :include, TimeDSL
|
53
|
+
# Everything above here has pretty much been implemented in the assistance gem...
|
54
|
+
|
55
|
+
# Time.now.to_ordinalized_s :long
|
56
|
+
# => "February 28th, 2006 21:10"
|
57
|
+
module OrdinalizedFormatting
|
58
|
+
def to_ordinalized_s(format = :default)
|
59
|
+
format = Merb::Helpers::DateAndTime::DATE_FORMATS[format]
|
60
|
+
return to_default_s if format.nil?
|
61
|
+
strftime_ordinalized(format)
|
62
|
+
end
|
63
|
+
|
64
|
+
def strftime_ordinalized(fmt)
|
65
|
+
strftime(fmt.gsub(/%d/, '_%d_')).gsub(/_(\d+)_/) { |s| s.to_i.ordinalize }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
class Date
|
70
|
+
include OrdinalizedFormatting
|
71
|
+
# Converts a Date instance to a Time, where the time is set to the beginning of the day.
|
72
|
+
# The timezone can be either :local or :utc (default :utc).
|
73
|
+
#
|
74
|
+
# ==== Examples:
|
75
|
+
# date = Date.new(2007, 11, 10) # => Sat, 10 Nov 2007
|
76
|
+
#
|
77
|
+
# date.to_time # => Sat Nov 10 00:00:00 0800 2007
|
78
|
+
# date.to_time(:local) # => Sat Nov 10 00:00:00 0800 2007
|
79
|
+
#
|
80
|
+
# date.to_time(:utc) # => Sat Nov 10 00:00:00 UTC 2007
|
81
|
+
def to_time(form = :utc)
|
82
|
+
::Time.send("#{form}_time", year, month, day)
|
83
|
+
end
|
84
|
+
def to_date; self; end
|
85
|
+
end
|
86
|
+
|
87
|
+
class Time
|
88
|
+
include OrdinalizedFormatting
|
89
|
+
# Ruby 1.8-cvs and 1.9 define private Time#to_date
|
90
|
+
%w(to_date to_datetime).each do |method|
|
91
|
+
public method if private_instance_methods.include?(method)
|
92
|
+
end
|
93
|
+
def to_time; self; end
|
94
|
+
end
|
95
|
+
|
1
96
|
module Merb
|
2
97
|
module Helpers
|
98
|
+
# Provides a number of methods for displaying and dealing with dates and times
|
99
|
+
#
|
100
|
+
# Parts were strongly based on http://ar-code.svn.engineyard.com/plugins/relative_time_helpers/, and
|
101
|
+
# active_support
|
102
|
+
#
|
103
|
+
# The key methods are `relative_date`, `relative_date_span`, and `relative_time_span`. This also gives
|
104
|
+
# you the Rails style Time DSL for working with numbers eg. 3.months.ago or 5.days.until(1.year.from_now)
|
3
105
|
module DateAndTime
|
106
|
+
TIME_CLASS = Time
|
107
|
+
TIME_OUTPUT = {
|
108
|
+
:today => 'today',
|
109
|
+
:yesterday => 'yesterday',
|
110
|
+
:tomorrow => 'tomorrow',
|
111
|
+
:initial_format => '%b %d',
|
112
|
+
:year_format => ', %Y'
|
113
|
+
}
|
114
|
+
DATE_FORMATS = {
|
115
|
+
:db => "%Y-%m-%d %H:%M:%S",
|
116
|
+
:time => "%H:%M",
|
117
|
+
:short => "%d %b %H:%M",
|
118
|
+
:long => "%B %d, %Y %H:%M",
|
119
|
+
:long_ordinal => lambda { |time| time.strftime("%B #{time.day.ordinalize}, %Y %H:%M") },
|
120
|
+
:rfc822 => "%a, %d %b %Y %H:%M:%S %z"
|
121
|
+
}
|
122
|
+
|
123
|
+
# Gives you a relative date in an attractive format
|
124
|
+
#
|
125
|
+
# ==== Parameters
|
126
|
+
# time<~to_date>:: The Date or Time to test
|
127
|
+
#
|
128
|
+
# ==== Returns
|
129
|
+
# String:: The sexy relative date
|
130
|
+
#
|
131
|
+
# ==== Examples
|
132
|
+
# relative_date(Time.now.utc) => "today"
|
133
|
+
# relative_date(5.days.ago) => "March 5th"
|
134
|
+
# relative_date(1.year.ago) => "March 10th, 2007"
|
135
|
+
def relative_date(time)
|
136
|
+
date = time.to_date
|
137
|
+
today = TIME_CLASS.now.to_date
|
138
|
+
if date == today
|
139
|
+
TIME_OUTPUT[:today]
|
140
|
+
elsif date == (today - 1)
|
141
|
+
TIME_OUTPUT[:yesterday]
|
142
|
+
elsif date == (today + 1)
|
143
|
+
TIME_OUTPUT[:tomorrow]
|
144
|
+
else
|
145
|
+
fmt = TIME_OUTPUT[:initial_format].dup
|
146
|
+
fmt << TIME_OUTPUT[:year_format] unless date.year == today.year
|
147
|
+
time.strftime_ordinalized(fmt)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
# Gives you a relative date span in an attractive format
|
152
|
+
#
|
153
|
+
# ==== Parameters
|
154
|
+
# times<~first,~last>:: The Dates or Times to test
|
155
|
+
#
|
156
|
+
# ==== Returns
|
157
|
+
# String:: The sexy relative date span
|
158
|
+
#
|
159
|
+
# ==== Examples
|
160
|
+
# relative_date([1.second.ago, 10.seconds.ago]) => "March 10th"
|
161
|
+
# relative_date([1.year.ago, 1.year.ago) => "March 10th, 2007"
|
162
|
+
# relative_date([Time.now, 1.day.from_now]) => "March 10th - 11th"
|
163
|
+
# relative_date([Time.now, 1.year.ago]) => "March 10th, 2007 - March 10th, 2008"
|
164
|
+
def relative_date_span(times)
|
165
|
+
times = [times.first, times.last].collect! { |t| t.to_date }
|
166
|
+
times.sort!
|
167
|
+
if times.first == times.last
|
168
|
+
relative_date(times.first)
|
169
|
+
else
|
170
|
+
first = times.first; last = times.last; now = TIME_CLASS.now
|
171
|
+
arr = [first.strftime_ordinalized('%b %d')]
|
172
|
+
arr << ", #{first.year}" unless first.year == last.year
|
173
|
+
arr << ' - '
|
174
|
+
arr << last.strftime('%b') << ' ' unless first.year == last.year && first.month == last.month
|
175
|
+
arr << last.day.ordinalize
|
176
|
+
arr << ", #{last.year}" unless first.year == last.year && last.year == now.year
|
177
|
+
arr.to_s
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
# Gives you a relative date span in an attractive format
|
182
|
+
#
|
183
|
+
# ==== Parameters
|
184
|
+
# times<~first,~last>:: The Dates or Times to test
|
185
|
+
#
|
186
|
+
# ==== Returns
|
187
|
+
# String:: The sexy relative time span
|
188
|
+
#
|
189
|
+
# ==== Examples
|
190
|
+
# relative_time_span([1.second.ago, 10.seconds.ago]) => "12:00 - 12:09 AM March 10th"
|
191
|
+
# relative_time_span([1.year.ago, 1.year.ago) => "12:09 AM March 10th, 2007"
|
192
|
+
# relative_time_span([Time.now, 13.hours.from_now]) => "12:09 AM - 1:09 PM March 10th"
|
193
|
+
# relative_time_span([Time.now, 1.year.ago]) => "12:09 AM March 10th, 2007 - 12:09 AM March 10th, 2008"
|
194
|
+
def relative_time_span(times)
|
195
|
+
times = [times.first, times.last].collect! { |t| t.to_time }
|
196
|
+
times.sort!
|
197
|
+
if times.first == times.last
|
198
|
+
"#{prettier_time(times.first)} #{relative_date(times.first)}"
|
199
|
+
elsif times.first.to_date == times.last.to_date
|
200
|
+
same_half = (times.first.hour/12 == times.last.hour/12)
|
201
|
+
"#{prettier_time(times.first, !same_half)} - #{prettier_time(times.last)} #{relative_date(times.first)}"
|
202
|
+
|
203
|
+
else
|
204
|
+
first = times.first; last = times.last; now = TIME_CLASS.now
|
205
|
+
arr = [prettier_time(first)]
|
206
|
+
arr << ' '
|
207
|
+
arr << first.strftime_ordinalized('%b %d')
|
208
|
+
arr << ", #{first.year}" unless first.year == last.year
|
209
|
+
arr << ' - '
|
210
|
+
arr << prettier_time(last)
|
211
|
+
arr << ' '
|
212
|
+
arr << last.strftime('%b') << ' ' unless first.year == last.year && first.month == last.month
|
213
|
+
arr << last.day.ordinalize
|
214
|
+
arr << ", #{last.year}" unless first.year == last.year && last.year == now.year
|
215
|
+
arr.to_s
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
# Condenses time... very similar to time_ago_in_words in ActionPack
|
220
|
+
#
|
221
|
+
# ==== Parameters
|
222
|
+
# from_time<~to_time>:: The Date or Time to start from
|
223
|
+
# to_time<~to_time>:: The Date or Time to go to, Defaults to Time.now.utc
|
224
|
+
# include_seconds<Boolean>:: Count the seconds initially, Defaults to false
|
225
|
+
#
|
226
|
+
# ==== Returns
|
227
|
+
# String:: The time distance
|
228
|
+
#
|
229
|
+
# ==== Examples
|
230
|
+
# time_lost_in_words(3.minutes.from_now) # => 3 minutes
|
231
|
+
# time_lost_in_words(Time.now - 15.hours) # => 15 hours
|
232
|
+
# time_lost_in_words(Time.now, 3.minutes.from_now) # => 3 minutes
|
233
|
+
# time_lost_in_words(Time.now) # => less than a minute
|
234
|
+
# time_lost_in_words(Time.now, Time.now, true) # => less than 5 seconds
|
235
|
+
#
|
236
|
+
def time_lost_in_words(from_time, to_time = Time.now.utc, include_seconds = false)
|
237
|
+
from_time = from_time.to_time if from_time.respond_to?(:to_time)
|
238
|
+
to_time = to_time.to_time if to_time.respond_to?(:to_time)
|
239
|
+
distance_in_minutes = (((to_time - from_time).abs)/60).round
|
240
|
+
distance_in_seconds = ((to_time - from_time).abs).round
|
241
|
+
|
242
|
+
case distance_in_minutes
|
243
|
+
when 0..1
|
244
|
+
return (distance_in_minutes == 0) ? 'less than a minute' : '1 minute' unless include_seconds
|
245
|
+
case distance_in_seconds
|
246
|
+
when 0..4 then 'less than 5 seconds'
|
247
|
+
when 5..9 then 'less than 10 seconds'
|
248
|
+
when 10..19 then 'less than 20 seconds'
|
249
|
+
when 20..39 then 'half a minute'
|
250
|
+
when 40..59 then 'less than a minute'
|
251
|
+
else '1 minute'
|
252
|
+
end
|
253
|
+
|
254
|
+
when 2..44 then "#{distance_in_minutes} minutes"
|
255
|
+
when 45..89 then 'about 1 hour'
|
256
|
+
when 90..1439 then "about #{(distance_in_minutes.to_f / 60.0).round} hours"
|
257
|
+
when 1440..2879 then '1 day'
|
258
|
+
when 2880..43199 then "#{(distance_in_minutes / 1440).round} days"
|
259
|
+
when 43200..86399 then 'about 1 month'
|
260
|
+
when 86400..525599 then "#{(distance_in_minutes / 43200).round} months"
|
261
|
+
when 525600..1051199 then 'about 1 year'
|
262
|
+
else "over #{(distance_in_minutes / 525600).round} years"
|
263
|
+
end
|
264
|
+
end
|
265
|
+
alias :time_ago_in_words :time_lost_in_words
|
4
266
|
|
267
|
+
def prettier_time(time, ampm=true)
|
268
|
+
time.strftime("%I:%M#{" %p" if ampm}").sub(/^0/, '')
|
269
|
+
end
|
5
270
|
end
|
6
271
|
end
|
272
|
+
end
|
273
|
+
|
274
|
+
class Merb::Controller #:nodoc:
|
275
|
+
include Merb::Helpers::DateAndTime
|
7
276
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/tag_helpers"
|
2
|
+
|
1
3
|
module Merb #:nodoc:
|
2
4
|
|
3
5
|
# Merb helpers include several helpers used for simplifying view creation.
|
@@ -28,7 +30,7 @@ module Merb #:nodoc:
|
|
28
30
|
# </form>
|
29
31
|
#
|
30
32
|
# You may also create a normal form using form_tag
|
31
|
-
# <% form_tag(
|
33
|
+
# <% form_tag(:action => url(:controller => "foo", :action => "bar", :id => 1)) do %>
|
32
34
|
# <%= text_field :name => 'first_name', :label => 'First Name' %>
|
33
35
|
# <%= submit_button 'Create' %>
|
34
36
|
# <% end %>
|
@@ -43,20 +45,35 @@ module Merb #:nodoc:
|
|
43
45
|
|
44
46
|
# Provides a HTML formatted display of resource errors in an unordered list with a h2 form submission error
|
45
47
|
# ==== Options
|
48
|
+
# +build_li+:: Block for generating a list item for an error. It receives an instance of the error.
|
46
49
|
# +html_class+:: Set for custom error div class default is <tt>submittal_failed<tt>
|
47
50
|
#
|
48
|
-
# ====
|
49
|
-
# <%= error_messages_for :person %>
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
51
|
+
# ==== Examples
|
52
|
+
# <%= error_messages_for :person %>
|
53
|
+
# <%= error_messages_for :person {|errors| "You can has probs nao: #{errors.size} of em!"}
|
54
|
+
# <%= error_messages_for :person, lambda{|error| "<li class='aieeee'>#{error.join(' ')}"} %>
|
55
|
+
# <%= error_messages_for :person, nil, 'bad_mojo' %>
|
56
|
+
def error_messages_for(obj, build_li = nil, html_class='error')
|
57
|
+
return "" unless obj.respond_to?(:errors) && ! obj.errors.empty?
|
58
|
+
|
59
|
+
header_message = if block_given?
|
60
|
+
yield(obj.errors)
|
61
|
+
else
|
62
|
+
error_plurality = (obj.errors.size == 1 ? 'problem' : 'problems')
|
63
|
+
"<h2>Form submittal failed because of #{obj.errors.size} #{error_plurality}</h2>"
|
64
|
+
end
|
65
|
+
|
66
|
+
build_li ||= lambda{|err| "<li>#{err.join(' ')}</li>"}
|
67
|
+
|
68
|
+
markup = %Q{
|
54
69
|
<div class='#{html_class}'>
|
55
70
|
#{header_message}
|
56
71
|
<ul>
|
57
72
|
}
|
58
|
-
|
59
|
-
|
73
|
+
|
74
|
+
obj.errors.each {|error| markup << build_li.call(error) }
|
75
|
+
|
76
|
+
markup << %Q{
|
60
77
|
</ul>
|
61
78
|
</div>
|
62
79
|
}
|
@@ -65,15 +82,10 @@ module Merb #:nodoc:
|
|
65
82
|
def obj_from_ivar_or_sym(obj) #:nodoc:
|
66
83
|
obj.is_a?(Symbol) ? instance_variable_get("@#{obj}") : obj
|
67
84
|
end
|
68
|
-
|
69
|
-
# Creates a generic HTML tag
|
70
|
-
def tag(tag_name, contents, attrs = {}) #:nodoc:
|
71
|
-
open_tag(tag_name, attrs) + contents.to_s + "</#{tag_name}>"
|
72
|
-
end
|
73
|
-
|
85
|
+
|
74
86
|
# Generates a form tag, which accepts a block that is not directly based on resource attributes
|
75
87
|
#
|
76
|
-
# <% form_tag(
|
88
|
+
# <% form_tag(:action => url(:controller => "foo", :action => "bar", :id => 1)) do %>
|
77
89
|
# <%= text_field :name => 'first_name', :label => 'First Name' %>
|
78
90
|
# <%= submit_button 'Create' %>
|
79
91
|
# <% end %>
|
@@ -152,7 +164,7 @@ module Merb #:nodoc:
|
|
152
164
|
end
|
153
165
|
|
154
166
|
def control_value(col) #:nodoc:
|
155
|
-
@_obj.send(col)
|
167
|
+
escape_xml(@_obj.send(col))
|
156
168
|
end
|
157
169
|
|
158
170
|
def control_name_value(col, attrs) #:nodoc:
|
@@ -175,7 +187,7 @@ module Merb #:nodoc:
|
|
175
187
|
# Provides a HTML text input tag based on a resource attribute.
|
176
188
|
#
|
177
189
|
# ==== Example
|
178
|
-
# <%= text_field :fav_color, :label => 'Your Favorite Color' %>
|
190
|
+
# <%= text_field :name => :fav_color, :label => 'Your Favorite Color' %>
|
179
191
|
# # => <label for="fav_color">Your Favorite Color</label><input type="text" name="fav_color" id="fav_color"/>
|
180
192
|
def text_field(attrs = {})
|
181
193
|
attrs.merge!(:type => "text")
|
@@ -197,7 +209,7 @@ module Merb #:nodoc:
|
|
197
209
|
# Provides a generic HTML password input tag.
|
198
210
|
#
|
199
211
|
# ==== Example
|
200
|
-
# <%= password_field :password, :label => "Password" %>
|
212
|
+
# <%= password_field :name => :password, :label => "Password" %>
|
201
213
|
# # => <label for="password">Password</label><input type="password" name="password" id="password"/>
|
202
214
|
def password_field(attrs = {})
|
203
215
|
attrs.delete(:value)
|
@@ -296,9 +308,10 @@ module Merb #:nodoc:
|
|
296
308
|
val = @_obj.send(col)
|
297
309
|
ret = ""
|
298
310
|
options.each do |opt|
|
299
|
-
value, label = opt.is_a?(Hash) ? [opt
|
300
|
-
hash = {:name => "#{@_object_name}[#{col}]", :value => value, :label => label}
|
301
|
-
hash.merge!(
|
311
|
+
value, label = opt.is_a?(Hash) ? [opt.delete(:value), opt.delete(:label)] : [opt, opt]
|
312
|
+
hash = {:name => "#{@_object_name}[#{col}]", :value => value, :label => label, :id => "#{control_id(col)}_#{value}" }
|
313
|
+
hash.merge!(opt) if opt.is_a?(Hash)
|
314
|
+
hash.merge!(:checked => "checked") if val.to_s == value.to_s
|
302
315
|
ret << radio_field(hash)
|
303
316
|
end
|
304
317
|
ret
|
@@ -324,6 +337,7 @@ module Merb #:nodoc:
|
|
324
337
|
def text_area_control(col, attrs = {})
|
325
338
|
attrs ||= {}
|
326
339
|
errorify_field(attrs, col)
|
340
|
+
attrs.merge!(:id => control_id(col))
|
327
341
|
text_area_field(control_value(col), attrs.merge(:name => control_name(col)))
|
328
342
|
end
|
329
343
|
|
@@ -388,6 +402,7 @@ module Merb #:nodoc:
|
|
388
402
|
def select_control(col, attrs = {})
|
389
403
|
attrs.merge!(:name => attrs[:name] || control_name(col))
|
390
404
|
attrs.merge!(:id => attrs[:id] || control_id(col))
|
405
|
+
attrs.merge!(:selected => attrs[:selected] || control_value(col))
|
391
406
|
errorify_field(attrs, col)
|
392
407
|
optional_label(attrs) { select_field(attrs) }
|
393
408
|
end
|
@@ -414,22 +429,24 @@ module Merb #:nodoc:
|
|
414
429
|
prompt = attrs.delete(:prompt)
|
415
430
|
blank = attrs.delete(:include_blank)
|
416
431
|
selected = attrs.delete(:selected)
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
432
|
+
ret = String.new
|
433
|
+
ret << tag('option', prompt, :value => '') if prompt
|
434
|
+
ret << tag("option", '', :value => '') if blank
|
435
|
+
unless collection.blank?
|
436
|
+
if collection.is_a?(Hash)
|
437
|
+
collection.each do |label,group|
|
438
|
+
ret << open_tag("optgroup", :label => label.to_s.gsub(/\b[a-z]/) {|x| x.upcase}) +
|
439
|
+
options_for_select(group, :selected => selected) + "</optgroup>"
|
440
|
+
end
|
441
|
+
else
|
442
|
+
collection.each do |value,text|
|
443
|
+
options = selected.to_a.include?(value) ? {:selected => 'selected'} : {}
|
444
|
+
ret << tag( 'option', text, {:value => value}.merge(options) )
|
430
445
|
end
|
431
446
|
end
|
432
447
|
end
|
448
|
+
|
449
|
+
return ret
|
433
450
|
end
|
434
451
|
|
435
452
|
# Returns a string of option tags that have been compiled by iterating over the collection and
|
@@ -442,7 +459,7 @@ module Merb #:nodoc:
|
|
442
459
|
# If we had a collection of people within a @project object, and want to use 'id' as the value, and 'name'
|
443
460
|
# as the option content we could do something similar to this;
|
444
461
|
#
|
445
|
-
# <%= options_from_collection_for_select(@project.people, :
|
462
|
+
# <%= options_from_collection_for_select(@project.people, :value_method => "id", :text_method => "name") %>
|
446
463
|
# The iteration of the collection would create options in this manner;
|
447
464
|
# => <option value="#{person.id}">#{person.name}</option>
|
448
465
|
#
|
@@ -458,14 +475,16 @@ module Merb #:nodoc:
|
|
458
475
|
def options_from_collection_for_select(collection, attrs = {})
|
459
476
|
prompt = attrs.delete(:prompt)
|
460
477
|
blank = attrs.delete(:include_blank)
|
478
|
+
ret = String.new
|
461
479
|
if collection.is_a?(Hash)
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
480
|
+
ret << tag("option", prompt, :value => '') if prompt
|
481
|
+
ret << tag("option", '', :value => '') if blank
|
482
|
+
collection.each do |label, group|
|
483
|
+
# .gsub(/_/, " ").gsub(/\b[a-z]/) {|x| x.upcase}) == .humanize.titleize, which is no longer in -core
|
484
|
+
ret << open_tag("optgroup", :label => label.to_s.gsub(/_/, " ").gsub(/\b[a-z]/) {|x| x.upcase}) +
|
485
|
+
options_from_collection_for_select(group, attrs) + "</optgroup>"
|
468
486
|
end
|
487
|
+
return ret
|
469
488
|
else
|
470
489
|
text_method = attrs[:text_method]
|
471
490
|
value_method = attrs[:value_method]
|
@@ -552,45 +571,51 @@ module Merb #:nodoc:
|
|
552
571
|
end
|
553
572
|
|
554
573
|
private
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
if
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
574
|
+
# Fake out the browser to send back the method for RESTful stuff.
|
575
|
+
# Fall silently back to post if a method is given that is not supported here
|
576
|
+
def set_form_method(options = {}, obj = nil)
|
577
|
+
options[:method] ||= ((obj && obj.respond_to?(:new_record?) && !obj.new_record?) ? :put : :post)
|
578
|
+
if ![:get,:post].include?(options[:method])
|
579
|
+
fake_form_method = options[:method] if [:put, :delete].include?(options[:method])
|
580
|
+
options[:method] = :post
|
581
|
+
end
|
582
|
+
fake_form_method
|
583
|
+
end
|
584
|
+
|
585
|
+
def generate_fake_form_method(fake_form_method)
|
586
|
+
fake_form_method ? hidden_field(:name => "_method", :value => "#{fake_form_method}") : ""
|
587
|
+
end
|
588
|
+
|
589
|
+
def optional_label(attrs = {})
|
590
|
+
label = attrs.delete(:label) if attrs
|
591
|
+
if label
|
592
|
+
title = label.is_a?(Hash) ? label.delete(:title) : label
|
593
|
+
named = attrs[:id].blank? ? {} : {:for => attrs[:id]}
|
594
|
+
align = label.delete(:align) if label.is_a?(Hash)
|
595
|
+
align ||= ['radio', 'checkbox'].include?(attrs[:type].to_s) ? :right : :left
|
596
|
+
label_tag = label(title, '', label.is_a?(Hash) ? label.merge(named) : named)
|
597
|
+
if align && align.to_sym == :right
|
598
|
+
yield + label_tag
|
577
599
|
else
|
578
|
-
yield
|
600
|
+
label_tag + yield
|
579
601
|
end
|
602
|
+
else
|
603
|
+
yield
|
580
604
|
end
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
605
|
+
end
|
606
|
+
|
607
|
+
def errorify_field(attrs, col)
|
608
|
+
attrs.add_html_class!("error") if @_obj.respond_to?(:errors) && @_obj.errors.on(col)
|
609
|
+
end
|
610
|
+
|
611
|
+
def set_multipart_attribute!(attrs = {})
|
612
|
+
attrs.merge!( :enctype => "multipart/form-data" ) if attrs.delete(:multipart)
|
613
|
+
end
|
589
614
|
|
590
615
|
end
|
591
616
|
end
|
592
617
|
end
|
593
618
|
|
594
|
-
class Merb::
|
619
|
+
class Merb::Controller #:nodoc:
|
595
620
|
include Merb::Helpers::Form
|
596
621
|
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Merb
|
2
|
+
module Helpers
|
3
|
+
module Tag
|
4
|
+
# Creates a generic HTML tag. You can invoke it a variety of ways.
|
5
|
+
#
|
6
|
+
# tag :div
|
7
|
+
# # <div></div>
|
8
|
+
#
|
9
|
+
# tag :div, 'content'
|
10
|
+
# # <div>content</div>
|
11
|
+
#
|
12
|
+
# tag :div, :class => 'class'
|
13
|
+
# # <div class="class"></div>
|
14
|
+
#
|
15
|
+
# tag :div, 'content', :class => 'class'
|
16
|
+
# # <div class="class">content</div>
|
17
|
+
#
|
18
|
+
# tag :div do
|
19
|
+
# 'content'
|
20
|
+
# end
|
21
|
+
# # <div>content</div>
|
22
|
+
#
|
23
|
+
# tag :div, :class => 'class' do
|
24
|
+
# 'content'
|
25
|
+
# end
|
26
|
+
# # <div class="class">content</div>
|
27
|
+
#
|
28
|
+
def tag(name, contents = nil, attrs = {}, &block)
|
29
|
+
attrs = contents if contents.is_a?(Hash)
|
30
|
+
contents = capture(&block) if block_given?
|
31
|
+
open_tag(name, attrs) + contents.to_s + close_tag(name)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Creates the opening tag with attributes for the provided +name+
|
35
|
+
# attrs is a hash where all members will be mapped to key="value"
|
36
|
+
#
|
37
|
+
# Note: This tag will need to be closed
|
38
|
+
def open_tag(name, attrs = nil)
|
39
|
+
"<#{name}#{' ' + attrs.to_html_attributes if attrs && !attrs.empty?}>"
|
40
|
+
end
|
41
|
+
|
42
|
+
# Creates a closing tag
|
43
|
+
def close_tag(name)
|
44
|
+
"</#{name}>"
|
45
|
+
end
|
46
|
+
|
47
|
+
# Creates a self closing tag. Like <br/> or <img src="..."/>
|
48
|
+
#
|
49
|
+
# +name+ : the name of the tag to create
|
50
|
+
# +attrs+ : a hash where all members will be mapped to key="value"
|
51
|
+
def self_closing_tag(name, attrs = nil)
|
52
|
+
"<#{name}#{' ' + attrs.to_html_attributes if attrs && !attrs.empty?}/>"
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class Merb::Controller #:nodoc:
|
60
|
+
include Merb::Helpers::Tag
|
61
|
+
end
|
metadata
CHANGED
@@ -1,66 +1,72 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
|
-
rubygems_version: 0.9.0
|
3
|
-
specification_version: 1
|
4
2
|
name: merb_helpers
|
5
3
|
version: !ruby/object:Gem::Version
|
6
|
-
version:
|
7
|
-
date: 2008-01-09 00:00:00 -08:00
|
8
|
-
summary: Helper support for merb (similar to the Rails form helpers)
|
9
|
-
require_paths:
|
10
|
-
- lib
|
11
|
-
email: wycats@gmail.com
|
12
|
-
homepage: http://merb.rubyforge.org/
|
13
|
-
rubyforge_project:
|
14
|
-
description: Helper support for merb (similar to the Rails form helpers)
|
15
|
-
autorequire: merb_helpers
|
16
|
-
default_executable:
|
17
|
-
bindir: bin
|
18
|
-
has_rdoc: true
|
19
|
-
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
-
requirements:
|
21
|
-
- - ">"
|
22
|
-
- !ruby/object:Gem::Version
|
23
|
-
version: 0.0.0
|
24
|
-
version:
|
4
|
+
version: 0.9.2
|
25
5
|
platform: ruby
|
26
|
-
signing_key:
|
27
|
-
cert_chain:
|
28
|
-
post_install_message:
|
29
6
|
authors:
|
30
7
|
- Yehuda Katz
|
8
|
+
autorequire: merb_helpers
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-03-24 00:00:00 -05:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: merb-core
|
17
|
+
version_requirement:
|
18
|
+
version_requirements: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 0.9.2
|
23
|
+
version:
|
24
|
+
description: Helper support for merb (similar to the Rails form helpers)
|
25
|
+
email: wycats@gmail.com
|
26
|
+
executables: []
|
27
|
+
|
28
|
+
extensions: []
|
29
|
+
|
30
|
+
extra_rdoc_files:
|
31
|
+
- README
|
32
|
+
- LICENSE
|
33
|
+
- TODO
|
31
34
|
files:
|
32
35
|
- LICENSE
|
33
36
|
- README
|
34
37
|
- Rakefile
|
35
38
|
- TODO
|
36
39
|
- lib/merb_helpers
|
37
|
-
- lib/merb_helpers.rb
|
38
|
-
- lib/tasks
|
39
40
|
- lib/merb_helpers/date_time_helpers.rb
|
40
41
|
- lib/merb_helpers/form_helpers.rb
|
41
42
|
- lib/merb_helpers/form_model.rb
|
42
|
-
- lib/
|
43
|
-
|
44
|
-
|
43
|
+
- lib/merb_helpers/tag_helpers.rb
|
44
|
+
- lib/merb_helpers.rb
|
45
|
+
has_rdoc: true
|
46
|
+
homepage: http://merb.rubyforge.org/
|
47
|
+
post_install_message:
|
45
48
|
rdoc_options: []
|
46
49
|
|
47
|
-
|
48
|
-
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
50
|
+
require_paths:
|
51
|
+
- lib
|
52
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: "0"
|
57
|
+
version:
|
58
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: "0"
|
63
|
+
version:
|
55
64
|
requirements: []
|
56
65
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
- !ruby/object:Gem::Version
|
65
|
-
version: "0.5"
|
66
|
-
version:
|
66
|
+
rubyforge_project:
|
67
|
+
rubygems_version: 1.0.1
|
68
|
+
signing_key:
|
69
|
+
specification_version: 2
|
70
|
+
summary: Helper support for merb (similar to the Rails form helpers)
|
71
|
+
test_files: []
|
72
|
+
|