hobo 0.9.0 → 0.9.100
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 +132 -0
- data/Rakefile +18 -22
- data/bin/hobo +14 -13
- data/doctest/scopes.rdoctest +1 -0
- data/dryml_generators/rapid/forms.dryml.erb +1 -1
- data/dryml_generators/rapid/pages.dryml.erb +24 -24
- data/lib/hobo.rb +3 -3
- data/lib/hobo/accessible_associations.rb +10 -3
- data/lib/hobo/controller.rb +2 -1
- data/lib/hobo/dryml.rb +7 -2
- data/lib/hobo/dryml/dryml_builder.rb +1 -4
- data/lib/hobo/dryml/dryml_generator.rb +5 -3
- data/lib/hobo/dryml/taglib.rb +3 -8
- data/lib/hobo/dryml/template.rb +3 -10
- data/lib/hobo/dryml/template_handler.rb +3 -2
- data/lib/hobo/hobo_helper.rb +5 -83
- data/lib/hobo/lifecycles.rb +9 -5
- data/lib/hobo/lifecycles/actions.rb +5 -5
- data/lib/hobo/lifecycles/lifecycle.rb +6 -2
- data/lib/hobo/model.rb +14 -36
- data/lib/hobo/model_controller.rb +28 -15
- data/lib/hobo/model_router.rb +1 -1
- data/lib/hobo/permissions.rb +55 -5
- data/lib/hobo/permissions/associations.rb +13 -5
- data/lib/hobo/rapid_helper.rb +4 -10
- data/lib/hobo/scopes/automatic_scopes.rb +9 -1
- data/lib/hobo/translations.rb +88 -0
- data/lib/hobo/user.rb +1 -2
- data/lib/hobo/user_controller.rb +31 -9
- data/lib/hobo/view_hints.rb +38 -6
- data/rails_generators/hobo_model/templates/hints.rb +4 -1
- data/rails_generators/hobo_model_controller/hobo_model_controller_generator.rb +1 -1
- data/rails_generators/hobo_rapid/hobo_rapid_generator.rb +2 -1
- data/rails_generators/hobo_rapid/templates/hobo-rapid.js +9 -0
- data/rails_generators/hobo_rapid/templates/ie7-recalc.js +166 -2
- data/rails_generators/hobo_user_model/templates/model.rb +1 -3
- data/taglibs/rapid.dryml +2 -1
- data/taglibs/rapid_core.dryml +7 -5
- data/taglibs/rapid_editing.dryml +14 -10
- data/taglibs/rapid_forms.dryml +7 -5
- data/taglibs/rapid_generics.dryml +1 -1
- data/taglibs/rapid_lifecycles.dryml +3 -2
- data/taglibs/rapid_pages.dryml +1 -1
- data/taglibs/rapid_support.dryml +1 -1
- data/tasks/hobo_tasks.rake +10 -0
- metadata +7 -7
- data/lib/hobo/bundle.rb +0 -330
data/lib/hobo/user.rb
CHANGED
@@ -31,7 +31,6 @@ module Hobo
|
|
31
31
|
remember_token_expires_at :datetime
|
32
32
|
end
|
33
33
|
|
34
|
-
validates_presence_of :password_confirmation, :if => :new_password_required?
|
35
34
|
validates_confirmation_of :password, :if => :new_password_required?
|
36
35
|
password_validations
|
37
36
|
validate :validate_current_password_when_changing_password
|
@@ -167,7 +166,7 @@ module Hobo
|
|
167
166
|
|
168
167
|
|
169
168
|
def validate_current_password_when_changing_password
|
170
|
-
changing_password? && !authenticated?(current_password) and errors.add :current_password, ht(
|
169
|
+
changing_password? && !authenticated?(current_password) and errors.add :current_password, Hobo::Translations.ht("hobo.messages.current_password_is_not_correct", :default => "is not correct")
|
171
170
|
end
|
172
171
|
|
173
172
|
end
|
data/lib/hobo/user_controller.rb
CHANGED
@@ -54,7 +54,13 @@ module Hobo
|
|
54
54
|
private
|
55
55
|
|
56
56
|
def hobo_login(options={})
|
57
|
-
|
57
|
+
if logged_in?
|
58
|
+
respond_to do |wants|
|
59
|
+
wants.html { redirect_to home_page }
|
60
|
+
wants.js { hobo_ajax_response }
|
61
|
+
end
|
62
|
+
return
|
63
|
+
end
|
58
64
|
|
59
65
|
login_attr = model.login_attribute.to_s.titleize.downcase
|
60
66
|
options.reverse_merge!(:success_notice => ht(:"users.messages.login.success", :default=>["You have logged in."]),
|
@@ -73,14 +79,24 @@ module Hobo
|
|
73
79
|
if !user.account_active?
|
74
80
|
# account not activate - cancel this login
|
75
81
|
self.current_user = old_user
|
76
|
-
|
82
|
+
unless performed?
|
83
|
+
respond_to do |wants|
|
84
|
+
wants.html {render :action => :account_disabled}
|
85
|
+
wants.js {hobo_ajax_response}
|
86
|
+
end
|
87
|
+
end
|
77
88
|
else
|
78
89
|
if params[:remember_me].present?
|
79
90
|
current_user.remember_me
|
80
91
|
create_auth_cookie
|
81
92
|
end
|
82
93
|
flash[:notice] ||= options[:success_notice]
|
83
|
-
|
94
|
+
unless performed?
|
95
|
+
respond_to do |wants|
|
96
|
+
wants.html {redirect_back_or_default(options[:redirect_to] || home_page) }
|
97
|
+
wants.js {hobo_ajax_response}
|
98
|
+
end
|
99
|
+
end
|
84
100
|
end
|
85
101
|
end
|
86
102
|
end
|
@@ -98,13 +114,13 @@ module Hobo
|
|
98
114
|
do_creator_action(:signup) do
|
99
115
|
if valid?
|
100
116
|
flash[:notice] = ht(:"users.messages.signup.success", :default=>["Thanks for signing up!"])
|
101
|
-
flash[:notice] << ht(:"users.messages.signup.must_activate", :default=>[" You must activate your account before you can log in. Please check your email."]) unless this.account_active?
|
102
117
|
end
|
103
118
|
response_block(&b) or if valid?
|
104
|
-
if this.account_active?
|
105
|
-
|
119
|
+
self.current_user = this if this.account_active?
|
120
|
+
respond_to do |wants|
|
121
|
+
wants.html { redirect_back_or_default(home_page) }
|
122
|
+
wants.js { hobo_ajax_response }
|
106
123
|
end
|
107
|
-
redirect_back_or_default(home_page)
|
108
124
|
end
|
109
125
|
end
|
110
126
|
end
|
@@ -127,7 +143,10 @@ module Hobo
|
|
127
143
|
if user && (!block_given? || yield(user))
|
128
144
|
user.lifecycle.request_password_reset!(:nobody)
|
129
145
|
end
|
130
|
-
|
146
|
+
respond_to do |wants|
|
147
|
+
wants.html { render_tag :forgot_password_email_sent_page }
|
148
|
+
wants.js { hobo_ajax_response}
|
149
|
+
end
|
131
150
|
end
|
132
151
|
end
|
133
152
|
|
@@ -137,7 +156,10 @@ module Hobo
|
|
137
156
|
response_block(&b) or if valid?
|
138
157
|
self.current_user = this
|
139
158
|
flash[:notice] = ht(:"users.messages.reset_password", :default=>["Your password has been reset"])
|
140
|
-
|
159
|
+
respond_to do |wants|
|
160
|
+
wants.html { redirect_to(home_page) }
|
161
|
+
wants.js { hobo_ajax_response }
|
162
|
+
end
|
141
163
|
end
|
142
164
|
end
|
143
165
|
end
|
data/lib/hobo/view_hints.rb
CHANGED
@@ -26,17 +26,29 @@ module Hobo
|
|
26
26
|
end
|
27
27
|
end
|
28
28
|
end
|
29
|
-
|
30
|
-
setter :model_name, proc { name.sub(/Hints$/, "") }
|
31
|
-
|
29
|
+
|
32
30
|
setter :field_names, {}
|
33
31
|
|
34
32
|
setter :field_help, {}
|
35
33
|
|
36
|
-
setter :children,
|
34
|
+
setter :children, [] do |*args|
|
35
|
+
# Setting children also gives a default parent using the reverse association
|
36
|
+
child_model = model.reflections[args.first].klass
|
37
|
+
if child_model.view_hints.parent.nil? and !child_model.view_hints.parent_defined
|
38
|
+
parent = model.reverse_reflection(args.first)
|
39
|
+
child_model.view_hints.parent(parent.name, :undefined => true)
|
40
|
+
end
|
37
41
|
args
|
38
42
|
end
|
39
43
|
|
44
|
+
setter :parent, nil do |*args|
|
45
|
+
options = args.extract_options!
|
46
|
+
parent_defined(true) unless options[:undefined]
|
47
|
+
args.first
|
48
|
+
end
|
49
|
+
|
50
|
+
setter :parent_defined, nil
|
51
|
+
|
40
52
|
setter :paginate?, proc { !sortable? }
|
41
53
|
|
42
54
|
setter :sortable?, proc { defined?(ActiveRecord::Acts::List::InstanceMethods) &&
|
@@ -54,14 +66,34 @@ module Hobo
|
|
54
66
|
# Accessors
|
55
67
|
|
56
68
|
class << self
|
69
|
+
|
70
|
+
def _name
|
71
|
+
@_name ||= name.sub(/Hints$/, '')
|
72
|
+
end
|
57
73
|
|
74
|
+
def model_name(new_name=nil)
|
75
|
+
if new_name.nil?
|
76
|
+
@model_name ||= Hobo::Translations.ht("#{_name.tableize}.model_name", :default => _name.titleize)
|
77
|
+
else
|
78
|
+
@model_name = Hobo::Translations.ht("#{_name.tableize}.model_name", :default => new_name)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def model_name_plural(new_name=nil)
|
83
|
+
if new_name.nil?
|
84
|
+
@model_name_plural ||= Hobo::Translations.ht("#{_name.tableize}.model_name_plural", :default => model_name.pluralize)
|
85
|
+
else
|
86
|
+
@model_name_plural = Hobo::Translations.ht("#{_name.tableize}.model_name_plural", :default => new_name)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
58
90
|
def model
|
59
|
-
@model ||=
|
91
|
+
@model ||= _name.constantize
|
60
92
|
end
|
61
93
|
|
62
94
|
|
63
95
|
def field_name(field)
|
64
|
-
field_names.fetch(field.to_sym, field.to_s.titleize)
|
96
|
+
Hobo::Translations.ht("#{_name.tableize}.#{field}", :default => field_names.fetch(field.to_sym, field.to_s.titleize))
|
65
97
|
end
|
66
98
|
|
67
99
|
def primary_children
|
@@ -1,4 +1,7 @@
|
|
1
1
|
class <%= class_name %>Hints < Hobo::ViewHints
|
2
2
|
|
3
|
-
|
3
|
+
# model_name "My Model"
|
4
|
+
# field_names :field1 => "First Field", :field2 => "Second Field"
|
5
|
+
# field_help :field1 => "Enter what you want in this field"
|
6
|
+
# children :primary_collection1, :aside_collection1, :aside_collection2
|
4
7
|
end
|
@@ -21,7 +21,8 @@ class HoboRapidGenerator < Hobo::Generator
|
|
21
21
|
create_all(m, "themes/clean/views", "app/views/taglibs/themes/clean")
|
22
22
|
|
23
23
|
if with_admin_site?
|
24
|
-
options = ["
|
24
|
+
options = ["admin"]
|
25
|
+
options.unshift "--make-front-site" unless File.exist?('app/views/taglibs/front_site.dryml')
|
25
26
|
options.unshift "--invite-only" if invite_only?
|
26
27
|
m.dependency 'hobo_admin_site', options
|
27
28
|
end
|
@@ -193,6 +193,7 @@ var Hobo = {
|
|
193
193
|
onLeaveHover: null,
|
194
194
|
callback: function(form, val) {
|
195
195
|
old = val
|
196
|
+
el.setAttribute("hobo-edit-text", val)
|
196
197
|
return (Hobo.fieldSetParam(el, val) + "&" + updateParams)
|
197
198
|
},
|
198
199
|
onFailure: function(_, resp) {
|
@@ -200,6 +201,10 @@ var Hobo = {
|
|
200
201
|
},
|
201
202
|
onEnterEditMode: function() {
|
202
203
|
var blank_message = el.getAttribute("hobo-blank-message")
|
204
|
+
var editable_text = el.getAttribute("hobo-edit-text")
|
205
|
+
if (editable_text) {
|
206
|
+
el.innerHTML = editable_text
|
207
|
+
}
|
203
208
|
if (el.innerHTML.gsub(" ", " ") == blank_message) {
|
204
209
|
el.innerHTML = ""
|
205
210
|
} else {
|
@@ -785,6 +790,10 @@ Event.addBehavior({
|
|
785
790
|
rows: 2, handleLineBreaks: false, okButton: true, cancelLink: true, okText: "Save", submitOnBlur: false
|
786
791
|
}
|
787
792
|
var ipe = Hobo._makeInPlaceEditor(this, options)
|
793
|
+
ipe.getText = function() {
|
794
|
+
// Be careful! we're not calling unescapeHTML() here!
|
795
|
+
return this.element.innerHTML
|
796
|
+
}
|
788
797
|
}
|
789
798
|
},
|
790
799
|
|
@@ -1,2 +1,166 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
|
2
|
+
// =========================================================================
|
3
|
+
// ie7-recalc.js
|
4
|
+
// =========================================================================
|
5
|
+
|
6
|
+
(function() {
|
7
|
+
/* ---------------------------------------------------------------------
|
8
|
+
|
9
|
+
This allows refreshing of IE7 style rules. If you modify the DOM
|
10
|
+
you can update IE7 by calling document.recalc().
|
11
|
+
|
12
|
+
This should be the LAST module included.
|
13
|
+
|
14
|
+
--------------------------------------------------------------------- */
|
15
|
+
|
16
|
+
if (!IE7.loaded) return;
|
17
|
+
|
18
|
+
// remove all IE7 classes from an element
|
19
|
+
CLASSES = /\sie7_class\d+/g;
|
20
|
+
|
21
|
+
IE7.CSS.extend({
|
22
|
+
// store for elements that have style properties calculated
|
23
|
+
elements: {},
|
24
|
+
handlers: [],
|
25
|
+
|
26
|
+
// clear IE7 classes and styles
|
27
|
+
reset: function() {
|
28
|
+
this.removeEventHandlers();
|
29
|
+
// reset IE7 classes here
|
30
|
+
var elements = this.elements;
|
31
|
+
for (var i in elements) elements[i].runtimeStyle.cssText = "";
|
32
|
+
this.elements = {};
|
33
|
+
// reset runtimeStyle here
|
34
|
+
var elements = IE7.Rule.elements;
|
35
|
+
for (var i in elements) {
|
36
|
+
with (elements[i]) className = className.replace(CLASSES, "");
|
37
|
+
}
|
38
|
+
IE7.Rule.elements = {};
|
39
|
+
},
|
40
|
+
|
41
|
+
reload: function() {
|
42
|
+
this.rules = [];
|
43
|
+
this.getInlineStyles();
|
44
|
+
this.screen.load();
|
45
|
+
if (this.print) this.print.load();
|
46
|
+
this.refresh();
|
47
|
+
this.trash();
|
48
|
+
},
|
49
|
+
|
50
|
+
addRecalc: function(propertyName, test, handler, replacement) {
|
51
|
+
// call the ancestor method to add a wrapped recalc method
|
52
|
+
this.base(propertyName, test, function(element) {
|
53
|
+
// execute the original recalc method
|
54
|
+
handler(element);
|
55
|
+
// store a reference to this element so we can clear its style later
|
56
|
+
IE7.CSS.elements[element.uniqueID] = element;
|
57
|
+
}, replacement);
|
58
|
+
},
|
59
|
+
|
60
|
+
recalc: function() {
|
61
|
+
// clear IE7 styles and classes
|
62
|
+
this.reset();
|
63
|
+
// execute the ancestor method to perform recalculations
|
64
|
+
this.base();
|
65
|
+
},
|
66
|
+
|
67
|
+
addEventHandler: function(element, type, handler) {
|
68
|
+
element.attachEvent(type, handler);
|
69
|
+
// store the handler so it can be detached later
|
70
|
+
this.handlers.push(arguments);
|
71
|
+
},
|
72
|
+
|
73
|
+
removeEventHandlers: function() {
|
74
|
+
var handler;
|
75
|
+
while (handler = this.handlers.pop()) {
|
76
|
+
handler[0].detachEvent(handler[1], handler[2]);
|
77
|
+
}
|
78
|
+
},
|
79
|
+
|
80
|
+
getInlineStyles: function() {
|
81
|
+
// load inline styles
|
82
|
+
var styleSheets = document.getElementsByTagName("style"), styleSheet;
|
83
|
+
for (var i = styleSheets.length - 1; (styleSheet = styleSheets[i]); i--) {
|
84
|
+
if (!styleSheet.disabled && !styleSheet.ie7) {
|
85
|
+
var cssText = styleSheet.cssText || styleSheet.innerHTML;
|
86
|
+
this.styles.push(cssText);
|
87
|
+
styleSheet.cssText = cssText;
|
88
|
+
}
|
89
|
+
}
|
90
|
+
},
|
91
|
+
|
92
|
+
trash: function() {
|
93
|
+
// trash the old style sheets
|
94
|
+
var styleSheets = document.styleSheets, styleSheet, i;
|
95
|
+
for (i = 0; i < styleSheets.length; i++) {
|
96
|
+
styleSheet = styleSheets[i];
|
97
|
+
if (!styleSheet.ie7 && !styleSheet.cssText && styleSheet.cssText != '') {
|
98
|
+
styleSheet.cssText = styleSheet.cssText;
|
99
|
+
}
|
100
|
+
}
|
101
|
+
this.base();
|
102
|
+
},
|
103
|
+
|
104
|
+
getText: function(styleSheet) {
|
105
|
+
return styleSheet.cssText || this.base(styleSheet);
|
106
|
+
}
|
107
|
+
});
|
108
|
+
|
109
|
+
// remove event handlers (they eat memory)
|
110
|
+
IE7.CSS.addEventHandler(window, "onunload", function() {
|
111
|
+
IE7.CSS.removeEventHandlers();
|
112
|
+
});
|
113
|
+
|
114
|
+
// store all elements with an IE7 class assigned
|
115
|
+
IE7.Rule.elements = {};
|
116
|
+
|
117
|
+
IE7.Rule.prototype.extend({
|
118
|
+
add: function(element) {
|
119
|
+
// execute the ancestor "add" method
|
120
|
+
this.base(element);
|
121
|
+
// store a reference to this element so we can clear its classes later
|
122
|
+
IE7.Rule.elements[element.uniqueID] = element;
|
123
|
+
}
|
124
|
+
});
|
125
|
+
|
126
|
+
// store created pseudo elements
|
127
|
+
if (IE7.PseudoElement) {
|
128
|
+
IE7.PseudoElement.hash = {};
|
129
|
+
|
130
|
+
IE7.PseudoElement.prototype.extend({
|
131
|
+
create: function(target) {
|
132
|
+
var key = this.selector + ":" + target.uniqueID;
|
133
|
+
if (!IE7.PseudoElement.hash[key]) {
|
134
|
+
IE7.PseudoElement.hash[key] = true;
|
135
|
+
this.base(target);
|
136
|
+
}
|
137
|
+
}
|
138
|
+
});
|
139
|
+
}
|
140
|
+
|
141
|
+
IE7.HTML.extend({
|
142
|
+
elements: {},
|
143
|
+
|
144
|
+
addRecalc: function(selector, handler) {
|
145
|
+
// call the ancestor method to add a wrapped recalc method
|
146
|
+
this.base(selector, function(element) {
|
147
|
+
if (!this.elements[element.uniqueID]) {
|
148
|
+
// execute the original recalc method
|
149
|
+
handler(element);
|
150
|
+
// store a reference to this element so that
|
151
|
+
// it is not "fixed" again
|
152
|
+
this.elements[element.uniqueID] = element;
|
153
|
+
}
|
154
|
+
});
|
155
|
+
}
|
156
|
+
});
|
157
|
+
|
158
|
+
// allow refreshing of IE7 fixes
|
159
|
+
document.recalc = function(reload) {
|
160
|
+
if (IE7.CSS.screen) {
|
161
|
+
if (reload) IE7.CSS.reload();
|
162
|
+
IE7.recalc();
|
163
|
+
}
|
164
|
+
};
|
165
|
+
|
166
|
+
})();
|
@@ -3,14 +3,12 @@ class <%= class_name %> < ActiveRecord::Base
|
|
3
3
|
hobo_user_model # Don't put anything above this
|
4
4
|
|
5
5
|
fields do
|
6
|
-
name
|
6
|
+
name :string, :required, :unique
|
7
7
|
email_address :email_address, :login => true
|
8
8
|
administrator :boolean, :default => false
|
9
9
|
timestamps
|
10
10
|
end
|
11
11
|
|
12
|
-
validates_presence_of :name
|
13
|
-
|
14
12
|
# This gives admin rights to the first sign-up.
|
15
13
|
# Just remove it if you don't want that
|
16
14
|
before_create { |user| user.administrator = true if !Rails.env.test? && count == 0 }
|
data/taglibs/rapid.dryml
CHANGED
@@ -18,4 +18,5 @@ The Rapid tag library makes web development go fast. The Rapid tag library is yo
|
|
18
18
|
<include src="rapid_plus"/>
|
19
19
|
<include src="rapid_generics"/>
|
20
20
|
<include src="rapid_lifecycles"/>
|
21
|
-
<include src="rapid_summary"/>
|
21
|
+
<include src="rapid_summary"/>
|
22
|
+
<include src="rapid_user_pages"/>
|
data/taglibs/rapid_core.dryml
CHANGED
@@ -13,17 +13,19 @@
|
|
13
13
|
|
14
14
|
- tag: The name of a tag to use inside the `<td>` to display the value. Defaults to `view`
|
15
15
|
|
16
|
-
-
|
17
|
-
|
18
|
-
|
19
|
-
|
16
|
+
- no-edit: Controls the behavior of `<input>` tags when the user doesn't have edit permission for a field.
|
17
|
+
- view: render the current value using the `<view>` tag
|
18
|
+
- disable: render the input as normal, but add HTML's `disabled` attribute
|
19
|
+
- skip: render nothing at all. This will omit the entire row (including the label)
|
20
|
+
- ignore: render the input normally. That is, don't even perform the edit check.
|
21
|
+
|
20
22
|
-->
|
21
23
|
<def tag="field-list" attrs="tag, no-edit">
|
22
24
|
<% tag ||= scope.in_form ? "input" : "view"; no_edit ||= "skip" %>
|
23
25
|
<labelled-item-list merge-attrs="&attributes - attrs_for(:with_fields)">
|
24
26
|
<with-fields merge-attrs="&attributes & attrs_for(:with_fields)">
|
25
27
|
<% field_name = this_field_name
|
26
|
-
input_attrs = {:no_edit => no_edit} if tag == "input"
|
28
|
+
input_attrs = {:no_edit => no_edit} if tag == "input"
|
27
29
|
-%>
|
28
30
|
<labelled-item unless="&tag == 'input' && no_edit == 'skip' && !can_edit?">
|
29
31
|
<item-label param="#{this_field.to_s.sub('?', '')}-label" unless="&field_name.blank?">
|