hobo 0.6.2 → 0.6.3

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.
Files changed (60) hide show
  1. data/bin/hobo +21 -22
  2. data/hobo_files/plugin/CHANGES.txt +429 -4
  3. data/hobo_files/plugin/Rakefile +2 -2
  4. data/hobo_files/plugin/generators/hobo_front_controller/templates/index.dryml +6 -5
  5. data/hobo_files/plugin/generators/hobo_front_controller/templates/search.dryml +2 -2
  6. data/hobo_files/plugin/generators/hobo_migration/hobo_migration_generator.rb +20 -15
  7. data/hobo_files/plugin/generators/hobo_model/templates/model.rb +1 -0
  8. data/hobo_files/plugin/generators/hobo_model_controller/templates/controller.rb +2 -0
  9. data/hobo_files/plugin/generators/hobo_rapid/templates/hobo_base.css +1 -2
  10. data/hobo_files/plugin/generators/hobo_rapid/templates/hobo_rapid.css +4 -3
  11. data/hobo_files/plugin/generators/hobo_rapid/templates/hobo_rapid.js +94 -12
  12. data/hobo_files/plugin/generators/hobo_rapid/templates/lowpro.js +5 -183
  13. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/stylesheets/application.css +1 -1
  14. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/views/application.dryml +23 -1
  15. data/hobo_files/plugin/generators/hobo_user_controller/templates/controller.rb +2 -0
  16. data/hobo_files/plugin/generators/hobo_user_model/templates/model.rb +3 -1
  17. data/hobo_files/plugin/init.rb +18 -7
  18. data/hobo_files/plugin/lib/active_record/has_many_association.rb +2 -2
  19. data/hobo_files/plugin/lib/extensions.rb +56 -12
  20. data/hobo_files/plugin/lib/hobo.rb +25 -88
  21. data/hobo_files/plugin/lib/hobo/composite_model.rb +2 -0
  22. data/hobo_files/plugin/lib/hobo/controller.rb +40 -20
  23. data/hobo_files/plugin/lib/hobo/dryml.rb +122 -106
  24. data/hobo_files/plugin/lib/hobo/dryml/dryml_builder.rb +2 -1
  25. data/hobo_files/plugin/lib/hobo/dryml/part_context.rb +3 -2
  26. data/hobo_files/plugin/lib/hobo/dryml/taglib.rb +19 -3
  27. data/hobo_files/plugin/lib/hobo/dryml/template.rb +40 -25
  28. data/hobo_files/plugin/lib/hobo/dryml/template_environment.rb +41 -20
  29. data/hobo_files/plugin/lib/hobo/email_address.rb +4 -1
  30. data/hobo_files/plugin/lib/hobo/enum_string.rb +50 -0
  31. data/hobo_files/plugin/lib/hobo/field_declaration_dsl.rb +36 -0
  32. data/hobo_files/plugin/lib/hobo/field_spec.rb +4 -7
  33. data/hobo_files/plugin/lib/hobo/hobo_helper.rb +47 -44
  34. data/hobo_files/plugin/lib/hobo/html_string.rb +2 -0
  35. data/hobo_files/plugin/lib/hobo/markdown_string.rb +2 -0
  36. data/hobo_files/plugin/lib/hobo/model.rb +158 -89
  37. data/hobo_files/plugin/lib/hobo/model_controller.rb +422 -376
  38. data/hobo_files/plugin/lib/hobo/model_queries.rb +1 -1
  39. data/hobo_files/plugin/lib/hobo/model_router.rb +174 -0
  40. data/hobo_files/plugin/lib/hobo/password_string.rb +2 -0
  41. data/hobo_files/plugin/lib/hobo/percentage.rb +14 -0
  42. data/hobo_files/plugin/lib/hobo/plugins.rb +4 -4
  43. data/hobo_files/plugin/lib/hobo/rapid_helper.rb +10 -2
  44. data/hobo_files/plugin/lib/hobo/text.rb +3 -3
  45. data/hobo_files/plugin/lib/hobo/textile_string.rb +2 -0
  46. data/hobo_files/plugin/lib/hobo/undefined.rb +3 -2
  47. data/hobo_files/plugin/lib/hobo/{authenticated_user.rb → user.rb} +10 -3
  48. data/hobo_files/plugin/lib/hobo/user_controller.rb +27 -23
  49. data/hobo_files/plugin/tags/core.dryml +8 -2
  50. data/hobo_files/plugin/tags/rapid.dryml +52 -40
  51. data/hobo_files/plugin/tags/rapid_document_tags.dryml +15 -11
  52. data/hobo_files/plugin/tags/rapid_editing.dryml +41 -9
  53. data/hobo_files/plugin/tags/rapid_forms.dryml +136 -36
  54. data/hobo_files/plugin/tags/rapid_navigation.dryml +2 -2
  55. data/hobo_files/plugin/tags/rapid_pages.dryml +204 -221
  56. data/hobo_files/plugin/tags/rapid_plus.dryml +8 -6
  57. data/hobo_files/plugin/tags/rapid_support.dryml +2 -3
  58. metadata +44 -42
  59. data/hobo_files/plugin/lib/hobo/define_tags.rb +0 -56
  60. data/hobo_files/plugin/lib/hobo/http_parameters.rb +0 -225
@@ -1,4 +1,4 @@
1
- <def tag="field_list"><table class="field_list"><tagbody/></table></def>
1
+ <def tag="field_list"><table class="field_list" merge_attrs><tagbody/></table></def>
2
2
 
3
3
  <def tag="field_list_item"><tr merge_attrs><tagbody/></tr></def>
4
4
 
@@ -11,36 +11,40 @@
11
11
  <%= content_tag "h#{scope.heading_level || '1'}", tagbody.call, attributes %>
12
12
  </def>
13
13
 
14
+ <def tag="sub_heading">
15
+ <%= content_tag "h#{scope.heading_level.to_i + 1|| '2'}", tagbody.call, attributes.merge(:class => "subheading") %>
16
+ </def>
17
+
14
18
  <def tag="nav">
15
19
  <div class="nav" merge_attrs><tagbody/></div>
16
20
  </def>
17
21
 
18
22
  <!-- section represents a generic document or application section. -->
19
- <def tag="section">
23
+ <def tag="section" attrs="empty">
20
24
  <set body="&tagbody ? tagbody.call : ''"/>
21
- <div class="section" merge_attrs if="&body"><%= body %></div>
25
+ <div class="section" merge_attrs if="&!body.blank? || empty"><%= body %></div>
22
26
  </def>
23
27
 
24
- <def tag="aside">
28
+ <def tag="aside" attrs="empty">
25
29
  <set body="&tagbody ? tagbody.call : ''"/>
26
- <div class="aside" merge_attrs if="&body"><%= body %></div>
30
+ <div class="aside" merge_attrs if="&!body.blank? || empty"><%= body %></div>
27
31
  </def>
28
32
 
29
- <def tag="header">
33
+ <def tag="header" attrs="empty">
30
34
  <set body="&tagbody ? tagbody.call : ''"/>
31
- <div class="header" merge_attrs if="&body"><%= body %></div>
35
+ <div class="header" merge_attrs if="&!body.blank? || empty"><%= body %></div>
32
36
  </def>
33
37
 
34
- <def tag="footer">
38
+ <def tag="footer" attrs="empty">
35
39
  <set body="&tagbody ? tagbody.call : ''"/>
36
- <div class="footer" merge_attrs if="&body"><%= body %></div>
40
+ <div class="footer" merge_attrs if="&!body.blank? || empty"><%= body %></div>
37
41
  </def>
38
42
 
39
43
  <!-- article represents an independent piece of content of a -->
40
44
  <!-- document, such as a blog entry or newspaper article. -->
41
- <def tag="article">
45
+ <def tag="article" attrs="empty">
42
46
  <set body="&tagbody ? tagbody.call : ''"/>
43
- <div class="article" merge_attrs if="&body"><%= body %></div>
47
+ <div class="article" merge_attrs if="&!body.blank? || empty"><%= body %></div>
44
48
  </def>
45
49
 
46
50
  <!-- temporary tag -->
@@ -41,13 +41,7 @@
41
41
 
42
42
  <def tag="editor" for="boolean"><boolean_checkbox_editor merge_attrs/></def>
43
43
 
44
-
45
- <def tag="submit" attrs="label, image">
46
- <input if="&image" type="image" src="&image" merge_attrs class="image_input submit_button"/>
47
- <else>
48
- <input type="submit" value="#{label}" merge_attrs class="button_input submit_button"/>
49
- </else>
50
- </def>
44
+ <def tag="editor" for="big_integer"><%= in_place_editor "in_place_textfield_bhv", attributes %></def>
51
45
 
52
46
 
53
47
  <def tag="autocompleter" attrs="completer_model, completer_attr, id, filter, name, value">
@@ -60,8 +54,7 @@
60
54
  end
61
55
  id ||= this_field_dom_id + "_completer"
62
56
  url = object_url(completer_model, "completions",
63
- { :for => completer_attr },
64
- attributes.select_hash {|k,v| k.to_s.starts_with? "where_"})
57
+ { :for => completer_attr }.update(attributes.select_hash {|k,v| k.to_s.starts_with? "where_"}))
65
58
  %>
66
59
  <input type="text" name="#{name}" id="#{id}" class="autocomplete_bhv"
67
60
  autocomplete_url="#{url}" value="#{value}"
@@ -188,3 +181,42 @@
188
181
  </def>
189
182
 
190
183
 
184
+ <def tag="has_many_checkbox_editor" attrs="model, update, message"><%=
185
+ raise HoboError.new("no update specified") unless update
186
+
187
+ fields = attributes.delete_if{|k,v|!k.ends_with? "_id"}
188
+ conditions = fields.map{|k,v|"#{k}=#{v}"}.join " AND "
189
+
190
+ klass = model.is_a?(String) ? model.constantize : model
191
+ obj = klass.find(:first, :conditions => conditions)
192
+
193
+ checkbox_attrs = {:type =>'checkbox'}
194
+
195
+ if obj == nil
196
+ new = klass.new(fields)
197
+ permission = if can_create?(new)
198
+ message ||= "Setting #{new.class.name.titleize}"
199
+ class_name = new.class.name.underscore
200
+ checkbox_attrs[:onclick] = ajax_updater(object_url(new.class), message, update,
201
+ ({:params => { class_name => fields }} unless fields.empty?))
202
+ end
203
+ else
204
+ permission = if can_delete?(obj)
205
+ checkbox_attrs[:checked] = 'checked'
206
+ message ||= "Unsetting #{obj.class.name.titleize}"
207
+ class_name = obj.class.name.underscore
208
+ checkbox_attrs[:onclick] = ajax_updater(object_url(obj, "destroy"), message, update, {:method => 'delete'})
209
+ end
210
+ end
211
+ tag :input, add_classes(attributes.merge(checkbox_attrs),
212
+ "checkbox_input has_many_checkbox has_many_#{class_name}_checkbox") if permission
213
+ %></def>
214
+
215
+ <def tag="HasManyCheckboxEditors">
216
+ <Table>
217
+ <tr>
218
+ <td><has_many_checkbox_editor param="editor" merge_attrs/></td>
219
+ <td><name param/></td>
220
+ </tr>
221
+ </Table>
222
+ </def>
@@ -9,9 +9,14 @@
9
9
  comma_split(fields)
10
10
  end
11
11
  pname = this.class.name.underscore
12
- hiddens.map { |h| [ "#{pname}[#{h}]", this.send(h) ] }
12
+ hiddens.map do |field|
13
+ val = this.send(field)
14
+ ["#{pname}[#{field}]", val] unless val.nil? ||
15
+ field.to_sym.in?(this.class.attr_protected) ||
16
+ (this.new_record? && val == this.class.column(field).default)
17
+ end.compact
13
18
  end
14
- pairs.map {|n, v| hidden_field_tag(n, v.to_s) if v && n.not_in?(skip)}.compact.join("\n")
19
+ pairs.map { |n, v| hidden_field_tag(n, v.to_s) if v && n.not_in?(skip) }.compact.join("\n")
15
20
  %></def>
16
21
 
17
22
 
@@ -35,6 +40,7 @@
35
40
  end
36
41
 
37
42
  if update || !ajax_attrs.empty?
43
+ message ||= "Creating #{this.class.name.titleize}" if new_record
38
44
  # add an onsubmit to convert to an ajax form if `update` is given
39
45
  function = ajax_updater(:post_form, message, update, ajax_attrs)
40
46
  html_attrs[:onsubmit] = [html_attrs[:onsubmit], "#{function}; return false;"].compact.join("; ")
@@ -46,8 +52,18 @@
46
52
  end
47
53
 
48
54
  hiddens = hidden_fields(:fields => hidden_fields, :skip => field_names) if new_record
49
-
50
- body = [http_method_hidden, hiddens, body].join
55
+
56
+ auth_token = if request_forgery_protection_token.nil?
57
+ ''
58
+ else
59
+ tag(:input, :type => "hidden",
60
+ :name => request_forgery_protection_token.to_s,
61
+ :value => form_authenticity_token)
62
+ end
63
+
64
+ page_path_hidden = hidden_field_tag("page_path", view_name)
65
+
66
+ body = [http_method_hidden, page_path_hidden, auth_token, hiddens, body].join
51
67
 
52
68
  if web_method
53
69
  add_classes!(html_attrs, "#{type_id}_#{web_method}_form")
@@ -59,32 +75,46 @@
59
75
  %></def>
60
76
 
61
77
 
78
+ <def tag="submit" attrs="label, image">
79
+ <input if="&image" type="image" src="&image" merge_attrs class="image_button submit_button"/>
80
+ <else>
81
+ <input type="submit" value="#{label}" merge_attrs class="button submit_button"/>
82
+ </else>
83
+ </def>
84
+
85
+
62
86
  <def tag="input"><%=
63
87
  if attributes[:type]
64
88
  tag :input, attributes
65
89
  elsif !can_edit?
66
90
  view
67
91
  else
68
- if this_type.respond_to?(:macro)
69
- if this_type.macro == :belongs_to
70
- belongs_to_input(attributes)
71
- elsif this_type.macro == :has_many
72
- has_many_input(attributes)
73
- end
92
+ attrs = add_classes(attributes, type_and_field)
93
+ the_input = if this_type.respond_to?(:macro)
94
+ if this_type.macro == :belongs_to
95
+ belongs_to_input(attrs)
96
+ elsif this_type.macro == :has_many
97
+ if this_type.options[:through]
98
+ has_many_through_input(attrs)
99
+ else
100
+ has_many_input(attrs)
101
+ end
102
+ end
103
+ else
104
+ add_classes!(attrs, type_id)
105
+ attrs[:name] ||= param_name_for_this
106
+ the_input = call_polymorphic_tag('input', attrs) or
107
+ raise HoboError, ("No input tag for #{this_field}:#{this_type} (this=#{this.inspect})")
108
+ end
109
+ if this_parent.errors[this_field]
110
+ "<div class='field_with_errors'>#{the_input}</div>"
74
111
  else
75
- attrs = add_classes(attributes, type_and_field, type_id)
76
- attrs[:name] ||= param_name_for_this
77
- the_input = call_polymorphic_tag('input', attrs) or
78
- raise HoboError, ("No input tag for #{this_field}:#{this_type} (this=#{this.inspect})")
79
- if this_parent.errors[this_field]
80
- "<div class='field_with_errors'>#{the_input}</div>"
81
- else
82
- the_input
83
- end
112
+ the_input
84
113
  end
85
114
  end
86
115
  %></def>
87
116
 
117
+
88
118
  <def tag="input" for="text" attrs="name">
89
119
  <%= text_area_tag(name, this, attributes) %>
90
120
  </def>
@@ -94,7 +124,7 @@
94
124
  </def>
95
125
 
96
126
  <def tag="input" for="password" attrs="name">
97
- <%= password_field_tag(name, this) %>
127
+ <%= password_field_tag(name, this, attributes) %>
98
128
  </def>
99
129
 
100
130
  <def tag="input" for="html" attrs="name">
@@ -123,6 +153,26 @@
123
153
  <%= text_field_tag(name, this, attributes) %>
124
154
  </def>
125
155
 
156
+ <def tag="input" for="big_integer" attrs="name">
157
+ <%= text_field_tag(name, this, attributes) %>
158
+ </def>
159
+
160
+
161
+
162
+
163
+ <def tag="input" for="Hobo::EnumString" attrs="labels,titleize">
164
+ <% labels ||= {} %>
165
+ <% titleize = true if titleize.nil? %>
166
+ <select name="#{param_name_for_this}" merge_attrs>
167
+ <%= options_for_select(this_type.values.map {|v| [labels.fetch(v.to_sym, titleize ? v.titleize : v), v] }, this) %>
168
+ </select>
169
+ </def>
170
+
171
+ <def tag="input" for="percentage" attrs="name">
172
+ <%= text_field_tag(name, this, attributes.merge(:size => '3', :maxlength => '3')) %>%
173
+ </def>
174
+
175
+
126
176
  <def tag="belongs_to_input">
127
177
  <%= belongs_to_menu_input(attributes) %>
128
178
  </def>
@@ -132,11 +182,17 @@
132
182
  <def tag="remote_method_button" attrs="method, update, result_update, params, label, message"><%=
133
183
  ajax_attributes, html_attributes = attributes.partition_hash(Hobo::RapidHelper::AJAX_ATTRS)
134
184
 
135
- message ||= method.titleize
136
- func = ajax_updater(object_url(this) + "/#{method}", message, update,
137
- ajax_attributes.merge(:params => params, :result_update => result_update))
138
- html_attributes.update(:type =>'button', :onclick => "var e = this; " + func, :value => label)
139
- tag(:input, add_classes(html_attributes, "button_input remote_method_button #{method}_button"))
185
+ url = object_url(this, method)
186
+ add_classes!(html_attributes, "button remote_method_button #{method}_button")
187
+ if update || result_update
188
+ message ||= method.titleize
189
+ func = ajax_updater(url, message, update,
190
+ ajax_attributes.merge(:params => params, :result_update => result_update))
191
+ html_attributes.update(:onclick => "var e = this; " + func, :type =>'button', :value => label)
192
+ tag(:input, html_attributes)
193
+ else
194
+ button_to(label, url, html_attributes)
195
+ end
140
196
  %></def>
141
197
 
142
198
 
@@ -147,7 +203,7 @@
147
203
  :params => { this.class.name.underscore => fields }.merge(params || {}),
148
204
  :method => :put)
149
205
  tag :input, add_classes(attributes.merge(:type =>'button', :onclick => func, :value => label),
150
- "button_input update_button update_#{this.class.name.underscore}_button") %>
206
+ "button update_button update_#{this.class.name.underscore}_button") %>
151
207
  </def>
152
208
 
153
209
 
@@ -159,19 +215,19 @@
159
215
  { :type => "button" }
160
216
  end)
161
217
  label ||= "Remove"
162
- confirm ||= "Are you sure?"
218
+ confirm = "Are you sure?" if confirm.nil?
163
219
 
164
220
  add_classes!(attributes,
165
- image ? "image_button_input" : "button_input",
221
+ image ? "image_button" : "button",
166
222
  "delete_button delete_#{this.class.name.underscore}_button")
167
223
  url = object_url(this, "destroy")
168
224
  if in_place == false
169
- attributes[:confirm] = confirm
225
+ attributes[:confirm] = confirm if confirm
170
226
  button_to(label, url, attributes)
171
227
  else
172
228
  fade = true if fade.nil?
173
229
  attributes[:value] = label
174
- attributes[:onclick] = "Hobo.removeButton(this, '#{url}', #{js_updates(update)}, #{fade ? 'true' : 'false'})"
230
+ attributes[:onclick] = "Hobo.removeButton(this, '#{url}', #{js_updates(update)}, {fade:#{fade}, confirm: #{confirm.inspect}})"
175
231
  tag(:input, attributes)
176
232
  end
177
233
  end
@@ -199,22 +255,22 @@
199
255
  func = ajax_updater(object_url(new.class), message, update,
200
256
  ({:params => { class_name => fields }} unless fields.empty?))
201
257
  tag :input, add_classes(attributes.merge(:type =>'button', :onclick => func, :value => label),
202
- "button_input create_button create_#{class_name}_button")
258
+ "button create_button create_#{class_name}_button")
203
259
  end
204
260
  %></def>
205
261
 
206
262
 
207
- <def tag="belongs_to_menu_input" attrs="include_none, none_message, options"><%
263
+ <def tag="belongs_to_menu_input" attrs="include_none, blank_message, options"><%
208
264
  raise HoboError.new("Not allowed to edit") unless can_edit?
209
265
 
210
- none_message ||= "(No #{this_type.name.to_s.titleize})"
211
- options ||= this_type.klass.find(:all).select {|x| can_view?(x)}
266
+ blank_message ||= "(No #{this_type.name.to_s.titleize})"
267
+ options ||= this_type.klass.find(:all, :conditions => this_type.options[:conditions]).select {|x| can_view?(x)}
212
268
  #Todo: switch to autocompleter for id_name when too many records, and id_name supported
213
269
  select_options = options.map { |x|
214
270
  [ name(:with => x, :no_wrapper => true), x.id ]
215
271
  }.sort
216
- select_options.insert(0, [none_message, ""]) if this.nil? || include_none
217
- attributes = add_classes(attributes, "input", type_and_field)
272
+ select_options.insert(0, [blank_message, ""]) if include_none || (this.nil? && include_none != false)
273
+ attributes = add_classes(attributes, "input", "belongs_to", type_and_field)
218
274
  %>
219
275
  <select name="#{param_name_for_this(true)}" merge_attrs>
220
276
  <%= options_for_select(select_options, this ? this.id : "") %>
@@ -249,3 +305,47 @@
249
305
  <tagbody/>
250
306
  </select>
251
307
  </def>
308
+
309
+
310
+ <def tag="ErrorMessages">
311
+ <section class="error_messages" merge_attrs if="&this.errors.length > 0">
312
+ <h2 param="heading">In order to proceed please correct the following:</h2>
313
+ <UL:errors.full_messages param>
314
+ <li param><%= this %></li>
315
+ </UL>
316
+ </section>
317
+ </def>
318
+
319
+
320
+ <def tag="name_array_input" attrs="targets, remove_label">
321
+ <%
322
+ all ||= this.member_class.find(:all)
323
+ values = this
324
+ %>
325
+ <div class="input has_many_through" merge_attrs>
326
+ <div style="display:none" class="item_proto">
327
+ <div class="item">
328
+ <span></span>
329
+ <input type="hidden" name="#{param_name_for_this}[]" />
330
+ <input type="button" class="remove_item" value="#{remove_label || 'Remove'}"/>
331
+ </div>
332
+ </div>
333
+ <div class="items">
334
+ <div class="item" repeat>
335
+ <span><%= this %></span>
336
+ <input type="hidden" name="#{param_name_for_this}[]" value="#{this}"/>
337
+ <input type="button" class="remove_item" value="#{remove_label || 'Remove'}"/>
338
+ </div>
339
+ </div>
340
+ <select>
341
+ <option value="">Add a <%= this_field.titleize.singularize %></option>
342
+ <option repeat="&all.sort_by {|x| name(:no_wrapper => true, :with => x).downcase}"
343
+ merge_attrs="&{:style => 'display:none'} if this.in?(values)"><name/></option>
344
+ </select>
345
+ </div>
346
+ </def>
347
+
348
+
349
+ <def tag="after_submit" attrs="uri">
350
+ <input type="hidden" value="&params[:after_submit] || uri" name="after_submit"/>
351
+ </def>
@@ -14,7 +14,7 @@
14
14
 
15
15
  <def tag="nav_item">
16
16
  <set body="&tagbody.call"/>
17
- <li class="#{'current' if (c = scope.current_navigation) && c.downcase == body.downcase.strip}"
17
+ <li class="#{'current' if (c = scope.current_navigation) && c.downcase == body.downcase.gsub(/<.*?>/, '').strip}"
18
18
  merge_attrs="&attributes - attrs_for(:a)">
19
19
  <a merge_attrs="&attributes & attrs_for(:a)"><%= body %></a>
20
20
  </li>
@@ -41,7 +41,7 @@
41
41
  <!--- Pagination Navigation -->
42
42
 
43
43
  <def tag="page_nav" attrs="params">
44
- <if test="&@pages.length > 1">
44
+ <if test="&@pages && @pages.length > 1">
45
45
  <page_n_of_count/> -
46
46
  <first_page_link params="&params">|&lt;</first_page_link>
47
47
  <previous_page_link params="&params">Previous</previous_page_link>
@@ -9,7 +9,7 @@
9
9
  <stylesheet name="application"/>
10
10
  </do>
11
11
  <do param="scripts">
12
- <%= javascript_include_tag :defaults %>
12
+ <javascript name="prototype,effects,dragdrop,controls,application"/>
13
13
  </do>
14
14
  </head>
15
15
  <body onload="Hobo.applyEvents();" param>
@@ -17,35 +17,54 @@
17
17
  </html>
18
18
  </def>
19
19
 
20
+
20
21
  <def tag="Page">
21
22
  <BasePage merge>
22
- <stylesheets>
23
+ <stylesheets param>
23
24
  <stylesheet name="hobo_base"/>
24
25
  <stylesheet name="hobo_rapid"/>
25
26
  <stylesheet name="application"/>
26
27
  </stylesheets>
27
- <scripts>
28
- <default_tagbody/>
28
+
29
+ <scripts param>
30
+ <javascript name="prototype, effects, dragdrop, controls, lowpro, hobo_rapid, application"/>
29
31
  <hobo_rapid_javascripts param/>
30
32
  </scripts>
31
33
 
32
34
  <body param>
33
35
  <div class="page_wrapper" param="wrapper">
34
36
  <ajax_progress/>
35
- <header id="page_header" param>
37
+ <header class="page_header" param>
36
38
  <nav param>
37
- <magic_nav class="main_nav" param="main_mav"/>
39
+ <magic_nav class="main_nav" param="main_nav"/>
38
40
  <account_nav if="&Hobo::UserController.user_models.first" param/>
39
41
  </nav>
40
42
  </header>
41
- <flash_message param/>
42
- <div id="page_main" param="main"></div>
43
- <footer id="page_footer" param/>
43
+ <section class="page_content" param="content">
44
+ <header class="content_header" param="content_header"/>
45
+ <flash_message param/>
46
+ <section class="content_body" param="content_body"/>
47
+ <footer class="content_footer" param="content_footer"/>
48
+ </section>
49
+ <footer class="page_footer" param/>
44
50
  </div>
45
51
  </body>
46
52
  </BasePage>
47
53
  </def>
48
54
 
55
+ <def tag="PageWithoutAside" alias_of="Page"/>
56
+ <def tag="PageWithAside">
57
+ <PageWithoutAside merge>
58
+ <content>
59
+ <section class="main_content" param="main_content">
60
+ <default_tagbody for="content"/>
61
+ </section>
62
+ <aside class="aside_content" param/>
63
+ </content>
64
+ </PageWithoutAside>
65
+ </def>
66
+
67
+
49
68
  <def tag="PageForIndex"><Page merge/></def>
50
69
  <def tag="PageForNew"><Page merge/></def>
51
70
  <def tag="PageForShow"><Page merge/></def>
@@ -53,56 +72,48 @@
53
72
  <def tag="PageForNewInCollection"><Page merge/></def>
54
73
  <def tag="PageForShowCollection"><Page merge/></def>
55
74
 
75
+
56
76
  <def tag="IndexPage">
57
77
  <% model_name = @model.name.titleize %>
58
78
  <PageForIndex title="All #{model_name.pluralize}" merge>
59
- <body class="rapid_generic_page"/>
60
- <main>
61
- <header>
62
- <heading><%= model_name.pluralize %></heading>
63
- </header>
64
-
65
- <nav param="top_page_nav"><page_nav/></nav>
66
-
67
- <panel param="main" class="main">
68
- <header param="main_header" with="&@model">
69
- <h2><count part="item_count"/></h2>
70
- </header>
71
- <section param="main_section">
72
- <Table param>
73
- <tr><td><a/></td><td><delete_button update="item_count"/></td></tr>
74
- </Table>
75
- </section>
76
-
77
- <nav param="bottom_page_nav"><page_nav/></nav>
78
-
79
- <section param="new_link"><a to="&@model" action="new"/></section>
80
- </panel>
81
- </main>
79
+ <body class="index_page #{@model.name.underscore.pluralize}" param/>
80
+ <content_header param>
81
+ <heading param><%= model_name.pluralize %></heading>
82
+ <p class="note" param>There <count part="item_count" prefix="are" with="&@model"/></p>
83
+ </content_header>
84
+
85
+ <content_body param>
86
+ <nav param="top_pagination_nav"><page_nav/></nav>
87
+
88
+ <Table param>
89
+ <tr><td><a/></td><td><delete_button update="item_count"/></td></tr>
90
+ </Table>
91
+
92
+ <nav param="bottom_pagination_nav"><page_nav/></nav>
93
+ </content_body>
94
+
95
+ <content_footer param>
96
+ <a to="&@model" action="new" param="new_link"/>
97
+ </content_footer>
82
98
  </PageForIndex>
83
99
  </def>
84
100
 
85
101
 
86
102
  <def tag="NewPage">
87
103
  <PageForNew title="New #{type_name}" merge>
88
- <body class="rapid_generic_page new_page new_#{type_name.underscore}"/>
89
- <main>
90
- <header param>
91
- <heading>New <type_name title/></heading>
92
- </header>
93
-
94
- <panel param="main" class="main">
95
- <header param="main_header"><h2>Details</h2></header>
96
- <section>
97
- <error_messages param="error_messages"/>
98
-
99
- <form>
100
- <FieldList skip_associations="has_many" param/>
101
- <submit label="Create" param/>
102
- </form>
103
- </section>
104
- </panel>
105
- </main>
104
+ <body class="new_page #{type_name.underscore}" param/>
105
+ <content_header param>
106
+ <heading param>New <type_name title/></heading>
107
+ </content_header>
108
+
109
+ <content_body param>
110
+ <ErrorMessages param/>
111
+
112
+ <form param>
113
+ <FieldList skip_associations="has_many" param/>
114
+ <submit label="Create" param/>
115
+ </form>
116
+ </content_body>
106
117
  </PageForNew>
107
118
  </def>
108
119
 
@@ -113,87 +124,61 @@
113
124
  end.compact
114
125
  %>
115
126
  <PageForShow merge>
116
- <body class="rapid_generic_page show_page show_#{type_name.underscore}"/>
117
- <main>
118
- <header>
119
- <heading><type_name/><if test="&this.respond_to? :name">: <editor:name/></if></heading>
120
- <delete_button in_place="&false"/>
121
- </header>
122
-
123
- <panel param="main_panel">
124
- <header param="main_header"><h2>Details</h2></header>
125
- <section>
126
- <FieldList skip="name" tag="editor" param/>
127
- </section>
128
-
129
- <nav param="new_links">
130
- <UL with="&has_many_assocs">
131
- <li><a action="new"/></li>
132
- </UL>
133
- </nav>
134
- </panel>
135
- </main>
127
+ <body class="show_page #{type_name.underscore}" param/>
128
+ <content_header param>
129
+ <heading param><type_name/><if test="&this.respond_to? :name">: <editor:name/></if></heading>
130
+ <delete_button in_place="&false" param/>
131
+ </content_header>
132
+
133
+ <content_body param>
134
+ <FieldList skip="name" tag="editor" param/>
135
+
136
+ <nav param="new_links">
137
+ <UL with="&has_many_assocs">
138
+ <li><a action="new"/></li>
139
+ </UL>
140
+ </nav>
141
+ </content_body>
136
142
  </PageForShow>
137
143
  </def>
138
144
 
139
145
 
140
146
  <def tag="EditPage">
141
- <% has_many_assocs = this.class.reflections.values.map do |refl|
142
- this.send(refl.name) if Hobo.simple_has_many_association?(refl)
143
- end.compact
144
- %>
145
147
  <PageForEdit merge>
146
- <body class="rapid_generic_page edit_page edit_#{type_name.underscore}"/>
147
- <main>
148
- <header>
149
- <heading><type_name/><if test="&this.respond_to? :name">: <name/></if></heading>
150
- <delete_button in_place="&false" param/>
151
- </header>
152
-
153
- <panel param="main_panel">
154
- <header param="main_header"><h2>Details</h2></header>
155
- <section>
156
- <error_messages param="error_messages"/>
157
- <form>
158
- <FieldList skip="name" param/>
159
- <submit label="Save"/>
160
- </form>
161
- </section>
148
+ <body class="edit_page #{this.class.name.underscore}" param/>
149
+ <content_header param>
150
+ <heading><type_name/><if test="&this.respond_to? :name">: <name/></if></heading>
151
+ <delete_button in_place="&false" param/>
152
+ </content_header>
153
+
154
+ <content_body param>
155
+ <ErrorMessages param/>
156
+ <form param>
157
+ <FieldList skip_associations="has_many" param/>
158
+ <submit label="Save"/>
159
+ </form>
162
160
 
163
- <section param="new_links">
164
- <UL with="&has_many_assocs">
165
- <li><a action="new"/></li>
166
- </UL>
167
- </section>
168
- </panel>
169
- </main>
161
+ </content_body>
170
162
  </PageForEdit>
171
163
  </def>
172
164
 
173
165
 
174
166
  <def tag="NewInCollectionPage">
175
167
  <PageForNewInCollection title="New #{type_name}" merge>
176
- <body class="rapid_generic_page"/>
177
- <main>
178
- <header param>
179
- <h1 param>New <type_name/></h1>
180
- <h2 param>For: <a with="&@owner" /></h2>
181
- </header>
182
-
183
- <panel param="main">
184
- <header param="main_header">
185
- <h2>Details</h2>
186
- </header>
187
- <section>
188
- <error_messages param="error_messages"/>
189
-
190
- <form>
191
- <FieldList skip_associations="has_many"/>
192
- <submit label='Add to #{name(:with => @owner, :no_wrapper => true)}' param/>
193
- </form>
194
- </section>
195
- </panel>
196
- </main>
168
+ <body class="new_in_collection_page #{type_name(:with => @owner)} #{type_name}" param/>
169
+ <content_header param>
170
+ <heading param>New <type_name/></heading>
171
+ <sub_heading param>For: <a with="&@owner" /></sub_heading>
172
+ </content_header>
173
+
174
+ <content_body param>
175
+ <ErrorMessages/>
176
+
177
+ <form param>
178
+ <FieldList skip_associations="has_many" param/>
179
+ <submit label='Add to #{name(:with => @owner, :no_wrapper => true)}' param/>
180
+ </form>
181
+ </content_body>
197
182
  </PageForNewInCollection>
198
183
  </def>
199
184
 
@@ -201,76 +186,64 @@
201
186
  <def tag="ShowCollectionPage">
202
187
  <% title = "#{@reflection.name.to_s.titleize} for #{name(:with => @owner)}" %>
203
188
  <PageForShowCollection title="&title" merge>
204
- <body class="rapid_generic_page"/>
205
- <main>
206
- <header>
207
- <h1><%= title %></h1>
208
- <h2>Back to <a with="&@owner"/></h2>
209
- </header>
210
-
211
- <panel param="main">
212
- <header param="main_header">
213
- <count with="&@pages.item_count" label="&@reflection.klass.name.titleize"/>
214
- </header>
215
-
216
- <nav param="top_page_nav"><page_nav/></nav>
217
-
218
- <section>
219
- <Table param="Table">
220
- <tr>
221
- <if test="can_view?">
222
- <td><a/></td><td><delete_button/></td>
223
- </if>
224
- </tr>
225
- </Table>
226
- </section>
227
-
228
- <nav param="bottom_page_nav"><page_nav param/></nav>
229
-
230
- <if test="&Hobo.simple_has_many_association?(@association)">
231
- <section param="new_link">
232
- <a to="&@association" action="new"/>
233
- </section>
234
- </if>
235
- </panel>
236
- </main>
189
+ <body class="show_collection_page #{type_name(:with => @owner)} #{type_name(:pluralize => true)}"
190
+ param/>
191
+ <content_header param>
192
+ <nav>Back to <a with="&@owner"/></nav>
193
+ <heading><%= title %></heading>
194
+ <sub_heading><count with="&@pages.item_count" label="&@reflection.klass.name.titleize"/></sub_heading>
195
+ </content_header>
196
+
197
+ <content_body param>
198
+ <nav param="top_pagination_nav"><page_nav/></nav>
199
+
200
+ <Table param="Table">
201
+ <tr>
202
+ <if test="can_view?">
203
+ <td><a/></td><td><delete_button/></td>
204
+ </if>
205
+ </tr>
206
+ </Table>
207
+
208
+ <nav param="bottom_pagination_nav"><page_nav param/></nav>
209
+
210
+ <nav if="&Hobo.simple_has_many_association?(@association)" param="new_link">
211
+ <a to="&@association" action="new"/>
212
+ </nav>
213
+ </content_body>
237
214
  </PageForShowCollection>
238
215
  </def>
239
216
 
240
217
 
241
218
  <def tag="LoginPage" attrs="remember_me">
242
- <Page title="Login" merge>
219
+ <Page title="Log In" merge>
243
220
  <body class="login_page" param/>
244
- <main>
245
- <h1 param="login_title">Log In</h1>
246
-
247
- <panel>
248
- <section param>
249
- <form action="&request.request_uri" param>
250
- <table class="login_table">
251
- <tr>
252
- <td class="field_label">
253
- <label param="login_label" for="login"><%= @user_model.login_attr.to_s.titleize %></label>
254
- </td>
255
- <td><input param="login_input" type="text" name="login" id="login"/></td>
256
- </tr>
257
-
258
- <tr>
259
- <td class="field_label"><label param="password_label" for="password">Password</label></td>
260
- <td><input param="password_input" type="password" name="password" id="password"/></td>
261
- </tr>
262
-
263
- <tr if="&remember_me">
264
- <td class="field_label"><label param="remember_me_label" for="remember_me">Remember me:</label></td>
265
- <td><input param="remember_me_input" type="checkbox" name="remember_me" id="remember_me"/></td>
266
- </tr>
267
- </table>
268
-
269
- <p><submit param label='Log in'/></p>
270
- </form>
271
- </section>
272
- </panel>
273
- </main>
221
+ <nav replace/>
222
+ <content_header param>
223
+ <heading param>Log In</heading>
224
+ </content_header>
225
+
226
+ <content_body param>
227
+ <form action="&request.request_uri" param>
228
+ <field_list>
229
+ <field_list_item>
230
+ <item_label param="login_label"><%= model.login_attr.to_s.titleize %></item_label>
231
+ <item_value><input type="text" name="login" id="login" param="login_input" /></item_value>
232
+ </field_list_item>
233
+
234
+ <field_list_item>
235
+ <item_label param="password_label">Password</item_label>
236
+ <item_value><input type="password" name="password" id="password" param="password_input"/></item_value>
237
+ </field_list_item>
238
+
239
+ <field_list_item if="&remember_me">
240
+ <item_label class="field_label" param="remember_me_label">Remember me:</item_label>
241
+ <item_value><input type="checkbox" name="remember_me" id="remember_me" param="remember_me_input"/></item_value>
242
+ </field_list_item>
243
+ </field_list>
244
+ <submit label='Log in' param/>
245
+ </form>
246
+ </content_body>
274
247
  </Page>
275
248
  </def>
276
249
 
@@ -278,40 +251,41 @@
278
251
  <def tag="SignupPage">
279
252
  <Page title="Sign Up" merge>
280
253
  <body class="signup_page" param/>
254
+ <nav replace/>
255
+ <content_header param>
256
+ <heading param>Sign Up</heading>
257
+ </content_header>
258
+
259
+ <content_body param>
260
+ <ErrorMessages/>
261
+ <form action="&request.request_uri" param>
262
+ <FieldList fields="login, password, password_confirmation" param>
263
+ <password_confirmation_label>Confirm Password</password_confirmation_label>
264
+ </FieldList>
265
+
266
+ <submit label='Sign Up'/>
267
+ </form>
268
+ </content_body>
281
269
 
282
- <main>
283
- <h1>Sign Up</h1>
284
-
285
- <panel>
286
- <section>
287
- <error_messages/>
288
- <form action="&request.request_uri">
289
- <table class="signup_table">
290
- <tr>
291
- <td class="field_label"><label for="login">Login</label></td>
292
- <td><input type="text" name="user[login]"/></td>
293
- </tr>
294
-
295
- <tr>
296
- <td class="field_label"><label for="password">Password</label></td>
297
- <td><input type="password" name="user[password]"/></td>
298
- </tr>
299
-
300
- <tr>
301
- <td class="field_label"><label for="password">Confirm Password</label></td>
302
- <td><input type="password" name="user[password_confirmation]"/></td>
303
- </tr>
304
- </table>
305
-
306
- <p><submit label='Sign Up'/></p>
307
- </form>
308
- </section>
309
- </panel>
310
- </main>
270
+ </Page>
271
+ </def>
311
272
 
273
+
274
+ <def tag="PermissionDeniedPage">
275
+ <Page merge>
276
+ <content_header param>
277
+ <heading param>That operation is not allowed</heading>
278
+ </content_header>
312
279
  </Page>
313
280
  </def>
314
281
 
282
+ <def tag="NotFoundPage">
283
+ <Page merge>
284
+ <content_header param>
285
+ <heading param>The page you were looking for could not be found</heading>
286
+ </content_header>
287
+ </Page>
288
+ </def>
315
289
 
316
290
  <def tag="doctype" attrs="version"><%=
317
291
  case version.upcase
@@ -333,26 +307,35 @@
333
307
  end
334
308
  %></def>
335
309
 
336
- <def tag="stylesheet" attrs="name,media">
337
- <link href="#{base_url}/stylesheets/#{name}.css" media="#{ media || 'all' }" rel="stylesheet" type="text/css" />
310
+ <def tag="stylesheet" attrs="name, media">
311
+ <repeat with="&comma_split(name)">
312
+ <link href="#{base_url}/stylesheets/#{this}.css" media="#{ media || 'all' }"
313
+ rel="stylesheet" type="text/css" />
314
+ </repeat>
315
+ </def>
316
+
317
+ <def tag="javascript" attrs="name">
318
+ <if test="&name.is_a?(Symbol)">
319
+ <%= javascript_include_tag name %>
320
+ </if>
321
+ <else>
322
+ <repeat with="&comma_split(name)">
323
+ <%= javascript_include_tag this %>
324
+ </repeat>
325
+ </else>
338
326
  </def>
339
327
 
340
- <def tag="flash_message" attr="type">
328
+ <def tag="flash_message" attrs="type">
341
329
  <% type = type ? type.to_sym : :notice %>
342
- <div class="flash" if="&flash[type]"><%= flash[type] %></div>
330
+ <div class="flash #{type}" if="&flash[type]" merge_attrs><%= flash[type] %></div>
343
331
  </def>
344
332
 
345
333
  <def tag="ajax_progress">
346
- <div id='ajax_progress'>
334
+ <div id="ajax_progress">
347
335
  <div>
348
336
  <span id="ajax_progress_text"></span>
349
337
  </div>
350
338
  </div>
351
339
  </def>
352
340
 
353
- <def tag="error_messages">
354
- <div class="error_messages">
355
- <%= error_messages_for 'this' %>
356
- </div>
357
- </def>
358
341