hobo 0.8.5 → 0.8.6
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.txt +41 -0
- data/Manifest +1 -5
- data/Rakefile +10 -3
- data/bin/hobo +38 -15
- data/dryml_generators/rapid/cards.dryml.erb +7 -7
- data/dryml_generators/rapid/pages.dryml.erb +52 -24
- data/hobo.gemspec +42 -322
- data/init.rb +0 -7
- data/lib/active_record/association_collection.rb +9 -0
- data/lib/hobo.rb +13 -14
- data/lib/hobo/accessible_associations.rb +32 -7
- data/lib/hobo/authentication_support.rb +1 -1
- data/lib/hobo/controller.rb +5 -7
- data/lib/hobo/dryml.rb +9 -2
- data/lib/hobo/dryml/dryml_builder.rb +11 -12
- data/lib/hobo/dryml/dryml_doc.rb +22 -24
- data/lib/hobo/dryml/dryml_generator.rb +41 -4
- data/lib/hobo/dryml/part_context.rb +5 -3
- data/lib/hobo/dryml/template.rb +7 -7
- data/lib/hobo/dryml/template_environment.rb +11 -22
- data/lib/hobo/dryml/template_handler.rb +94 -25
- data/lib/hobo/find_for.rb +2 -2
- data/lib/hobo/hobo_helper.rb +21 -21
- data/lib/hobo/include_in_save.rb +9 -5
- data/lib/hobo/lifecycles/transition.rb +2 -2
- data/lib/hobo/model.rb +11 -61
- data/lib/hobo/model_controller.rb +28 -29
- data/lib/hobo/model_router.rb +12 -13
- data/lib/hobo/permissions.rb +47 -37
- data/lib/hobo/permissions/associations.rb +1 -1
- data/lib/hobo/scopes/association_proxy_extensions.rb +5 -6
- data/lib/hobo/scopes/automatic_scopes.rb +7 -4
- data/lib/hobo/tasks/rails.rb +4 -0
- data/lib/hobo/user.rb +0 -1
- data/lib/hobo/user_controller.rb +3 -1
- data/lib/hobo/view_hints.rb +17 -3
- data/rails_generators/hobo/hobo_generator.rb +1 -0
- data/rails_generators/hobo_front_controller/templates/functional_test.rb +1 -11
- data/rails_generators/hobo_front_controller/templates/index.dryml +1 -6
- data/rails_generators/hobo_rapid/hobo_rapid_generator.rb +1 -0
- data/rails_generators/hobo_rapid/templates/hobo-rapid.css +3 -2
- data/rails_generators/hobo_rapid/templates/hobo-rapid.js +24 -15
- data/rails_generators/hobo_rapid/templates/themes/clean/public/stylesheets/clean.css +17 -12
- data/rails_generators/hobo_rapid/templates/themes/clean/public/stylesheets/rapid-ui.css +6 -2
- data/rails_generators/hobo_rapid/templates/themes/clean/views/clean.dryml +2 -2
- data/rails_generators/hobo_user_model/templates/forgot_password.erb +2 -2
- data/rails_generators/hobo_user_model/templates/model.rb +2 -2
- data/taglibs/rapid.dryml +3 -2
- data/taglibs/rapid_core.dryml +21 -16
- data/taglibs/rapid_document_tags.dryml +1 -1
- data/taglibs/rapid_editing.dryml +7 -10
- data/taglibs/rapid_forms.dryml +115 -26
- data/taglibs/rapid_generics.dryml +13 -3
- data/taglibs/rapid_lifecycles.dryml +18 -1
- data/taglibs/rapid_navigation.dryml +50 -61
- data/taglibs/rapid_pages.dryml +103 -19
- data/taglibs/rapid_plus.dryml +54 -6
- data/taglibs/rapid_support.dryml +38 -1
- data/taglibs/rapid_user_pages.dryml +17 -5
- data/test/permissions/models/models.rb +24 -12
- data/test/permissions/models/test.sqlite3 +0 -0
- metadata +6 -15
- data/lib/extensions/test_case.rb +0 -129
- data/lib/hobo/composite_model.rb +0 -73
- data/lib/hobo/model_support.rb +0 -44
- data/tasks/fix_dryml.rake +0 -143
- data/tasks/generate_tag_reference.rake +0 -192
- data/test/dryml/complilation_test.rb +0 -261
data/taglibs/rapid_core.dryml
CHANGED
@@ -98,12 +98,12 @@ This will use `<input/>` as the tag in each table cell instead of `<view/>`
|
|
98
98
|
<thead if="&all_parameters[:thead] || fields" param>
|
99
99
|
<tr param="field-heading-row">
|
100
100
|
<with-field-names merge-attrs="&all_attributes & attrs_for(:with_fields)">
|
101
|
-
<th param="#{scope.field_name}-heading"><%= this.member_class.view_hints.field_name(scope.field_name) %></th>
|
101
|
+
<th param="#{scope.field_name}-heading"><%= this.member_class.try.view_hints.try.field_name(scope.field_name) if scope %></th>
|
102
102
|
</with-field-names>
|
103
103
|
<th if="&all_parameters[:controls]" class="controls"/>
|
104
104
|
</tr>
|
105
105
|
</thead>
|
106
|
-
<tbody>
|
106
|
+
<tbody param>
|
107
107
|
<repeat>
|
108
108
|
<tr param if="&can_view?"
|
109
109
|
class="#{scope.even_odd} #{this_type.name.underscore} #{model_id_class}">
|
@@ -112,7 +112,7 @@ This will use `<input/>` as the tag in each table cell instead of `<view/>`
|
|
112
112
|
<td param="#{this_field.to_s.sub('?', '').gsub('.', '-')}-view"><call-tag tag="&field_tag"/></td>
|
113
113
|
</with-fields>
|
114
114
|
<td class="controls" param="controls" if="&all_parameters[:controls]">
|
115
|
-
<a param="edit-link" action="edit">Edit</a>
|
115
|
+
<a param="edit-link" action="edit" if="&can_edit?">Edit</a>
|
116
116
|
<delete-button param/>
|
117
117
|
</td>
|
118
118
|
</if>
|
@@ -213,8 +213,9 @@ Provides a short hand way of displaying images in public/images
|
|
213
213
|
-->
|
214
214
|
<def tag="type-name" attrs="plural, lowercase, dasherize"><%=
|
215
215
|
type ||= (this if this.is_a?(Class)) || this.try.member_class || this.class
|
216
|
-
|
217
|
-
name =
|
216
|
+
|
217
|
+
name = type.respond_to?(:view_hints) ? type.view_hints.model_name : type.name
|
218
|
+
name = dasherize ? name.underscore.dasherize : name.titleize
|
218
219
|
name = name.pluralize if plural
|
219
220
|
name = name.downcase if lowercase
|
220
221
|
name
|
@@ -293,7 +294,7 @@ Or a new page if the context is a class:
|
|
293
294
|
* If `action="new"` then `<a>` will check that the current user has permission to create the object
|
294
295
|
* Several useful classes are added automatically to the output `<a>`.
|
295
296
|
-->
|
296
|
-
<def tag="a" attrs="action, to, params, query-params, href, format, subsite"><%=
|
297
|
+
<def tag="a" attrs="action, to, params, query-params, href, format, subsite, force"><%=
|
297
298
|
content = parameters.default
|
298
299
|
|
299
300
|
params = self.query_params.merge(params || HashWithIndifferentAccess.new) if query_params
|
@@ -314,7 +315,7 @@ Or a new page if the context is a class:
|
|
314
315
|
new_record.set_creator(current_user)
|
315
316
|
href = object_url(target, "new", params._?.merge(:subsite => subsite))
|
316
317
|
|
317
|
-
if href && can_create?(new_record)
|
318
|
+
if href && (force || can_create?(new_record))
|
318
319
|
new_class_name = if target.respond_to?(:proxy_reflection)
|
319
320
|
target.proxy_reflection.klass.name
|
320
321
|
else
|
@@ -527,7 +528,7 @@ The label can be customised using the `label` attribute, e.g.
|
|
527
528
|
<def tag="theme-stylesheet" attrs="name">
|
528
529
|
<% name ||= Hobo.current_theme -%>
|
529
530
|
<link href="#{base_url}/hobothemes/#{Hobo.current_theme}/stylesheets/#{name}.css"
|
530
|
-
media="
|
531
|
+
media="all" rel="Stylesheet" type="text/css" merge/>
|
531
532
|
</def>
|
532
533
|
|
533
534
|
<!-- Convenience tag to help with the common situation where you need to address the current user as "you", and refer to other users by name
|
@@ -562,14 +563,7 @@ The context should be a user object. If `this == current_user` the "you" form is
|
|
562
563
|
<else><do param="default"><%= n = name; n.ends_with?('s') ? "#{n}'" : "#{n}'s" %></do></else>
|
563
564
|
</def>
|
564
565
|
|
565
|
-
<!--
|
566
|
-
|
567
|
-
### Usage
|
568
|
-
|
569
|
-
To render either "Please select a recipe" or "Please select an event", according to the type of the `this`:
|
570
|
-
|
571
|
-
<a-or-an word="&type_name"/>
|
572
|
-
|
566
|
+
<!-- Deprecated. It's harder than you think to do this (e.g. an umbrealla, an user)
|
573
567
|
-->
|
574
568
|
<def tag="a-or-an" attrs="word"><%=
|
575
569
|
(word =~ /^[aeiou]/i ? "an " : "a ") + word
|
@@ -584,3 +578,14 @@ To render either "Please select a recipe" or "Please select an event", according
|
|
584
578
|
|
585
579
|
<!-- Renders a collection of string joined with ", ", or some other string passed in the `join` attribute -->
|
586
580
|
<def tag="comma-list" attrs="join"><%= this.join(join || ", ") %></def>
|
581
|
+
|
582
|
+
|
583
|
+
<!-- Development mode only - a menu to change the `current_user` -->
|
584
|
+
<def tag="dev-user-changer">
|
585
|
+
<set user="&Hobo::User.default_user_model"/>
|
586
|
+
<select-menu if="&user && RAILS_ENV == 'development'"
|
587
|
+
first-option="Guest" options="&user.all(:limit => 30).*.login"
|
588
|
+
onchange="location.href = '/dev/set_current_user?login=' + this.options[this.selectedIndex].value"
|
589
|
+
selected="#{current_user.login}"
|
590
|
+
class="dev-user-changer"/>
|
591
|
+
</def>
|
@@ -19,7 +19,7 @@
|
|
19
19
|
-->
|
20
20
|
<def tag="section" attrs="empty, with-flash-messages">
|
21
21
|
<set body="¶meters.default" flash="&with_flash_messages && !scope.flash_rendered"/>
|
22
|
-
<div class="section #{'with-flash' if flash}" merge-attrs if="&!body.blank? || empty">
|
22
|
+
<div class="section #{'with-flash' if flash}" merge-attrs if="&!body.blank? || empty || flash">
|
23
23
|
<flash-messages if="&flash"/>
|
24
24
|
<%= body %>
|
25
25
|
</div>
|
data/taglibs/rapid_editing.dryml
CHANGED
@@ -58,9 +58,6 @@ This area of Hobo has had less attention that the non-ajax forms of late, so it'
|
|
58
58
|
<!-- Provides a simple Scriptaculous in-place-editor that uses an `<input type='text'>` -->
|
59
59
|
<def tag="editor" for="float"><%= in_place_editor attributes %></def>
|
60
60
|
|
61
|
-
<!-- Provides a simple Scriptaculous in-place-editor that uses an `<input type='text'>` -->
|
62
|
-
<def tag="editor" for="big_integer"><%= in_place_editor attributes %></def>
|
63
|
-
|
64
61
|
<!-- Raises an error - passwords cannot be edited in place -->
|
65
62
|
<def tag="editor" for="password"><% raise HoboError, "passwords cannot be edited in place" %></def>
|
66
63
|
|
@@ -88,14 +85,14 @@ This area of Hobo has had less attention that the non-ajax forms of late, so it'
|
|
88
85
|
NOTE: yes that's *DOM ID's* not part-names. A common source of confusion because by default the part name and DOM ID are the same.
|
89
86
|
|
90
87
|
-->
|
91
|
-
<def tag="select-one-editor" attrs="include-none, blank-message, sort, update"><%
|
88
|
+
<def tag="select-one-editor" attrs="include-none, blank-message, sort, update, options"><%
|
92
89
|
raise HoboError.new("Not allowed to edit") unless can_edit?
|
93
90
|
blank_message ||= "(No #{this_type.name.to_s.titleize})"
|
94
|
-
|
91
|
+
options ||= this_field_reflection.klass.find(:all).select {|x| can_view?(x)}.map {|x|
|
95
92
|
[ name(:with => x, :no_wrapper => true), x.id ]
|
96
93
|
}
|
97
|
-
|
98
|
-
|
94
|
+
options = options.sort if sort
|
95
|
+
options.insert(0, [blank_message, ""]) if this.nil? || include_none
|
99
96
|
f = ajax_updater(object_url(this_parent, :method => :put),
|
100
97
|
update,
|
101
98
|
:method => "put",
|
@@ -104,7 +101,7 @@ This area of Hobo has had less attention that the non-ajax forms of late, so it'
|
|
104
101
|
} })
|
105
102
|
%>
|
106
103
|
<select onchange="#{f}" merge-attrs>
|
107
|
-
<%= options_for_select(
|
104
|
+
<%= options_for_select(options, this ? this.id : "") %>
|
108
105
|
</select>
|
109
106
|
</def>
|
110
107
|
|
@@ -212,10 +209,10 @@ This area of Hobo has had less attention that the non-ajax forms of late, so it'
|
|
212
209
|
-->
|
213
210
|
<def tag="integer-select-editor" attrs="options, min, max, update, nil-option, message">
|
214
211
|
<% options ||= (min.to_i..max.to_i).to_a %>
|
215
|
-
<select class="
|
212
|
+
<select class="integer editor #{'update:' + comma_split(update).join(':') unless update.blank?} #{model_id_class(this_parent, this_field)}"
|
216
213
|
merge-attrs="&message ? attributes.merge(:hobo_message => message) : attributes">
|
217
214
|
<if test="&this.nil?"><option value=""><%= nil_option || "Choose a value" %></option></if>
|
218
|
-
<%= options_for_select(options.*.to_s, this) %>
|
215
|
+
<%= options_for_select(options.*.to_s, this.to_s) %>
|
219
216
|
</select>
|
220
217
|
</def>
|
221
218
|
|
data/taglibs/rapid_forms.dryml
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
<!-- Rapid Forms provides various tags that make it quick and easy to produce working new or edit forms.
|
2
2
|
|
3
|
+
### Overview
|
4
|
+
|
3
5
|
The main tags are:
|
4
6
|
|
5
7
|
- `<form>`, which acts like the dumb HTML tag if you provide the `action` attribute, and picks up various Rapid smarts
|
@@ -169,7 +171,7 @@ AJAX based submission can be enabled by simply adding an `update` attribute. e.g
|
|
169
171
|
b
|
170
172
|
end
|
171
173
|
|
172
|
-
auth_token = if method.nil? || method == 'get' ||
|
174
|
+
auth_token = if method.nil? || method == 'get' || !protect_against_forgery?
|
173
175
|
''
|
174
176
|
else
|
175
177
|
element(:input, {:type => "hidden",
|
@@ -278,7 +280,7 @@ If the context is a `has_many :through` association, the polymorphic `<collectio
|
|
278
280
|
if refl.options[:through]
|
279
281
|
collection_input(attrs)
|
280
282
|
else
|
281
|
-
|
283
|
+
input_many(attrs)
|
282
284
|
end
|
283
285
|
end
|
284
286
|
else
|
@@ -363,7 +365,7 @@ The menus default to the current time if the current value is nil.
|
|
363
365
|
### Attributes
|
364
366
|
|
365
367
|
- order: The order of the year, month and date menus. A comma separated string or an array. Default: "year, month,
|
366
|
-
day, hour, minute
|
368
|
+
day, hour, minute"
|
367
369
|
|
368
370
|
Any other attributes are passed through to the `select_datetime` helper.
|
369
371
|
|
@@ -371,8 +373,13 @@ The menus default to the current time if the current value is nil.
|
|
371
373
|
|
372
374
|
-->
|
373
375
|
<def tag="input" for="datetime" attrs="order">
|
374
|
-
<%
|
375
|
-
|
376
|
+
<% if ! order.nil?
|
377
|
+
order = comma_split(order).*.to_sym
|
378
|
+
attributes.merge!(:order => order)
|
379
|
+
require 'ruby-debug'
|
380
|
+
debugger
|
381
|
+
end -%>
|
382
|
+
<%= select_datetime(this || Time.now, attributes.merge(:prefix => param_name_for_this)) %>
|
376
383
|
</def>
|
377
384
|
|
378
385
|
<!-- An `<input type='text'>` input. -->
|
@@ -390,11 +397,6 @@ The menus default to the current time if the current value is nil.
|
|
390
397
|
<%= text_field_tag(name, this, attributes) %>
|
391
398
|
</def>
|
392
399
|
|
393
|
-
<!-- An `<input type='text'>` input. -->
|
394
|
-
<def tag="input" for="big_integer" attrs="name">
|
395
|
-
<%= text_field_tag(name, this, attributes) %>
|
396
|
-
</def>
|
397
|
-
|
398
400
|
<!-- A `<select>` menu containing the values of an 'enum string'.
|
399
401
|
|
400
402
|
### Attributes
|
@@ -405,12 +407,13 @@ The menus default to the current time if the current value is nil.
|
|
405
407
|
- titleize: Set to false to have the value itself (rather than `value.titleize`) be the default label. Default: true
|
406
408
|
|
407
409
|
-->
|
408
|
-
<def tag="input" for="HoboFields::EnumString" attrs="labels, titleize"><%
|
410
|
+
<def tag="input" for="HoboFields::EnumString" attrs="labels, titleize, first-option, first-value"><%
|
409
411
|
labels ||= {}
|
410
412
|
titleize = true if titleize.nil?
|
411
413
|
options = this_type.values.map {|v| [labels.fetch(v.to_sym, titleize ? v.titleize : v), v] }
|
412
414
|
%>
|
413
415
|
<select name="#{param_name_for_this}" merge-attrs>
|
416
|
+
<option value="#{first_value}" unless="&first_option.nil?"><first-option/></option>
|
414
417
|
<%= options_for_select(options, this) %>
|
415
418
|
</select>
|
416
419
|
</def>
|
@@ -547,7 +550,7 @@ All the standard ajax attributes *except the callbacks* are supported (see the m
|
|
547
550
|
%></def>
|
548
551
|
|
549
552
|
|
550
|
-
<!-- Provides
|
553
|
+
<!-- Provides an ajax create button that will send a RESTful "POST" to the server to create a new resource.
|
551
554
|
|
552
555
|
All of the standard ajax attributes are supported (see the main taglib documention for Rapid Forms).
|
553
556
|
|
@@ -582,6 +585,21 @@ All of the standard ajax attributes are supported (see the main taglib documenti
|
|
582
585
|
%></def>
|
583
586
|
|
584
587
|
|
588
|
+
<!-- A `<select>` menu from which the user can choose the target record for a `belongs_to` association.
|
589
|
+
|
590
|
+
This is the default input that Rapid uses for `belongs_to` associations. The menu is constructed using the `to_s` representation of the records.
|
591
|
+
|
592
|
+
### Attributes
|
593
|
+
|
594
|
+
- `include-none` - whether to include a 'none' option (i.e. set the foreign key to null). Defaults to false
|
595
|
+
- `blank-message` - the message for the 'none' option. Defaults to "(No `<model-name>`)", e.g. "(No Product)"
|
596
|
+
- `options` - an array of records to include in the menu. Defaults to the all the records in the target table that match any `:conditions` declared on the `belongs_to` (limited to 100).
|
597
|
+
|
598
|
+
### See Also
|
599
|
+
|
600
|
+
For situations where there are too many target records to practically include in a menu, `<name-one>` provides an autocompleter which would be more suitable.
|
601
|
+
|
602
|
+
-->
|
585
603
|
<def tag="select-one" attrs="include-none, blank-message, options, sort"><%
|
586
604
|
raise HoboError.new("Not allowed to edit #{this_field}") if !attributes[:disabled] && !can_edit?
|
587
605
|
|
@@ -589,7 +607,7 @@ All of the standard ajax attributes are supported (see the main taglib documenti
|
|
589
607
|
|
590
608
|
options ||= begin
|
591
609
|
conditions = ActiveRecord::Associations::BelongsToAssociation.new(this_parent, this_field_reflection).conditions
|
592
|
-
this_field_reflection.klass.all(:conditions => conditions).select {|x| can_view?(x)}
|
610
|
+
this_field_reflection.klass.all(:conditions => conditions, :limit => 100).select {|x| can_view?(x)}
|
593
611
|
end
|
594
612
|
|
595
613
|
select_options = options.map { |x| [x.to_s, x.id ] }
|
@@ -603,6 +621,23 @@ All of the standard ajax attributes are supported (see the main taglib documenti
|
|
603
621
|
</def>
|
604
622
|
|
605
623
|
|
624
|
+
<!-- An `<input type="text">` with auto-completion. Allows the user to chose the target of a `belongs_to` association
|
625
|
+
by name.
|
626
|
+
|
627
|
+
### Attributes
|
628
|
+
|
629
|
+
- `complete-target`
|
630
|
+
- `completer`
|
631
|
+
|
632
|
+
In the simple case no attributes are needed, e.g.: `<name-one:category/>`.
|
633
|
+
|
634
|
+
The completions are provided by the server with a GET request. The `complete-target` and `completer` attributes can be used to customise the URL for the request. For example:
|
635
|
+
|
636
|
+
- If `completer` is a class, say `Product`: `/products/complete_name` (where `name` is the declared name attribute of `Product`)
|
637
|
+
- If `completer` is a record, say a `Product` with id `12`: `/products/complete_name?id=12`
|
638
|
+
- If `completer-name` is given, e.g. with `completer-name="new_product_names"`: `/products/complete_new_product_names`
|
639
|
+
|
640
|
+
-->
|
606
641
|
<def tag="name-one" attrs="complete-target, completer"><%
|
607
642
|
complete_target ||= this_field_reflection.klass
|
608
643
|
completer ||= (complete_target.is_a?(Class) ? complete_target : complete_target.class).name_attribute
|
@@ -615,18 +650,31 @@ All of the standard ajax attributes are supported (see the main taglib documenti
|
|
615
650
|
</def>
|
616
651
|
|
617
652
|
|
653
|
+
<!-- nodoc. -->
|
618
654
|
<def tag="sti-type-input">
|
619
655
|
<select name="#{param_name_for(form_field_path + ['type'])}">
|
620
656
|
<%= options_for_select(this.class.send(:subclasses).map{|x| [x.name.titleize, x.name]}, this.class.name) %>
|
621
657
|
</select>
|
622
658
|
</def>
|
623
659
|
|
624
|
-
|
660
|
+
|
661
|
+
<!-- A `<select>` menu input. This tag differes from `<select-menu>` only in that it adds the correct `name` attribute for the current field, and `selected` default to `this`.
|
662
|
+
|
663
|
+
### Attributes
|
664
|
+
|
665
|
+
- `options` - an array of options suitable to be passed to the Rails `options_for_select` helper.
|
666
|
+
- `selected` - the value (from the `options` array) that should be initially selected. Defaults to `this`
|
667
|
+
- first-option - A string to be used for an extra option in the first position. E.g. "Please choose..."
|
668
|
+
- first-value - the value to be used with the `first-option`. Typcially not used, meaning the option has a blank value.
|
669
|
+
|
670
|
+
-->
|
625
671
|
<def tag="select-input">
|
626
672
|
<select-menu name="#{param_name_for_this}" selected="&this" merge/>
|
627
673
|
</def>
|
628
674
|
|
629
|
-
|
675
|
+
|
676
|
+
<!-- Renders a readable list of error messages following a form submission. Expects the errors to be in `this.errors`. Renders nothing if there are no errors.
|
677
|
+
-->
|
630
678
|
<def tag="error-messages">
|
631
679
|
<section class="error-messages" merge-attrs if="&this.errors.length > 0">
|
632
680
|
<h2 param="heading">To proceed please correct the following:</h2>
|
@@ -676,6 +724,7 @@ To use this tag, the model of the items the user is chosing *must* have unique n
|
|
676
724
|
</div>
|
677
725
|
</def>
|
678
726
|
|
727
|
+
|
679
728
|
<!--
|
680
729
|
Used inside a form to specify where to redirect after successful submission. This works by inserting a hidden field called `after_submit` which is used by Hobo if present to perform a redirect after the form submission.
|
681
730
|
|
@@ -710,31 +759,68 @@ Use the `uri` option to specify a redirect location:
|
|
710
759
|
</def>
|
711
760
|
|
712
761
|
|
762
|
+
<!-- A simple wrapper around the `<select>` tag and `options_for_select` helper
|
763
|
+
|
764
|
+
### Attributes
|
765
|
+
|
766
|
+
- `options` - an array of options suitable to be passed to the Rails `options_for_select` helper.
|
767
|
+
- `selected` - the value (from the `options` array) that should be initially selected. Defaults to `this`
|
768
|
+
- first-option - A string to be used for an extra option in the first position. E.g. "Please choose..."
|
769
|
+
- first-value - the value to be used with the `first-option`. Typcially not used, meaning the option has a blank value.
|
770
|
+
|
771
|
+
-->
|
713
772
|
<def tag="select-menu" attrs="options, selected, first-option, first-value">
|
714
773
|
<select merge-attrs param="default">
|
774
|
+
<% selected=this if selected.nil? %>
|
715
775
|
<option value="#{first_value}" unless="&first_option.nil?"><first-option/></option>
|
716
|
-
<do param="options"><% options_for_select(options, selected
|
776
|
+
<do param="options"><% options_for_select(options, selected) %></do>
|
717
777
|
</select>
|
718
778
|
</def>
|
719
779
|
|
720
780
|
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
781
|
+
<!-- Renders a `<ul>` list of checkboxes, one for each of the potential targt in a `has_many` association. The use can check the items they wish to have associated. A typical use might be selecting categories for a blog post.
|
782
|
+
-->
|
783
|
+
<def tag="check-many" attrs="disabled"><%
|
784
|
+
collection = this
|
785
|
+
param_name = param_name_for_this
|
786
|
+
options ||= begin
|
787
|
+
conditions = ActiveRecord::Associations::BelongsToAssociation.new(this_parent, this_field_reflection).conditions
|
788
|
+
this_field_reflection.klass.all(:conditions => conditions, :limit => 100).select {|x| can_view?(x)}
|
789
|
+
end
|
790
|
+
-%>
|
791
|
+
<ul class="check-many" param="default" merge-attrs>
|
792
|
+
<input type="hidden" name="#{param_name}[]" value=""/><% # ensure all items are removed when nothing checked %>
|
793
|
+
<li repeat="&options" param>
|
794
|
+
<input type="checkbox" name="#{param_name}[]" value="@#{this.id}" checked="&this.in?(collection)" disabled="&disabled"/>
|
795
|
+
<name param/>
|
727
796
|
</li>
|
728
797
|
</ul>
|
729
798
|
</def>
|
730
799
|
|
731
800
|
|
801
|
+
<!-- Renders an `<input type='hidden'>` for the `id` field of the current context -->
|
732
802
|
<def tag="hidden-id-field">
|
733
803
|
<if:id><input type="hidden" name="#{param_name_for_this}" value="#{this}" /></if>
|
734
804
|
</def>
|
735
805
|
|
736
806
|
|
737
|
-
|
807
|
+
<!-- Creates a sub-section of the form which the user can repeat using (+) and (-) buttons, in order to allow an entire `has_many` collection to be created/edited in a single form.
|
808
|
+
|
809
|
+
This tag is very different from tags like `<select-many>` and `<check-many>` in that:
|
810
|
+
|
811
|
+
- Those tags are used to *chose existing records* to include in the assocaition, while `<input-many>` is used to actually create or edit the records in the association.
|
812
|
+
- Those tags work by themselves, while `<input-many>` is just a wrapper for other input fields.
|
813
|
+
|
814
|
+
### Example
|
815
|
+
|
816
|
+
Say you are creating a new `Category` in your online shop, and you want to create some initial products *in the same form*, you can add the following to your form:
|
817
|
+
|
818
|
+
<input-many:products><field-list fields="name, price"/></input-many>
|
819
|
+
|
820
|
+
The body of the tag will be repeated for each of the current records in the collection, or will just appear once (with blank fields) if the colleciton is empty.
|
821
|
+
|
822
|
+
-->
|
823
|
+
<def tag="input-many" polymorphic>
|
738
824
|
<set empty="&this.empty?"/>
|
739
825
|
<ul class="input-many #{this_field.dasherize} #{css_data :input_many_prefix, param_name_for_this}">
|
740
826
|
<li repeat class="#{'record-with-errors' unless this.errors.empty?}">
|
@@ -742,12 +828,12 @@ Use the `uri` option to specify a redirect location:
|
|
742
828
|
<hidden-id-field/>
|
743
829
|
<div class="input-many-item" param="default"/>
|
744
830
|
<div class="buttons">
|
745
|
-
<button class="remove-item"
|
831
|
+
<button class="remove-item" merge-attrs="disabled">-</button>
|
746
832
|
<button class="add-item" if="&last_item?" merge-attrs="disabled">+</button>
|
747
833
|
</div>
|
748
834
|
</li>
|
749
835
|
<li if="&empty">
|
750
|
-
<fake-field-context fake-field="0" context="&this.new">
|
836
|
+
<fake-field-context fake-field="0" context="&this.try.new_candidate || this.member_class.new">
|
751
837
|
<div class="input-many-item" param="default"/>
|
752
838
|
</fake-field-context>
|
753
839
|
<div class="buttons">
|
@@ -758,6 +844,8 @@ Use the `uri` option to specify a redirect location:
|
|
758
844
|
</def>
|
759
845
|
|
760
846
|
|
847
|
+
<!-- Renders a sub-section of a form with fields for every record in a `has_many` association. This is similar to `<input-many>` except there is no ability to add and remove items (i.e. no (+) and (-) buttons).
|
848
|
+
-->
|
761
849
|
<def tag="input-all">
|
762
850
|
<% association_fkey = this_field_reflection.primary_key_name -%>
|
763
851
|
<ul class="input-all #{this_field.dasherize}">
|
@@ -771,7 +859,8 @@ Use the `uri` option to specify a redirect location:
|
|
771
859
|
</ul>
|
772
860
|
</def>
|
773
861
|
|
774
|
-
|
862
|
+
<!-- Renders the common "or (Cancel)" for a form. Attributes are merged into the link (`<a>Cancel</a>`), making it easy to customise the destination of the cancel link. By default it will link to `this` or `this.class`.
|
863
|
+
-->
|
775
864
|
<def tag="or-cancel">
|
776
865
|
<if test="&linkable?">or <a merge-attrs>Cancel</a></if>
|
777
866
|
<else>
|
@@ -1,3 +1,6 @@
|
|
1
|
+
<!-- Rapid Generics provides tags that provide generic renderings that can adapt to the model being renderd. At the moment this library provides cards and collections of cards. -->
|
2
|
+
|
3
|
+
<!-- A 'card' is a representation of an sub-object *within* a page, such as a comment on a blog-post, or a single product in a list of produtcs. This definition is just the very basic framework which gives the basis for the automatic cards that get generated. See `app/views/taglibs/auto/rapid/cards.dryml` for the cards that have been generated for your specific application. -->
|
1
4
|
<def tag="card" polymorphic>
|
2
5
|
<div class="card" param="default" merge-attrs>
|
3
6
|
<header param/>
|
@@ -6,11 +9,14 @@
|
|
6
9
|
</def>
|
7
10
|
|
8
11
|
|
12
|
+
<!-- A special card which is used by live-search to render the results. By default this just calls card, but you can define your own search cards with `<def tag='search-card' for="MyModel">` to customise search results for that model. -->
|
9
13
|
<def tag="search-card" polymorphic>
|
10
|
-
<card/>
|
14
|
+
<card merge/>
|
11
15
|
</def>
|
12
16
|
|
13
17
|
|
18
|
+
<!-- Renders a message such as "No products to display". If the collection (`this`) is empty, `style="display:none"` is added. This means the message is still present and can be revealed with JavaScript if all items in the collection are removed with ajax remove buttons.
|
19
|
+
-->
|
14
20
|
<def tag="empty-collection-message">
|
15
21
|
<div class="empty-collection-message" style="#{'display:none' if !this.empty?}" param="default">
|
16
22
|
No <collection-name lowercase/> to display
|
@@ -18,6 +24,10 @@
|
|
18
24
|
</def>
|
19
25
|
|
20
26
|
|
27
|
+
<!-- Repeats the body of the tag inside a `<ul>` list with one item for each object in the collection (`this`). If no body is given, renders a `<card>` inside the `<li>`.
|
28
|
+
|
29
|
+
The `<li>` tags are automatically given a 'model ID' CSS class, which means the ajax `<remove-button>` will automatically be able to remove items from the collection. Also adds 'even' and 'odd' CSS classes.
|
30
|
+
-->
|
21
31
|
<def tag="collection">
|
22
32
|
<ul class="collection #{collection_name :dasherize => true}" merge-attrs unless="empty?">
|
23
33
|
<li param="item" class="#{scope.even_odd} #{model_id_class}" repeat="&select_viewable">
|
@@ -27,7 +37,7 @@
|
|
27
37
|
<empty-collection-message param="empty-message"/>
|
28
38
|
</def>
|
29
39
|
|
30
|
-
|
31
|
-
<def tag="
|
40
|
+
<!-- Renders a comma separated list of any fields passed in the `fields` attribute that are true (in the Ruby sense). For example, if a forum post had a boolean field `sticky`, this tag can be used to automatically label sticky posts "Sticky". Similarly, you could automatically add an "Administrator" label to the user's home page (this is seen in the default Hobo app). -->
|
41
|
+
<def tag="record-flags" attrs="fields"><%=
|
32
42
|
comma_split(fields).select { |f| this.send(f) }.map { |f| f.titleize }.join(', ')
|
33
43
|
%></def>
|