hobo_rapid 1.4.0.pre2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +5 -0
- data/VERSION +1 -0
- data/app/controllers/dev_controller.rb +25 -0
- data/app/helpers/hobo_rapid_helper.rb +197 -0
- data/hobo_rapid.gemspec +26 -0
- data/lib/hobo_rapid/railtie.rb +6 -0
- data/lib/hobo_rapid.rb +13 -0
- data/taglibs/buttons/buttons.dryml +1 -0
- data/taglibs/buttons/create_button.dryml +40 -0
- data/taglibs/buttons/delete-button.dryml +75 -0
- data/taglibs/buttons/remote_method_button.dryml +34 -0
- data/taglibs/buttons/transition_button.dryml +71 -0
- data/taglibs/buttons/transition_link.dryml +22 -0
- data/taglibs/buttons/update_button.dryml +29 -0
- data/taglibs/cache/cache.dryml +1 -0
- data/taglibs/cache/nested_cache.dryml +332 -0
- data/taglibs/cards/card.dryml +7 -0
- data/taglibs/cards/cards.dryml +1 -0
- data/taglibs/cards/search_card.dryml +4 -0
- data/taglibs/editors/click_editor.dryml +60 -0
- data/taglibs/editors/editors.dryml +27 -0
- data/taglibs/editors/live_editor.dryml +37 -0
- data/taglibs/forms/error_messages.dryml +21 -0
- data/taglibs/forms/form.dryml +101 -0
- data/taglibs/forms/formlet.dryml +48 -0
- data/taglibs/forms/forms.dryml +5 -0
- data/taglibs/forms/submit.dryml +14 -0
- data/taglibs/hobo_rapid.dryml +14 -0
- data/taglibs/html/a.dryml +156 -0
- data/taglibs/html/aside.dryml +5 -0
- data/taglibs/html/doctype.dryml +39 -0
- data/taglibs/html/empty_tag.dryml +23 -0
- data/taglibs/html/footer.dryml +5 -0
- data/taglibs/html/header.dryml +5 -0
- data/taglibs/html/html.dryml +18 -0
- data/taglibs/html/if_ie.dryml +11 -0
- data/taglibs/html/image.dryml +11 -0
- data/taglibs/html/javascript.dryml +12 -0
- data/taglibs/html/section.dryml +12 -0
- data/taglibs/html/section_group.dryml +11 -0
- data/taglibs/html/stylesheet.dryml +5 -0
- data/taglibs/html/table.dryml +174 -0
- data/taglibs/i18n/ht.dryml +48 -0
- data/taglibs/i18n/human_attribute_name +18 -0
- data/taglibs/i18n/human_collection_name.dryml +69 -0
- data/taglibs/i18n/i18n.dryml +1 -0
- data/taglibs/i18n/model_name_human.dryml +16 -0
- data/taglibs/i18n/t.dryml +12 -0
- data/taglibs/inputs/after_submit.dryml +32 -0
- data/taglibs/inputs/check_many.dryml +25 -0
- data/taglibs/inputs/collection_input.dryml +10 -0
- data/taglibs/inputs/hidden_field.dryml +48 -0
- data/taglibs/inputs/hot_input.dryml +50 -0
- data/taglibs/inputs/input.dryml +76 -0
- data/taglibs/inputs/input_all.dryml +14 -0
- data/taglibs/inputs/input_for.dryml +38 -0
- data/taglibs/inputs/input_for_date.dryml +86 -0
- data/taglibs/inputs/input_for_enum_string.dryml +26 -0
- data/taglibs/inputs/input_many.dryml +131 -0
- data/taglibs/inputs/inputs.dryml +1 -0
- data/taglibs/inputs/name_one.dryml +74 -0
- data/taglibs/inputs/or_cancel.dryml +8 -0
- data/taglibs/inputs/select_input.dryml +13 -0
- data/taglibs/inputs/select_many.dryml +58 -0
- data/taglibs/inputs/select_menu.dryml +23 -0
- data/taglibs/inputs/select_one.dryml +46 -0
- data/taglibs/inputs/sortable_input_many.dryml +31 -0
- data/taglibs/inputs/sti_type_input.dryml +6 -0
- data/taglibs/lists/collection.dryml +26 -0
- data/taglibs/lists/empty_collection_message.dryml +13 -0
- data/taglibs/lists/feckless_fieldset.dryml +94 -0
- data/taglibs/lists/field_list.dryml +21 -0
- data/taglibs/lists/field_list_v1.dryml +64 -0
- data/taglibs/lists/labelled_item_list.dryml +11 -0
- data/taglibs/lists/lists.dryml +2 -0
- data/taglibs/lists/with_fields.dryml +98 -0
- data/taglibs/pages/account.dryml +30 -0
- data/taglibs/pages/account_disabled.dryml +19 -0
- data/taglibs/pages/flash_message.dryml +23 -0
- data/taglibs/pages/forgot_password.dryml +62 -0
- data/taglibs/pages/login.dryml +57 -0
- data/taglibs/pages/not_found_page.dryml +18 -0
- data/taglibs/pages/page_nav.dryml +17 -0
- data/taglibs/pages/pages.dryml +12 -0
- data/taglibs/pages/permission_denied_page.dryml +24 -0
- data/taglibs/plus/collection_preview.dryml +23 -0
- data/taglibs/plus/filter_menu.dryml +103 -0
- data/taglibs/plus/gravatar.dryml +12 -0
- data/taglibs/plus/live_search.dryml +40 -0
- data/taglibs/plus/plus.dryml +1 -0
- data/taglibs/plus/sortable_collection.dryml +36 -0
- data/taglibs/plus/table_plus.dryml +63 -0
- data/taglibs/views/a_or_an.dryml +10 -0
- data/taglibs/views/collection_name.dryml +28 -0
- data/taglibs/views/comma_list.dryml +2 -0
- data/taglibs/views/count.dryml +99 -0
- data/taglibs/views/links_for_collection.dryml +2 -0
- data/taglibs/views/name.dryml +30 -0
- data/taglibs/views/nil_view.dryml +10 -0
- data/taglibs/views/record_flags.dryml +5 -0
- data/taglibs/views/type_name.dryml +24 -0
- data/taglibs/views/view.dryml +79 -0
- data/taglibs/views/view_for.dryml +42 -0
- data/taglibs/views/views.dryml +1 -0
- data/taglibs/views/you.dryml +150 -0
- data/vendor/assets/javascripts/hobo_rapid.js +1 -0
- data/vendor/assets/stylesheets/feckless-fieldset.css +40 -0
- data/vendor/assets/stylesheets/hobo-rapid.css +94 -0
- data/vendor/assets/stylesheets/hobo_rapid.css +1 -0
- metadata +174 -0
@@ -0,0 +1,8 @@
|
|
1
|
+
<!-- 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`.
|
2
|
+
-->
|
3
|
+
<def tag="or-cancel">
|
4
|
+
<if test="&linkable?"><t key="hobo.support.or">or</t> <a merge-attrs><t key="hobo.actions.cancel">Cancel</t></a></if>
|
5
|
+
<else>
|
6
|
+
<if test="&linkable?(this.class)"><t key="hobo.support.or">or</t> <a to="&this.class" merge-attrs><t key="hobo.actions.cancel">Cancel</t></a></if>
|
7
|
+
</else>
|
8
|
+
</def>
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<!-- 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`.
|
2
|
+
|
3
|
+
### Attributes
|
4
|
+
|
5
|
+
- `options` - an array of options suitable to be passed to the Rails `options_for_select` helper.
|
6
|
+
- `selected` - the value (from the `options` array) that should be initially selected. Defaults to `this`
|
7
|
+
- `first-option` - a string to be used for an extra option in the first position. E.g. "Please choose..."
|
8
|
+
- `first-value` - the value to be used with the `first-option`. Typically not used, meaning the option has a blank value.
|
9
|
+
|
10
|
+
-->
|
11
|
+
<def tag="select-input">
|
12
|
+
<select-menu name="#{param_name_for_this}" selected="&this" merge/>
|
13
|
+
</def>
|
@@ -0,0 +1,58 @@
|
|
1
|
+
<%#
|
2
|
+
An input for `has_many :through` associations that lets the user chose the items from a `<select>` menu.
|
3
|
+
|
4
|
+
To use this tag, the model of the items the user is chosing *must* have unique names.
|
5
|
+
|
6
|
+
### Attributes
|
7
|
+
|
8
|
+
`options`: An array of ActiveRecord objects
|
9
|
+
|
10
|
+
`remove-label`: the label on the remove button. i18n
|
11
|
+
hobo.actions.remove is the preferred way of changing this value.
|
12
|
+
|
13
|
+
`prompt`: default: "Add foos", where foo is the name of the field.
|
14
|
+
i18n foos.form.select_many.prompt is the preferred way to change
|
15
|
+
the prompt.
|
16
|
+
|
17
|
+
`name`: the parameter name. Defaults to `param_name_for_this`.
|
18
|
+
|
19
|
+
%>
|
20
|
+
<def tag="select-many" attrs="options, remove-label, prompt, disabled, name"><%
|
21
|
+
prompt ||= ht("#{this_field_reflection.klass.to_s.underscore}.form.select_many.prompt", :default=>"Add #{this_field.titleize.singularize}")
|
22
|
+
options ||= this_field_reflection.klass.all(:conditions => this_field_reflection.options[:conditions]).select {|x| can_view?(x)}
|
23
|
+
name ||= param_name_for_this
|
24
|
+
|
25
|
+
values = this
|
26
|
+
remove_label ||= t("hobo.actions.remove", :default=>'Remove')
|
27
|
+
effect_attrs, attributes = attributes.partition_hash(HoboRapidHelper::AJAX_EFFECT_ATTRS)
|
28
|
+
-%>
|
29
|
+
<div class="input select-many" data-rapid="#{data_rapid('select-many', effect_attrs)}" merge-attrs>
|
30
|
+
<div style="display:none" class="item-proto">
|
31
|
+
<div class="item" param="proto-item">
|
32
|
+
<span></span>
|
33
|
+
<input type="hidden" name="#{name}[]" param="proto-hidden"/>
|
34
|
+
<input type="button" class="remove-item" value="#{remove_label}" param="proto-remove-button"/>
|
35
|
+
</div>
|
36
|
+
</div>
|
37
|
+
<div class="items">
|
38
|
+
<div class="item" param="item" repeat>
|
39
|
+
<span><%= h this.to_s %></span>
|
40
|
+
<input type="hidden" name="#{name}[]" value="@#{h this.id}" disabled="&disabled"
|
41
|
+
param="hidden"/>
|
42
|
+
<input type="button" class="remove-item" value="#{remove_label}" disabled="&disabled"
|
43
|
+
param="remove-button"/>
|
44
|
+
</div>
|
45
|
+
</div>
|
46
|
+
<select merge-attrs="&{:disabled => disabled}">
|
47
|
+
<option value=""><prompt/></option>
|
48
|
+
<repeat with="&options">
|
49
|
+
<if test="&this.in?(values)">
|
50
|
+
<optgroup class="disabled-option" label="#{h this.to_s}" alt="@#{this.id}"> </optgroup>
|
51
|
+
</if>
|
52
|
+
<else>
|
53
|
+
<option value="@#{this.id}"><%= h this.to_s %></option>
|
54
|
+
</else>
|
55
|
+
</repeat>
|
56
|
+
</select>
|
57
|
+
</div>
|
58
|
+
</def>
|
@@ -0,0 +1,23 @@
|
|
1
|
+
<!-- A simple wrapper around the `<select>` tag and `options_for_select` helper
|
2
|
+
|
3
|
+
### Attributes
|
4
|
+
|
5
|
+
- `options` - an array of options suitable to be passed to the Rails `options_for_select` helper.
|
6
|
+
- `selected` - the value (from the `options` array) that should be initially selected. Defaults to `this`
|
7
|
+
- `first-option` - a string to be used for an extra option in the first position. E.g. "Please choose..."
|
8
|
+
- `first-value` - the value to be used with the `first-option`. Typically not used, meaning the option has a blank value.
|
9
|
+
- `key` - the key used to lookup in the locale file or 'default' by default. If you pass it hobo will lookup in the namespace "tags.select_menu.#{key}" in order to find `options`, `first_option` and `first_value`. The passed attributes are used as a default in case the lookups fail. (see the documentation of filter-menu tag for a similar example).
|
10
|
+
-->
|
11
|
+
<def tag="select-menu" attrs="options, selected, first-option, first-value, key">
|
12
|
+
<% key ||= 'default'
|
13
|
+
%w[options first_option first_value].each do |a|
|
14
|
+
str = t("tags.select_menu.#{key}.#{a}", :default=>'')
|
15
|
+
eval "#{a} = str unless str.blank?"
|
16
|
+
end
|
17
|
+
-%>
|
18
|
+
<select merge-attrs param="default">
|
19
|
+
<% selected=this if selected.nil? %>
|
20
|
+
<option value="#{first_value}" unless="&first_option.nil?"><first-option/></option>
|
21
|
+
<do param="options"><%= options_for_select(options, selected) %></do>
|
22
|
+
</select>
|
23
|
+
</def>
|
@@ -0,0 +1,46 @@
|
|
1
|
+
<!-- A `<select>` menu from which the user can choose the target record for a `belongs_to` association.
|
2
|
+
|
3
|
+
This is the default input that Rapid uses for `belongs_to` associations. The menu is constructed using the `to_s` representation of the records.
|
4
|
+
|
5
|
+
### Attributes
|
6
|
+
|
7
|
+
- `include-none` - whether to include a 'none' option (i.e. set the foreign key to null). If this value is not supplied, the default is "true" if the current value is nil; otherwise the default is "false". One implication of this is that the default may change when the form is re-rendered due to a validation failure. Setting this value explicitly is recommended.
|
8
|
+
- `blank-message` - the message for the 'none' option. Defaults to "(No `<model-name-human>`)", e.g. "(No Product)"
|
9
|
+
- `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` (subject to `limit`)
|
10
|
+
- `sort` - whether to sort the array of options. Defaults to no sorting.
|
11
|
+
- `limit` - if `options` is not specified, this limits the number of records. Default: 100
|
12
|
+
- `text_method` - The method to call on each record to get the text for the option. Multiple methods are supported ie "institution.name"
|
13
|
+
|
14
|
+
### See Also
|
15
|
+
|
16
|
+
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.
|
17
|
+
|
18
|
+
-->
|
19
|
+
<def tag="select-one" attrs="include-none, blank-message, options, sort, limit, text-method"><%
|
20
|
+
raise Hobo::PermissionDeniedError.new("Not allowed to edit #{this_field}") if !attributes[:disabled] && !can_edit?
|
21
|
+
blank_message ||= ht("#{this_type.name.underscore}.messages.none", :default=>"No #{this_type.model_name.human} available.")
|
22
|
+
limit ||= 100
|
23
|
+
|
24
|
+
options ||= begin
|
25
|
+
conditions = ActiveRecord::Associations::BelongsToAssociation.new(this_parent, this_field_reflection).options[:conditions]
|
26
|
+
order = this_field_reflection.klass.default_order
|
27
|
+
this_field_reflection.klass.all(:conditions => conditions, :limit => limit, :order => order).select {|x| can_view?(x)}
|
28
|
+
end
|
29
|
+
|
30
|
+
id_method = this_field_reflection.options[:primary_key] || this_field_reflection.klass.primary_key
|
31
|
+
if text_method.nil?
|
32
|
+
select_options = options.map { |x| [name(:with => x, :no_wrapper => true), x.send(id_method)] }
|
33
|
+
else
|
34
|
+
select_options = options.map do |x|
|
35
|
+
[ text_method.split(".").inject(x) { |v, method| v.send(method) },
|
36
|
+
x.send(id_method) ]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
select_options = select_options.sort if sort
|
40
|
+
select_options.insert(0, [blank_message, ""]) if include_none || (this.nil? && include_none != false)
|
41
|
+
attributes = add_classes(attributes, "input", "belongs_to", type_and_field)
|
42
|
+
-%>
|
43
|
+
<select name="#{param_name_for_this(true)}" merge-attrs="&attributes.except :name">
|
44
|
+
<%= options_for_select(select_options, this ? this.send(id_method) : "") %>
|
45
|
+
</select>
|
46
|
+
</def>
|
@@ -0,0 +1,31 @@
|
|
1
|
+
<!-- An enhanced version of [`<input-many>`](/api_tag_defs/input-many) that supports drag-and-drop re-ordering.
|
2
|
+
|
3
|
+
Each item in the collection has a `<div class="ordering-handle" param="handle">` added, which can be used to drag the item up and down.
|
4
|
+
|
5
|
+
If the items in the collection contain an [`acts_as_list`](http://ar.rubyonrails.org/classes/ActiveRecord/Acts/List/ClassMethods.html) declaration, it is updated.
|
6
|
+
|
7
|
+
The specified sort order may be maintained even without `acts_as_list`. The items will be passed to the controller in the correct order, so the order may be persisted there.
|
8
|
+
|
9
|
+
### Attributes
|
10
|
+
|
11
|
+
- `id`: Due to a limitation in script.aculo.us, an id is required. If you do not supply one, one will be generated.
|
12
|
+
- `position-column`: The position column may be specified via `acts_as_list`, via a `position_column` method on your model or via this attribute.
|
13
|
+
- others: all other attributes are passed through to `<input-many>`
|
14
|
+
|
15
|
+
-->
|
16
|
+
|
17
|
+
<def tag="sortable-input-many" attrs="id, position-column, template">
|
18
|
+
<% this_id = this_parent.id || rand(100000) -%>
|
19
|
+
<% id ||= "sortable-input-many-#{this_parent.class.name.underscore.dasherize}-#{this_id}-#{this_field_reflection.name}" -%>
|
20
|
+
<% template ||= this.try.new_candidate || this.member_class.new %>
|
21
|
+
<% position_column ||= template.try.position_column -%>
|
22
|
+
<input-many merge id="&id" class="sortable-input-many" template="&template" more-skip="&position_column">
|
23
|
+
<default: replace>
|
24
|
+
<div class="ordering-handle" param="handle" if="&can_edit?">↑<br/>↓</div>
|
25
|
+
<if test="&position_column">
|
26
|
+
<input class="sortable-position" type="hidden" value="&this.send(position_column)" name="#{param_name_for_this}[#{position_column}]" />
|
27
|
+
</if>
|
28
|
+
<default restore/>
|
29
|
+
</default:>
|
30
|
+
</input-many>
|
31
|
+
</def>
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<!-- 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>`.
|
2
|
+
|
3
|
+
Automatically adds 'even' and 'odd' CSS classes as well as the data-rapid-context attribute.
|
4
|
+
|
5
|
+
`empty-collection-message` is called from this tag. To suppress you can use the `without-empty-message` pseudo-attribute:
|
6
|
+
|
7
|
+
<collection without-empty-message/>
|
8
|
+
|
9
|
+
If your collection is an ActiveRecord result set (and in Hobo it most likely is), the best way to customize the empty message is via translations. Example: for product models, the key to customize would be `products.collection.empty_message`.
|
10
|
+
|
11
|
+
If your collection is a generic array, empty-collection-message doesn't work. `<collection>` also sets the last_if flag, so you can use the `<else>` tag to display a message:
|
12
|
+
|
13
|
+
<collection with="&[]"/>
|
14
|
+
<else>No items.</else>
|
15
|
+
-->
|
16
|
+
<def tag="collection" attrs="list-tag">
|
17
|
+
<% list_tag ||= 'ul' %>
|
18
|
+
<call-tag tag="&list_tag" class="collection #{collection_name :dasherize => true}" merge-attrs unless="empty?">
|
19
|
+
<li param="item" class="#{scope.even_odd}" data-rapid-context="&typed_id" repeat="&select_viewable">
|
20
|
+
<do param="default"><card param/></do>
|
21
|
+
</li>
|
22
|
+
</call-tag>
|
23
|
+
<empty-collection-message param="empty-message"/>
|
24
|
+
<if/><%# set last-if so <else/> works %>
|
25
|
+
</def>
|
26
|
+
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<!-- 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 via ajax remove buttons.
|
2
|
+
|
3
|
+
The message can be customized via the `empty-collection-message` parameter or by changing the `products.collection.empty_message` translation.
|
4
|
+
-->
|
5
|
+
<def tag="empty-collection-message">
|
6
|
+
<unless test="&this._?.member_class.nil?">
|
7
|
+
<div class="empty-collection-message" style="#{'display:none' if !this.empty?}" param="default">
|
8
|
+
<ht key="#{this.member_class.name.underscore}.collection.empty_message">
|
9
|
+
No <collection-name/> to display
|
10
|
+
</ht>
|
11
|
+
</div>
|
12
|
+
</unless>
|
13
|
+
</def>
|
@@ -0,0 +1,94 @@
|
|
1
|
+
<!--- This tag is very similar `<field-list-v1>`. However, instead of rendering a table, it renders what [Anatoli Papirovski calls "perfect form markup"](http://web.archive.org/web/20090922234755/http://fecklessmind.com/2009/01/23/how-to-reliable-css-forms/)
|
2
|
+
|
3
|
+
It takes the same attributes & parameters as `<field-list-v1>`, with the addition of a `legend` parameter and a `required` attribute.
|
4
|
+
|
5
|
+
The accompanying css allows this fieldset to be rendered in three different ways. You may trigger these by setting a class of `horizontal`, `vertical` or `inline-vertical`. `inline-vertical` fieldset's may also be nested inside of a `horizontal` fieldset.
|
6
|
+
|
7
|
+
### Attributes
|
8
|
+
|
9
|
+
- fields: Comma separated list of field names to display. Defaults to
|
10
|
+
the fields returned by the `standard_fields` helper. That is, all
|
11
|
+
fields apart from IDs and timestamps.
|
12
|
+
|
13
|
+
- force-all: All non-viewable fields will be skipped unless this
|
14
|
+
attribute is given
|
15
|
+
|
16
|
+
- skip: Comma separated list of fields to exclude
|
17
|
+
|
18
|
+
- tag: The name of a tag to use inside the `<td>` to display the
|
19
|
+
value. Defaults to `view`
|
20
|
+
|
21
|
+
- no-edit: Controls the behavior of `<input>` tags when the user doesn't have edit permission for a field.
|
22
|
+
- view: render the current value using the `<view>` tag
|
23
|
+
- disable: render the input as normal, but add HTML's `disabled` attribute
|
24
|
+
- skip: render nothing at all. This will omit the entire row (including the label)
|
25
|
+
- ignore: render the input normally. That is, don't even perform the edit check.
|
26
|
+
|
27
|
+
- no-blanks: (boolean) Controls the behavior of `<view>` tags. The
|
28
|
+
entire row (including the label) will be omitted if `this` is blank.
|
29
|
+
Default false.
|
30
|
+
|
31
|
+
- required: a list of methods. If the current field is included in the list, the field div has the `required` class added to it.
|
32
|
+
|
33
|
+
### Example
|
34
|
+
|
35
|
+
<field-list fields="first-name, last-name, city">
|
36
|
+
<first-name-label:>Given Name</first-name-label:>
|
37
|
+
<last-name-label:>Family Name</last-name-label:>
|
38
|
+
<city-view:><name-one/></city-view:>
|
39
|
+
</field-list>
|
40
|
+
|
41
|
+
A more complicated example stolen from actual working code:
|
42
|
+
|
43
|
+
<extend tag="signup-form" for="User">
|
44
|
+
<old-signup-form >
|
45
|
+
<field-list: replace>
|
46
|
+
<fieldset class="horizontal">
|
47
|
+
<legend>New Account Registration</legend>
|
48
|
+
<div class="field name-field">
|
49
|
+
<label class="name-label" for="user_name">Name</label>
|
50
|
+
<feckless-fieldset id="user_name" class="inline-vertical" fields="salutation, first_name, last_name, suffix" required="first_name, last_name" />
|
51
|
+
</div>
|
52
|
+
<div class="field contact-field">
|
53
|
+
<label class="contact-label" for="user_contact">Contact</label>
|
54
|
+
<feckless-fieldset id="user_contact" class="inline-vertical" fields="email_address, phone_number" required="email_address" />
|
55
|
+
</div>
|
56
|
+
<div class="field passwords-field">
|
57
|
+
<label class="passwords-label" for="user_contact">Password</label>
|
58
|
+
<feckless-fieldset id="user_passwords" class="inline-vertical" fields="password, password_confirmation" required="password, password_confirmation">
|
59
|
+
<password-label:></password-label:>
|
60
|
+
<password-confirmation-label:>Confirmation</password-confirmation-label:>
|
61
|
+
</feckless-fieldset>
|
62
|
+
</div>
|
63
|
+
</fieldset>
|
64
|
+
</field-list:>
|
65
|
+
</old-signup-form>
|
66
|
+
</extend>
|
67
|
+
|
68
|
+
-->
|
69
|
+
<def tag="feckless-fieldset" attrs="tag, no-edit, required, no-blanks">
|
70
|
+
<% tag ||= scope.in_form ? "input" : "view"; no_edit ||= "skip" -%>
|
71
|
+
<% required ||= "" ; required = comma_split(required.gsub('-', '_')) -%>
|
72
|
+
<fieldset class="feckless-fields" merge-attrs="&attributes - attrs_for(:with_fields)">
|
73
|
+
<legend param if="&all_parameters[:legend]" />
|
74
|
+
<with-fields merge-attrs="&attributes & attrs_for(:with_fields)">
|
75
|
+
<% field_name = this_field_name
|
76
|
+
input_attrs = {:no_edit => no_edit} if tag == "input" && no_edit == "disable"
|
77
|
+
field_method = scope.field_name.to_s.sub('?', '').gsub('.', '-')
|
78
|
+
id_for_this = param_name_for_this.gsub('[', '_').gsub(']', '')
|
79
|
+
-%>
|
80
|
+
<div class="field #{'required' if required.include?(scope.field_name)}" unless="&(tag == 'input' && no_edit == 'skip' && !can_edit?) || (tag == 'view' && no_blanks && this.blank?)" param="#{field_method}-field">
|
81
|
+
<label for="&id_for_this" param="#{field_method}-label" unless="&field_name.blank?">
|
82
|
+
<%= field_name %>
|
83
|
+
</label>
|
84
|
+
|
85
|
+
<do param="#{field_method}-view">
|
86
|
+
<do param="view"><call-tag tag="&tag" param="#{field_method}-tag" merge-attrs="&input_attrs"/></do>
|
87
|
+
</do>
|
88
|
+
<span param="#{field_method}-help" class="input-help" if="&tag.to_sym == :input && !this_field_help.blank?">
|
89
|
+
<%= this_field_help %>
|
90
|
+
</span>
|
91
|
+
</div>
|
92
|
+
</with-fields>
|
93
|
+
</fieldset>
|
94
|
+
</def>
|
@@ -0,0 +1,21 @@
|
|
1
|
+
<!-- Selects `<feckless-fieldset>` as the default tag for field lists
|
2
|
+
in Hobo. The previous version is still available in
|
3
|
+
`<field-list-v1>`. To revert to this usage, add to your
|
4
|
+
application.dryml:
|
5
|
+
|
6
|
+
<def tag="field-list">
|
7
|
+
<field-list-v1 merge/>
|
8
|
+
</def>
|
9
|
+
|
10
|
+
You can use feckless-fieldset in a manner stylistically more similar
|
11
|
+
to field-list-v1 via:
|
12
|
+
|
13
|
+
<def tag="field-list">
|
14
|
+
<feckless-fieldset class="horizontal" merge/>
|
15
|
+
</def>
|
16
|
+
|
17
|
+
-->
|
18
|
+
<def tag="field-list">
|
19
|
+
<feckless-fieldset merge/>
|
20
|
+
</def>
|
21
|
+
|
@@ -0,0 +1,64 @@
|
|
1
|
+
<!-- Renders a table with one row per field, where each row contains a
|
2
|
+
`<th>` with the field name, and a `<td>` with (by default) a `<view>`
|
3
|
+
of the field.
|
4
|
+
|
5
|
+
### Attributes
|
6
|
+
|
7
|
+
- fields: Comma separated list of field names to display. Defaults to
|
8
|
+
the fields returned by the `standard_fields` helper. That is, all
|
9
|
+
fields apart from IDs and timestamps.
|
10
|
+
|
11
|
+
- force-all: All non-viewable fields will be skipped unless this
|
12
|
+
attribute is given
|
13
|
+
|
14
|
+
- skip: Comma separated list of fields to exclude
|
15
|
+
|
16
|
+
- tag: The name of a tag to use inside the `<td>` to display the
|
17
|
+
value. Defaults to `view`
|
18
|
+
|
19
|
+
- no-edit: Controls the behavior of `<input>` tags when the user doesn't have edit permission for a field.
|
20
|
+
- view: render the current value using the `<view>` tag
|
21
|
+
- disable: render the input as normal, but add HTML's `disabled` attribute
|
22
|
+
- skip: render nothing at all. This will omit the entire row (including the label)
|
23
|
+
- ignore: render the input normally. That is, don't even perform the edit check.
|
24
|
+
|
25
|
+
- no-blanks: (boolean) Controls the behavior of `<view>` tags. The entire row (including the label) will be omitted if `this` is blank. Default false.
|
26
|
+
|
27
|
+
### Example
|
28
|
+
|
29
|
+
<field-list-v1 fields="first-name, last-name, city">
|
30
|
+
<first-name-label:>Given Name</first-name-label:>
|
31
|
+
<last-name-label:>Family Name</last-name-label:>
|
32
|
+
<city-view:><name-one/></city-view:>
|
33
|
+
</field-list-v1>
|
34
|
+
|
35
|
+
### Making this tag the default
|
36
|
+
|
37
|
+
This tag used to be called `<field-list>` in Hobo versions prior to
|
38
|
+
1.4. To return to this behaviour, add this to your application.dryml:
|
39
|
+
|
40
|
+
<def tag="field-list">
|
41
|
+
<field-list-v1 merge/>
|
42
|
+
</def>
|
43
|
+
|
44
|
+
-->
|
45
|
+
<def tag="field-list-v1" attrs="tag, no-edit, no-blanks">
|
46
|
+
<% tag ||= scope.in_form ? "input" : "view"; no_edit ||= "skip" %>
|
47
|
+
<labelled-item-list merge-attrs="&attributes - attrs_for(:with_fields)">
|
48
|
+
<with-fields merge-attrs="&attributes & attrs_for(:with_fields)">
|
49
|
+
<% field_name = this_field_name
|
50
|
+
input_attrs = {:no_edit => no_edit} if tag == "input"
|
51
|
+
field_name_as_param = scope.field_name.to_s.sub('?', '').gsub('.', '-')
|
52
|
+
-%>
|
53
|
+
<labelled-item param="#{field_name_as_param}-row" unless="&(tag == 'input' && no_edit == 'skip' && !can_edit?) || (tag == 'view' && no_blanks && this.blank?)">
|
54
|
+
<item-label param="#{field_name_as_param}-label" unless="&field_name.blank?">
|
55
|
+
<do param="label"><%= field_name %></do>
|
56
|
+
</item-label>
|
57
|
+
<item-value param="#{field_name_as_param}-view" colspan="&2 if field_name.blank?">
|
58
|
+
<do param="view"><call-tag tag="&tag" param="#{field_name_as_param}-tag" merge-attrs="&input_attrs"/></do>
|
59
|
+
<div param="input-help" if="&tag.to_sym == :input && !this_field_help.blank?"><%= this_field_help %></div>
|
60
|
+
</item-value>
|
61
|
+
</labelled-item>
|
62
|
+
</with-fields>
|
63
|
+
</labelled-item-list>
|
64
|
+
</def>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<!-- nodoc - to be removed -->
|
2
|
+
<def tag="labelled-item-list"><table class="field-list" merge-attrs><do param="default"/></table></def>
|
3
|
+
|
4
|
+
<!-- nodoc - to be removed -->
|
5
|
+
<def tag="labelled-item"><tr merge-attrs><do param="default"/></tr></def>
|
6
|
+
|
7
|
+
<!-- nodoc - to be removed -->
|
8
|
+
<def tag="item-label"><th merge-attrs><do param="default"/></th></def>
|
9
|
+
|
10
|
+
<!-- nodoc - to be removed -->
|
11
|
+
<def tag="item-value"><td merge-attrs><do param="default"/></td></def>
|
@@ -0,0 +1,98 @@
|
|
1
|
+
<!-- Call with the context set to a record. Repeats the content of the tag with `this` and `this_field` set to the value and name of each of the record's fields in turn. E.g. this is useful for generating a form containing each of the fields. Tags like `<field-list>` and `<table>` forward their attributes to this tag and also have the features described here. For example, the `fields` attribute to `<field-list>` supports the same options as described here.
|
2
|
+
|
3
|
+
This tag is in need of a review - it's a bit funky.
|
4
|
+
|
5
|
+
### Attributes
|
6
|
+
|
7
|
+
- `fields` - set to one of:
|
8
|
+
- A model class - equivalent to listing all of the regular 'content columns' of that model
|
9
|
+
- '`*`' - equivalent to listing all of the regular 'content columns' of the current record
|
10
|
+
- A comma separated list of field names.
|
11
|
+
Defaults to '`*`'
|
12
|
+
- `associations` - set to `has_many` to select the associations `has_many` relationships used as the "fields". Do not also give the `fields` attribute.
|
13
|
+
- `skip` - comma separated list of field names to omit.
|
14
|
+
- `skip-associations` - set to `has-many` to omit all `has_many` associations.
|
15
|
+
- `include-timestamps` - whether or not to include the standard ActiveRecord timestamp fields such as `created_at` and `updated_at`. Defaults to false.
|
16
|
+
- `force-all` - by default fields are skipped if the current user does not have view permission. Set `force-all` to true to skip this permission check and include all the fields.
|
17
|
+
|
18
|
+
-->
|
19
|
+
<def tag="with-fields" attrs="fields, associations, skip, skip-associations, include-timestamps, force-all"><%
|
20
|
+
fields.nil? || associations.nil? or raise ArgumentError, "with-fields -- specify either fields or associations but not both"
|
21
|
+
|
22
|
+
field_names = if associations == "has_many"
|
23
|
+
this.class.reflections.values.select { |refl| refl.macro == :has_many }.map { |refl| refl.name.to_s }
|
24
|
+
|
25
|
+
elsif fields.nil? || fields == "*" || fields.is_a?(Class)
|
26
|
+
klass = fields.is_a?(Class) ? fields : this.class
|
27
|
+
columns = standard_fields(klass, include_timestamps)
|
28
|
+
|
29
|
+
if skip_associations == "has_many"
|
30
|
+
assocs = this.class.reflections.values.reject {|r| r.macro == :has_many }.map &its.name.to_s
|
31
|
+
columns + assocs
|
32
|
+
elsif skip_associations
|
33
|
+
columns
|
34
|
+
else
|
35
|
+
assocs = klass.reflections.values.map &its.name.to_s
|
36
|
+
columns + assocs
|
37
|
+
end
|
38
|
+
else
|
39
|
+
comma_split(fields.gsub('-', '_'))
|
40
|
+
end
|
41
|
+
field_names -= comma_split(skip) if skip
|
42
|
+
field_names = field_names.select {|f| can_view?(this, f)} unless force_all
|
43
|
+
field_names.each do |field|
|
44
|
+
%><set-scoped field-name="&field"><%
|
45
|
+
if field == "this"
|
46
|
+
%><do param="default"/><%
|
47
|
+
else
|
48
|
+
%><with field="&field"><do param="default"/></with><%
|
49
|
+
end
|
50
|
+
%></set-scoped><%
|
51
|
+
end
|
52
|
+
%></def>
|
53
|
+
|
54
|
+
<!-- Call with the context set to a model class. Repeats the content of the tag with `this` set name of each of the model's fields in turn. E.g. this tag is used when generating the heading row in a `<table fields='...'/>`.
|
55
|
+
|
56
|
+
This tag is in need of a review - it's a bit funky.
|
57
|
+
|
58
|
+
### Attributes
|
59
|
+
|
60
|
+
- `fields` - set to one of:
|
61
|
+
- A model class - equivalent to listing all of the regular 'content columns' of that model
|
62
|
+
- '`*`' - equivalent to listing all of the regular 'content columns' of the current record
|
63
|
+
- A comma separated list of field names.
|
64
|
+
Defaults to '`*`'
|
65
|
+
- `skip` - comma separated list of field names to omit.
|
66
|
+
- `skip-associations` - set to `has-many` to omit all `has_many` associations.
|
67
|
+
- `include-timestamps` - whether or not to include the standard ActiveRecord timestamp fields such as `created_at` and `updated_at`. Defaults to false.
|
68
|
+
|
69
|
+
-->
|
70
|
+
<def tag="with-field-names" attrs="fields, skip, skip-associations, include-timestamps"><%=
|
71
|
+
field_names = if fields.nil? || fields == "*" || fields.is_a?(Class)
|
72
|
+
klass = fields.is_a?(Class) ? fields : this.member_class
|
73
|
+
columns = klass.content_columns.*.name
|
74
|
+
columns -= %w{created_at updated_at created_on updated_on deleted_at} unless include_timestamps
|
75
|
+
|
76
|
+
if skip_associations == "has_many"
|
77
|
+
assocs = this.reflections.values.reject {|r| r.macro == :has_many }.map &its.name.to_s
|
78
|
+
columns + assocs
|
79
|
+
elsif skip_associations
|
80
|
+
columns
|
81
|
+
else
|
82
|
+
assocs = klass.reflections.values.map &its.name.to_s
|
83
|
+
columns + assocs
|
84
|
+
end
|
85
|
+
else
|
86
|
+
comma_split(fields)
|
87
|
+
end
|
88
|
+
|
89
|
+
field_names -= comma_split(skip) if skip
|
90
|
+
scope.new_scope :field_name => nil, :field_path => nil do
|
91
|
+
field_names.map do |n|
|
92
|
+
scope.field_name = n == "this" ? (this.member_class.try.name || 'this') : n.to_s.gsub("." , "_")
|
93
|
+
scope.field_path = n
|
94
|
+
parameters.default
|
95
|
+
end.safe_join
|
96
|
+
end
|
97
|
+
%>
|
98
|
+
</def>
|
@@ -0,0 +1,30 @@
|
|
1
|
+
<!-- Basic account page that provides the ability for the user to change their email address and password. -->
|
2
|
+
<def tag="account-page">
|
3
|
+
|
4
|
+
<page title="#{t 'hobo.account_page.title', :default=>['Your Account'] }" merge>
|
5
|
+
|
6
|
+
<body: class="user-account-page #{type_name}" param/>
|
7
|
+
|
8
|
+
<content: param>
|
9
|
+
<header param="content-header">
|
10
|
+
<h2 param="heading"><name/></h2>
|
11
|
+
</header>
|
12
|
+
|
13
|
+
<section param="content-body">
|
14
|
+
<error-messages param/>
|
15
|
+
<form class="change-password" param>
|
16
|
+
<field-list fields="email_address, current_password, password, password_confirmation" param>
|
17
|
+
<password-label:><t key="hobo.account_page.new_password">New Password</t></password-label:>
|
18
|
+
<password-confirmation-label:><t key="hobo.account_page.confirm_new_password">Confirm New Password</t></password-confirmation-label:>
|
19
|
+
</field-list>
|
20
|
+
|
21
|
+
<div class="actions" param="actions">
|
22
|
+
<submit label="#{t 'hobo.actions.save_account', :default=>'Save'}" param/>
|
23
|
+
</div>
|
24
|
+
</form>
|
25
|
+
</section>
|
26
|
+
</content:>
|
27
|
+
|
28
|
+
</page>
|
29
|
+
|
30
|
+
</def>
|
@@ -0,0 +1,19 @@
|
|
1
|
+
<!-- The page that is displayed on attempting to log in to an account that has been disabled. -->
|
2
|
+
<def tag="account-disabled-page">
|
3
|
+
|
4
|
+
<simple-page title="#{t 'hobo.account_disabled_page.title', :default=>['Account Disabled'] }" merge>
|
5
|
+
|
6
|
+
<body: class="account-disabled-page" param/>
|
7
|
+
|
8
|
+
<content: param>
|
9
|
+
<header param="content-header">
|
10
|
+
<h2 param><t key="hobo.account_disabled_page.heading">Account is disabled</t></h2>
|
11
|
+
</header>
|
12
|
+
|
13
|
+
<section param="content-body">
|
14
|
+
<p><t key="hobo.account_disabled_page.text">Your account is disabled at this time.</t></p>
|
15
|
+
</section>
|
16
|
+
</content:>
|
17
|
+
</simple-page>
|
18
|
+
|
19
|
+
</def>
|
@@ -0,0 +1,23 @@
|
|
1
|
+
<!-- Renders a Rails flash message wrapped in a `<div>` tag
|
2
|
+
|
3
|
+
### Attributes
|
4
|
+
|
5
|
+
- `type` - which flash message to display. Defaults to `:notice`
|
6
|
+
|
7
|
+
### CSS Classes
|
8
|
+
|
9
|
+
The flash is output in a `<div class="flash notice">`, where `notice` is the `type` specified.
|
10
|
+
|
11
|
+
-->
|
12
|
+
<def tag="flash-message" attrs="type">
|
13
|
+
<% type = type ? type.to_sym : :notice -%>
|
14
|
+
<div class="flash #{type}" if="&flash[type]" merge-attrs><%= flash[type] %></div>
|
15
|
+
</def>
|
16
|
+
|
17
|
+
|
18
|
+
<!-- Renders `<flash-message>` for every flash type given in the `names` attribute (comma separated), or for all flash messages that have been set if `names` is not given -->
|
19
|
+
<def tag="flash-messages" attrs="names"><%=
|
20
|
+
scope.flash_rendered = true if scope.respond_to? :flash_rendered
|
21
|
+
names = names.nil? ? flash.keys : comma_split(names)
|
22
|
+
names.map { |name| flash_message :type => name }.safe_join
|
23
|
+
%></def>
|