hobo 0.7.2 → 0.7.3

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