hobo 0.6.2 → 0.6.3

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