merb_helpers 0.5 → 0.9.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|