hobo 1.1.0.pre2 → 1.1.0.pre3
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.txt +34 -0
- data/doctest/scopes.rdoctest +20 -6
- data/lib/active_record/association_collection.rb +0 -11
- data/lib/hobo/authentication_support.rb +1 -1
- data/lib/hobo/controller.rb +4 -3
- data/lib/hobo/lifecycles/lifecycle.rb +5 -2
- data/lib/hobo/lifecycles/transition.rb +2 -1
- data/lib/hobo/model.rb +16 -8
- data/lib/hobo/model_controller.rb +7 -5
- data/lib/hobo/scopes/automatic_scopes.rb +29 -1
- data/lib/hobo/scopes/named_scope_extensions.rb +26 -14
- data/lib/hobo/user.rb +6 -6
- data/lib/hobo.rb +1 -1
- data/rails_generators/hobo_rapid/templates/hobo-rapid.js +1 -1
- data/rapid_generators/rapid/pages.dryml.erb +2 -2
- data/taglibs/rapid_core.dryml +15 -8
- data/taglibs/rapid_forms.dryml +10 -9
- data/taglibs/rapid_plus.dryml +1 -1
- data/taglibs/rapid_user_pages.dryml +2 -2
- metadata +13 -13
data/CHANGES.txt
CHANGED
@@ -14,6 +14,40 @@ likely to cause conflicts, so it is highly recommended that you have
|
|
14
14
|
your code backed up and in a change control system such as git or
|
15
15
|
subversion.
|
16
16
|
|
17
|
+
=== Hobo 1.1 ===
|
18
|
+
|
19
|
+
The default password validation has been changed to 6 characters, one
|
20
|
+
of which must not be lowercase. Luckily, we also made the password
|
21
|
+
validation easier to change. See
|
22
|
+
[Bug #638](https://hobo.lighthouseapp.com/projects/8324/tickets/638) for
|
23
|
+
more information.
|
24
|
+
|
25
|
+
=== Hobo 1.0.3 ===
|
26
|
+
|
27
|
+
This is a security release. All applications that use the reset
|
28
|
+
password functionality should upgrade.
|
29
|
+
|
30
|
+
To patch the vulnerability, two changes have been made.
|
31
|
+
|
32
|
+
First of all, the lifecycle key hash mechanism has been changed.
|
33
|
+
Existing lifecycle keys will become invalid after you upgrade.
|
34
|
+
Lifecycle keys are typically short lived, so this is unlikely to be a
|
35
|
+
problem for most applications.
|
36
|
+
|
37
|
+
Secondly, lifecycle keys are now cleared on every transition to avoid
|
38
|
+
replay vulnerabilities. This new behaviour may be avoided by added
|
39
|
+
the `:keep_key => true` option to a transition.
|
40
|
+
|
41
|
+
More information about the vulnerability can be viewed on the [bug
|
42
|
+
report](https://hobo.lighthouseapp.com/projects/8324/tickets/666-user-model-secure-links-have-low-security).
|
43
|
+
|
44
|
+
All code changes may viewed on the [github
|
45
|
+
log](https://github.com/tablatom/hobo/compare/v1.0.2...v1.0.3)
|
46
|
+
|
47
|
+
The "include" automatic scope has been aliased to "includes" to
|
48
|
+
increase future compatibility with Rails 3. Future versions of Hobo
|
49
|
+
will remove support for "include".
|
50
|
+
|
17
51
|
=== Hobo 1.0.2 ===
|
18
52
|
|
19
53
|
This release is almost identical to 1.0.1 except that it updates the
|
data/doctest/scopes.rdoctest
CHANGED
@@ -95,6 +95,7 @@ Let's set up a few models for our testing:
|
|
95
95
|
born_at :date
|
96
96
|
code :integer
|
97
97
|
male :boolean
|
98
|
+
foo :string
|
98
99
|
timestamps
|
99
100
|
end
|
100
101
|
|
@@ -119,19 +120,19 @@ Generate a migration and run it:
|
|
119
120
|
|
120
121
|
>> ActiveRecord::Migration.class_eval(HoboFields::MigrationGenerator.run[0])
|
121
122
|
>> Person.columns.*.name
|
122
|
-
=> ["id", "name", "born_at", "code", "male", "created_at", "updated_at", "state"]
|
123
|
+
=> ["id", "name", "born_at", "code", "male", "foo", "created_at", "updated_at", "state"]
|
123
124
|
{.hidden}
|
124
125
|
|
125
126
|
And create a couple of fixtures:
|
126
127
|
|
127
128
|
>>
|
128
129
|
Bryan = Person.new(:name => "Bryan", :code => 17,
|
129
|
-
:born_at => Date.new(1973,4,8), :male => true)
|
130
|
+
:born_at => Date.new(1973,4,8), :male => true, :foo => "common")
|
130
131
|
>> Bryan.state = "active"
|
131
132
|
>> Bryan.save!
|
132
133
|
>>
|
133
134
|
Bethany = Person.new(:name => "Bethany", :code => 42,
|
134
|
-
:born_at => Date.new(1975,5,13), :male => false)
|
135
|
+
:born_at => Date.new(1975,5,13), :male => false, :foo => "common")
|
135
136
|
>> Bethany.state = "inactive"
|
136
137
|
>> Bethany.save!
|
137
138
|
>> Friendship.new(:person => Bryan, :friend => Bethany).save!
|
@@ -287,12 +288,16 @@ Gives the N most recent items:
|
|
287
288
|
>> Person.order_by(:code).*.name
|
288
289
|
=> ["Bryan", "Bethany"]
|
289
290
|
|
290
|
-
##
|
291
|
+
## includes
|
291
292
|
|
292
|
-
Adding the
|
293
|
+
Adding the includes function to your query chain has the same effect as
|
293
294
|
the `:include` option to the `find` method.
|
294
295
|
|
295
|
-
>> Person.include(:friends).*.name
|
296
|
+
>> Person.search("B", :name).include(:friends).*.name # test LH#839
|
297
|
+
=> ["Bryan", "Bethany"]
|
298
|
+
.hidden
|
299
|
+
|
300
|
+
>> Person.includes(:friends).*.name
|
296
301
|
=> ["Bryan", "Bethany"]
|
297
302
|
|
298
303
|
## search
|
@@ -397,6 +402,15 @@ Like named scopes, Hobo scopes can be chained:
|
|
397
402
|
>> Bryan.inactive_friends.inactive.*.name
|
398
403
|
=> ["Bethany"]
|
399
404
|
|
405
|
+
>> Person.scoped(:conditions => {:state => "active"}).scoped(:conditions => {:foo => "common"}).*.name
|
406
|
+
=> ["Bryan"]
|
407
|
+
|
408
|
+
>> Person.with_friendship(Friendship.first).born_before(Date.new(1974)).*.name
|
409
|
+
=> ["Bryan"]
|
410
|
+
|
411
|
+
>> Person.born_after(Date.new(1974)).with_friendship(Friendship.first).*.name
|
412
|
+
=> []
|
413
|
+
|
400
414
|
Clean up our test database:
|
401
415
|
{.hidden}
|
402
416
|
|
@@ -25,17 +25,6 @@ module ActiveRecord
|
|
25
25
|
record
|
26
26
|
end
|
27
27
|
|
28
|
-
# DO NOT call super here - AssociationProxy's version loads the collection, and that's bad.
|
29
|
-
# TODO: this really belongs in Rails; migrate it there ASAP
|
30
|
-
def respond_to?(*args)
|
31
|
-
proxy_respond_to?(*args) || Array.new.respond_to?(*args)
|
32
|
-
end
|
33
|
-
|
34
|
-
# TODO: send this patch into Rails. There's no reason to load the collection just to find out it acts like an array.
|
35
|
-
def is_a?(klass)
|
36
|
-
[].is_a?(klass)
|
37
|
-
end
|
38
|
-
|
39
28
|
def member_class
|
40
29
|
proxy_reflection.klass
|
41
30
|
end
|
@@ -67,7 +67,7 @@ module Hobo
|
|
67
67
|
accepts.xml do
|
68
68
|
headers["Status"] = "Unauthorized"
|
69
69
|
headers["WWW-Authenticate"] = %(Basic realm="Web Password")
|
70
|
-
render :text => ht("hobo.messages.unauthenticated", :default=>["Couldn't authenticate you"], :status => '401 Unauthorized'
|
70
|
+
render :text => ht("hobo.messages.unauthenticated", :default=>["Couldn't authenticate you"]), :status => '401 Unauthorized'
|
71
71
|
end
|
72
72
|
end
|
73
73
|
false
|
data/lib/hobo/controller.rb
CHANGED
@@ -58,7 +58,7 @@ module Hobo
|
|
58
58
|
|
59
59
|
def redirect_to_with_object_url(destination, *args)
|
60
60
|
if destination.is_one_of?(String, Hash, Symbol)
|
61
|
-
redirect_to_without_object_url(destination)
|
61
|
+
redirect_to_without_object_url(destination, *args)
|
62
62
|
else
|
63
63
|
redirect_to_without_object_url(object_url(destination, *args))
|
64
64
|
end
|
@@ -78,12 +78,12 @@ module Hobo
|
|
78
78
|
end
|
79
79
|
|
80
80
|
|
81
|
-
def ajax_update_response(page_path, render_specs, results={})
|
81
|
+
def ajax_update_response(page_path, render_specs, results={}, options={})
|
82
82
|
@template.send(:_evaluate_assigns_and_ivars)
|
83
83
|
renderer = Dryml.page_renderer(@template, [], page_path) if page_path
|
84
84
|
|
85
85
|
render :update do |page|
|
86
|
-
page << "var _update = typeof Hobo == 'undefined' ? Element.update : Hobo.updateElement;"
|
86
|
+
page << (options[:preamble] || "var _update = typeof Hobo == 'undefined' ? Element.update : Hobo.updateElement;")
|
87
87
|
for spec in render_specs
|
88
88
|
function = spec[:function] || "_update"
|
89
89
|
dom_id = spec[:id]
|
@@ -99,6 +99,7 @@ module Hobo
|
|
99
99
|
end
|
100
100
|
end
|
101
101
|
page << renderer.part_contexts_storage if renderer
|
102
|
+
page << options[:postamble] if options[:postamble]
|
102
103
|
end
|
103
104
|
end
|
104
105
|
|
@@ -168,7 +168,6 @@ module Hobo
|
|
168
168
|
def become(state_name, validate=true)
|
169
169
|
state_name = state_name.to_sym
|
170
170
|
record.write_attribute self.class.state_field, state_name.to_s
|
171
|
-
|
172
171
|
if state_name == :destroy
|
173
172
|
record.destroy
|
174
173
|
true
|
@@ -210,7 +209,7 @@ module Hobo
|
|
210
209
|
timestamp = record.read_attribute(key_timestamp_field)
|
211
210
|
if timestamp
|
212
211
|
timestamp = timestamp.getutc
|
213
|
-
Digest::SHA1.hexdigest("#{record.id}-#{state_name}-#{timestamp}")
|
212
|
+
Digest::SHA1.hexdigest("#{record.id}-#{state_name}-#{timestamp}-#{ActionController::Base.session_options[:secret]}")
|
214
213
|
end
|
215
214
|
end
|
216
215
|
|
@@ -223,6 +222,10 @@ module Hobo
|
|
223
222
|
provided_key && provided_key == key && !key_expired?
|
224
223
|
end
|
225
224
|
|
225
|
+
def clear_key
|
226
|
+
record.write_attribute key_timestamp_field, nil
|
227
|
+
end
|
228
|
+
|
226
229
|
def invariants_satisfied?
|
227
230
|
self.class.invariants.all? { |i| record.instance_eval(&i) }
|
228
231
|
end
|
data/lib/hobo/model.rb
CHANGED
@@ -32,13 +32,17 @@ module Hobo
|
|
32
32
|
|
33
33
|
alias_method_chain :has_one, :new_method
|
34
34
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
35
|
+
# eval avoids the ruby 1.9.2 "super from singleton method ..." error
|
36
|
+
# see LH#840
|
37
|
+
eval %(
|
38
|
+
def inherited(klass)
|
39
|
+
super
|
40
|
+
fields(false) do
|
41
|
+
Hobo.register_model(klass)
|
42
|
+
field(klass.inheritance_column, :string)
|
43
|
+
end
|
40
44
|
end
|
41
|
-
|
45
|
+
)
|
42
46
|
end
|
43
47
|
|
44
48
|
# https://hobo.lighthouseapp.com/projects/8324/tickets/762-hobo_model-outside-a-full-rails-env-can-lead-to-stack-level-too-deep
|
@@ -121,8 +125,12 @@ module Hobo
|
|
121
125
|
|
122
126
|
ActiveRecord::Base.class_eval do
|
123
127
|
def self.hobo_model
|
124
|
-
include
|
125
|
-
|
128
|
+
if self.ancestors.include?(Hobo::Model)
|
129
|
+
Rails.logger.error "#{self}: Do not call hobo_model in derived classes."
|
130
|
+
else
|
131
|
+
include Hobo::Model
|
132
|
+
fields(false) # force hobofields to load
|
133
|
+
end
|
126
134
|
end
|
127
135
|
def self.hobo_user_model
|
128
136
|
include Hobo::Model
|
@@ -455,6 +455,7 @@ module Hobo
|
|
455
455
|
|
456
456
|
if do_pagination
|
457
457
|
options.reverse_merge!(:page => params[:page] || 1)
|
458
|
+
options[:order] = :created_at if options[:order] == :default
|
458
459
|
finder.paginate(options)
|
459
460
|
else
|
460
461
|
finder.all(options.except(*WILL_PAGINATE_OPTIONS))
|
@@ -521,7 +522,7 @@ module Hobo
|
|
521
522
|
this.user_update_attributes(current_user, attributes)
|
522
523
|
else
|
523
524
|
self.this = new_for_create(attributes)
|
524
|
-
this.
|
525
|
+
this.user_save(current_user)
|
525
526
|
end
|
526
527
|
create_response(:new, options, &b)
|
527
528
|
end
|
@@ -590,10 +591,11 @@ module Hobo
|
|
590
591
|
|
591
592
|
self.this ||= args.first || find_instance
|
592
593
|
changes = options[:attributes] || attribute_parameters or raise RuntimeError, ht(:"hobo.messages.update.no_attribute_error", :default=>["No update specified in params"])
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
594
|
+
|
595
|
+
if this.user_update_attributes(current_user, changes)
|
596
|
+
# Ensure current_user isn't out of date
|
597
|
+
@current_user = @this if @this == current_user
|
598
|
+
end
|
597
599
|
|
598
600
|
in_place_edit_field = changes.keys.first if changes.size == 1 && params[:render]
|
599
601
|
update_response(in_place_edit_field, options, &b)
|
@@ -267,7 +267,30 @@ module Hobo
|
|
267
267
|
field, asc = args
|
268
268
|
type = klass.attr_type(field)
|
269
269
|
if type.nil? #a virtual attribute from an SQL alias, e.g., 'total' from 'COUNT(*) AS total'
|
270
|
-
|
270
|
+
# can also be has_many association, let's check it out
|
271
|
+
_, assoc, count = *field._?.match(/^([a-z_]+)(?:\.([a-z_]+))?/)
|
272
|
+
refl = klass.attr_type(assoc)
|
273
|
+
|
274
|
+
if refl.respond_to?(:primary_key_name) && refl.macro == :has_many && count._?.upcase == 'COUNT'
|
275
|
+
owner_primary_key = "#{klass.quoted_table_name}.#{klass.primary_key}"
|
276
|
+
# now we have :has_many association in refl, is this a through association?
|
277
|
+
if (through = refl.through_reflection) && (source = refl.source_reflection)
|
278
|
+
# has_many through association was found and now we have a few variants:
|
279
|
+
# 1) owner.has_many -> through.belongs_to <- source.has_many (many to many, source.macro == :belongs_to )
|
280
|
+
# 2) owner.has_many -> through.has_many -> source.belongs_to (many to one through table, source.macro == :has_many)
|
281
|
+
colspec = "(SELECT COUNT(*) AS count_all FROM #{refl.quoted_table_name} INNER JOIN #{through.quoted_table_name}" +
|
282
|
+
" ON #{source.quoted_table_name}.#{source.macro == :belongs_to ? source.klass.primary_key : through.association_foreign_key}" +
|
283
|
+
" = #{through.quoted_table_name}.#{source.macro == :belongs_to ? source.association_foreign_key : through.klass.primary_key}" +
|
284
|
+
" WHERE #{through.quoted_table_name}.#{through.primary_key_name} = #{owner_primary_key} )"
|
285
|
+
else
|
286
|
+
# simple many to one (has_many -> belongs_to) association
|
287
|
+
colspec = "(SELECT COUNT(*) as count_all FROM #{refl.quoted_table_name}" +
|
288
|
+
" WHERE #{refl.quoted_table_name}.#{refl.primary_key_name} = #{owner_primary_key})"
|
289
|
+
end
|
290
|
+
|
291
|
+
else
|
292
|
+
colspec = "#{field}" # don't prepend the table name
|
293
|
+
end
|
271
294
|
elsif type.respond_to?(:name_attribute) && (name = type.name_attribute)
|
272
295
|
include = field
|
273
296
|
colspec = "#{type.table_name}.#{name}"
|
@@ -283,6 +306,11 @@ module Hobo
|
|
283
306
|
{ :include => inclusions }
|
284
307
|
end
|
285
308
|
|
309
|
+
when "includes"
|
310
|
+
def_scope do |inclusions|
|
311
|
+
{ :include => inclusions }
|
312
|
+
end
|
313
|
+
|
286
314
|
when "search"
|
287
315
|
def_scope do |query, *fields|
|
288
316
|
match_keyword = ::ActiveRecord::Base.connection.adapter_name == "PostgreSQL" ? "ILIKE" : "LIKE"
|
@@ -1,27 +1,39 @@
|
|
1
1
|
module ActiveRecord
|
2
2
|
module NamedScope
|
3
|
-
|
4
|
-
|
5
|
-
delegate :member_class, :to => :proxy_found
|
6
|
-
|
7
|
-
|
3
|
+
|
4
|
+
class Scope
|
5
|
+
delegate :member_class, :to => :proxy_found
|
6
|
+
include Hobo::Scopes::ApplyScopes
|
7
|
+
end
|
8
8
|
|
9
|
-
|
10
|
-
|
9
|
+
module ClassMethods
|
10
|
+
def scopes
|
11
|
+
hash = read_inheritable_attribute(:scopes)
|
12
|
+
if hash.nil?
|
13
|
+
if respond_to?(:create_automatic_scope)
|
14
|
+
write_inheritable_attribute(:scopes, new_automatic_scoping_hash(self))
|
15
|
+
else
|
16
|
+
# add a default_proc to optimize the next condition
|
17
|
+
write_inheritable_attribute(:scopes, Hash.new { |hash, key| nil })
|
18
|
+
end
|
19
|
+
elsif hash.default_proc.nil? && respond_to?(:create_automatic_scope)
|
20
|
+
write_inheritable_attribute(:scopes, new_automatic_scoping_hash(self).merge!(hash))
|
21
|
+
else
|
22
|
+
hash
|
23
|
+
end
|
11
24
|
end
|
12
25
|
|
13
26
|
private
|
14
27
|
|
15
|
-
def
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
proxy_scope.send(method, *args, &block)
|
28
|
+
def new_automatic_scoping_hash(o)
|
29
|
+
hash = Hash.new { |hash, key| o.create_automatic_scope(key) && hash[key] }
|
30
|
+
hash.meta_eval do
|
31
|
+
define_method :include? do |key, *args|
|
32
|
+
super(key, *args) || o.create_automatic_scope(key)
|
21
33
|
end
|
22
34
|
end
|
35
|
+
hash
|
23
36
|
end
|
24
|
-
|
25
37
|
end
|
26
38
|
end
|
27
39
|
end
|
data/lib/hobo/user.rb
CHANGED
@@ -32,7 +32,7 @@ module Hobo
|
|
32
32
|
end
|
33
33
|
|
34
34
|
validates_confirmation_of :password, :if => :new_password_required?
|
35
|
-
|
35
|
+
validate :validate_password
|
36
36
|
validate :validate_current_password_when_changing_password
|
37
37
|
|
38
38
|
# Virtual attributes for setting and changing the password
|
@@ -56,11 +56,6 @@ module Hobo
|
|
56
56
|
# Additional classmethods for authentication
|
57
57
|
module ClassMethods
|
58
58
|
|
59
|
-
# Validation of the plaintext password
|
60
|
-
def password_validations
|
61
|
-
validates_length_of :password, :within => 4..40, :if => :new_password_required?
|
62
|
-
end
|
63
|
-
|
64
59
|
def login_attribute=(attr, validate=true)
|
65
60
|
@login_attribute = attr = attr.to_sym
|
66
61
|
unless attr == :login
|
@@ -177,6 +172,11 @@ module Hobo
|
|
177
172
|
changing_password? && !authenticated?(current_password) and errors.add :current_password, Hobo::Translations.ht("hobo.messages.current_password_is_not_correct", :default => "is not correct")
|
178
173
|
end
|
179
174
|
|
175
|
+
# Validation of the plaintext password. Override this function
|
176
|
+
# to change your validation.
|
177
|
+
def validate_password
|
178
|
+
errors.add(:password, Hobo::Translations.ht("hobo.messages.validate_password", :default => "must be at least 6 characters long and must not consist solely of lowercase letters.")) if new_password_required? && (password.nil? || password.length<6 || /^[[:lower:]]*$/.match(password))
|
179
|
+
end
|
180
180
|
end
|
181
181
|
|
182
182
|
end
|
data/lib/hobo.rb
CHANGED
@@ -691,7 +691,7 @@ HoboInputMany = {
|
|
691
691
|
Event.stop(ev);
|
692
692
|
var ul = el.up('ul.input-many'), li = el.up('li.input-many-li');
|
693
693
|
|
694
|
-
if(li.id.search(/_-1$/ && ul.immediateDescendants().length>2)
|
694
|
+
if(li.id.search(/_-1$/)>=0 && ul.immediateDescendants().length>2) {
|
695
695
|
/* if(console) console.log("IE7 messed up again (bug 605)"); */
|
696
696
|
return;
|
697
697
|
}
|
@@ -140,7 +140,7 @@ end
|
|
140
140
|
<a:<%= back_link %> param="parent-link">« <ht key="<%= model_key %>.actions.back" to="<%= back_link %>"><name/></ht></a:<%= back_link %>>
|
141
141
|
<% end -%>
|
142
142
|
<h2 param="heading">
|
143
|
-
<ht key="<%= model_key %>.show.heading" name="&this.respond_to?(:
|
143
|
+
<ht key="<%= model_key %>.show.heading" name="&this.respond_to?(:to_s) ? this.to_s : ''">
|
144
144
|
<name/>
|
145
145
|
</ht>
|
146
146
|
</h2>
|
@@ -175,7 +175,7 @@ end
|
|
175
175
|
<% if collection -%>
|
176
176
|
<section param="collection-section">
|
177
177
|
<h3 param="collection-heading">
|
178
|
-
<ht key="<%=
|
178
|
+
<ht key="<%= collection.to_s.tableize %>.collection.heading.<%= (is_user_model ? 'your':'other') %>" >
|
179
179
|
<%= '<Your/>' if is_user_model %><%= collection.to_s.titleize %>
|
180
180
|
</ht>
|
181
181
|
</h3>
|
data/taglibs/rapid_core.dryml
CHANGED
@@ -466,14 +466,14 @@ Assuming the context is a blog post...
|
|
466
466
|
<!-- Renders a comma separated list of links (`<a>`), or "(none)" if the list is empty -->
|
467
467
|
<def tag="links-for-collection"><%= this.empty? ? "(none)" : context_map { a }.join(", ") %></def>
|
468
468
|
|
469
|
-
<!-- Renders `
|
470
|
-
<def tag="view" for="Date" attrs="format"><%= this && (format ?
|
469
|
+
<!-- Renders `I18n.l(this, :format => :long)`, or `I18n.l(this, :format => format)` if the `format` attribute is given -->
|
470
|
+
<def tag="view" for="Date" attrs="format"><%= this && (format ? I18n.l(this, :format => format) : I18n.l(this, :format => :long)) %></def>
|
471
471
|
|
472
|
-
<!-- Renders `
|
473
|
-
<def tag="view" for="Time" attrs="format"><%= this && (format ?
|
472
|
+
<!-- Renders `I18n.l(this, :format => :long)`, or `I18n.l(this, :format => format)` if the `format` attribute is given -->
|
473
|
+
<def tag="view" for="Time" attrs="format"><%= this && (format ? I18n.l(this, :format => format) : I18n.l(this, :format => :long)) %></def>
|
474
474
|
|
475
|
-
<!-- Renders `
|
476
|
-
<def tag="view" for="ActiveSupport::TimeWithZone" attrs="format"><%= this && (format ?
|
475
|
+
<!-- Renders `I18n.l(this, :format => :long)`, or `I18n.l(this, :format => format)` if the `format` attribute is given -->
|
476
|
+
<def tag="view" for="ActiveSupport::TimeWithZone" attrs="format"><%= this && (format ? I18n.l(this, :format => format) : I18n.l(this, :format => :long)) %></def>
|
477
477
|
|
478
478
|
<!-- Renders `this.to_s`, or `format % this` if the `format` attribute is given -->
|
479
479
|
<def tag="view" for="Numeric" attrs="format"><%= format ? format % this : this.to_s %></def>
|
@@ -487,12 +487,19 @@ Assuming the context is a blog post...
|
|
487
487
|
end
|
488
488
|
%></def>
|
489
489
|
|
490
|
-
<!-- Renders 'Yes' for true and 'No' for false -->
|
491
|
-
<def tag="view" for="boolean"><%= this ? 'Yes' : 'No' %></def>
|
490
|
+
<!-- Renders 'Yes' for true and 'No' for false with localization support -->
|
491
|
+
<def tag="view" for="boolean"><%= this ? ht('hobo.boolean_yes', {:default => 'Yes'}) : ht('hobo.boolean_no', {:default => 'No'}) %></def>
|
492
492
|
|
493
493
|
<!-- Renders a link (`<a>`) to `this` -->
|
494
494
|
<def tag="view" for="ActiveRecord::Base"><a merge-attrs/></def>
|
495
495
|
|
496
|
+
<!-- Renders `this.to_s` with localization support -->
|
497
|
+
<def tag="view" for="HoboFields::LifecycleState">
|
498
|
+
<span class='#{this.class.parent.name.downcase}-states #{this.class.parent.name.downcase}-state-#{this.to_s.downcase} state-#{this.to_s.downcase}'>
|
499
|
+
<ht key='#{this.class.parent.name.tableize}.lifecycle_states.#{this.to_s.downcase}'><%= this.to_s %></ht>
|
500
|
+
</span>
|
501
|
+
</def>
|
502
|
+
|
496
503
|
|
497
504
|
<!--
|
498
505
|
A convenience tag used to output a count and a correctly pluralised label. Works with any kind of collection such as an `ActiveRecord` association or an array.
|
data/taglibs/rapid_forms.dryml
CHANGED
@@ -51,7 +51,8 @@ executed at various points in the ajax request cycle:
|
|
51
51
|
hiddens = case fields
|
52
52
|
when '*', nil
|
53
53
|
# TODO: Need a better (i.e. extensible) way to eleminate certain fields
|
54
|
-
|
54
|
+
# marking a field as attr_protected is one way to eliminate a field
|
55
|
+
this.class.column_names - [this.class.inheritance_column, 'created_at', 'updated_at']
|
55
56
|
else
|
56
57
|
comma_split(fields)
|
57
58
|
end
|
@@ -574,7 +575,7 @@ All the standard ajax attributes *except the callbacks* are supported (see the m
|
|
574
575
|
else
|
575
576
|
{ :type => "button" }
|
576
577
|
end)
|
577
|
-
label ||= ht("
|
578
|
+
label ||= ht("#{this.class.name.tableize}.actions.remove", :default=>"Remove")
|
578
579
|
confirm = ht("hobo.messages.confirm", :default=>"Are you sure?") if confirm.nil?
|
579
580
|
|
580
581
|
add_classes!(attributes,
|
@@ -588,7 +589,7 @@ All the standard ajax attributes *except the callbacks* are supported (see the m
|
|
588
589
|
else
|
589
590
|
fade = true if fade.nil?
|
590
591
|
attributes[:value] = label
|
591
|
-
attributes[:onclick] = "Hobo.removeButton(this, '#{url}', #{js_updates(update)}, {fade:#{fade}, confirm: #{confirm
|
592
|
+
attributes[:onclick] = "Hobo.removeButton(this, '#{url}', #{js_updates(update)}, {fade:#{fade}, confirm: '#{confirm}'})"
|
592
593
|
element(:input, attributes, nil, true, true)
|
593
594
|
end
|
594
595
|
end
|
@@ -622,7 +623,7 @@ All of the standard ajax attributes are supported (see the main taglib documenti
|
|
622
623
|
new = class_or_assoc.new(fields)
|
623
624
|
new.set_creator(current_user)
|
624
625
|
if can_create?(new)
|
625
|
-
label ||= ht("#{new.class.name.
|
626
|
+
label ||= ht("#{new.class.name.tableize}.actions.new", :default=>"New #{new.class.name.titleize}")
|
626
627
|
ajax_attributes = { :message => message }
|
627
628
|
class_name = new.class.name.underscore
|
628
629
|
ajax_attributes[:params] = { class_name => fields } unless fields.empty?
|
@@ -653,7 +654,7 @@ For situations where there are too many target records to practically include in
|
|
653
654
|
<def tag="select-one" attrs="include-none, blank-message, options, sort, limit, text-method"><%
|
654
655
|
raise Hobo::PermissionDeniedError.new("Not allowed to edit #{this_field}") if !attributes[:disabled] && !can_edit?
|
655
656
|
|
656
|
-
blank_message ||= ht("#{this_type.name.
|
657
|
+
blank_message ||= ht("#{this_type.name.tableize}.message.none", :default=>"(No #{this_type.view_hints.model_name})")
|
657
658
|
limit ||= 100
|
658
659
|
|
659
660
|
options ||= begin
|
@@ -780,10 +781,10 @@ If you wish to set `min-chars` to 0, you will require this [patch to controls.js
|
|
780
781
|
-->
|
781
782
|
<def tag="error-messages">
|
782
783
|
<section class="error-messages" merge-attrs if="&this.errors.length > 0">
|
783
|
-
|
784
|
+
<h2 param="heading"><ht key="hobo.messages.error_correct_following">To proceed please correct the following:</ht></h2>
|
784
785
|
<ul param>
|
785
786
|
<% this.errors.each do |attr, message|; next if message == "..." -%>
|
786
|
-
<li param><%= this.class.
|
787
|
+
<li param><%= this.class.view_hints.field_name(attr) unless attr.to_s == 'base' %> <%= message %></li>
|
787
788
|
<% end -%>
|
788
789
|
</ul>
|
789
790
|
</section>
|
@@ -796,12 +797,12 @@ An input for `has_many :through` associations that lets the user chose the items
|
|
796
797
|
To use this tag, the model of the items the user is chosing *must* have unique names, and the
|
797
798
|
-->
|
798
799
|
<def tag="select-many" attrs="options, targets, remove-label, prompt, disabled, name"><%
|
799
|
-
prompt ||= "Add #{
|
800
|
+
prompt ||= ht("#{this.name.tableize}.message.none", :default=>"Add #{this.view_hints.model_name}")
|
800
801
|
options ||= this_field_reflection.klass.all(:conditions =>this.conditions).select {|x| can_view?(x)}
|
801
802
|
name ||= param_name_for_this
|
802
803
|
|
803
804
|
values = this
|
804
|
-
remove_label ||= ht("
|
805
|
+
remove_label ||= ht("#{this.name.tableize}.actions.remove", :default=>'Remove')
|
805
806
|
-%>
|
806
807
|
<div class="input select-many" merge-attrs>
|
807
808
|
<div style="display:none" class="item-proto">
|
data/taglibs/rapid_plus.dryml
CHANGED
@@ -172,7 +172,7 @@ See [Filtering stories by status](/tutorials/agility#filtering_stories_by_status
|
|
172
172
|
<% no_filter ||= "All" %>
|
173
173
|
<form action="&request.request_uri" method="get" class="filter-menu" merge-attrs="id">
|
174
174
|
<div>
|
175
|
-
<% selected = options.detect {|o| o.to_s==params[param_name.gsub('-', '_')] } %>
|
175
|
+
<% selected = options.detect {|o| o.is_a?(Array) ? o[1].to_s==params[param_name.gsub('-', '_')] : o.to_s==params[param_name.gsub('-', '_')] } %>
|
176
176
|
<select-menu name="¶m_name" options="&options" selected="&selected"
|
177
177
|
first-option="&no_filter" merge-params/>
|
178
178
|
</div>
|
@@ -165,8 +165,8 @@ if a given email is associated with an account or not. -->
|
|
165
165
|
<error-messages param/>
|
166
166
|
<form class="change-password" param>
|
167
167
|
<field-list fields="email_address, current_password, password, password_confirmation" param>
|
168
|
-
|
169
|
-
|
168
|
+
<password-label:><ht key="users.new_password">"New Password</ht></password-label:>
|
169
|
+
<password-confirmation-label:><ht key="users.confirm_new_password">Confirm New Password</ht></password-confirmation-label:>
|
170
170
|
</field-list>
|
171
171
|
|
172
172
|
<div class="actions" param="actions">
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hobo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash: -
|
4
|
+
hash: -1876988186
|
5
5
|
prerelease: true
|
6
6
|
segments:
|
7
7
|
- 1
|
8
8
|
- 1
|
9
9
|
- 0
|
10
|
-
-
|
11
|
-
version: 1.1.0.
|
10
|
+
- pre3
|
11
|
+
version: 1.1.0.pre3
|
12
12
|
platform: ruby
|
13
13
|
authors:
|
14
14
|
- Tom Locke
|
@@ -16,7 +16,7 @@ autorequire:
|
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
18
|
|
19
|
-
date:
|
19
|
+
date: 2011-01-16 00:00:00 -05:00
|
20
20
|
default_executable: hobo
|
21
21
|
dependencies:
|
22
22
|
- !ruby/object:Gem::Dependency
|
@@ -73,13 +73,13 @@ dependencies:
|
|
73
73
|
requirements:
|
74
74
|
- - "="
|
75
75
|
- !ruby/object:Gem::Version
|
76
|
-
hash: -
|
76
|
+
hash: -1876988186
|
77
77
|
segments:
|
78
78
|
- 1
|
79
79
|
- 1
|
80
80
|
- 0
|
81
|
-
-
|
82
|
-
version: 1.1.0.
|
81
|
+
- pre3
|
82
|
+
version: 1.1.0.pre3
|
83
83
|
type: :runtime
|
84
84
|
version_requirements: *id003
|
85
85
|
- !ruby/object:Gem::Dependency
|
@@ -90,13 +90,13 @@ dependencies:
|
|
90
90
|
requirements:
|
91
91
|
- - "="
|
92
92
|
- !ruby/object:Gem::Version
|
93
|
-
hash: -
|
93
|
+
hash: -1876988186
|
94
94
|
segments:
|
95
95
|
- 1
|
96
96
|
- 1
|
97
97
|
- 0
|
98
|
-
-
|
99
|
-
version: 1.1.0.
|
98
|
+
- pre3
|
99
|
+
version: 1.1.0.pre3
|
100
100
|
type: :runtime
|
101
101
|
version_requirements: *id004
|
102
102
|
- !ruby/object:Gem::Dependency
|
@@ -107,13 +107,13 @@ dependencies:
|
|
107
107
|
requirements:
|
108
108
|
- - "="
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
hash: -
|
110
|
+
hash: -1876988186
|
111
111
|
segments:
|
112
112
|
- 1
|
113
113
|
- 1
|
114
114
|
- 0
|
115
|
-
-
|
116
|
-
version: 1.1.0.
|
115
|
+
- pre3
|
116
|
+
version: 1.1.0.pre3
|
117
117
|
type: :runtime
|
118
118
|
version_requirements: *id005
|
119
119
|
description:
|