File: has_fields.rb

package info (click to toggle)
ruby-rails-admin 0.8.1%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 2,492 kB
  • ctags: 1,292
  • sloc: ruby: 5,341; makefile: 3
file content (139 lines) | stat: -rw-r--r-- 5,292 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
module RailsAdmin
  module Config
    # Provides accessors and autoregistering of model's fields.
    module HasFields
      # Defines a configuration for a field.
      def field(name, type = nil, add_to_section = true, &block)
        field = _fields.detect { |f| name == f.name }

        # some fields are hidden by default (belongs_to keys, has_many associations in list views.)
        # unhide them if config specifically defines them
        if field
          field.show unless field.instance_variable_get("@#{field.name}_registered").is_a?(Proc)
        end
        # Specify field as virtual if type is not specifically set and field was not
        # found in default stack
        if field.nil? && type.nil?
          field = (_fields << RailsAdmin::Config::Fields::Types.load(:string).new(self, name, nil)).last

        # Register a custom field type if one is provided and it is different from
        # one found in default stack
        elsif type && type != (field.nil? ? nil : field.type)
          if field
            properties = field.properties
            field = _fields[_fields.index(field)] = RailsAdmin::Config::Fields::Types.load(type).new(self, name, properties)
          else
            properties = abstract_model.properties.detect { |p| name == p.name }
            field = (_fields << RailsAdmin::Config::Fields::Types.load(type).new(self, name, properties)).last
          end
        end

        # If field has not been yet defined add some default properties
        if add_to_section && !field.defined
          field.defined = true
          field.order = _fields.count(&:defined)
        end

        # If a block has been given evaluate it and sort fields after that
        field.instance_eval(&block) if block
        field
      end

      # configure a field without adding it.
      def configure(name, type = nil, &block)
        field(name, type, false, &block)
      end

      # include fields by name and apply an optionnal block to each (through a call to fields),
      # or include fields by conditions if no field names
      def include_fields(*field_names, &block)
        if field_names.empty?
          _fields.select { |f| f.instance_eval(&block) }.each do |f|
            next if f.defined
            f.defined = true
            f.order = _fields.count(&:defined)
          end
        else
          fields(*field_names, &block)
        end
      end

      # exclude fields by name or by condition (block)
      def exclude_fields(*field_names, &block)
        block ||= proc { |f| field_names.include?(f.name) }
        _fields.each { |f| f.defined = true } if _fields.select(&:defined).empty?
        _fields.select { |f| f.instance_eval(&block) }.each { |f| f.defined = false }
      end

      # API candy
      alias_method :exclude_fields_if, :exclude_fields
      alias_method :include_fields_if, :include_fields

      def include_all_fields
        include_fields_if { true }
      end

      # Returns all field configurations for the model configuration instance. If no fields
      # have been defined returns all fields. Defined fields are sorted to match their
      # order property. If order was not specified it will match the order in which fields
      # were defined.
      #
      # If a block is passed it will be evaluated in the context of each field
      def fields(*field_names, &block)
        return all_fields if field_names.empty? && !block

        if field_names.empty?
          defined = _fields.select(&:defined)
          defined = _fields if defined.empty?
        else
          defined = field_names.collect { |field_name| _fields.detect { |f| f.name == field_name } }
        end
        defined.collect do |f|
          unless f.defined
            f.defined = true
            f.order = _fields.count(&:defined)
          end
          f.instance_eval(&block) if block
          f
        end
      end

      # Defines configuration for fields by their type.
      def fields_of_type(type, &block)
        _fields.select { |f| type == f.type }.map! { |f| f.instance_eval(&block) } if block
      end

      # Accessor for all fields
      def all_fields
        ((ro_fields = _fields(true)).select(&:defined).presence || ro_fields).collect do |f|
          f.section = self
          f
        end
      end

      # Get all fields defined as visible, in the correct order.
      def visible_fields
        i = 0
        all_fields.collect { |f| f.with(bindings) }.select(&:visible?).sort_by { |f| [f.order, i += 1] } # stable sort, damn
      end

    protected

      # Raw fields.
      # Recursively returns parent section's raw fields
      # Duping it if accessed for modification.
      def _fields(readonly = false)
        return @_fields if @_fields
        return @_ro_fields if readonly && @_ro_fields

        if self.class == RailsAdmin::Config::Sections::Base
          @_ro_fields = @_fields = RailsAdmin::Config::Fields.factory(self)
        else
          # parent is RailsAdmin::Config::Model, recursion is on Section's classes
          @_ro_fields ||= parent.send(self.class.superclass.to_s.underscore.split('/').last)._fields(true).freeze
        end
        readonly ? @_ro_fields : (@_fields ||= @_ro_fields.collect(&:clone))
      end
    end
  end
end