chobble-forms 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
 - data/README.md +3 -0
 - data/lib/chobble-forms.rb +6 -0
 - data/lib/engine.rb +21 -0
 - data/lib/helpers.rb +206 -0
 - data/lib/version.rb +3 -0
 - data/views/chobble_forms/_auto_submit_select.html.erb +55 -0
 - data/views/chobble_forms/_autocomplete_field.html.erb +17 -0
 - data/views/chobble_forms/_checkbox.html.erb +12 -0
 - data/views/chobble_forms/_comment.html.erb +40 -0
 - data/views/chobble_forms/_comment_checkbox.html.erb +18 -0
 - data/views/chobble_forms/_date_field.html.erb +15 -0
 - data/views/chobble_forms/_decimal_comment.html.erb +58 -0
 - data/views/chobble_forms/_display_field.html.erb +11 -0
 - data/views/chobble_forms/_errors.html.erb +26 -0
 - data/views/chobble_forms/_field_with_link.html.erb +33 -0
 - data/views/chobble_forms/_fields.html.erb +9 -0
 - data/views/chobble_forms/_fieldset.html.erb +29 -0
 - data/views/chobble_forms/_file_field.html.erb +29 -0
 - data/views/chobble_forms/_form_context.html.erb +74 -0
 - data/views/chobble_forms/_header.html.erb +3 -0
 - data/views/chobble_forms/_integer_comment.html.erb +58 -0
 - data/views/chobble_forms/_number.html.erb +29 -0
 - data/views/chobble_forms/_number_pass_fail_comment.html.erb +73 -0
 - data/views/chobble_forms/_number_pass_fail_na_comment.html.erb +83 -0
 - data/views/chobble_forms/_pass_fail.html.erb +14 -0
 - data/views/chobble_forms/_pass_fail_comment.html.erb +47 -0
 - data/views/chobble_forms/_pass_fail_na_comment.html.erb +49 -0
 - data/views/chobble_forms/_radio_comment.html.erb +47 -0
 - data/views/chobble_forms/_radio_pass_fail.html.erb +43 -0
 - data/views/chobble_forms/_search_field.html.erb +15 -0
 - data/views/chobble_forms/_select.html.erb +41 -0
 - data/views/chobble_forms/_submit_button.html.erb +1 -0
 - data/views/chobble_forms/_text_area.html.erb +22 -0
 - data/views/chobble_forms/_text_field.html.erb +20 -0
 - data/views/chobble_forms/_yes_no_radio.html.erb +15 -0
 - data/views/chobble_forms/_yes_no_radio_comment.html.erb +48 -0
 - metadata +186 -0
 
    
        checksums.yaml
    ADDED
    
    | 
         @@ -0,0 +1,7 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            ---
         
     | 
| 
      
 2 
     | 
    
         
            +
            SHA256:
         
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: a667bfdadedd91552428ae7b8de49675340618beabd0a6784941861805a4655e
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 6461e968376cf809af015f83dc89fd8cde783a79819c68faca28d3a938a945bb
         
     | 
| 
      
 5 
     | 
    
         
            +
            SHA512:
         
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: ac860f4f3d10aa3ab790b19a49871d8802a099ea4868f626888d2bd7dd29de2901ec604bd4f4fe31e7e47b327ac870d7565007c6ea18c0f6ac9c097e5d6429a3
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 7c32149a54105636daffb3b88dc74327293cd3c0bd60abc4396ce256cac2562fa732fc1a17e66426c52947deb7251c8205bb60f1b2b6bad47f95021ec305149b
         
     | 
    
        data/README.md
    ADDED
    
    
    
        data/lib/engine.rb
    ADDED
    
    | 
         @@ -0,0 +1,21 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module ChobbleForms
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Engine < ::Rails::Engine
         
     | 
| 
      
 3 
     | 
    
         
            +
                isolate_namespace ChobbleForms
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                initializer "chobble_forms.add_view_paths" do |app|
         
     | 
| 
      
 6 
     | 
    
         
            +
                  ActiveSupport.on_load(:action_controller) do
         
     | 
| 
      
 7 
     | 
    
         
            +
                    prepend_view_path ChobbleForms::Engine.root.join("views")
         
     | 
| 
      
 8 
     | 
    
         
            +
                  end
         
     | 
| 
      
 9 
     | 
    
         
            +
                end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                config.to_prepare do
         
     | 
| 
      
 12 
     | 
    
         
            +
                  ApplicationController.helper(ChobbleForms::Helpers)
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                initializer "chobble_forms.view_helpers" do
         
     | 
| 
      
 16 
     | 
    
         
            +
                  ActiveSupport.on_load(:action_view) do
         
     | 
| 
      
 17 
     | 
    
         
            +
                    include ChobbleForms::Helpers
         
     | 
| 
      
 18 
     | 
    
         
            +
                  end
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
              end
         
     | 
| 
      
 21 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/helpers.rb
    ADDED
    
    | 
         @@ -0,0 +1,206 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "action_view"
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module ChobbleForms
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Helpers
         
     | 
| 
      
 5 
     | 
    
         
            +
                include ActionView::Helpers::NumberHelper
         
     | 
| 
      
 6 
     | 
    
         
            +
                def form_field_setup(field, local_assigns)
         
     | 
| 
      
 7 
     | 
    
         
            +
                  validate_local_assigns(local_assigns)
         
     | 
| 
      
 8 
     | 
    
         
            +
                  validate_form_context
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  field_translations = build_field_translations(field)
         
     | 
| 
      
 11 
     | 
    
         
            +
                  value, prefilled = get_field_value_and_prefilled_status(@_current_form,
         
     | 
| 
      
 12 
     | 
    
         
            +
                    field)
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  build_field_setup_result(field_translations, value, prefilled)
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                def get_field_value_and_prefilled_status(form_object, field)
         
     | 
| 
      
 18 
     | 
    
         
            +
                  return [nil, false] unless form_object&.object
         
     | 
| 
      
 19 
     | 
    
         
            +
                  model = form_object.object
         
     | 
| 
      
 20 
     | 
    
         
            +
                  resolved = resolve_field_value(model, field)
         
     | 
| 
      
 21 
     | 
    
         
            +
                  [resolved[:value], resolved[:prefilled]]
         
     | 
| 
      
 22 
     | 
    
         
            +
                end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                def comment_field_options(form, comment_field, base_field_label)
         
     | 
| 
      
 25 
     | 
    
         
            +
                  raise ArgumentError, "form_object required" unless form
         
     | 
| 
      
 26 
     | 
    
         
            +
                  model = form.object
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                  comment_value, comment_prefilled =
         
     | 
| 
      
 29 
     | 
    
         
            +
                    get_field_value_and_prefilled_status(
         
     | 
| 
      
 30 
     | 
    
         
            +
                      form,
         
     | 
| 
      
 31 
     | 
    
         
            +
                      comment_field
         
     | 
| 
      
 32 
     | 
    
         
            +
                    )
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                  has_comment = comment_value.present?
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                  base_field = comment_field.to_s.chomp("_comment")
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                  placeholder_text = t("shared.field_comment_placeholder", field: base_field_label)
         
     | 
| 
      
 39 
     | 
    
         
            +
                  textarea_id = "#{base_field}_comment_textarea_#{model.object_id}"
         
     | 
| 
      
 40 
     | 
    
         
            +
                  checkbox_id = "#{base_field}_has_comment_#{model.object_id}"
         
     | 
| 
      
 41 
     | 
    
         
            +
                  display_style = has_comment ? "block" : "none"
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                  {
         
     | 
| 
      
 44 
     | 
    
         
            +
                    options: {
         
     | 
| 
      
 45 
     | 
    
         
            +
                      rows: 2,
         
     | 
| 
      
 46 
     | 
    
         
            +
                      placeholder: placeholder_text,
         
     | 
| 
      
 47 
     | 
    
         
            +
                      id: textarea_id,
         
     | 
| 
      
 48 
     | 
    
         
            +
                      style: "display: #{display_style};",
         
     | 
| 
      
 49 
     | 
    
         
            +
                      value: comment_value
         
     | 
| 
      
 50 
     | 
    
         
            +
                    },
         
     | 
| 
      
 51 
     | 
    
         
            +
                    prefilled: comment_prefilled,
         
     | 
| 
      
 52 
     | 
    
         
            +
                    has_comment: has_comment,
         
     | 
| 
      
 53 
     | 
    
         
            +
                    checkbox_id: checkbox_id
         
     | 
| 
      
 54 
     | 
    
         
            +
                  }
         
     | 
| 
      
 55 
     | 
    
         
            +
                end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                def radio_button_options(prefilled, checked_value, expected_value)
         
     | 
| 
      
 58 
     | 
    
         
            +
                  (prefilled && checked_value == expected_value) ? {checked: true} : {}
         
     | 
| 
      
 59 
     | 
    
         
            +
                end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                private
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                ALLOWED_LOCAL_ASSIGNS = %i[
         
     | 
| 
      
 64 
     | 
    
         
            +
                  accept
         
     | 
| 
      
 65 
     | 
    
         
            +
                  field
         
     | 
| 
      
 66 
     | 
    
         
            +
                  max
         
     | 
| 
      
 67 
     | 
    
         
            +
                  min
         
     | 
| 
      
 68 
     | 
    
         
            +
                  number_options
         
     | 
| 
      
 69 
     | 
    
         
            +
                  options
         
     | 
| 
      
 70 
     | 
    
         
            +
                  preview_size
         
     | 
| 
      
 71 
     | 
    
         
            +
                  required
         
     | 
| 
      
 72 
     | 
    
         
            +
                  rows
         
     | 
| 
      
 73 
     | 
    
         
            +
                  step
         
     | 
| 
      
 74 
     | 
    
         
            +
                  type
         
     | 
| 
      
 75 
     | 
    
         
            +
                ]
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                def validate_local_assigns(local_assigns)
         
     | 
| 
      
 78 
     | 
    
         
            +
                  if local_assigns[:field].present? &&
         
     | 
| 
      
 79 
     | 
    
         
            +
                      local_assigns[:field].to_s.match?(/^[A-Z]/)
         
     | 
| 
      
 80 
     | 
    
         
            +
                    raise ArgumentError, "Field names must be snake_case symbols, not class names. Use :field, not Field."
         
     | 
| 
      
 81 
     | 
    
         
            +
                  end
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
                  locally_assigned_keys = (local_assigns || {}).keys
         
     | 
| 
      
 84 
     | 
    
         
            +
                  disallowed_keys = locally_assigned_keys - ALLOWED_LOCAL_ASSIGNS
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
                  if disallowed_keys.any?
         
     | 
| 
      
 87 
     | 
    
         
            +
                    raise ArgumentError, "local_assigns contains #{disallowed_keys.inspect}"
         
     | 
| 
      
 88 
     | 
    
         
            +
                  end
         
     | 
| 
      
 89 
     | 
    
         
            +
                end
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
                def validate_form_context
         
     | 
| 
      
 92 
     | 
    
         
            +
                  raise ArgumentError, "missing i18n_base" unless @_current_i18n_base
         
     | 
| 
      
 93 
     | 
    
         
            +
                  raise ArgumentError, "missing form_object" unless @_current_form
         
     | 
| 
      
 94 
     | 
    
         
            +
                end
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
                def build_field_translations(field)
         
     | 
| 
      
 97 
     | 
    
         
            +
                  fields_key = "#{@_current_i18n_base}.fields.#{field}"
         
     | 
| 
      
 98 
     | 
    
         
            +
                  field_label = t(fields_key, raise: true)
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
                  base_parts = @_current_i18n_base.split(".")
         
     | 
| 
      
 101 
     | 
    
         
            +
                  root = base_parts[0..-2]
         
     | 
| 
      
 102 
     | 
    
         
            +
                  hint_key = (root + ["hints", field]).join(".")
         
     | 
| 
      
 103 
     | 
    
         
            +
                  placeholder_key = (root + ["placeholders", field]).join(".")
         
     | 
| 
      
 104 
     | 
    
         
            +
             
     | 
| 
      
 105 
     | 
    
         
            +
                  {
         
     | 
| 
      
 106 
     | 
    
         
            +
                    field_label:,
         
     | 
| 
      
 107 
     | 
    
         
            +
                    field_hint: t(hint_key, default: nil),
         
     | 
| 
      
 108 
     | 
    
         
            +
                    field_placeholder: t(placeholder_key, default: nil)
         
     | 
| 
      
 109 
     | 
    
         
            +
                  }
         
     | 
| 
      
 110 
     | 
    
         
            +
                end
         
     | 
| 
      
 111 
     | 
    
         
            +
             
     | 
| 
      
 112 
     | 
    
         
            +
                def build_field_setup_result(field_translations, value, prefilled)
         
     | 
| 
      
 113 
     | 
    
         
            +
                  {
         
     | 
| 
      
 114 
     | 
    
         
            +
                    form_object: @_current_form,
         
     | 
| 
      
 115 
     | 
    
         
            +
                    i18n_base: @_current_i18n_base,
         
     | 
| 
      
 116 
     | 
    
         
            +
                    value:,
         
     | 
| 
      
 117 
     | 
    
         
            +
                    prefilled:
         
     | 
| 
      
 118 
     | 
    
         
            +
                  }.merge(field_translations)
         
     | 
| 
      
 119 
     | 
    
         
            +
                end
         
     | 
| 
      
 120 
     | 
    
         
            +
             
     | 
| 
      
 121 
     | 
    
         
            +
                def resolve_field_value(model, field)
         
     | 
| 
      
 122 
     | 
    
         
            +
                  field_str = field.to_s
         
     | 
| 
      
 123 
     | 
    
         
            +
             
     | 
| 
      
 124 
     | 
    
         
            +
                  # Never return values for password fields
         
     | 
| 
      
 125 
     | 
    
         
            +
                  if field_str.include?("password")
         
     | 
| 
      
 126 
     | 
    
         
            +
                    return {value: nil, prefilled: false}
         
     | 
| 
      
 127 
     | 
    
         
            +
                  end
         
     | 
| 
      
 128 
     | 
    
         
            +
             
     | 
| 
      
 129 
     | 
    
         
            +
                  # Check current model value
         
     | 
| 
      
 130 
     | 
    
         
            +
                  current_value = model.send(field) if model.respond_to?(field)
         
     | 
| 
      
 131 
     | 
    
         
            +
             
     | 
| 
      
 132 
     | 
    
         
            +
                  # Check if this field should be excluded from prefilling
         
     | 
| 
      
 133 
     | 
    
         
            +
                  if defined?(InspectionsController::NOT_COPIED_FIELDS) &&
         
     | 
| 
      
 134 
     | 
    
         
            +
                      InspectionsController::NOT_COPIED_FIELDS.include?(field_str)
         
     | 
| 
      
 135 
     | 
    
         
            +
                    return {value: current_value, prefilled: false}
         
     | 
| 
      
 136 
     | 
    
         
            +
                  end
         
     | 
| 
      
 137 
     | 
    
         
            +
             
     | 
| 
      
 138 
     | 
    
         
            +
                  # Extract previous value if available
         
     | 
| 
      
 139 
     | 
    
         
            +
                  previous_value = extract_previous_value(@previous_inspection, model, field)
         
     | 
| 
      
 140 
     | 
    
         
            +
             
     | 
| 
      
 141 
     | 
    
         
            +
                  # Return previous value if current is nil and previous exists
         
     | 
| 
      
 142 
     | 
    
         
            +
                  if current_value.nil? && !previous_value.nil?
         
     | 
| 
      
 143 
     | 
    
         
            +
                    return {
         
     | 
| 
      
 144 
     | 
    
         
            +
                      value: format_numeric_value(previous_value),
         
     | 
| 
      
 145 
     | 
    
         
            +
                      prefilled: true
         
     | 
| 
      
 146 
     | 
    
         
            +
                    }
         
     | 
| 
      
 147 
     | 
    
         
            +
                  end
         
     | 
| 
      
 148 
     | 
    
         
            +
             
     | 
| 
      
 149 
     | 
    
         
            +
                  if field_str.end_with?("_id") && field_str != "id"
         
     | 
| 
      
 150 
     | 
    
         
            +
                    resolve_association_value(model, field_str)
         
     | 
| 
      
 151 
     | 
    
         
            +
                  else
         
     | 
| 
      
 152 
     | 
    
         
            +
                    # Always return current value, even if nil
         
     | 
| 
      
 153 
     | 
    
         
            +
                    {value: current_value, prefilled: false}
         
     | 
| 
      
 154 
     | 
    
         
            +
                  end
         
     | 
| 
      
 155 
     | 
    
         
            +
                end
         
     | 
| 
      
 156 
     | 
    
         
            +
             
     | 
| 
      
 157 
     | 
    
         
            +
                def extract_previous_value(previous_inspection, current_model, field)
         
     | 
| 
      
 158 
     | 
    
         
            +
                  if !previous_inspection
         
     | 
| 
      
 159 
     | 
    
         
            +
                    nil
         
     | 
| 
      
 160 
     | 
    
         
            +
                  elsif current_model.class.name.include?("Assessment")
         
     | 
| 
      
 161 
     | 
    
         
            +
                    assessment_type = current_model.class.name.demodulize.underscore
         
     | 
| 
      
 162 
     | 
    
         
            +
                    previous_model = previous_inspection.send(assessment_type)
         
     | 
| 
      
 163 
     | 
    
         
            +
                    previous_model&.send(field)
         
     | 
| 
      
 164 
     | 
    
         
            +
                  else
         
     | 
| 
      
 165 
     | 
    
         
            +
                    previous_inspection.send(field)
         
     | 
| 
      
 166 
     | 
    
         
            +
                  end
         
     | 
| 
      
 167 
     | 
    
         
            +
                end
         
     | 
| 
      
 168 
     | 
    
         
            +
             
     | 
| 
      
 169 
     | 
    
         
            +
                def format_numeric_value(value)
         
     | 
| 
      
 170 
     | 
    
         
            +
                  if value.is_a?(String) &&
         
     | 
| 
      
 171 
     | 
    
         
            +
                      value.match?(/\A-?\d*\.?\d+\z/) &&
         
     | 
| 
      
 172 
     | 
    
         
            +
                      (float_value = Float(value, exception: false))
         
     | 
| 
      
 173 
     | 
    
         
            +
                    value = float_value
         
     | 
| 
      
 174 
     | 
    
         
            +
                  end
         
     | 
| 
      
 175 
     | 
    
         
            +
             
     | 
| 
      
 176 
     | 
    
         
            +
                  return value unless value.is_a?(Numeric)
         
     | 
| 
      
 177 
     | 
    
         
            +
             
     | 
| 
      
 178 
     | 
    
         
            +
                  number_with_precision(
         
     | 
| 
      
 179 
     | 
    
         
            +
                    value,
         
     | 
| 
      
 180 
     | 
    
         
            +
                    precision: 4,
         
     | 
| 
      
 181 
     | 
    
         
            +
                    strip_insignificant_zeros: true
         
     | 
| 
      
 182 
     | 
    
         
            +
                  )
         
     | 
| 
      
 183 
     | 
    
         
            +
                end
         
     | 
| 
      
 184 
     | 
    
         
            +
             
     | 
| 
      
 185 
     | 
    
         
            +
                def resolve_association_value(model, field_str)
         
     | 
| 
      
 186 
     | 
    
         
            +
                  base_name = field_str.chomp("_id")
         
     | 
| 
      
 187 
     | 
    
         
            +
                  association_name = base_name.to_sym
         
     | 
| 
      
 188 
     | 
    
         
            +
             
     | 
| 
      
 189 
     | 
    
         
            +
                  if model.respond_to?(association_name)
         
     | 
| 
      
 190 
     | 
    
         
            +
                    {value: model.send(association_name), prefilled: true}
         
     | 
| 
      
 191 
     | 
    
         
            +
                  elsif model.respond_to?(field_str)
         
     | 
| 
      
 192 
     | 
    
         
            +
                    value = model.send(field_str)
         
     | 
| 
      
 193 
     | 
    
         
            +
                    if value && model.class.reflect_on_association(association_name)
         
     | 
| 
      
 194 
     | 
    
         
            +
                      associated = model.class
         
     | 
| 
      
 195 
     | 
    
         
            +
                        .reflect_on_association(association_name)
         
     | 
| 
      
 196 
     | 
    
         
            +
                        .klass.find_by(id: value)
         
     | 
| 
      
 197 
     | 
    
         
            +
                      {value: associated, prefilled: true}
         
     | 
| 
      
 198 
     | 
    
         
            +
                    else
         
     | 
| 
      
 199 
     | 
    
         
            +
                      {value: value, prefilled: true}
         
     | 
| 
      
 200 
     | 
    
         
            +
                    end
         
     | 
| 
      
 201 
     | 
    
         
            +
                  else
         
     | 
| 
      
 202 
     | 
    
         
            +
                    {value: nil, prefilled: false}
         
     | 
| 
      
 203 
     | 
    
         
            +
                  end
         
     | 
| 
      
 204 
     | 
    
         
            +
                end
         
     | 
| 
      
 205 
     | 
    
         
            +
              end
         
     | 
| 
      
 206 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/version.rb
    ADDED
    
    
| 
         @@ -0,0 +1,55 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            <%
         
     | 
| 
      
 2 
     | 
    
         
            +
              # Auto-submit select field options
         
     | 
| 
      
 3 
     | 
    
         
            +
              field = local_assigns[:field] or raise ArgumentError, "field is required for auto submit select"
         
     | 
| 
      
 4 
     | 
    
         
            +
              options = local_assigns[:options] or raise ArgumentError, "options is required for auto submit select"
         
     | 
| 
      
 5 
     | 
    
         
            +
              
         
     | 
| 
      
 6 
     | 
    
         
            +
              # Check if we're in a form context with form object or need standalone
         
     | 
| 
      
 7 
     | 
    
         
            +
              if local_assigns[:form]
         
     | 
| 
      
 8 
     | 
    
         
            +
                form_object = local_assigns[:form]
         
     | 
| 
      
 9 
     | 
    
         
            +
                selected_value = params[field] || form_object.object.send(field) rescue nil
         
     | 
| 
      
 10 
     | 
    
         
            +
              else
         
     | 
| 
      
 11 
     | 
    
         
            +
                # Standalone usage - must provide url
         
     | 
| 
      
 12 
     | 
    
         
            +
                url = local_assigns[:url] or raise ArgumentError, "url is required for standalone auto submit select"
         
     | 
| 
      
 13 
     | 
    
         
            +
                selected_value = params[field]
         
     | 
| 
      
 14 
     | 
    
         
            +
              end
         
     | 
| 
      
 15 
     | 
    
         
            +
              
         
     | 
| 
      
 16 
     | 
    
         
            +
              # Optional parameters
         
     | 
| 
      
 17 
     | 
    
         
            +
              label = local_assigns[:label]
         
     | 
| 
      
 18 
     | 
    
         
            +
              include_blank = local_assigns[:include_blank]
         
     | 
| 
      
 19 
     | 
    
         
            +
              blank_text = local_assigns[:blank_text] || "All"
         
     | 
| 
      
 20 
     | 
    
         
            +
              turbo_disabled = local_assigns.has_key?(:turbo_disabled) ? local_assigns[:turbo_disabled] : true
         
     | 
| 
      
 21 
     | 
    
         
            +
              preserve_params = local_assigns[:preserve_params] || []
         
     | 
| 
      
 22 
     | 
    
         
            +
            %>
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
            <% if local_assigns[:form] %>
         
     | 
| 
      
 25 
     | 
    
         
            +
              <% if label %>
         
     | 
| 
      
 26 
     | 
    
         
            +
                <%= form_object.label field, label %>
         
     | 
| 
      
 27 
     | 
    
         
            +
              <% end %>
         
     | 
| 
      
 28 
     | 
    
         
            +
              
         
     | 
| 
      
 29 
     | 
    
         
            +
              <%= form_object.select field,
         
     | 
| 
      
 30 
     | 
    
         
            +
                  options_for_select(options, selected_value),
         
     | 
| 
      
 31 
     | 
    
         
            +
                  include_blank ? { include_blank: blank_text } : {},
         
     | 
| 
      
 32 
     | 
    
         
            +
                  { onchange: "this.form.submit();" } %>
         
     | 
| 
      
 33 
     | 
    
         
            +
                  
         
     | 
| 
      
 34 
     | 
    
         
            +
            <% else %>
         
     | 
| 
      
 35 
     | 
    
         
            +
              <!-- Standalone auto-submit select form -->
         
     | 
| 
      
 36 
     | 
    
         
            +
              <%= form_with url: url, method: :get, data: (turbo_disabled ? { turbo: false } : {}) do |form| %>
         
     | 
| 
      
 37 
     | 
    
         
            +
                
         
     | 
| 
      
 38 
     | 
    
         
            +
                <!-- Preserve other parameters -->
         
     | 
| 
      
 39 
     | 
    
         
            +
                <% preserve_params.each do |param| %>
         
     | 
| 
      
 40 
     | 
    
         
            +
                  <% if params[param].present? %>
         
     | 
| 
      
 41 
     | 
    
         
            +
                    <%= form.hidden_field param, value: params[param] %>
         
     | 
| 
      
 42 
     | 
    
         
            +
                  <% end %>
         
     | 
| 
      
 43 
     | 
    
         
            +
                <% end %>
         
     | 
| 
      
 44 
     | 
    
         
            +
                
         
     | 
| 
      
 45 
     | 
    
         
            +
                <% if label %>
         
     | 
| 
      
 46 
     | 
    
         
            +
                  <%= form.label field, label %>
         
     | 
| 
      
 47 
     | 
    
         
            +
                <% end %>
         
     | 
| 
      
 48 
     | 
    
         
            +
                
         
     | 
| 
      
 49 
     | 
    
         
            +
                <%= form.select field,
         
     | 
| 
      
 50 
     | 
    
         
            +
                    options_for_select(options, selected_value),
         
     | 
| 
      
 51 
     | 
    
         
            +
                    include_blank ? { include_blank: blank_text } : {},
         
     | 
| 
      
 52 
     | 
    
         
            +
                    { onchange: "this.form.submit();" } %>
         
     | 
| 
      
 53 
     | 
    
         
            +
                    
         
     | 
| 
      
 54 
     | 
    
         
            +
              <% end %>
         
     | 
| 
      
 55 
     | 
    
         
            +
            <% end %>
         
     | 
| 
         @@ -0,0 +1,17 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            <%
         
     | 
| 
      
 2 
     | 
    
         
            +
              setup = form_field_setup(field, local_assigns)
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
              field_options = {
         
     | 
| 
      
 5 
     | 
    
         
            +
                required: local_assigns[:required] || false,
         
     | 
| 
      
 6 
     | 
    
         
            +
                list: "#{field}_autocomplete_#{setup[:form_object].object.object_id}",
         
     | 
| 
      
 7 
     | 
    
         
            +
                value: setup[:value]
         
     | 
| 
      
 8 
     | 
    
         
            +
              }
         
     | 
| 
      
 9 
     | 
    
         
            +
            %>
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            <%= setup[:form_object].label field, setup[:field_label] %>
         
     | 
| 
      
 12 
     | 
    
         
            +
            <%= setup[:form_object].text_field field, field_options %>
         
     | 
| 
      
 13 
     | 
    
         
            +
            <datalist id="<%= field_options[:list] %>">
         
     | 
| 
      
 14 
     | 
    
         
            +
              <% options&.each do |option| %>
         
     | 
| 
      
 15 
     | 
    
         
            +
                <option value="<%= option %>"></option>
         
     | 
| 
      
 16 
     | 
    
         
            +
              <% end %>
         
     | 
| 
      
 17 
     | 
    
         
            +
            </datalist>
         
     | 
| 
         @@ -0,0 +1,12 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            <%
         
     | 
| 
      
 2 
     | 
    
         
            +
              # Get i18n_base from section (already validated there)
         
     | 
| 
      
 3 
     | 
    
         
            +
              setup = form_field_setup(field, local_assigns)
         
     | 
| 
      
 4 
     | 
    
         
            +
            %>
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            <%= setup[:form_object].label field do %>
         
     | 
| 
      
 7 
     | 
    
         
            +
              <%= setup[:form_object].check_box field %>
         
     | 
| 
      
 8 
     | 
    
         
            +
              <%= setup[:field_label] %>
         
     | 
| 
      
 9 
     | 
    
         
            +
              <% if setup[:field_hint].present? %>
         
     | 
| 
      
 10 
     | 
    
         
            +
                <small><%= setup[:field_hint] %></small>
         
     | 
| 
      
 11 
     | 
    
         
            +
              <% end %>
         
     | 
| 
      
 12 
     | 
    
         
            +
            <% end %>
         
     | 
| 
         @@ -0,0 +1,40 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            <%
         
     | 
| 
      
 2 
     | 
    
         
            +
              # Form partial for comment fields with toggle visibility
         
     | 
| 
      
 3 
     | 
    
         
            +
              # Required parameters:
         
     | 
| 
      
 4 
     | 
    
         
            +
              #   field: Symbol representing the field name
         
     | 
| 
      
 5 
     | 
    
         
            +
              # Optional parameters:
         
     | 
| 
      
 6 
     | 
    
         
            +
              #   maxlength: Maximum character length (default: 1000)
         
     | 
| 
      
 7 
     | 
    
         
            +
              #   placeholder: Placeholder text
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
              maxlength ||= 1000
         
     | 
| 
      
 10 
     | 
    
         
            +
              placeholder ||= nil
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
              form = @_current_form
         
     | 
| 
      
 13 
     | 
    
         
            +
              checkbox_id = "toggle_#{field}_#{form.object.object_id}"
         
     | 
| 
      
 14 
     | 
    
         
            +
              textarea_id = "#{form.object_name}_#{field}"
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
              # Check if there's existing content
         
     | 
| 
      
 17 
     | 
    
         
            +
              has_content = form.object.send(field).present?
         
     | 
| 
      
 18 
     | 
    
         
            +
            %>
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
            <div class="comment-field-container">
         
     | 
| 
      
 21 
     | 
    
         
            +
              <label for="<%= checkbox_id %>">
         
     | 
| 
      
 22 
     | 
    
         
            +
                <input type="checkbox" id="<%= checkbox_id %>"
         
     | 
| 
      
 23 
     | 
    
         
            +
                  <%= 'checked' if has_content %>
         
     | 
| 
      
 24 
     | 
    
         
            +
                  data-comment-toggle="<%= textarea_id %>"
         
     | 
| 
      
 25 
     | 
    
         
            +
                  data-comment-container="<%= textarea_id %>_container"
         
     | 
| 
      
 26 
     | 
    
         
            +
                >
         
     | 
| 
      
 27 
     | 
    
         
            +
                <%= t("shared.comment") %>
         
     | 
| 
      
 28 
     | 
    
         
            +
              </label>
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
              <div id="<%= textarea_id %>_container"
         
     | 
| 
      
 31 
     | 
    
         
            +
                style="display: <%= has_content ? 'block' : 'none' %>"
         
     | 
| 
      
 32 
     | 
    
         
            +
              >
         
     | 
| 
      
 33 
     | 
    
         
            +
                <%= form.text_field field,
         
     | 
| 
      
 34 
     | 
    
         
            +
                    maxlength: maxlength,
         
     | 
| 
      
 35 
     | 
    
         
            +
                    placeholder: placeholder,
         
     | 
| 
      
 36 
     | 
    
         
            +
                    id: textarea_id,
         
     | 
| 
      
 37 
     | 
    
         
            +
                    title: "Max #{maxlength} characters"
         
     | 
| 
      
 38 
     | 
    
         
            +
                %>
         
     | 
| 
      
 39 
     | 
    
         
            +
              </div>
         
     | 
| 
      
 40 
     | 
    
         
            +
            </div>
         
     | 
| 
         @@ -0,0 +1,18 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            <%
         
     | 
| 
      
 2 
     | 
    
         
            +
              # Partial for comment checkbox
         
     | 
| 
      
 3 
     | 
    
         
            +
              # Required parameters:
         
     | 
| 
      
 4 
     | 
    
         
            +
              #   comment_field: The comment field name (e.g., :width_comment)
         
     | 
| 
      
 5 
     | 
    
         
            +
              #   checkbox_id: Unique ID for the checkbox
         
     | 
| 
      
 6 
     | 
    
         
            +
              #   textarea_id: ID of the textarea to show/hide
         
     | 
| 
      
 7 
     | 
    
         
            +
              #   has_comment: Whether comment exists
         
     | 
| 
      
 8 
     | 
    
         
            +
            %>
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            <label for="<%= checkbox_id %>" class="comment-checkbox">
         
     | 
| 
      
 11 
     | 
    
         
            +
              <input type="checkbox"
         
     | 
| 
      
 12 
     | 
    
         
            +
                id="<%= checkbox_id %>"
         
     | 
| 
      
 13 
     | 
    
         
            +
                <%= 'checked' if has_comment %>
         
     | 
| 
      
 14 
     | 
    
         
            +
                data-comment-toggle="<%= textarea_id %>"
         
     | 
| 
      
 15 
     | 
    
         
            +
                data-comment-container="<%= textarea_id %>"
         
     | 
| 
      
 16 
     | 
    
         
            +
              >
         
     | 
| 
      
 17 
     | 
    
         
            +
              <%= t('shared.comment') %>
         
     | 
| 
      
 18 
     | 
    
         
            +
            </label>
         
     | 
| 
         @@ -0,0 +1,15 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            <%
         
     | 
| 
      
 2 
     | 
    
         
            +
              setup = form_field_setup(field, local_assigns)
         
     | 
| 
      
 3 
     | 
    
         
            +
              required ||= false
         
     | 
| 
      
 4 
     | 
    
         
            +
              field_options = {
         
     | 
| 
      
 5 
     | 
    
         
            +
                placeholder: setup[:field_placeholder],
         
     | 
| 
      
 6 
     | 
    
         
            +
                required: required
         
     | 
| 
      
 7 
     | 
    
         
            +
              }.compact
         
     | 
| 
      
 8 
     | 
    
         
            +
              field_options[:value] = local_assigns[:value] if local_assigns[:value]
         
     | 
| 
      
 9 
     | 
    
         
            +
            %>
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            <%= setup[:form_object].label field, setup[:field_label] %>
         
     | 
| 
      
 12 
     | 
    
         
            +
            <%= setup[:form_object].send(:date_field, field, field_options) %>
         
     | 
| 
      
 13 
     | 
    
         
            +
            <% if setup[:field_hint].present? %>
         
     | 
| 
      
 14 
     | 
    
         
            +
              <small><%= setup[:field_hint] %></small>
         
     | 
| 
      
 15 
     | 
    
         
            +
            <% end %>
         
     | 
| 
         @@ -0,0 +1,58 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            <%
         
     | 
| 
      
 2 
     | 
    
         
            +
              # Composite partial for decimal + comment fields with grid layout
         
     | 
| 
      
 3 
     | 
    
         
            +
              # Required parameters:
         
     | 
| 
      
 4 
     | 
    
         
            +
              #   field: Base field name (e.g., 'platform_height')
         
     | 
| 
      
 5 
     | 
    
         
            +
              # Optional parameters:
         
     | 
| 
      
 6 
     | 
    
         
            +
              #   min: Minimum value
         
     | 
| 
      
 7 
     | 
    
         
            +
              #   max: Maximum value
         
     | 
| 
      
 8 
     | 
    
         
            +
              #   required: Whether the decimal field is required
         
     | 
| 
      
 9 
     | 
    
         
            +
              #   placeholder: Placeholder text
         
     | 
| 
      
 10 
     | 
    
         
            +
              #
         
     | 
| 
      
 11 
     | 
    
         
            +
              # This will render:
         
     | 
| 
      
 12 
     | 
    
         
            +
              #   - Decimal field: field (e.g., 'platform_height')
         
     | 
| 
      
 13 
     | 
    
         
            +
              #   - Comment field: field + '_comment' (e.g., 'platform_height_comment')
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
              decimal_field = field
         
     | 
| 
      
 16 
     | 
    
         
            +
              comment_field = "#{field}_comment".to_sym
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
              form = @_current_form
         
     | 
| 
      
 19 
     | 
    
         
            +
              model = form.object
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
              field_data = form_field_setup(field, local_assigns)
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
              decimal_options = {
         
     | 
| 
      
 24 
     | 
    
         
            +
                inputmode: "decimal",
         
     | 
| 
      
 25 
     | 
    
         
            +
                pattern: "[0-9]*[.]?[0-9]*",
         
     | 
| 
      
 26 
     | 
    
         
            +
                placeholder: field_data[:field_placeholder] || local_assigns[:placeholder],
         
     | 
| 
      
 27 
     | 
    
         
            +
                required: local_assigns[:required] || false,
         
     | 
| 
      
 28 
     | 
    
         
            +
                class: "number"
         
     | 
| 
      
 29 
     | 
    
         
            +
              }
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
              if field_data[:prefilled]
         
     | 
| 
      
 32 
     | 
    
         
            +
                decimal_options[:value] = field_data[:value]
         
     | 
| 
      
 33 
     | 
    
         
            +
              end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
              decimal_options[:data] = {}
         
     | 
| 
      
 36 
     | 
    
         
            +
              decimal_options[:data][:min] = local_assigns[:min] if local_assigns[:min]
         
     | 
| 
      
 37 
     | 
    
         
            +
              decimal_options[:data][:max] = local_assigns[:max] if local_assigns[:max]
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
              comment_info = comment_field_options(
         
     | 
| 
      
 40 
     | 
    
         
            +
                form,
         
     | 
| 
      
 41 
     | 
    
         
            +
                comment_field,
         
     | 
| 
      
 42 
     | 
    
         
            +
                field_data[:field_label]
         
     | 
| 
      
 43 
     | 
    
         
            +
              )
         
     | 
| 
      
 44 
     | 
    
         
            +
            %>
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
            <div class="form-grid number-comment" id="<%= decimal_field %>">
         
     | 
| 
      
 47 
     | 
    
         
            +
              <%= form.label decimal_field, field_data[:field_label], class: "label" %>
         
     | 
| 
      
 48 
     | 
    
         
            +
              <%= form.text_field decimal_field, decimal_options %>
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
              <%= render 'chobble_forms/comment_checkbox',
         
     | 
| 
      
 51 
     | 
    
         
            +
                  comment_field: comment_field,
         
     | 
| 
      
 52 
     | 
    
         
            +
                  checkbox_id: comment_info[:checkbox_id],
         
     | 
| 
      
 53 
     | 
    
         
            +
                  textarea_id: comment_info[:options][:id],
         
     | 
| 
      
 54 
     | 
    
         
            +
                  has_comment: comment_info[:has_comment],
         
     | 
| 
      
 55 
     | 
    
         
            +
                  prefilled: comment_info[:prefilled] %>
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
              <%= form.text_area comment_field, comment_info[:options] %>
         
     | 
| 
      
 58 
     | 
    
         
            +
            </div>
         
     | 
| 
         @@ -0,0 +1,11 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            <%
         
     | 
| 
      
 2 
     | 
    
         
            +
              # Get i18n_base from section (already validated there)
         
     | 
| 
      
 3 
     | 
    
         
            +
              setup = form_field_setup(field, local_assigns)
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
              # Get value from model object automatically
         
     | 
| 
      
 6 
     | 
    
         
            +
              model_object = setup[:form_object].object
         
     | 
| 
      
 7 
     | 
    
         
            +
              value = model_object.send(field) if model_object.respond_to?(field)
         
     | 
| 
      
 8 
     | 
    
         
            +
            %>
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            <%= setup[:form_object].label field, setup[:field_label] %>
         
     | 
| 
      
 11 
     | 
    
         
            +
            <p><%= value %></p>
         
     | 
| 
         @@ -0,0 +1,26 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            <%
         
     | 
| 
      
 2 
     | 
    
         
            +
              # Form errors component - displays validation errors for any model object
         
     | 
| 
      
 3 
     | 
    
         
            +
              model_object = local_assigns[:model] || local_assigns[:object]
         
     | 
| 
      
 4 
     | 
    
         
            +
              raise ArgumentError, "model object is required for form errors" if model_object.nil?
         
     | 
| 
      
 5 
     | 
    
         
            +
              
         
     | 
| 
      
 6 
     | 
    
         
            +
              # Use inherited i18n_base from form context
         
     | 
| 
      
 7 
     | 
    
         
            +
              i18n_base = @_current_i18n_base
         
     | 
| 
      
 8 
     | 
    
         
            +
              raise ArgumentError, "i18n_base is required for form errors" if i18n_base.nil?
         
     | 
| 
      
 9 
     | 
    
         
            +
              
         
     | 
| 
      
 10 
     | 
    
         
            +
              # Custom header text or use i18n lookup - no fallbacks
         
     | 
| 
      
 11 
     | 
    
         
            +
              header_text = local_assigns[:header] || 
         
     | 
| 
      
 12 
     | 
    
         
            +
                            t("#{i18n_base}.errors.header", 
         
     | 
| 
      
 13 
     | 
    
         
            +
                              count: model_object.errors.count, 
         
     | 
| 
      
 14 
     | 
    
         
            +
                              raise: true)
         
     | 
| 
      
 15 
     | 
    
         
            +
            %>
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            <% if model_object.errors.any? %>
         
     | 
| 
      
 18 
     | 
    
         
            +
              <aside class="form-errors" role="alert">
         
     | 
| 
      
 19 
     | 
    
         
            +
                <h3><%= header_text %></h3>
         
     | 
| 
      
 20 
     | 
    
         
            +
                <ul>
         
     | 
| 
      
 21 
     | 
    
         
            +
                  <% model_object.errors.each do |error| %>
         
     | 
| 
      
 22 
     | 
    
         
            +
                    <li><%= error.full_message %></li>
         
     | 
| 
      
 23 
     | 
    
         
            +
                  <% end %>
         
     | 
| 
      
 24 
     | 
    
         
            +
                </ul>
         
     | 
| 
      
 25 
     | 
    
         
            +
              </aside>
         
     | 
| 
      
 26 
     | 
    
         
            +
            <% end %>
         
     | 
| 
         @@ -0,0 +1,33 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            <%
         
     | 
| 
      
 2 
     | 
    
         
            +
              # Field with optional link to the right
         
     | 
| 
      
 3 
     | 
    
         
            +
              # Required locals:
         
     | 
| 
      
 4 
     | 
    
         
            +
              #   - field_type: :text_field or :autocomplete_field
         
     | 
| 
      
 5 
     | 
    
         
            +
              #   - field: field name
         
     | 
| 
      
 6 
     | 
    
         
            +
              #   - required: boolean
         
     | 
| 
      
 7 
     | 
    
         
            +
              # Optional locals:
         
     | 
| 
      
 8 
     | 
    
         
            +
              #   - link_url: URL for the link
         
     | 
| 
      
 9 
     | 
    
         
            +
              #   - link_text: Text for the link
         
     | 
| 
      
 10 
     | 
    
         
            +
              #   - options: options for autocomplete_field
         
     | 
| 
      
 11 
     | 
    
         
            +
              
         
     | 
| 
      
 12 
     | 
    
         
            +
              field_type = local_assigns[:field_type] || :text_field
         
     | 
| 
      
 13 
     | 
    
         
            +
              field = local_assigns[:field]
         
     | 
| 
      
 14 
     | 
    
         
            +
              required = local_assigns[:required] || false
         
     | 
| 
      
 15 
     | 
    
         
            +
              link_url = local_assigns[:link_url]
         
     | 
| 
      
 16 
     | 
    
         
            +
              link_text = local_assigns[:link_text]
         
     | 
| 
      
 17 
     | 
    
         
            +
              options = local_assigns[:options] || []
         
     | 
| 
      
 18 
     | 
    
         
            +
              
         
     | 
| 
      
 19 
     | 
    
         
            +
              has_link = link_url.present? && link_text.present?
         
     | 
| 
      
 20 
     | 
    
         
            +
              css_classes = has_link ? "field field-with-link" : "field"
         
     | 
| 
      
 21 
     | 
    
         
            +
            %>
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
            <div class="<%= css_classes %>">
         
     | 
| 
      
 24 
     | 
    
         
            +
              <% if field_type == :autocomplete_field %>
         
     | 
| 
      
 25 
     | 
    
         
            +
                <%= render 'chobble_forms/autocomplete_field', field: field, required: required, options: options %>
         
     | 
| 
      
 26 
     | 
    
         
            +
              <% else %>
         
     | 
| 
      
 27 
     | 
    
         
            +
                <%= render 'chobble_forms/text_field', field: field, required: required %>
         
     | 
| 
      
 28 
     | 
    
         
            +
              <% end %>
         
     | 
| 
      
 29 
     | 
    
         
            +
              
         
     | 
| 
      
 30 
     | 
    
         
            +
              <% if has_link %>
         
     | 
| 
      
 31 
     | 
    
         
            +
                <%= link_to link_text, link_url %>
         
     | 
| 
      
 32 
     | 
    
         
            +
              <% end %>
         
     | 
| 
      
 33 
     | 
    
         
            +
            </div>
         
     | 
| 
         @@ -0,0 +1,9 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            <% model.class.form_fields(user: current_user).each do |fieldset| %>
         
     | 
| 
      
 2 
     | 
    
         
            +
              <%= render 'chobble_forms/fieldset', legend_key: fieldset[:legend_i18n_key] do %>
         
     | 
| 
      
 3 
     | 
    
         
            +
                <% fieldset[:fields].each do |field_config| %>
         
     | 
| 
      
 4 
     | 
    
         
            +
                  <% render_options = { field: field_config[:field] } %>
         
     | 
| 
      
 5 
     | 
    
         
            +
                  <% render_options.merge!(field_config[:attributes]) if field_config[:attributes] %>
         
     | 
| 
      
 6 
     | 
    
         
            +
                  <%= render "chobble_forms/#{field_config[:partial]}", render_options %>
         
     | 
| 
      
 7 
     | 
    
         
            +
                <% end %>
         
     | 
| 
      
 8 
     | 
    
         
            +
              <% end %>
         
     | 
| 
      
 9 
     | 
    
         
            +
            <% end %>
         
     | 
| 
         @@ -0,0 +1,29 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            <%
         
     | 
| 
      
 2 
     | 
    
         
            +
              # Set form and i18n context for child form controls
         
     | 
| 
      
 3 
     | 
    
         
            +
              @_current_form = local_assigns[:form] || @_current_form
         
     | 
| 
      
 4 
     | 
    
         
            +
              i18n_base = @_current_i18n_base || local_assigns[:i18n_base]
         
     | 
| 
      
 5 
     | 
    
         
            +
              raise ArgumentError, "i18n_base is required for form fieldsets" if i18n_base.nil?
         
     | 
| 
      
 6 
     | 
    
         
            +
              @_current_i18n_base = i18n_base
         
     | 
| 
      
 7 
     | 
    
         
            +
              
         
     | 
| 
      
 8 
     | 
    
         
            +
              # Determine legend text
         
     | 
| 
      
 9 
     | 
    
         
            +
              if local_assigns[:legend]
         
     | 
| 
      
 10 
     | 
    
         
            +
                legend_text = local_assigns[:legend]
         
     | 
| 
      
 11 
     | 
    
         
            +
              elsif local_assigns[:legend_key] && i18n_base
         
     | 
| 
      
 12 
     | 
    
         
            +
                # Remove .fields suffix if present to get to sections level
         
     | 
| 
      
 13 
     | 
    
         
            +
                sections_base = i18n_base.sub(/\.fields$/, '')
         
     | 
| 
      
 14 
     | 
    
         
            +
                legend_text = t("#{sections_base}.sections.#{local_assigns[:legend_key]}")
         
     | 
| 
      
 15 
     | 
    
         
            +
                # Fail loudly if translation is missing
         
     | 
| 
      
 16 
     | 
    
         
            +
                if legend_text.start_with?("translation missing:")
         
     | 
| 
      
 17 
     | 
    
         
            +
                  raise "Missing i18n key: #{sections_base}.sections.#{local_assigns[:legend_key]}"
         
     | 
| 
      
 18 
     | 
    
         
            +
                end
         
     | 
| 
      
 19 
     | 
    
         
            +
              else
         
     | 
| 
      
 20 
     | 
    
         
            +
                legend_text = local_assigns[:legend_key]&.to_s&.humanize || "Section"
         
     | 
| 
      
 21 
     | 
    
         
            +
              end
         
     | 
| 
      
 22 
     | 
    
         
            +
            %>
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
            <fieldset>
         
     | 
| 
      
 25 
     | 
    
         
            +
              <% if legend_text.present? %>
         
     | 
| 
      
 26 
     | 
    
         
            +
                <legend><%= legend_text %></legend>
         
     | 
| 
      
 27 
     | 
    
         
            +
              <% end %>
         
     | 
| 
      
 28 
     | 
    
         
            +
              <%= yield %>
         
     | 
| 
      
 29 
     | 
    
         
            +
            </fieldset>
         
     | 
| 
         @@ -0,0 +1,29 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            <%
         
     | 
| 
      
 2 
     | 
    
         
            +
              # Get i18n_base from section (already validated there)
         
     | 
| 
      
 3 
     | 
    
         
            +
              setup = form_field_setup(field, local_assigns)
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
              # Form field options
         
     | 
| 
      
 6 
     | 
    
         
            +
              accept = local_assigns[:accept] || "image/*"
         
     | 
| 
      
 7 
     | 
    
         
            +
              preview_size = local_assigns[:preview_size] || 200
         
     | 
| 
      
 8 
     | 
    
         
            +
              model = setup[:form_object].object
         
     | 
| 
      
 9 
     | 
    
         
            +
              current_file = model.send(field) if model.respond_to?(field)
         
     | 
| 
      
 10 
     | 
    
         
            +
            %>
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            <%= setup[:form_object].label field, setup[:field_label] %>
         
     | 
| 
      
 13 
     | 
    
         
            +
            <%= setup[:form_object].file_field field, accept: accept %>
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            <% if current_file&.attached? %>
         
     | 
| 
      
 16 
     | 
    
         
            +
              <div class="file-preview" style="margin-top: 10px;">
         
     | 
| 
      
 17 
     | 
    
         
            +
                <% if current_file.image? %>
         
     | 
| 
      
 18 
     | 
    
         
            +
                  <%= image_tag current_file.variant(resize_to_limit: [preview_size, preview_size]),
         
     | 
| 
      
 19 
     | 
    
         
            +
                      alt: "Current #{setup[:field_label].downcase}" %>
         
     | 
| 
      
 20 
     | 
    
         
            +
                  <p><small>Current <%= setup[:field_label].downcase %>: <strong><%= current_file.filename %></strong></small></p>
         
     | 
| 
      
 21 
     | 
    
         
            +
                <% else %>
         
     | 
| 
      
 22 
     | 
    
         
            +
                  <p>Current <%= setup[:field_label].downcase %>: <strong><%= current_file.filename %></strong></p>
         
     | 
| 
      
 23 
     | 
    
         
            +
                <% end %>
         
     | 
| 
      
 24 
     | 
    
         
            +
              </div>
         
     | 
| 
      
 25 
     | 
    
         
            +
            <% end %>
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
            <% if setup[:field_hint].present? %>
         
     | 
| 
      
 28 
     | 
    
         
            +
              <small class="form-text"><%= setup[:field_hint] %></small>
         
     | 
| 
      
 29 
     | 
    
         
            +
            <% end %>
         
     |