hobo 0.7.3 → 0.7.4

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 (46) hide show
  1. data/bin/hobo +1 -1
  2. data/hobo_files/plugin/CHANGES.txt +302 -0
  3. data/hobo_files/plugin/generators/hobo_front_controller/templates/index.dryml +2 -9
  4. data/hobo_files/plugin/generators/hobo_model/templates/model.rb +1 -1
  5. data/hobo_files/plugin/generators/hobo_model_resource/hobo_model_resource_generator.rb +0 -2
  6. data/hobo_files/plugin/generators/hobo_rapid/templates/hobo-rapid.js +76 -46
  7. data/hobo_files/plugin/generators/hobo_rapid/templates/lowpro.js +25 -18
  8. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/clean/public/stylesheets/application.css +29 -11
  9. data/hobo_files/plugin/generators/hobo_user_model/templates/model.rb +2 -2
  10. data/hobo_files/plugin/init.rb +0 -1
  11. data/hobo_files/plugin/lib/active_record/has_many_association.rb +3 -0
  12. data/hobo_files/plugin/lib/hobo.rb +12 -8
  13. data/hobo_files/plugin/lib/hobo/bundle.rb +1 -1
  14. data/hobo_files/plugin/lib/hobo/dryml/dryml_builder.rb +1 -1
  15. data/hobo_files/plugin/lib/hobo/dryml/parser/attribute.rb +41 -0
  16. data/hobo_files/plugin/lib/hobo/dryml/parser/base_parser.rb +253 -0
  17. data/hobo_files/plugin/lib/hobo/dryml/parser/document.rb +26 -0
  18. data/hobo_files/plugin/lib/hobo/dryml/parser/element.rb +27 -0
  19. data/hobo_files/plugin/lib/hobo/dryml/parser/elements.rb +45 -0
  20. data/hobo_files/plugin/lib/hobo/dryml/parser/source.rb +58 -0
  21. data/hobo_files/plugin/lib/hobo/dryml/parser/text.rb +13 -0
  22. data/hobo_files/plugin/lib/hobo/dryml/parser/tree_parser.rb +67 -0
  23. data/hobo_files/plugin/lib/hobo/dryml/scoped_variables.rb +10 -5
  24. data/hobo_files/plugin/lib/hobo/dryml/template.rb +48 -27
  25. data/hobo_files/plugin/lib/hobo/dryml/template_environment.rb +28 -13
  26. data/hobo_files/plugin/lib/hobo/hobo_helper.rb +3 -1
  27. data/hobo_files/plugin/lib/hobo/model.rb +70 -10
  28. data/hobo_files/plugin/lib/hobo/model_controller.rb +49 -34
  29. data/hobo_files/plugin/lib/hobo/model_router.rb +10 -2
  30. data/hobo_files/plugin/lib/hobo/rapid_helper.rb +1 -0
  31. data/hobo_files/plugin/lib/hobo/scopes.rb +15 -0
  32. data/hobo_files/plugin/lib/hobo/scopes/apply_scopes.rb +23 -0
  33. data/hobo_files/plugin/lib/hobo/scopes/association_proxy_extensions.rb +4 -2
  34. data/hobo_files/plugin/lib/hobo/scopes/automatic_scopes.rb +34 -7
  35. data/hobo_files/plugin/lib/hobo/scopes/defined_scope_proxy_extender.rb +3 -1
  36. data/hobo_files/plugin/lib/hobo/scopes/scoped_proxy.rb +1 -5
  37. data/hobo_files/plugin/taglibs/rapid.dryml +33 -24
  38. data/hobo_files/plugin/taglibs/rapid_editing.dryml +6 -5
  39. data/hobo_files/plugin/taglibs/rapid_forms.dryml +37 -31
  40. data/hobo_files/plugin/taglibs/rapid_generics.dryml +68 -27
  41. data/hobo_files/plugin/taglibs/rapid_navigation.dryml +5 -8
  42. data/hobo_files/plugin/taglibs/rapid_pages.dryml +71 -47
  43. data/hobo_files/plugin/taglibs/rapid_plus.dryml +4 -5
  44. data/hobo_files/plugin/taglibs/rapid_support.dryml +11 -4
  45. metadata +23 -6
  46. data/hobo_files/plugin/lib/rexml.rb +0 -443
@@ -8,6 +8,8 @@ module Hobo
8
8
 
9
9
  include AutomaticScopes
10
10
 
11
+ include ApplyScopes
12
+
11
13
  def method_missing(name, *args, &block)
12
14
  if (scope = named_scope(name))
13
15
  association_proxy_for_scope(name, scope, args)
@@ -69,7 +71,7 @@ module Hobo
69
71
  options[:order] = scope[:order] if scope[:order]
70
72
  options[:include] = scope[:include] if scope[:include]
71
73
 
72
- r = ScopeReflection.new(:has_many, name, options, proxy_owner.class, proxy_reflection.name)
74
+ r = ScopeReflection.new(:has_many, name, options, proxy_owner.class, proxy_reflection.association_name)
73
75
 
74
76
  @reflections ||= {}
75
77
  @reflections[name] = r
@@ -4,7 +4,7 @@ module Hobo
4
4
 
5
5
  class ScopedProxy
6
6
 
7
- #include AutomaticScopes
7
+ include ApplyScopes
8
8
 
9
9
  def initialize(klass, scope)
10
10
  @klass = klass
@@ -22,10 +22,6 @@ module Hobo
22
22
  end
23
23
  end
24
24
 
25
- def all
26
- self.find(:all)
27
- end
28
-
29
25
  def first
30
26
  self.find(:first)
31
27
  end
@@ -31,18 +31,20 @@
31
31
 
32
32
  <def tag="nil-view"><%= scope.nil_view || "(Not Available)" %></def>
33
33
 
34
- <def tag="ul">
34
+ <def tag="ul" attrs="empty">
35
35
  <% if all_parameters.li? # don't use dryml if, because it will mess up <ul/><else> %>
36
- <unless test="&this.empty?">
36
+ <if test="&empty || all_parameters[:head] || all_parameters[:foot] || !this.empty?">
37
37
  <% element "ul", attributes do %>
38
+ <do param="head"/>
38
39
  <repeat>
39
40
  <li param if="&can_view?" class="#{scope.even_odd} #{this_type.name.underscore.dasherize}"
40
41
  merge-attrs="&{'hobo-model-id' => dom_id(this)} if this.respond_to?(:typed_id)">
41
42
  <do param="default"><a/></do>
42
43
  </li>
43
44
  </repeat>
45
+ <do param="foot"/>
44
46
  <% end %>
45
- </unless>
47
+ </if>
46
48
  <% else %>
47
49
  <%= element("ul", attributes, all_parameters.default) %>
48
50
  <% end %>
@@ -162,6 +164,16 @@
162
164
  name = name.downcase if lowercase
163
165
  name
164
166
  %></def>
167
+
168
+
169
+ <def tag="name-for-collection" attrs="singular, lowercase"><%=
170
+ name = (attr = this.try.origin_attribute and attr.to_s) || type_name(:plural => true)
171
+ name = name.titleize
172
+ name = name.singularize if singular
173
+ name = name.downcase if lowercase
174
+ name
175
+ %></def>
176
+
165
177
 
166
178
 
167
179
  <def tag="a" attrs="action, to, params, query-params, href, format, subsite"><%=
@@ -194,6 +206,7 @@
194
206
 
195
207
  add_classes!(attributes, "new-#{new_class_name.underscore}-link")
196
208
  content = "New #{new_class_name.titleize}" if content.blank?
209
+ Hobo::Dryml.last_if = true
197
210
  element(:a, attributes.update(:href => href), content)
198
211
  else
199
212
  Hobo::Dryml.last_if = false
@@ -209,7 +222,8 @@
209
222
  # This target is registered with ModelRouter as not linkable
210
223
  content
211
224
  else
212
- add_classes!(attributes, "#{target.class.name.underscore}-link")
225
+ css_class = target.try.origin_attribute || target.class.name.underscore
226
+ add_classes!(attributes, "#{css_class}-link")
213
227
 
214
228
  href.sub!(/\?|$/, ".#{format}\\0") unless format.blank?
215
229
 
@@ -227,18 +241,18 @@
227
241
 
228
242
  res = if this.nil? && if_blank.nil?
229
243
  this_type.is_a?(Class) && this_type <= String ? "" : nil_view
230
- elsif refl = this_field_reflection
231
- if refl.macro == :belongs_to
232
- belongs_to_view(attributes)
233
- elsif refl.macro == :has_many
234
- has_many_view(attributes)
235
- end
244
+ elsif (refl = this_field_reflection) && refl.macro == :has_many
245
+ has_many_view(attributes)
236
246
  else
237
247
 
238
248
  view_tag = find_polymorphic_tag("view")
239
249
 
240
250
  if view_tag == "view" # i.e. it didn't find a type specific tag
241
- raise HoboError, "Cannot view: #{this.inspect} (field is #{this_field}, type is #{this.class})"
251
+ if this.respond_to?(:to_html)
252
+ this.to_html
253
+ else
254
+ raise HoboError, "Cannot view: #{this.inspect} (field is #{this_field}, type is #{this.class})"
255
+ end
242
256
  else
243
257
  attrs = add_classes(attributes, "view", type_and_field)
244
258
  id = dom_id
@@ -282,20 +296,12 @@
282
296
 
283
297
  <def tag="view" for="Numeric" attrs="format"><%= format ? format % this : this.to_s %></def>
284
298
 
285
- <def tag="view" for="Hobo::Text"><%= h(this).gsub("\n", "<br/>") %></def>
286
-
287
- <def tag="view" for="html"><%= this %></def>
288
-
289
- <def tag="view" for="markdown"><%= this.to_html %></def>
290
-
291
- <def tag="view" for="textile"><%= this.to_html %></def>
292
-
293
- <def tag="view" for="password">[password withheld]</def>
294
-
295
299
  <def tag="view" for="string"><%= h(this).gsub("\n", "<br/>") %></def>
296
300
 
297
301
  <def tag="view" for="boolean"><%= this ? 'Yes' : 'No' %></def>
298
302
 
303
+ <def tag="view" for="ActiveRecord::Base"><a/></def>
304
+
299
305
 
300
306
  <def tag="count" attrs="label, prefix, if-any, lowercase"><%=
301
307
  raise Exception.new("asked for count of a string") if this.is_a?(String)
@@ -304,9 +310,11 @@
304
310
 
305
311
  label ||= if this.is_a?(Class)
306
312
  this.name
313
+ elsif (attr = this.try.origin_attribute)
314
+ attr.to_s.singularize
307
315
  else
308
- (this.try.association_name || this.try.member_class._?.name)
309
- end.to_s.singularize.titleize
316
+ this.member_class.name
317
+ end.titleize
310
318
 
311
319
  label = label.downcase if lowercase
312
320
 
@@ -378,7 +386,7 @@ in the future - use at your own risk. -->
378
386
  </def>
379
387
 
380
388
 
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>
389
+ <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>
382
390
 
383
391
  <def tag="You"><you merge titleize/></def>
384
392
 
@@ -417,6 +425,7 @@ in the future - use at your own risk. -->
417
425
 
418
426
 
419
427
  <def tag="filter-menu" attrs="param-name, options, no-filter">
428
+ <% no_filter ||= "All" %>
420
429
  <form action="&request.request_uri" method="get" class="filter-menu">
421
430
  <hidden-field name="filter-parameter" value="&param_name"/>
422
431
  <select-menu name="&param_name" options="&options" selected="&params[param_name.gsub('-', '_')]" first-option="&no_filter" merge-params/>
@@ -43,7 +43,7 @@
43
43
 
44
44
  <def tag="editor" for="big_integer"><%= in_place_editor "in_place_textfield_bhv", attributes %></def>
45
45
 
46
- <def tag="editor" for="Hobo::EnumString">
46
+ <def tag="editor" for="HoboFields::EnumString">
47
47
  <string-select-editor values="&this_type.values" merge/>
48
48
  </def>
49
49
 
@@ -67,13 +67,14 @@
67
67
  </def>
68
68
 
69
69
 
70
- <def tag="belongs-to-menu-editor"><%
70
+ <def tag="belongs-to-menu-editor" attrs="sort"><%
71
71
  raise HoboError.new("Not allowed to edit") unless can_edit?
72
72
  link_id = "#{dom_id}_editor" %>
73
- <span id="#{link_id}" part="rapid-belongs-to-edit">
73
+ <span id="#{link_id}" part="rapid-belongs-to-edit" part-locals="sort">
74
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
+ select_options = select_options.sort if sort
77
78
  select_options.insert(0, ["(No #{this_type.name.to_s.titleize})", ""]) if this.nil?
78
79
  link_id = "#{dom_id}_editor"
79
80
  f = ajax_updater(object_url(this_parent),
@@ -84,8 +85,8 @@
84
85
  } })
85
86
  %>
86
87
  <select onchange="#{f}">
87
- <%= options_for_select(select_options.sort, this ? this.id : "") %>
88
- </select>&nbsp;<a if="&this">View</a>
88
+ <%= options_for_select(select_options, this ? this.id : "") %>
89
+ </select>&nbsp;<a if="&this && linkable?">View</a>
89
90
  </span>
90
91
  </def>
91
92
 
@@ -58,7 +58,7 @@
58
58
 
59
59
  hiddens = hidden_fields(:fields => hidden_fields, :skip => field_names) if new_record
60
60
 
61
- auth_token = if request_forgery_protection_token.nil?
61
+ auth_token = if method.nil? || method == 'get' || request_forgery_protection_token.nil?
62
62
  ''
63
63
  else
64
64
  element(:input, :type => "hidden",
@@ -107,10 +107,10 @@
107
107
  attrs = add_classes(attributes, type_id, type_and_field)
108
108
  the_input = if (refl = this_field_reflection)
109
109
  if refl.macro == :belongs_to
110
- belongs_to_input(attrs)
110
+ select_one(attrs)
111
111
  elsif refl.macro == :has_many
112
112
  if refl.options[:through]
113
- has_many_through_input(attrs)
113
+ select_many(attrs)
114
114
  else
115
115
  has_many_input(attrs)
116
116
  end
@@ -145,13 +145,21 @@
145
145
  <%= text_area_tag(name, this, add_classes(attributes, :tiny_mce)) %>
146
146
  </def>
147
147
 
148
+ <def tag="input" for="markdown" attrs="name">
149
+ <%= text_area_tag(name, this, attributes) %>
150
+ </def>
151
+
152
+ <def tag="input" for="textile" attrs="name">
153
+ <%= text_area_tag(name, this, attributes) %>
154
+ </def>
155
+
148
156
  <def tag="input" for="date" attrs="order">
149
157
  <% order = order.nil? ? [:year, :month, :day] : comma_split(order).*.to_sym -%>
150
158
  <%= select_date(this || Time.now, attributes.merge(:prefix => param_name_for_this, :order => order)) %>
151
159
  </def>
152
160
 
153
161
  <def tag="input" for="datetime" attrs="order">
154
- <% order = order.nil? ? [:year, :month, :day, :hour, :minute] : comma_split(order).*.to_sym -%>
162
+ <% order = order.nil? ? [:year, :month, :day ] : comma_split(order).*.to_sym -%>
155
163
  <%= select_datetime(this || Time.now, attributes.merge(:prefix => param_name_for_this, :order => order)) %>
156
164
  </def>
157
165
 
@@ -179,16 +187,8 @@
179
187
  </select>
180
188
  </def>
181
189
 
182
- <def tag="input" for="percentage" attrs="name">
183
- <%= text_field_tag(name, this, attributes.merge(:size => '3', :maxlength => '3')) %>%
184
- </def>
185
-
186
190
 
187
- <def tag="belongs-to-input">
188
- <%= belongs_to_menu_input(attributes) %>
189
- </def>
190
-
191
- <!--- Buttons --->
191
+ <!-- Buttons -->
192
192
 
193
193
  <def tag="remote-method-button" attrs="method, update, label"><%=
194
194
  ajax_attributes, html_attributes = attributes.partition_hash(Hobo::RapidHelper::AJAX_ATTRS)
@@ -219,7 +219,7 @@
219
219
 
220
220
 
221
221
  <def tag="delete-button" attrs="label, update, in-place, image, confirm, fade, subsite"><%=
222
- in_place = false if in_place.nil? && this == @this
222
+ in_place = false if in_place.nil? && this == @this && !request.xhr?
223
223
  url = object_url(this, :method => :delete, :subsite => subsite)
224
224
  if (Hobo::Dryml.last_if = url && can_delete?)
225
225
  attributes = attributes.merge(if image
@@ -240,6 +240,7 @@
240
240
  button_to(label, url, attributes)
241
241
  else
242
242
  fade = true if fade.nil?
243
+ scope.collection_contains_delete_button = true if fade
243
244
  attributes[:value] = label
244
245
  attributes[:onclick] = "Hobo.removeButton(this, '#{url}', #{js_updates(update)}, {fade:#{fade}, confirm: #{confirm.inspect}})"
245
246
  element(:input, attributes)
@@ -277,16 +278,17 @@
277
278
  %></def>
278
279
 
279
280
 
280
- <def tag="belongs-to-menu-input" attrs="include-none, blank-message, options"><%
281
+ <def tag="select-one" attrs="include-none, blank-message, options, sort"><%
281
282
  raise HoboError.new("Not allowed to edit") unless can_edit?
282
283
 
283
284
  blank_message ||= "(No #{this_type.name.to_s.titleize})"
284
285
  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
+ options ||= this_field_reflection.klass.all(:conditions => conditions).select {|x| can_view?(x)}
286
287
  #Todo: switch to autocompleter for id_name when too many records, and id_name supported
287
288
  select_options = options.map { |x|
288
289
  [ name(:with => x, :no_wrapper => true), x.id ]
289
- }.sort
290
+ }
291
+ select_options = select_options.sort if sort
290
292
  select_options.insert(0, [blank_message, ""]) if include_none || (this.nil? && include_none != false)
291
293
  attributes = add_classes(attributes, "input", "belongs_to", type_and_field)
292
294
  %>
@@ -335,29 +337,33 @@
335
337
  </def>
336
338
 
337
339
 
338
- <def tag="name-array-input" attrs="targets, remove-label">
340
+ <def tag="select-many" attrs="options, targets, remove-label, prompt">
339
341
  <%
340
- all ||= this.member_class.find(:all)
342
+ prompt ||= "Add a #{this_field.titleize.singularize}"
343
+ options ||= this.member_class.all
341
344
  values = this
342
345
  %>
343
- <div class="input has-many-through" merge-attrs>
346
+ <div class="input select-many" merge-attrs>
344
347
  <div style="display:none" class="item-proto">
345
- <div class="item">
348
+ <div class="item" param="proto-item">
346
349
  <span></span>
347
- <input type="hidden" name="#{param_name_for_this}[]" />
348
- <input type="button" class="remove-item" value="#{remove_label || 'Remove'}"/>
350
+ <input type="hidden" name="#{param_name_for_this}[]" param="proto-hidden"/>
351
+ <input type="button" class="remove-item" value="#{remove_label || 'Remove'}" param="proto-remove-button"/>
349
352
  </div>
350
353
  </div>
351
354
  <div class="items">
352
- <div class="item" repeat>
353
- <span><%= this %></span>
354
- <input type="hidden" name="#{param_name_for_this}[]" value="#{this}"/>
355
- <input type="button" class="remove-item" value="#{remove_label || 'Remove'}"/>
356
- </div>
355
+ <set param-name="&param_name_for_this"/>
356
+ <repeat>
357
+ <div class="item" param="item">
358
+ <span><%= this %></span>
359
+ <input type="hidden" name="#{param_name}[]" value="#{this}" param="hidden"/>
360
+ <input type="button" class="remove-item" value="#{remove_label || 'Remove'}" param="remove-button"/>
361
+ </div>
362
+ </repeat>
357
363
  </div>
358
364
  <select>
359
- <option value="">Add a <%= this_field.titleize.singularize %></option>
360
- <option repeat="&all.sort_by {|x| name(:no_wrapper => true, :with => x).downcase}"
365
+ <option value=""><prompt/></option>
366
+ <option repeat="&options.sort_by {|x| name(:no_wrapper => true, :with => x).downcase}"
361
367
  merge-attrs="&{:style => 'display:none'} if this.in?(values)"><name/></option>
362
368
  </select>
363
369
  </div>
@@ -377,6 +383,6 @@
377
383
  <def tag="select-menu" attrs="options, selected, first-option, first-value">
378
384
  <select merge-attrs param="default">
379
385
  <option value="#{first_value}" unless="&first_option.nil?"><first-option/></option>
380
- <do param="options"><%= options_for_select(options, selected) %></do>
386
+ <do param="options"><% options_for_select(options.*.to_s, selected) %></do>
381
387
  </select>
382
388
  </def>
@@ -1,8 +1,8 @@
1
1
  <def tag="creation-details">
2
- <span class="creation-details">
3
- <view field="&this.class.creator_attribute" class="creator" if="&this.class.creator_attribute" />
4
- <view:created_at class="created-at" if="&this.respond_to?(:created_at)"/>
5
- </span>
2
+ <div class="creation-details">
3
+ <view field="&this.class.creator_attribute" class="creator" if="&this.class.creator_attribute" param="by"/>
4
+ <view:created_at class="created-at" if="&this.respond_to?(:created_at)" param="at"/>
5
+ </div>
6
6
  </def>
7
7
 
8
8
  <def tag="primary-content">
@@ -17,9 +17,15 @@
17
17
 
18
18
  <def tag="base-card">
19
19
  <if test="&can_view?">
20
- <div class="card #{linkable? ? 'linkable' : 'content'} #{type_name :dasherize => true}" merge-attrs>
21
- <h3 param="title"><a if="&linkable?"/></h3>
22
- <div class="content" param="content" if="&!linkable?">
20
+ <set has-heading="&this.class.name_attribute || all_parameters[:heading]"/>
21
+ <set has-link="&has_heading && linkable?"/>
22
+ <div class="card #{has_link ? 'linkable' : 'content'} #{'with-owner' if this.class.creator_attribute} #{type_name :dasherize => true}"
23
+ merge-attrs>
24
+ <a action="edit" class="edit" if="&!has_link && linkable?(:edit)" param="edit-link">Edit</a>
25
+ <delete-button label="X" unless="&linkable?(:edit)" param/>
26
+
27
+ <h3 param="heading" if="&has_heading"><a><name/></a></h3>
28
+ <div class="content" param="content" unless="&has_link">
23
29
  <primary-content/>
24
30
  </div>
25
31
  <creation-details param/>
@@ -29,7 +35,6 @@
29
35
  <span class="dependents"><count field="&primary_collection"/></span>
30
36
  </if>
31
37
  </do>
32
- <delete-button label="X" unless="&linkable?(this, :edit)" param/>
33
38
  </div>
34
39
  </if>
35
40
  </def>
@@ -47,28 +52,64 @@
47
52
  </def>
48
53
 
49
54
  <def tag="collection">
50
- <%= poly = call_polymorphic_tag('collection', attributes, parameters) %>
51
- <ul class="collection" merge-attrs unless="&poly">
52
- <li:><card param/></li:>
55
+ <set-scoped collection-contains-delete-button="&false">
56
+ <%= poly = call_polymorphic_tag('collection', attributes, parameters) %>
57
+ <base-collection if="&poly.nil?" merge/>
58
+ <p class="empty-collection-message"
59
+ if="&this.empty? || scope.collection_contains_delete_button"
60
+ style="#{'display:none' if !this.empty?}"
61
+ param="empty-message">
62
+ There are no <name-for-collection lowercase/>
63
+ </p>
64
+ </set-scoped>
65
+ </def>
66
+
67
+
68
+ <def tag="base-collection" attrs="sortable, sortable-options"><%
69
+ sortable = (sortable != false and
70
+ first = this.first and
71
+ first.respond_to?(:position_column) and
72
+ reorder_url = object_url(this.member_class, :reorder, :method => :post) and
73
+ can_edit?(first, first.position_column))
74
+ if sortable
75
+ singular_name = first.class.name.underscore
76
+ attributes[:id] ||= "#{singular_name}_ordering"
77
+ end
78
+ %>
79
+ <ul class="collection #{this.origin_attribute.to_s.gsub('_', '-')}" merge-attrs>
80
+ <li: id="&%(#{singular_name}_#{this.id}) if sortable" param>
81
+ <div class="ordering-handle" param="handle" if="&sortable">&uarr;<br/>&darr;</div>
82
+ <card param/>
83
+ </li:>
53
84
  </ul>
54
- <p class="empty-collection-message" if="&this.empty?" param="empty-message">
55
- <% label = if (refl = this.try.proxy_reflection)
56
- refl.association_name.to_s.humanize.downcase
57
- elsif (klass = this.try.member_class)
58
- klass.name.humanize.downcase.pluralize
59
- else
60
- type_name(:plural => true).pluralize.humanize.downcase.to_s
61
- end %>
62
- There are no <%= label.pluralize %>
63
- </p>
85
+ <%= if sortable && Hobo::Dryml.last_if
86
+ opts = { :url => reorder_url,
87
+ :constraint => :vertical,
88
+ :overlap => :vertical,
89
+ :scroll => :window,
90
+ :handle => 'ordering-handle',
91
+ :complete => [visual_effect(:highlight, attributes[:id])]
92
+ }
93
+ opts.reverse_merge!(sortable_options) if sortable_options
94
+ sortable_element attributes[:id], opts
95
+ end
96
+ %>
64
97
  </def>
65
98
 
99
+
66
100
  <def tag="collection-preview" attrs="limit">
67
101
  <% limit ||= 6 %>
68
- <div class="collection-preview" merge-attrs>
69
- <h2><do param="heading"><this-field.titleize/></do> <span param="show-all-link" if="&linkable?">(<a>show all</a>)</span></h2>
70
- <collection with="&this.limit(limit)" merge-params>
71
- <card: class="small"/>
72
- </collection>
73
- </div>
102
+ <do with="&this.is_a?(Class) ? this.limit(limit).all : this.limit(limit)">
103
+ <set collection-name="&(this.try.origin_attribute || this.member_class.name.pluralize).to_s"/>
104
+ <div class="collection-preview" merge-attrs>
105
+ <h2>
106
+ <do param="heading"><collection-name.titleize/></do>
107
+ <span param="show-all-link" if="&this.any? && linkable?">(<a>show all</a>)</span>
108
+ </h2>
109
+ <collection merge-params>
110
+ <card: class="small"/>
111
+ </collection>
112
+ </div>
113
+ </do>
74
114
  </def>
115
+