hobo_rapid 1.4.0.pre2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (110) hide show
  1. data/README.markdown +5 -0
  2. data/VERSION +1 -0
  3. data/app/controllers/dev_controller.rb +25 -0
  4. data/app/helpers/hobo_rapid_helper.rb +197 -0
  5. data/hobo_rapid.gemspec +26 -0
  6. data/lib/hobo_rapid/railtie.rb +6 -0
  7. data/lib/hobo_rapid.rb +13 -0
  8. data/taglibs/buttons/buttons.dryml +1 -0
  9. data/taglibs/buttons/create_button.dryml +40 -0
  10. data/taglibs/buttons/delete-button.dryml +75 -0
  11. data/taglibs/buttons/remote_method_button.dryml +34 -0
  12. data/taglibs/buttons/transition_button.dryml +71 -0
  13. data/taglibs/buttons/transition_link.dryml +22 -0
  14. data/taglibs/buttons/update_button.dryml +29 -0
  15. data/taglibs/cache/cache.dryml +1 -0
  16. data/taglibs/cache/nested_cache.dryml +332 -0
  17. data/taglibs/cards/card.dryml +7 -0
  18. data/taglibs/cards/cards.dryml +1 -0
  19. data/taglibs/cards/search_card.dryml +4 -0
  20. data/taglibs/editors/click_editor.dryml +60 -0
  21. data/taglibs/editors/editors.dryml +27 -0
  22. data/taglibs/editors/live_editor.dryml +37 -0
  23. data/taglibs/forms/error_messages.dryml +21 -0
  24. data/taglibs/forms/form.dryml +101 -0
  25. data/taglibs/forms/formlet.dryml +48 -0
  26. data/taglibs/forms/forms.dryml +5 -0
  27. data/taglibs/forms/submit.dryml +14 -0
  28. data/taglibs/hobo_rapid.dryml +14 -0
  29. data/taglibs/html/a.dryml +156 -0
  30. data/taglibs/html/aside.dryml +5 -0
  31. data/taglibs/html/doctype.dryml +39 -0
  32. data/taglibs/html/empty_tag.dryml +23 -0
  33. data/taglibs/html/footer.dryml +5 -0
  34. data/taglibs/html/header.dryml +5 -0
  35. data/taglibs/html/html.dryml +18 -0
  36. data/taglibs/html/if_ie.dryml +11 -0
  37. data/taglibs/html/image.dryml +11 -0
  38. data/taglibs/html/javascript.dryml +12 -0
  39. data/taglibs/html/section.dryml +12 -0
  40. data/taglibs/html/section_group.dryml +11 -0
  41. data/taglibs/html/stylesheet.dryml +5 -0
  42. data/taglibs/html/table.dryml +174 -0
  43. data/taglibs/i18n/ht.dryml +48 -0
  44. data/taglibs/i18n/human_attribute_name +18 -0
  45. data/taglibs/i18n/human_collection_name.dryml +69 -0
  46. data/taglibs/i18n/i18n.dryml +1 -0
  47. data/taglibs/i18n/model_name_human.dryml +16 -0
  48. data/taglibs/i18n/t.dryml +12 -0
  49. data/taglibs/inputs/after_submit.dryml +32 -0
  50. data/taglibs/inputs/check_many.dryml +25 -0
  51. data/taglibs/inputs/collection_input.dryml +10 -0
  52. data/taglibs/inputs/hidden_field.dryml +48 -0
  53. data/taglibs/inputs/hot_input.dryml +50 -0
  54. data/taglibs/inputs/input.dryml +76 -0
  55. data/taglibs/inputs/input_all.dryml +14 -0
  56. data/taglibs/inputs/input_for.dryml +38 -0
  57. data/taglibs/inputs/input_for_date.dryml +86 -0
  58. data/taglibs/inputs/input_for_enum_string.dryml +26 -0
  59. data/taglibs/inputs/input_many.dryml +131 -0
  60. data/taglibs/inputs/inputs.dryml +1 -0
  61. data/taglibs/inputs/name_one.dryml +74 -0
  62. data/taglibs/inputs/or_cancel.dryml +8 -0
  63. data/taglibs/inputs/select_input.dryml +13 -0
  64. data/taglibs/inputs/select_many.dryml +58 -0
  65. data/taglibs/inputs/select_menu.dryml +23 -0
  66. data/taglibs/inputs/select_one.dryml +46 -0
  67. data/taglibs/inputs/sortable_input_many.dryml +31 -0
  68. data/taglibs/inputs/sti_type_input.dryml +6 -0
  69. data/taglibs/lists/collection.dryml +26 -0
  70. data/taglibs/lists/empty_collection_message.dryml +13 -0
  71. data/taglibs/lists/feckless_fieldset.dryml +94 -0
  72. data/taglibs/lists/field_list.dryml +21 -0
  73. data/taglibs/lists/field_list_v1.dryml +64 -0
  74. data/taglibs/lists/labelled_item_list.dryml +11 -0
  75. data/taglibs/lists/lists.dryml +2 -0
  76. data/taglibs/lists/with_fields.dryml +98 -0
  77. data/taglibs/pages/account.dryml +30 -0
  78. data/taglibs/pages/account_disabled.dryml +19 -0
  79. data/taglibs/pages/flash_message.dryml +23 -0
  80. data/taglibs/pages/forgot_password.dryml +62 -0
  81. data/taglibs/pages/login.dryml +57 -0
  82. data/taglibs/pages/not_found_page.dryml +18 -0
  83. data/taglibs/pages/page_nav.dryml +17 -0
  84. data/taglibs/pages/pages.dryml +12 -0
  85. data/taglibs/pages/permission_denied_page.dryml +24 -0
  86. data/taglibs/plus/collection_preview.dryml +23 -0
  87. data/taglibs/plus/filter_menu.dryml +103 -0
  88. data/taglibs/plus/gravatar.dryml +12 -0
  89. data/taglibs/plus/live_search.dryml +40 -0
  90. data/taglibs/plus/plus.dryml +1 -0
  91. data/taglibs/plus/sortable_collection.dryml +36 -0
  92. data/taglibs/plus/table_plus.dryml +63 -0
  93. data/taglibs/views/a_or_an.dryml +10 -0
  94. data/taglibs/views/collection_name.dryml +28 -0
  95. data/taglibs/views/comma_list.dryml +2 -0
  96. data/taglibs/views/count.dryml +99 -0
  97. data/taglibs/views/links_for_collection.dryml +2 -0
  98. data/taglibs/views/name.dryml +30 -0
  99. data/taglibs/views/nil_view.dryml +10 -0
  100. data/taglibs/views/record_flags.dryml +5 -0
  101. data/taglibs/views/type_name.dryml +24 -0
  102. data/taglibs/views/view.dryml +79 -0
  103. data/taglibs/views/view_for.dryml +42 -0
  104. data/taglibs/views/views.dryml +1 -0
  105. data/taglibs/views/you.dryml +150 -0
  106. data/vendor/assets/javascripts/hobo_rapid.js +1 -0
  107. data/vendor/assets/stylesheets/feckless-fieldset.css +40 -0
  108. data/vendor/assets/stylesheets/hobo-rapid.css +94 -0
  109. data/vendor/assets/stylesheets/hobo_rapid.css +1 -0
  110. 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}">&nbsp;</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?">&uarr;<br/>&darr;</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,6 @@
1
+ <!-- nodoc. -->
2
+ <def tag="sti-type-input">
3
+ <select name="#{param_name_for(form_field_path + ['type'])}">
4
+ <%= options_for_select(this.class.send(:descendants).map{|x| [x.name.titleize, x.name]}, this.class.name) %>
5
+ </select>
6
+ </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
+ &nbsp;
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,2 @@
1
+ <!-- Tags that generate lists of one type or another. Some of these
2
+ are lists only in spirit because they actually render tables -->
@@ -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>