hobo 1.1.0.pre2 → 1.1.0.pre3
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/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:
|