Shadowfiend / awesome_fields
- Source
- Commits
- Network (2)
- Issues (0)
- Downloads (0)
- Wiki (1)
- Graphs
-
Tree:
4411fcd
shadowfiend (author)
Thu Jun 05 21:48:36 -0700 2008
| 1b76dbb1 » | shadowfiend | 2008-06-05 | 1 | module AwesomeFields | |
| 4411fcda » | shadowfiend | 2008-06-05 | 2 | # This class presents a builder that provides a per-field block-level element. | |
| 3 | # The class also takes care of labeling fields, as well as adding errors to | ||||
| 4 | # the fields when needed. | ||||
| 5 | # | ||||
| 6 | # == Label | ||||
| 7 | # | ||||
| 8 | # Each field method that has been redefined in this builder uses the field | ||||
| 9 | # name as a label by default (converted to the label text by #humanize-ing it. | ||||
| 10 | # It also takes an optional <tt>:label</tt> parameter that specifies label | ||||
| 11 | # text other than the humanized field name. Whatever the field, it is placed | ||||
| 12 | # in label tag that is linked to the generated field when possible. | ||||
| 13 | # | ||||
| 14 | # In addition, the <tt>:no_label</tt> option may be passed to omit the label | ||||
| 15 | # when generating the field. | ||||
| 16 | # | ||||
| 17 | # == Wrapping div | ||||
| 18 | # | ||||
| 19 | # When producing a field, the field is wrapped with a div whose CSS class is | ||||
| 20 | # +form_line+. If the field has errors, that class is instead | ||||
| 21 | # +form_line_with_errors+. This div is, obviously, a block-level element by | ||||
| 22 | # default, but can be floated or what have you if needed. | ||||
| 23 | # | ||||
| 24 | # == Errors | ||||
| 25 | # | ||||
| 26 | # As mentioned above, if the field has an error, the wrapping div is given the | ||||
| 27 | # +form_line_with_errors+ CSS class instead of the regular +form_line+ class. | ||||
| 28 | # Additionally, the error text is placed within the containing +form_line+ div | ||||
| 29 | # within its own div, whose class is +field_error+. | ||||
| 30 | # | ||||
| 31 | # The error message is assembled in parts: first, the field is checked for | ||||
| 32 | # errors. If it has more than one error, these are turned into a sentence via | ||||
| 33 | # a call to +to_sentence+. Then, the error text has the label prepended to it. | ||||
| 34 | # By default, the label is the field name, so the error text will have the | ||||
| 35 | # field name, humanized, prepended to it. Finally, a period (.) is appended to | ||||
| 36 | # the end. This is the error message that is displayed. | ||||
| 37 | # | ||||
| 38 | # == Results | ||||
| 39 | # | ||||
| 40 | # The resulting structure of a field with errors is: | ||||
| 41 | # | ||||
| 42 | # <div class="form_line_with_errors"> | ||||
| 43 | # <div class="field_error">Field should not be blank.</div> | ||||
| 44 | # | ||||
| 45 | # <label for="model_field">Field:</label> | ||||
| 46 | # <input type="text" id="model_field" name="model[field]" value="" /> | ||||
| 47 | # </div> | ||||
| 48 | # | ||||
| 49 | # While one without errors has structure: | ||||
| 50 | # | ||||
| 51 | # <div class="form_line"> | ||||
| 52 | # <label for="model_field">Field:</label> | ||||
| 53 | # <input type="text" id="model_field" name="model[field]" value="" /> | ||||
| 54 | # </div> | ||||
| 55 | # | ||||
| 56 | # And one with no errors and no label has structure: | ||||
| 57 | # | ||||
| 58 | # <div class="form_line"> | ||||
| 59 | # <input type="text" id="model_field" name="model[field]" value="" /> | ||||
| 60 | # </div> | ||||
| 61 | # | ||||
| 62 | # == <tt>:long</tt> option | ||||
| 63 | # | ||||
| 64 | # All helpers support a <tt>:long</tt> option in case the field is meant to | ||||
| 65 | # contain `long' content. For most fields, all this means is that the label | ||||
| 66 | # for the field will receive the CSS class +long+ if that option is set to | ||||
| 67 | # true. | ||||
| 68 | # | ||||
| 69 | # Currently the only exception to this is +text_area+, which makes use of the | ||||
| 70 | # <tt>:long</tt> option to modify the default rows and columns of the text | ||||
| 71 | # area. If the text area is not `long', then it has 10 rows and 30 columns. If | ||||
| 72 | # it is `long', then it has 20 rows and 70 columns. | ||||
| 73 | # | ||||
| 74 | # == Submit button | ||||
| 75 | # | ||||
| 76 | # This builder also adds a method +submit_button+ (which is aliased to the | ||||
| 77 | # default +submit+) that wraps the submit button in a div of class | ||||
| 78 | # +form_buttons+. | ||||
| 1b76dbb1 » | shadowfiend | 2008-06-05 | 79 | class LinedBuilder < ActionView::Helpers::FormBuilder | |
| 80 | def text_field(label, options = {}) | ||||
| 81 | labeled_field(label, options) { super label, options } | ||||
| 82 | end | ||||
| 83 | |||||
| 84 | def password_field(label, options = {}) | ||||
| 85 | labeled_field(label, options) { super label, options } | ||||
| 86 | end | ||||
| 87 | |||||
| 88 | def file_field(label, options = {}) | ||||
| 89 | labeled_field(label, options) { super label, options } | ||||
| 90 | end | ||||
| 91 | |||||
| 92 | def check_box(label, options = {}) | ||||
| 93 | labeled_field(label, options) { super label, options } | ||||
| 94 | end | ||||
| 95 | |||||
| 4411fcda » | shadowfiend | 2008-06-05 | 96 | # Takes the additional option <tt>:long</tt> which, if set to true, will, in | |
| 97 | # addition to setting the label's CSS class to +long+ (which happens for all | ||||
| 98 | # other fields to), change the default rows and columns to 20x70 (instead of | ||||
| 99 | # the non-long 10x30 defaults). | ||||
| 1b76dbb1 » | shadowfiend | 2008-06-05 | 100 | def text_area(label, options = {}) | |
| 101 | if options[:long] | ||||
| 102 | options.reverse_merge!({ :rows => 20, :cols => 70 }) | ||||
| 103 | else | ||||
| 104 | options.reverse_merge!({ :rows => 10, :cols => 30 }) | ||||
| 105 | end | ||||
| 106 | |||||
| 107 | labeled_field(label, options) { super label, options } | ||||
| 108 | end | ||||
| 109 | |||||
| 4411fcda » | shadowfiend | 2008-06-05 | 110 | # Produces a date select. The date select has a default order of month, day, | |
| 111 | # year. Aliased as +date_field+ for uniformity with other field invocations | ||||
| 112 | # and for good interoperability with the +AwesomeFields+ field helpers. | ||||
| 1b76dbb1 » | shadowfiend | 2008-06-05 | 113 | def date_select(label, options = {}) | |
| 4411fcda » | shadowfiend | 2008-06-05 | 114 | options.reverse_merge!({ :order => [ :month, :day, :year ] }) | |
| 1b76dbb1 » | shadowfiend | 2008-06-05 | 115 | ||
| 116 | labeled_field(label, options) { super label, options } | ||||
| 117 | end | ||||
| 118 | alias_method :date_field, :date_select | ||||
| 119 | |||||
| 4411fcda » | shadowfiend | 2008-06-05 | 120 | # Produces a select box. If the html_options contains the <tt>:multiple</tt> | |
| 121 | # option and it is set to true, then the default size is set to 5. | ||||
| 1b76dbb1 » | shadowfiend | 2008-06-05 | 122 | def select(label, choices, options = {}, html_options = {}) | |
| 123 | err = error_on label, options | ||||
| 124 | |||||
| 125 | html_options.reverse_merge!({ :size => 5 }) unless html_options[:multiple].nil? | ||||
| 126 | |||||
| 127 | @template.content_tag( 'div', | ||||
| 128 | (err ? err : '') + label_tag( label, options ) + | ||||
| 129 | super, | ||||
| 130 | :class => err ? 'form_line_with_errors' : 'form_line' ) | ||||
| 131 | end | ||||
| 132 | |||||
| 4411fcda » | shadowfiend | 2008-06-05 | 133 | # Produces a submit button wrapped in a div of class +form_buttons+. The | |
| 134 | # label is turned into a string and humanized, so it can be a string, | ||||
| 135 | # potentially underscored. | ||||
| 136 | # | ||||
| 137 | # Aliased to +submit+, which is the default Rails name for this method. | ||||
| 1b76dbb1 » | shadowfiend | 2008-06-05 | 138 | def submit_button(label = 'submit', options = {}) | |
| 139 | @template.content_tag 'div', | ||||
| 140 | @template.submit_tag(label.to_s.humanize), | ||||
| 141 | :class => 'form_buttons' | ||||
| 142 | end | ||||
| 4411fcda » | shadowfiend | 2008-06-05 | 143 | alias_method :submit, :submit_button | |
| 1b76dbb1 » | shadowfiend | 2008-06-05 | 144 | ||
| 145 | protected | ||||
| 146 | # Produces a labeled field given the label, the options, and a block that | ||||
| 147 | # will generate the appropriate field content. | ||||
| 148 | def labeled_field(attr, options, &content_gen) | ||||
| 149 | err = error_on attr, options | ||||
| 150 | after = options.delete(:after) || '' | ||||
| 151 | |||||
| 152 | @template.content_tag 'div', | ||||
| 153 | (err ? err : '') + label_tag(attr, options) + content_gen.call + after, | ||||
| 154 | :class => (err ? 'form_line_with_errors' : 'form_line') | ||||
| 155 | end | ||||
| 156 | |||||
| 157 | # Produces the appropriate label tag for the given attribute, including | ||||
| 158 | # returning nothing if the :no_label option was passed and using the :label | ||||
| 159 | # option instead of the attribute name if it was provided. | ||||
| 160 | def label_tag(attr_name, options = {}) | ||||
| 161 | return '' if options.delete(:no_label) | ||||
| 162 | |||||
| 163 | @template.content_tag 'label', | ||||
| 164 | "#{(options.delete(:label) || attr_name.to_s.humanize)}:", | ||||
| 165 | :for => "#{@object_name}_#{attr_name}", | ||||
| 166 | :class => (options[:long] ? 'long' : '') | ||||
| 167 | end | ||||
| 168 | |||||
| 169 | # Produces a formatted version of the error on the given attribute. If a | ||||
| 170 | # label was provided, includes that instead of the attribute name. | ||||
| 171 | # Prefixes the error with the label or the attribute name and postfixes it | ||||
| 172 | # with a `.'. Returns a div string with the class field_error. | ||||
| 173 | def error_on(attr, options) | ||||
| 174 | errors = @object.errors[attr] | ||||
| 175 | return nil unless errors | ||||
| 176 | |||||
| 177 | errors = errors.to_sentence if errors.respond_to?(:to_sentence) | ||||
| 178 | |||||
| 179 | @template.content_tag 'div', | ||||
| 180 | "#{options[:label] || attr.to_s.humanize} #{errors}.", | ||||
| 181 | :class => 'field_error' | ||||
| 182 | end | ||||
| 183 | end | ||||
