|
|
| 14 |
17 |
|
| 1 | | module ActionView |
| 2 | | module Helpers |
| 1 | module ActionView #:nodoc: |
| 2 | module Helpers #:nodoc: |
| 3 | 3 | module FormHelper |
| 4 | 4 | |
| 5 | 5 | |
| 6 | | # Overrides <tt>ActionView::Helpers::FormHelper#text_field</tt> to append |
| 7 | | # templating behavior using unobtrusive javascript. Note, the javascript |
| 8 | | # used requires Prototype to add <tt>onLoad</tt> event listeners. |
| 9 | | def text_field_with_templating(*args) |
| 10 | | field_with_templating :text_field, *args |
| 6 | # When this plugin is installed, calls to |
| 7 | # <tt>ActionView::Helpers::FormHelper#text_area</tt> in your forms will |
| 8 | # transparently call this method instead. |
| 9 | # |
| 10 | # When you call <tt>#text_area</tt> for an attribute which is declared as |
| 11 | # templated using |
| 12 | # +templated_attribute+[link:classes/TemplatedAttribute/ActiveRecordExtensions/ClassMethods.html] |
| 13 | # in the model, we enhance the normal <tt>#text_area</tt> |
| 14 | # by inserting templated values insetad of empty field values, and |
| 15 | # appending unobtrusive Javascript to enable smart templating behavior |
| 16 | # and styling on <tt><textarea></tt> tags. |
| 17 | # |
| 18 | # When you call <tt>#text_area</tt> for attributes which are not |
| 19 | # templated, we defer to Rails's original <tt>#text_area</tt> without |
| 20 | # changes. |
| 21 | # |
| 22 | # Javascript support will be disabled if <tt>:templated_javascript => |
| 23 | # false</tt> is passed in the options hash of +text_area+. |
| 24 | # |
| 25 | # <b>Note:</b> The Javascript uses Prototype to add event handlers to |
| 26 | # your form. Make sure <tt>prototype.js</tt> is included in your layout. |
| 27 | def text_area_with_templating(class_name, method, options={}) |
| 28 | args = [class_name, method, options] # use params above for docs' sake |
| 29 | if templated?(*args) |
| 30 | field_with_templating :text_area, *args |
| 31 | else |
| 32 | text_area_without_templating *args |
| 33 | end |
| 11 | 34 | end |
| 35 | alias_method_chain :text_area, :templating |
| 36 | |
| 37 | |
| 38 | # Same as <tt>#text_area_with_templating</tt>, but overrides |
| 39 | # <tt>ActionView::Helpers::FormHelper#text_field</tt> so you can get |
| 40 | # templated attribute behavior with <tt><input type="text"></tt> tags. |
| 41 | # See notes for <tt>#text_area_with_templating</tt> above. |
| 42 | def text_field_with_templating(class_name, method, options={}) |
| 43 | args = [class_name, method, options] # use params above for docs' sake |
| 44 | if templated?(*args) |
| 45 | field_with_templating :text_field, *args |
| 46 | else |
| 47 | text_field_without_templating *args |
| 48 | end |
| 49 | end |
| 12 | 50 | alias_method_chain :text_field, :templating |
| 51 | |
| 13 | 52 | |
| 14 | 53 | |
| 15 | 54 | |
| 16 | | # Overrides <tt>ActionView::Helpers::FormHelper#text_area</tt> to append |
| 17 | | # templating behavior using unobtrusive javascript. Note, the javascript |
| 18 | | # used requires Prototype to add <tt>onLoad</tt> event listeners. |
| 19 | | def text_area_with_templating(*args) |
| 20 | | field_with_templating :text_area, *args |
| 55 | |
| 56 | private |
| 57 | |
| 58 | |
| 59 | # Helper method to determine whether or not +templated_attribute+ has |
| 60 | # been called for a given class and method. |
| 61 | def templated?(class_name, method, options={}) # :nodoc: |
| 62 | klass = class_name.classify.constantize |
| 63 | klass.respond_to?(:templated_attributes_options) && klass.templated_attributes_options[method.to_sym] |
| 21 | 64 | end |
| 22 | | alias_method_chain :text_area, :templating |
| 23 | 65 | |
| 24 | 66 | |
| 67 | # Behind the scenes, figure out the starting value for the field, then |
| 68 | # render the field normally with that value (if applicable) and append a |
| 69 | # touch of Javascript to add behavior. |
| 70 | def field_with_templating(field_helper, class_name, method, options = {}) # :nodoc: |
| 71 | options = { :templated_javascript => true }.merge(options) |
| 72 | template_options = class_name.classify.constantize.templated_attributes_options[method.to_sym] |
| 25 | 73 | |
| 26 | | |
| 27 | | private |
| 28 | | |
| 29 | | def field_with_templating(field_helper, object_name, method, options = {}) |
| 30 | | object = object_name.classify.constantize |
| 31 | | template_options = object.templated_attributes_options[method.to_sym] |
| 74 | # If calling method on object returns nil, use template value instead |
| 75 | field_value = options[:object].__send__(method.to_sym) |
| 76 | if field_value.nil? || field_value.strip.empty? |
| 77 | field_value = template_options[:value] |
| 78 | end |
| 32 | 79 | |
| 33 | | send("#{field_helper}_without_templating".to_sym, object_name, method, options) + |
| 34 | | javascript_tag("Event.observe(window, 'load', function() { |
| 35 | | new TemplatedAttribute($('#{object_name}_#{method}'), |
| 36 | | '#{template_options[:type]}', |
| 37 | | '#{template_options[:value]}'); |
| 38 | | });") |
| 80 | # Only use javascript if not explicitly disabled in options |
| 81 | if options.delete(:templated_javascript) |
| 82 | javascript_string = javascript_tag \ |
| 83 | "Event.observe(window, 'load', function() { new TemplatedAttribute($('#{class_name}_#{method}'), |
| 84 | '#{template_options[:type]}', '#{template_options[:value]}'); });" |
| 85 | else |
| 86 | javascript_string = '' |
| 87 | end |
| 88 | |
| 89 | # output using the original method with our modified form field value, |
| 90 | # plus the javascript |
| 91 | send("#{field_helper}_without_templating".to_sym, class_name, method, options.merge({:value => field_value})) + javascript_string |
| 39 | 92 | end |
| 40 | 93 | |
| 41 | 94 | |