gregbell/active_admin

View on GitHub
lib/active_admin/views/components/active_admin_form.rb

Summary

Maintainability
A
55 mins
Test Coverage
# frozen_string_literal: true
module ActiveAdmin
  module Views
    class FormtasticProxy < ::Arbre::Rails::Forms::FormBuilderProxy
      def split_string_on(string, match)
        return "" unless string && match
        part_1 = string.split(Regexp.new("#{match}\\z")).first
        [part_1, match]
      end

      def opening_tag
        @opening_tag || ""
      end

      def closing_tag
        @closing_tag || ""
      end

      def to_s
        opening_tag + children.to_s + closing_tag
      end
    end

    class ActiveAdminForm < FormtasticProxy
      builder_method :active_admin_form_for

      def build(resource, options = {}, &block)
        @resource = resource
        options = options.deep_dup
        options[:builder] ||= ActiveAdmin::FormBuilder
        form_string = helpers.semantic_form_for(resource, options) do |f|
          @form_builder = f
        end

        @opening_tag, @closing_tag = split_string_on(form_string, "</form>")
        instance_eval(&block) if block

        # Rails sets multipart automatically if a file field is present,
        # but the form tag has already been rendered before the block eval.
        if multipart? && !@opening_tag.include?('multipart')
          @opening_tag.sub!(/<form/, '<form enctype="multipart/form-data"')
        end
      end

      def inputs(*args, &block)
        if block
          form_builder.template.assigns[:has_many_block] = true
        end
        if block && block.arity == 0
          wrapped_block = proc do
            wrap_it = form_builder.already_in_an_inputs_block ? true : false
            form_builder.already_in_an_inputs_block = true
            content = form_builder.template.capture do
              block.call
            end
            form_builder.already_in_an_inputs_block = wrap_it
            content
          end
          insert_tag(SemanticInputsProxy, form_builder, *args, &wrapped_block)
        else
          # Set except option to prevent sensitive fields from being shown in forms by default.
          opts = args.extract_options!
          opts[:except] ||= []
          ActiveAdmin.application.filter_attributes.each { |e| opts[:except] << e }
          args << opts

          proxy_call_to_form(:inputs, *args, &block)
        end
      end

      def input(*args)
        proxy_call_to_form :input, *args
      end

      def actions(*args, &block)
        if block
          insert_tag(SemanticActionsProxy, form_builder, *args, &block)
        else
          add_create_another_checkbox
          actions(*args) { commit_action_with_cancel_link }
        end
      end

      def commit_action_with_cancel_link
        action(:submit)
        cancel_link
      end

      def add_create_another_checkbox
        if %w(new create).include?(helpers.action_name) && active_admin_config && active_admin_config.create_another
          current_arbre_element.add_child(create_another_checkbox)
        end
      end

      def has_many(*args, &block)
        insert_tag(HasManyProxy, form_builder, *args, &block)
      end

      def multipart?
        form_builder && form_builder.multipart?
      end

      def object
        form_builder.object
      end

      private

      def create_another_checkbox
        create_another = params[:create_another]
        label = @resource.class.model_name.human
        Arbre::Context.new do
          div class: "boolean input input-create-another" do
            label for: "create_another" do
              input(
                checked: create_another,
                id: "create_another",
                name: "create_another",
                type: "checkbox"
              )
              text_node I18n.t("active_admin.create_another", model: label)
            end
          end
        end
      end
    end

    class SemanticInputsProxy < FormtasticProxy
      def build(form_builder, *args, &block)
        html_options = args.extract_options!
        html_options[:class] ||= "inputs"
        legend = args.shift if args.first.is_a?(::String)
        legend = html_options.delete(:name) if html_options.key?(:name)
        legend_tag = legend ? "<legend class=\"fieldset-title\">#{legend}</legend>" : ""
        fieldset_attrs = html_options.map { |k, v| %Q{#{k}="#{v}"} }.join(" ")
        @opening_tag = "<fieldset #{fieldset_attrs}>#{legend_tag}<ol>"
        @closing_tag = "</ol></fieldset>"
        super(*(args << html_options), &block)
      end
    end

    class SemanticActionsProxy < FormtasticProxy
      def build(form_builder, *args, &block)
        @opening_tag = "<fieldset class=\"actions\"><ol>"
        @closing_tag = "</ol></fieldset>"
        super(*args, &block)
      end
    end

    class HasManyProxy < FormtasticProxy
      def build(form_builder, *args, &block)
        text_node form_builder.has_many(*args, &block)
      end
    end
  end
end