hobo 0.7.2 → 0.7.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 (77) hide show
  1. data/bin/hobo +24 -7
  2. data/hobo_files/plugin/CHANGES.txt +501 -0
  3. data/hobo_files/plugin/generators/hobo/hobo_generator.rb +8 -6
  4. data/hobo_files/plugin/generators/hobo/templates/application.dryml +3 -0
  5. data/hobo_files/plugin/generators/hobo/templates/dryml-support.js +132 -0
  6. data/hobo_files/plugin/generators/hobo_front_controller/hobo_front_controller_generator.rb +4 -5
  7. data/hobo_files/plugin/generators/hobo_model_resource/hobo_model_resource_generator.rb +75 -0
  8. data/hobo_files/plugin/generators/hobo_model_resource/templates/controller.rb +7 -0
  9. data/hobo_files/plugin/generators/hobo_model_resource/templates/functional_test.rb +8 -0
  10. data/hobo_files/plugin/generators/hobo_model_resource/templates/helper.rb +2 -0
  11. data/hobo_files/plugin/generators/hobo_rapid/templates/hobo-rapid.js +30 -11
  12. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/clean/public/stylesheets/application.css +149 -92
  13. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/clean/public/stylesheets/rapid-ui.css +0 -48
  14. data/hobo_files/plugin/init.rb +45 -13
  15. data/hobo_files/plugin/lib/action_view_extensions/base.rb +4 -3
  16. data/hobo_files/plugin/lib/active_record/association_proxy.rb +18 -0
  17. data/hobo_files/plugin/lib/active_record/association_reflection.rb +5 -0
  18. data/hobo_files/plugin/lib/active_record/has_many_association.rb +7 -11
  19. data/hobo_files/plugin/lib/active_record/has_many_through_association.rb +8 -0
  20. data/hobo_files/plugin/lib/extensions/test_case.rb +1 -1
  21. data/hobo_files/plugin/lib/hobo.rb +38 -60
  22. data/hobo_files/plugin/lib/hobo/authentication_support.rb +1 -1
  23. data/hobo_files/plugin/lib/hobo/bundle.rb +131 -34
  24. data/hobo_files/plugin/lib/hobo/composite_model.rb +1 -1
  25. data/hobo_files/plugin/lib/hobo/controller.rb +7 -8
  26. data/hobo_files/plugin/lib/hobo/dev_controller.rb +21 -0
  27. data/hobo_files/plugin/lib/hobo/dryml/dryml_builder.rb +14 -8
  28. data/hobo_files/plugin/lib/hobo/dryml/dryml_support_controller.rb +13 -0
  29. data/hobo_files/plugin/lib/hobo/dryml/taglib.rb +6 -7
  30. data/hobo_files/plugin/lib/hobo/dryml/template.rb +207 -73
  31. data/hobo_files/plugin/lib/hobo/dryml/template_environment.rb +67 -55
  32. data/hobo_files/plugin/lib/hobo/dryml/template_handler.rb +53 -3
  33. data/hobo_files/plugin/lib/hobo/hobo_helper.rb +75 -107
  34. data/hobo_files/plugin/lib/hobo/model.rb +236 -429
  35. data/hobo_files/plugin/lib/hobo/model_controller.rb +277 -437
  36. data/hobo_files/plugin/lib/hobo/model_router.rb +62 -29
  37. data/hobo_files/plugin/lib/hobo/rapid_helper.rb +48 -9
  38. data/hobo_files/plugin/lib/hobo/scopes.rb +98 -0
  39. data/hobo_files/plugin/lib/hobo/scopes/association_proxy_extensions.rb +31 -0
  40. data/hobo_files/plugin/lib/hobo/scopes/automatic_scopes.rb +282 -0
  41. data/hobo_files/plugin/lib/hobo/scopes/defined_scope_proxy_extender.rb +88 -0
  42. data/hobo_files/plugin/lib/hobo/scopes/scope_reflection.rb +18 -0
  43. data/hobo_files/plugin/lib/hobo/scopes/scoped_proxy.rb +59 -0
  44. data/hobo_files/plugin/lib/hobo/undefined.rb +2 -0
  45. data/hobo_files/plugin/lib/hobo/user.rb +31 -14
  46. data/hobo_files/plugin/lib/hobo/user_controller.rb +41 -27
  47. data/hobo_files/plugin/taglibs/core.dryml +9 -11
  48. data/hobo_files/plugin/taglibs/rapid.dryml +51 -108
  49. data/hobo_files/plugin/taglibs/rapid_editing.dryml +25 -25
  50. data/hobo_files/plugin/taglibs/rapid_forms.dryml +111 -79
  51. data/hobo_files/plugin/taglibs/rapid_generics.dryml +74 -0
  52. data/hobo_files/plugin/taglibs/rapid_navigation.dryml +23 -21
  53. data/hobo_files/plugin/taglibs/rapid_pages.dryml +83 -169
  54. data/hobo_files/plugin/taglibs/rapid_plus.dryml +16 -2
  55. data/hobo_files/plugin/taglibs/rapid_support.dryml +3 -3
  56. data/hobo_files/plugin/taglibs/rapid_user_pages.dryml +104 -0
  57. metadata +60 -55
  58. data/hobo_files/plugin/generators/hobo_migration/hobo_migration_generator.rb +0 -276
  59. data/hobo_files/plugin/generators/hobo_migration/templates/migration.rb +0 -9
  60. data/hobo_files/plugin/lib/active_record/table_definition.rb +0 -34
  61. data/hobo_files/plugin/lib/extensions.rb +0 -375
  62. data/hobo_files/plugin/lib/hobo/email_address.rb +0 -12
  63. data/hobo_files/plugin/lib/hobo/enum_string.rb +0 -50
  64. data/hobo_files/plugin/lib/hobo/field_declaration_dsl.rb +0 -43
  65. data/hobo_files/plugin/lib/hobo/field_spec.rb +0 -68
  66. data/hobo_files/plugin/lib/hobo/html_string.rb +0 -7
  67. data/hobo_files/plugin/lib/hobo/lazy_hash.rb +0 -40
  68. data/hobo_files/plugin/lib/hobo/markdown_string.rb +0 -11
  69. data/hobo_files/plugin/lib/hobo/migrations.rb +0 -12
  70. data/hobo_files/plugin/lib/hobo/model_queries.rb +0 -117
  71. data/hobo_files/plugin/lib/hobo/password_string.rb +0 -7
  72. data/hobo_files/plugin/lib/hobo/percentage.rb +0 -14
  73. data/hobo_files/plugin/lib/hobo/predicate_dispatch.rb +0 -78
  74. data/hobo_files/plugin/lib/hobo/proc_binding.rb +0 -32
  75. data/hobo_files/plugin/lib/hobo/text.rb +0 -3
  76. data/hobo_files/plugin/lib/hobo/textile_string.rb +0 -25
  77. data/hobo_files/plugin/lib/hobo/where_fragment.rb +0 -28
@@ -7,6 +7,8 @@
7
7
  <include src="rapid_forms"/>
8
8
  <include src="rapid_navigation"/>
9
9
  <include src="rapid_plus"/>
10
+ <include src="rapid_generics"/>
11
+
10
12
 
11
13
  <def tag="field-list" attrs="tag">
12
14
  <% tag ||= scope.in_form ? "input" : "view" %>
@@ -73,7 +75,7 @@
73
75
  <td param="#{this_field.to_s.sub('?', '').gsub('.', '-')}-view"><call-tag tag="&field_tag"/></td>
74
76
  </with-fields>
75
77
  <td class="controls" param="controls" if="&all_parameters[:controls]">
76
- <a param="edit-link">Edit</a>
78
+ <a param="edit-link" action="edit">Edit</a>
77
79
  <delete-button param/>
78
80
  </td>
79
81
  </if>
@@ -97,39 +99,9 @@
97
99
  </def>
98
100
 
99
101
 
100
- <def tag="theme-image" attrs="src">
101
- <img src="#{theme_asset('images/' + src)}" merge-attrs/>
102
- </def>
103
-
104
-
105
- <def tag="card">
106
- <if test="&can_view?">
107
- <%= poly = call_polymorphic_tag('card', attributes, parameters) %>
108
- <div class="card #{linkable? ? 'linkable' : 'content'} #{type_name :dasherize => true}" unless="&poly">
109
- <a if="&linkable?"/>
110
- <div class="content" param="content">
111
- <primary-content if="&!linkable?"/>
112
- </div>
113
- <creation-details/>
114
- <span class="dependents"><count-dependents /></span>
115
- </div>
116
- </if>
117
- </def>
118
-
119
-
120
- <def tag="collection">
121
- <%= poly = call_polymorphic_tag('collection', attributes, parameters) %>
122
- <ul class="collection" merge-attrs unless="&poly">
123
- <li:><card param/></li:>
124
- </ul>
125
- <p class="empty-collection-message" if="&this.empty?" param="empty-message">
126
- There are no <type-name plural/>
127
- </p>
128
- </def>
129
-
130
-
131
102
  <def tag="hobo-rapid-javascripts" attrs="tiny-mce"><%=
132
103
  res = '<script type="text/javascript">var hoboParts = {};'
104
+ # FIXME: This should interrogate the model-router - not the models
133
105
  unless Hobo.all_models.empty?
134
106
  # Tell JS code how to pluralize names, unless they follow the simple rule
135
107
  names = Hobo.all_models.map do |m|
@@ -147,7 +119,7 @@
147
119
  if tiny_mce
148
120
  res += javascript_include_tag("tiny_mce/tiny_mce_src") + %{
149
121
  <script type="text/javascript">
150
- tinyMCE.init({ mode: "textareas", editor_selector: "tiny_mce",
122
+ tinyMCE.init({ mode: "textareas", editor_selector: "tiny-mce",
151
123
  plugins: 'save',
152
124
  theme_advanced_buttons1 : "bold, italic, separator, " +
153
125
  "bullist, outdent, indent, separator, " +
@@ -183,13 +155,8 @@
183
155
  %></def>
184
156
 
185
157
  <def tag="type-name" attrs="type, plural, lowercase, dasherize"><%=
186
- type ||= if this.is_a?(Class)
187
- this
188
- elsif this.respond_to? :proxy_reflection
189
- this.proxy_reflection.klass
190
- else
191
- this.class
192
- end
158
+ type ||= (this if this.is_a?(Class)) || this.try.member_class || this.class
159
+
193
160
  name = dasherize ? type.name.underscore.dasherize : type.name.titleize
194
161
  name = name.pluralize if plural
195
162
  name = name.downcase if lowercase
@@ -216,15 +183,15 @@
216
183
  # Link to a new object form
217
184
  new_record = target.new
218
185
  new_record.set_creator(current_user)
219
- if can_create?(new_record)
220
-
186
+ href = object_url(target, "new", params._?.merge(:subsite => subsite))
187
+
188
+ if href && can_create?(new_record)
221
189
  new_class_name = if target.respond_to?(:proxy_reflection)
222
190
  target.proxy_reflection.klass.name
223
191
  else
224
192
  target.name
225
193
  end
226
194
 
227
- href = object_url(target, "new", params._?.merge(:subsite => subsite))
228
195
  add_classes!(attributes, "new-#{new_class_name.underscore}-link")
229
196
  content = "New #{new_class_name.titleize}" if content.blank?
230
197
  element(:a, attributes.update(:href => href), content)
@@ -235,17 +202,9 @@
235
202
  else
236
203
  # Link to an existing object
237
204
 
238
- if target.is_a?(Array) && !target.respond_to?(:proxy_reflection) && target.respond_to?(:member_class)
239
- # Not much to go on here - last guess is that this is an index page
240
- target = target.member_class
241
- end
242
-
243
205
  content = name if content.blank?
244
206
 
245
- # Do we want automatic disabling of links to thinks that are not
246
- # linkable?
247
- only_if_linkable = format.blank?
248
- href = object_url(target, action, (params || {}).merge(:subsite => subsite, :if_available => only_if_linkable))
207
+ href = object_url(target, action, (params || {}).merge(:subsite => subsite))
249
208
  if href.nil?
250
209
  # This target is registered with ModelRouter as not linkable
251
210
  content
@@ -268,21 +227,23 @@
268
227
 
269
228
  res = if this.nil? && if_blank.nil?
270
229
  this_type.is_a?(Class) && this_type <= String ? "" : nil_view
271
- elsif this_type.respond_to?(:macro)
272
- if this_type.macro == :belongs_to
230
+ elsif refl = this_field_reflection
231
+ if refl.macro == :belongs_to
273
232
  belongs_to_view(attributes)
274
- elsif this_type.macro == :has_many
233
+ elsif refl.macro == :has_many
275
234
  has_many_view(attributes)
276
235
  end
277
236
  else
278
- attrs = add_classes(attributes, "view", type_id, type_and_field)
279
- attrs['hobo-model-id'] = this_field_dom_id if this_parent && this_parent.respond_to?(:typed_id)
280
237
 
281
238
  view_tag = find_polymorphic_tag("view")
282
239
 
283
240
  if view_tag == "view" # i.e. it didn't find a type specific tag
284
241
  raise HoboError, "Cannot view: #{this.inspect} (field is #{this_field}, type is #{this.class})"
285
242
  else
243
+ attrs = add_classes(attributes, "view", type_and_field)
244
+ id = dom_id
245
+ attrs['hobo-model-id'] = id unless id == "nil"
246
+
286
247
  view_attrs = attrs_for(view_tag)
287
248
  the_view = send(view_tag, attrs & view_attrs)
288
249
 
@@ -325,32 +286,29 @@
325
286
 
326
287
  <def tag="view" for="html"><%= this %></def>
327
288
 
328
- <def tag="view" for="Hobo::MarkdownString"><%= this.to_html %></def>
289
+ <def tag="view" for="markdown"><%= this.to_html %></def>
290
+
291
+ <def tag="view" for="textile"><%= this.to_html %></def>
329
292
 
330
- <def tag="view" for="Hobo::TextileString"><%= this.to_html %></def>
293
+ <def tag="view" for="password">[password withheld]</def>
331
294
 
332
- <def tag="view" for="Hobo::PasswordString">[password withheld]</def>
295
+ <def tag="view" for="string"><%= h(this).gsub("\n", "<br/>") %></def>
333
296
 
334
- <def tag="view" for="String"><%= h(this).gsub("\n", "<br/>") %></def>
297
+ <def tag="view" for="boolean"><%= this ? 'Yes' : 'No' %></def>
335
298
 
336
- <def tag="view" for="TrueClass"><%= this ? 'Yes' : 'No' %></def>
337
299
 
338
- <def tag="count" attrs="label, prefix, if-any"><%=
300
+ <def tag="count" attrs="label, prefix, if-any, lowercase"><%=
339
301
  raise Exception.new("asked for count of a string") if this.is_a?(String)
340
302
 
341
- if this.is_a?(Class) and this < ActiveRecord::Base
342
- c = this.count
343
- label ||= this.name.titleize
344
- else
345
- label ||= this.respond_to?(:proxy_reflection) && this.proxy_reflection.name.to_s.singularize.titleize
346
- c = if this.is_a?(Fixnum)
347
- this
348
- elsif this.respond_to?(:count)
349
- this.count
350
- else
351
- this.length
352
- end
353
- end
303
+ c = this.try.to_int || this.try.total_entries || this.try.count || this.try.length
304
+
305
+ label ||= if this.is_a?(Class)
306
+ this.name
307
+ else
308
+ (this.try.association_name || this.try.member_class._?.name)
309
+ end.to_s.singularize.titleize
310
+
311
+ label = label.downcase if lowercase
354
312
 
355
313
  Hobo::Dryml.last_if = c > 0 if if_any
356
314
  if if_any && c == 0
@@ -360,7 +318,7 @@
360
318
 
361
319
  if prefix.in? %w(are is)
362
320
  p = c == 1 ? "is" : "are"
363
- p + ' ' + main
321
+ p + ' ' + main.to_s
364
322
  else
365
323
  main
366
324
  end
@@ -370,14 +328,11 @@
370
328
 
371
329
  <def tag="theme-stylesheet" attrs="name">
372
330
  <% name ||= 'application' -%>
373
- <link href="<%= base_url %>/hobothemes/<%= Hobo.current_theme %>/stylesheets/<%= name %>.css"
331
+ <link href="#{base_url}/hobothemes/#{Hobo.current_theme}/stylesheets/#{name}.css"
374
332
  media="screen" rel="Stylesheet" type="text/css" />
375
333
  </def>
376
334
 
377
335
 
378
- <def tag="clearer"><div class='clearer'>&nbsp;</div></def>
379
-
380
-
381
336
  <!-- The Tags defined below here are a bit rough and will be improved
382
337
  in the future - use at your own risk. -->
383
338
 
@@ -386,12 +341,12 @@ in the future - use at your own risk. -->
386
341
 
387
342
  <do param="default"/>
388
343
 
389
- <if test="&delete_buttons != false and can_delete?(this)">
344
+ <if test="&delete_buttons != false && can_delete?(this)">
390
345
  <td><delete-button/></td>
391
346
  </if>
392
347
  </table-for>
393
348
  <else>
394
- <p>There are no <%= this_type.klass.name.titleize.pluralize.downcase %></p>
349
+ <p>There are no <%= this.member_class.name.titleize.pluralize.downcase %></p>
395
350
  </else>
396
351
  <div>
397
352
  <create-button update="&id || part_id"/>
@@ -423,16 +378,9 @@ in the future - use at your own risk. -->
423
378
  </def>
424
379
 
425
380
 
426
- <def tag="you" attrs="have, are">
427
- <if test="&this == current_user">you <%= if have then 'have' elsif are then 'are' end %></if>
428
- <else><do param="default"><name/> <%= if have then 'has' elsif are then 'is' end %></do></else>
429
- </def>
381
+ <def tag="you" attrs="have, are, do, titleize"><if test="&this == current_user"><%= "#{titleize ? 'Y' : 'y'}ou #{'have' if have}#{'are' if are}#{'do' if do_}" %></if><else><do param="default"><name/> <%= "#{'has' if have}#{'is' if are}#{'does' if do_}" %></do></else></def>
430
382
 
431
-
432
- <def tag="You" attrs="have, are">
433
- <if test="&this == current_user">You <%= if have then 'have' elsif are then 'are' end %></if>
434
- <else><do param="default"><name/> <%= if have then 'has' elsif are then 'is' end %></do></else>
435
- </def>
383
+ <def tag="You"><you merge titleize/></def>
436
384
 
437
385
  <def tag="your">
438
386
  <if test="&this == current_user">your</if>
@@ -446,17 +394,6 @@ in the future - use at your own risk. -->
446
394
  </def>
447
395
 
448
396
 
449
- <def tag="creation-details">
450
- <span class="creation-details">
451
- <view with="&this.send(this.class.creator_attribute)" class="creator" if="&this.class.creator_attribute" />
452
- <view:created_at class="created-at" if="&this.respond_to?(:created_at)"/>
453
- </span>
454
- </def>
455
-
456
- <def tag="primary-content">
457
- <view class="primary-content" field="&this.class.primary_content_attribute" if="&this.class.primary_content_attribute"/>
458
- </def>
459
-
460
397
  <def tag="live-search">
461
398
  <div class="search">
462
399
  <label for="search-field">Search</label><input type="search" id="search-field" name="search-field" class="search-bhv search"/>
@@ -468,11 +405,6 @@ in the future - use at your own risk. -->
468
405
  </section>
469
406
  </def>
470
407
 
471
- <def tag="count-dependents">
472
- <% assoc = this.class.dependent_collections.first if this.class.dependent_collections.length == 1 %>
473
- <count field="&assoc" if="&assoc"/>
474
- </def>
475
-
476
408
 
477
409
  <def tag="a-or-an" attrs="word"><%=
478
410
  (word =~ /^[aeiouh]/i ? "an " : "a ") + word
@@ -482,3 +414,14 @@ in the future - use at your own risk. -->
482
414
  <def tag="A-or-An" attrs="word"><%=
483
415
  (word =~ /^[aeiouh]/i ? "An " : "A ") + word
484
416
  %></def>
417
+
418
+
419
+ <def tag="filter-menu" attrs="param-name, options, no-filter">
420
+ <form action="&request.request_uri" method="get" class="filter-menu">
421
+ <hidden-field name="filter-parameter" value="&param_name"/>
422
+ <select-menu name="&param_name" options="&options" selected="&params[param_name.gsub('-', '_')]" first-option="&no_filter" merge-params/>
423
+ </form>
424
+ </def>
425
+
426
+
427
+ <def tag="comma-list" attrs="separator"><%= this.join(separator || ", ") %></def>
@@ -1,14 +1,14 @@
1
1
  <def tag="editor" ><%=
2
2
  if !can_edit?
3
3
  view(attributes)
4
- elsif this_type.respond_to?(:macro)
5
- if this_type.macro == :belongs_to
4
+ elsif (refl = this_field_reflection)
5
+ if refl.macro == :belongs_to
6
6
  belongs_to_editor(attributes)
7
7
  else
8
8
  has_many_editor(attributes)
9
9
  end
10
10
  else
11
- attrs = add_classes(attributes, "#{type_and_field}", "#{type_id}", "editor")
11
+ attrs = add_classes(attributes, type_id, type_and_field, "editor")
12
12
  call_polymorphic_tag("editor", attrs) or
13
13
  raise HoboError.new("<editor> not implemented for #{this.class.name}\##{this_field} " +
14
14
  "(#{this.inspect}:#{this_type})")
@@ -44,7 +44,7 @@
44
44
  <def tag="editor" for="big_integer"><%= in_place_editor "in_place_textfield_bhv", attributes %></def>
45
45
 
46
46
  <def tag="editor" for="Hobo::EnumString">
47
- <string-select-editor values="&this_type.values"/>
47
+ <string-select-editor values="&this_type.values" merge/>
48
48
  </def>
49
49
 
50
50
 
@@ -56,31 +56,31 @@
56
56
  else
57
57
  completer_model = completer_model.constantize if completer_model.is_a? String
58
58
  end
59
- id ||= this_field_dom_id + "_completer"
59
+ id ||= dom_id + "_completer"
60
60
  url = object_url(completer_model, "completions",
61
61
  { :for => completer_attr }.update(attributes.select_hash {|k,v| k.to_s.starts_with? "where_"}))
62
62
  %>
63
63
  <input type="text" name="#{name}" id="#{id}" class="autocomplete-bhv"
64
64
  autocomplete-url="#{url}" value="#{value}"
65
65
  merge-attrs/>
66
- <div id="<%= id %>-completions" class="completions-popup" style="display:none"></div>
66
+ <div id="#{id}-completions" class="completions-popup" style="display:none"></div>
67
67
  </def>
68
68
 
69
69
 
70
70
  <def tag="belongs-to-menu-editor"><%
71
71
  raise HoboError.new("Not allowed to edit") unless can_edit?
72
- link_id = "#{this_field_dom_id}_editor" %>
72
+ link_id = "#{dom_id}_editor" %>
73
73
  <span id="#{link_id}" part="rapid-belongs-to-edit">
74
- <% select_options = this_type.klass.find(:all).select {|x| can_view?(x)}.map {|x|
74
+ <% select_options = this_field_reflection.klass.find(:all).select {|x| can_view?(x)}.map {|x|
75
75
  [ name(:with => x, :no_wrapper => true), x.id ]
76
76
  }
77
77
  select_options.insert(0, ["(No #{this_type.name.to_s.titleize})", ""]) if this.nil?
78
- link_id = "#{this_field_dom_id}_editor"
78
+ link_id = "#{dom_id}_editor"
79
79
  f = ajax_updater(object_url(this_parent),
80
- "Change #{this_field.to_s.titleize}", [link_id],
80
+ [link_id],
81
81
  :method => "put",
82
82
  :params => { this_parent.class.name.underscore => {
83
- this_type.primary_key_name => Hobo.raw_js('this.value')
83
+ this_field_reflection.primary_key_name => Hobo.raw_js('this.value')
84
84
  } })
85
85
  %>
86
86
  <select onchange="#{f}">
@@ -94,9 +94,9 @@
94
94
  <if-can-edit><%
95
95
  return object_link unless can_edit?
96
96
 
97
- id ||= this_field_dom_id + "_completer"
97
+ id ||= dom_id + "_completer"
98
98
  f = ajax_updater(object_url(this_parent),
99
- "Change #{this_field.to_s.titleize}", update,
99
+ update,
100
100
  :method => "put",
101
101
  :params => { this_parent.class.name.underscore => {
102
102
  this_field => Hobo.raw_js("$('#{id}').value")
@@ -125,7 +125,7 @@
125
125
 
126
126
  values = comma_split(values)
127
127
  f = ajax_updater(object_url(this_parent),
128
- "Change #{this_field.to_s.titleize}", update,
128
+ update,
129
129
  :method => "put",
130
130
  :params => { this_parent.class.name.underscore => {
131
131
  this_field => Hobo.raw_js('this.value')
@@ -141,9 +141,9 @@
141
141
  <def tag="boolean-checkbox-editor" attrs="update, message"><%
142
142
  raise HoboError.new("Not allowed to edit") unless can_edit?
143
143
  f = ajax_updater(object_url(this_parent),
144
- message || "Change #{this_field.to_s.titleize}",
145
144
  update,
146
145
  :method => "put",
146
+ :message => message,
147
147
  :spinner_next_to => Hobo.raw_js("this"),
148
148
  :params => { this_parent.class.name.underscore => {
149
149
  this_field => Hobo.raw_js('this.checked')
@@ -159,11 +159,11 @@
159
159
  <% base_class = this.class
160
160
  base_class = base_class.superclass while base_class.superclass != ActiveRecord::Base
161
161
  f = ajax_updater("#{base_url}/#{controller_for base_class}/#{this.id}",
162
- "Change #{this_field.to_s.titleize}", update,
163
- :method => "put",
164
- :params => { base_class.name.underscore => {
165
- "type" => Hobo.raw_js('this.value')
166
- } })
162
+ update,
163
+ :method => "put",
164
+ :params => { base_class.name.underscore => {
165
+ "type" => Hobo.raw_js('this.value')
166
+ } })
167
167
  %>
168
168
 
169
169
  <select onchange="#{f}">
@@ -175,7 +175,7 @@
175
175
 
176
176
  <def tag="integer-select-editor" attrs="min, max, update, nil-option, message">
177
177
  <select class="number-editor-bhv" hobo-update="#{update}"
178
- hobo-model-id="#{this_field_dom_id}"
178
+ hobo-model-id="#{dom_id}"
179
179
  merge-attrs="&message ? attributes.merge(:hobo_message => message) : attributes">
180
180
  <if test="&this.nil?"><option value=""><%= nil_option || "Choose a value" %></option></if>
181
181
  <%= options_for_select((min.to_i..max.to_i).to_a, this) %>
@@ -197,17 +197,17 @@
197
197
  if obj == nil
198
198
  new = klass.new(fields)
199
199
  permission = if can_create?(new)
200
- message ||= "Setting #{new.class.name.titleize}"
201
200
  class_name = new.class.name.underscore
202
- checkbox_attrs[:onclick] = ajax_updater(object_url(new.class), message, update,
203
- ({:params => { class_name => fields }} unless fields.empty?))
201
+ ajax_options = { :message => message }
202
+ ajax_options[:params] = { class_name => fields } unless fields.empty?
203
+ checkbox_attrs[:onclick] = ajax_updater(object_url(new.class), update, ajax_options)
204
204
  end
205
205
  else
206
206
  permission = if can_delete?(obj)
207
207
  checkbox_attrs[:checked] = 'checked'
208
208
  message ||= "Unsetting #{obj.class.name.titleize}"
209
209
  class_name = obj.class.name.underscore
210
- checkbox_attrs[:onclick] = ajax_updater(object_url(obj, "destroy"), message, update, {:method => 'delete'})
210
+ checkbox_attrs[:onclick] = ajax_updater(object_url(obj, "destroy"), update, {:message => message, :method => 'delete'})
211
211
  end
212
212
  end
213
213
  element(:input, add_classes(attributes.merge(checkbox_attrs),
@@ -20,58 +20,73 @@
20
20
  %></def>
21
21
 
22
22
 
23
- <def tag="form" attrs="message, update, hidden-fields, action, method, web-method"><%=
23
+ <def tag="form" attrs="update, hidden-fields, action, method, web-method"><%=
24
24
  ajax_attrs, html_attrs = attributes.partition_hash(Hobo::RapidHelper::AJAX_ATTRS)
25
25
 
26
- html_attrs[:action] = action || object_url(this, web_method)
26
+ new_record = this.try.new_record?
27
27
 
28
- new_record = this.respond_to?(:new_record?) && this.new_record?
29
-
30
28
  method = if method.nil?
31
29
  (action || web_method || new_record) ? "post" : "put"
32
30
  else
33
31
  method.downcase
34
32
  end
35
- if method == "put"
36
- http_method_hidden = hidden_field_tag("_method", "PUT")
37
- html_attrs[:method] = "post"
38
- else
39
- html_attrs[:method] = method
40
- end
41
-
42
- if update || !ajax_attrs.empty?
43
- message ||= "Creating #{this.class.name.titleize}" if new_record
44
- # add an onsubmit to convert to an ajax form if `update` is given
45
- function = ajax_updater(:post_form, message, update, ajax_attrs)
46
- html_attrs[:onsubmit] = [html_attrs[:onsubmit], "#{function}; return false;"].compact.join("; ")
47
- end
48
33
 
49
- body, field_names = scope.new_scope do
50
- scope[:in_form] = true
51
- with_form_context { parameters.default }
52
- end
53
-
54
- hiddens = hidden_fields(:fields => hidden_fields, :skip => field_names) if new_record
55
-
56
- auth_token = if request_forgery_protection_token.nil?
57
- ''
58
- else
59
- element(: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
34
+ html_attrs[:action] = action || object_url(this, web_method, :method => method)
67
35
 
68
- if web_method
69
- add_classes!(html_attrs, "#{type_id}_#{web_method}_form")
36
+ if html_attrs[:action].nil? || (new_record && !this.user_can_create?(current_user))
37
+ Hobo::Dryml.last_if = false
38
+ ""
70
39
  else
71
- add_classes!(html_attrs, "#{'new_' if new_record}#{type_id}")
40
+ if method == "put"
41
+ # browsers don't support put -- use post and add the Rails _method hack
42
+ http_method_hidden = hidden_field_tag("_method", "PUT")
43
+ html_attrs[:method] = "post"
44
+ else
45
+ html_attrs[:method] = method
46
+ end
47
+
48
+ if update || !ajax_attrs.empty?
49
+ # add an onsubmit to convert to an ajax form if `update` is given
50
+ function = ajax_updater(:post_form, update, ajax_attrs)
51
+ html_attrs[:onsubmit] = [html_attrs[:onsubmit], "#{function}; return false;"].compact.join("; ")
52
+ end
53
+
54
+ body, field_names = scope.new_scope do
55
+ scope[:in_form] = true
56
+ with_form_context { parameters.default }
57
+ end
58
+
59
+ hiddens = hidden_fields(:fields => hidden_fields, :skip => field_names) if new_record
60
+
61
+ auth_token = if request_forgery_protection_token.nil?
62
+ ''
63
+ else
64
+ element(:input, :type => "hidden",
65
+ :name => request_forgery_protection_token.to_s,
66
+ :value => form_authenticity_token)
67
+ end
68
+
69
+ page_path = if request.post? || request.put? && params[:page_path]
70
+ params[:page_path]
71
+ else
72
+ view_name.sub(Hobo::Dryml::EMPTY_PAGE, params[:action])
73
+ end
74
+ page_path_hidden = hidden_field_tag("page_path", page_path) unless method == "get"
75
+
76
+ body = [http_method_hidden, page_path_hidden, auth_token, hiddens, body].join
77
+
78
+
79
+ if action.nil? # don't add automatic css classes if the action was specified
80
+ if web_method
81
+ add_classes!(html_attrs, "#{type_id}_#{web_method}_form")
82
+ else
83
+ add_classes!(html_attrs, "#{'new_' if new_record}#{type_id}")
84
+ end
85
+ end
86
+
87
+ Hobo::Dryml.last_if = true
88
+ element("form", html_attrs, body)
72
89
  end
73
-
74
- element("form", html_attrs, body)
75
90
  %></def>
76
91
 
77
92
 
@@ -89,19 +104,18 @@
89
104
  elsif !can_edit?
90
105
  view
91
106
  else
92
- attrs = add_classes(attributes, type_and_field)
93
- the_input = if this_type.respond_to?(:macro)
94
- if this_type.macro == :belongs_to
107
+ attrs = add_classes(attributes, type_id, type_and_field)
108
+ the_input = if (refl = this_field_reflection)
109
+ if refl.macro == :belongs_to
95
110
  belongs_to_input(attrs)
96
- elsif this_type.macro == :has_many
97
- if this_type.options[:through]
111
+ elsif refl.macro == :has_many
112
+ if refl.options[:through]
98
113
  has_many_through_input(attrs)
99
114
  else
100
115
  has_many_input(attrs)
101
116
  end
102
117
  end
103
118
  else
104
- add_classes!(attrs, type_id)
105
119
  attrs[:name] ||= param_name_for_this
106
120
  the_input = call_polymorphic_tag('input', attrs) or
107
121
  raise HoboError, ("No input tag for #{this_field}:#{this_type} (this=#{this.inspect})")
@@ -132,12 +146,12 @@
132
146
  </def>
133
147
 
134
148
  <def tag="input" for="date" attrs="order">
135
- <% order = order.nil? ? [:year, :month, :day] : comma_split(order).every(:to_sym) -%>
149
+ <% order = order.nil? ? [:year, :month, :day] : comma_split(order).*.to_sym -%>
136
150
  <%= select_date(this || Time.now, attributes.merge(:prefix => param_name_for_this, :order => order)) %>
137
151
  </def>
138
152
 
139
153
  <def tag="input" for="datetime" attrs="order">
140
- <% order = order.nil? ? [:year, :month, :day, :hour, :minute] : comma_split(order).every(:to_sym) -%>
154
+ <% order = order.nil? ? [:year, :month, :day, :hour, :minute] : comma_split(order).*.to_sym -%>
141
155
  <%= select_datetime(this || Time.now, attributes.merge(:prefix => param_name_for_this, :order => order)) %>
142
156
  </def>
143
157
 
@@ -157,7 +171,7 @@
157
171
  <%= text_field_tag(name, this, attributes) %>
158
172
  </def>
159
173
 
160
- <def tag="input" for="Hobo::EnumString" attrs="labels,titleize">
174
+ <def tag="input" for="HoboFields::EnumString" attrs="labels,titleize">
161
175
  <% labels ||= {} %>
162
176
  <% titleize = true if titleize.nil? %>
163
177
  <select name="#{param_name_for_this}" merge-attrs>
@@ -176,15 +190,15 @@
176
190
 
177
191
  <!--- Buttons --->
178
192
 
179
- <def tag="remote-method-button" attrs="method, update, result-update, params, label, message"><%=
193
+ <def tag="remote-method-button" attrs="method, update, label"><%=
180
194
  ajax_attributes, html_attributes = attributes.partition_hash(Hobo::RapidHelper::AJAX_ATTRS)
181
195
 
182
196
  url = object_url(this, method)
183
197
  add_classes!(html_attributes, "button remote-method-button #{method}-button")
184
- if update || result_update
185
- message ||= method.titleize
186
- func = ajax_updater(url, message, update,
187
- ajax_attributes.merge(:params => params, :result_update => result_update))
198
+ if update || result_update || !ajax_attrs.empty?
199
+ label ||= method.titleize
200
+ ajax_attributes[:message] ||= label
201
+ func = ajax_updater(url, update, ajax_attributes)
188
202
  html_attributes.update(:onclick => "var e = this; " + func, :type =>'button', :value => label)
189
203
  element(:input, html_attributes)
190
204
  else
@@ -193,10 +207,10 @@
193
207
  %></def>
194
208
 
195
209
 
196
- <def tag="update-button" attrs="label, message, update, fields, params"><%=
210
+ <def tag="update-button" attrs="label, update, fields, params"><%=
197
211
  raise HoboError.new("no update specified") unless update
198
- message ||= label
199
- func = ajax_updater(object_url(this), message, update,
212
+ ajax_attributes[:message] ||= label
213
+ func = ajax_updater(object_url(this), update,
200
214
  :params => { this.class.name.underscore => fields }.merge(params || {}),
201
215
  :method => :put)
202
216
  element :input, add_classes(attributes.merge(:type =>'button', :onclick => func, :value => label),
@@ -204,8 +218,10 @@
204
218
  </def>
205
219
 
206
220
 
207
- <def tag="delete-button" attrs="label, message, update, in-place, image, confirm, fade, subsite"><%=
208
- if (Hobo::Dryml.last_if = can_delete?)
221
+ <def tag="delete-button" attrs="label, update, in-place, image, confirm, fade, subsite"><%=
222
+ in_place = false if in_place.nil? && this == @this
223
+ url = object_url(this, :method => :delete, :subsite => subsite)
224
+ if (Hobo::Dryml.last_if = url && can_delete?)
209
225
  attributes = attributes.merge(if image
210
226
  { :type => "image", :src => "#{base_url}/images/#{image}" }
211
227
  else
@@ -217,15 +233,17 @@
217
233
  add_classes!(attributes,
218
234
  image ? "image-button" : "button",
219
235
  "delete-button delete-#{this.class.name.underscore.dasherize}-button")
220
- url = object_url(this, "destroy", :subsite => subsite)
221
- if in_place == false
222
- attributes[:confirm] = confirm if confirm
223
- button_to(label, url, attributes)
224
- else
225
- fade = true if fade.nil?
226
- attributes[:value] = label
227
- attributes[:onclick] = "Hobo.removeButton(this, '#{url}', #{js_updates(update)}, {fade:#{fade}, confirm: #{confirm.inspect}})"
228
- element(:input, attributes)
236
+ if url
237
+ if in_place == false
238
+ attributes[:confirm] = confirm if confirm
239
+ attributes[:method] = :delete
240
+ button_to(label, url, attributes)
241
+ else
242
+ fade = true if fade.nil?
243
+ attributes[:value] = label
244
+ attributes[:onclick] = "Hobo.removeButton(this, '#{url}', #{js_updates(update)}, {fade:#{fade}, confirm: #{confirm.inspect}})"
245
+ element(:input, attributes)
246
+ end
229
247
  end
230
248
  else
231
249
  ""
@@ -233,14 +251,14 @@
233
251
  %></def>
234
252
 
235
253
 
236
- <def tag="create-button" attrs="model, update, label, message, fields"><%=
254
+ <def tag="create-button" attrs="model, update, label, fields, message"><%=
237
255
  raise HoboError.new("no update specified") unless update
238
256
 
239
257
  fields ||= {}
240
258
  class_or_assoc = if model
241
259
  model.is_a?(String) ? model.constantize : model
242
260
  elsif Hobo.simple_has_many_association?(this)
243
- fields[this.proxy_reflection.primary_key_name] = this.proxy_owner.id
261
+ fields[this_field_reflection.primary_key_name] = this.proxy_owner.id
244
262
  this
245
263
  else
246
264
  raise HoboError.new("invalid context for <create-button>")
@@ -249,12 +267,12 @@
249
267
  new.set_creator(current_user)
250
268
  if can_create?(new)
251
269
  label ||= "New #{new.class.name.titleize}"
252
- message ||= label
270
+ ajax_attributes = { :message => message }
271
+ ajax_attributes[:params] = { class_name => fields } unless fields.empty?
253
272
  class_name = new.class.name.underscore
254
- func = ajax_updater(object_url(new.class), message, update,
255
- ({:params => { class_name => fields }} unless fields.empty?))
273
+ func = ajax_updater(object_url(new.class), message, update, ajax_attributes)
256
274
  element :input, add_classes(attributes.merge(:type =>'button', :onclick => func, :value => label),
257
- "button create-button create-#{class_name}-button")
275
+ "button create-button create-#{class_name}-button")
258
276
  end
259
277
  %></def>
260
278
 
@@ -263,8 +281,9 @@
263
281
  raise HoboError.new("Not allowed to edit") unless can_edit?
264
282
 
265
283
  blank_message ||= "(No #{this_type.name.to_s.titleize})"
266
- options ||= this_type.klass.find(:all, :conditions => this_type.options[:conditions]).select {|x| can_view?(x)}
267
- #Todo: switch to autocompleter for id_name when too many records, and id_name supported
284
+ conditions = ActiveRecord::Associations::BelongsToAssociation.new(this, this_field_reflection).conditions
285
+ options ||= this_field_reflection.klass.find(:all, :conditions => conditions).select {|x| can_view?(x)}
286
+ #Todo: switch to autocompleter for id_name when too many records, and id_name supported
268
287
  select_options = options.map { |x|
269
288
  [ name(:with => x, :no_wrapper => true), x.id ]
270
289
  }.sort
@@ -281,7 +300,7 @@
281
300
  <% refl = this_type
282
301
  completer_model ||= refl.klass
283
302
  completer_attr ||= refl.klass.id_name_column
284
- id ||= this_field_dom_id + "_completer"
303
+ id ||= dom_id + "_completer"
285
304
  where_attributes = attributes.select_hash {|k,v| k.to_s.starts_with? "where_"}
286
305
  url = object_url(completer_model, :completions, { :for => completer_attr }.update(where_attributes))
287
306
  %>
@@ -345,6 +364,19 @@
345
364
  </def>
346
365
 
347
366
 
348
- <def tag="after-submit" attrs="uri">
349
- <input type="hidden" value="&params[:after_submit] || uri" name="after_submit"/>
367
+ <def tag="after-submit" attrs="uri, stay-here, go-back">
368
+ <% uri = request.request_uri if stay_here %>
369
+ <% uri = session[:previous_uri] if go_back %>
370
+ <input type="hidden" value="&params[:after_submit] || uri" name="after_submit" if="&uri"/>
371
+ </def>
372
+
373
+
374
+ <def tag="hidden-field" attrs="name, value"><input type="hidden" name="&name" value="&value" merge-attrs/></def>
375
+
376
+
377
+ <def tag="select-menu" attrs="options, selected, first-option, first-value">
378
+ <select merge-attrs param="default">
379
+ <option value="#{first_value}" unless="&first_option.nil?"><first-option/></option>
380
+ <do param="options"><%= options_for_select(options, selected) %></do>
381
+ </select>
350
382
  </def>