netzke-basepack 0.12.9 → 1.0.0.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. data/CHANGELOG.md +75 -44
  2. data/Gemfile +4 -2
  3. data/LICENSE +2 -6
  4. data/README.md +22 -24
  5. data/javascripts/basepack.js +0 -8
  6. data/javascripts/{columns.js → grid/columns.js} +59 -71
  7. data/javascripts/grid/event_handlers.js +218 -0
  8. data/javascripts/netzkeremotecombo.js +5 -13
  9. data/javascripts/tristate.js +62 -0
  10. data/javascripts/xdatetime.js +8 -37
  11. data/lib/netzke-basepack.rb +3 -2
  12. data/lib/netzke/basepack.rb +1 -1
  13. data/lib/netzke/basepack/action_column.rb +6 -23
  14. data/lib/netzke/basepack/active_record.rb +0 -6
  15. data/lib/netzke/basepack/attr_config.rb +20 -11
  16. data/lib/netzke/basepack/attribute_config.rb +10 -0
  17. data/lib/netzke/basepack/attributes.rb +196 -0
  18. data/lib/netzke/basepack/column_config.rb +47 -39
  19. data/lib/netzke/basepack/columns.rb +127 -97
  20. data/lib/netzke/basepack/data_accessor.rb +7 -48
  21. data/lib/netzke/basepack/data_adapters/abstract_adapter.rb +15 -17
  22. data/lib/netzke/basepack/data_adapters/active_record_adapter.rb +111 -90
  23. data/lib/netzke/basepack/dynamic_tab_panel.rb +3 -5
  24. data/lib/netzke/basepack/dynamic_tab_panel/{javascripts → client}/dynamic_tab_panel.js +6 -5
  25. data/lib/netzke/basepack/field_config.rb +30 -19
  26. data/lib/netzke/basepack/fields.rb +22 -12
  27. data/lib/netzke/basepack/grid_live_search.rb +1 -4
  28. data/lib/netzke/basepack/grid_live_search/{javascripts → client}/grid_live_search.js +9 -7
  29. data/lib/netzke/basepack/item_persistence.rb +3 -3
  30. data/lib/netzke/basepack/item_persistence/events_plugin.rb +8 -10
  31. data/lib/netzke/basepack/paging_form.rb +7 -11
  32. data/lib/netzke/basepack/paging_form/{javascripts → client}/paging_form.js +4 -4
  33. data/lib/netzke/basepack/query_builder.rb +12 -10
  34. data/lib/netzke/basepack/query_builder/{javascripts → client}/query_builder.js +14 -12
  35. data/lib/netzke/basepack/record_form_window.rb +8 -8
  36. data/lib/netzke/basepack/search_panel.rb +4 -6
  37. data/lib/netzke/basepack/search_panel/{javascripts → client}/condition_field.js +13 -16
  38. data/lib/netzke/basepack/search_panel/{javascripts → client}/search_panel.js +7 -7
  39. data/lib/netzke/basepack/search_window.rb +6 -6
  40. data/lib/netzke/basepack/simple_app/{javascripts → client}/statusbar_ext.js +0 -0
  41. data/lib/netzke/basepack/version.rb +1 -1
  42. data/lib/netzke/form/base.rb +166 -0
  43. data/lib/netzke/{basepack/form/javascripts/form.js → form/base/client/base.js} +77 -38
  44. data/lib/netzke/form/base/client/readonly_mode.css +4 -0
  45. data/lib/netzke/{basepack/form/javascripts → form/base/client}/readonly_mode.js +5 -5
  46. data/lib/netzke/form/endpoints.rb +33 -0
  47. data/lib/netzke/form/services.rb +74 -0
  48. data/lib/netzke/grid/actions.rb +52 -0
  49. data/lib/netzke/grid/base.rb +289 -0
  50. data/lib/netzke/{basepack/grid/javascripts → grid/base/client}/advanced_search.js +5 -1
  51. data/lib/netzke/{basepack/grid/javascripts/grid.js → grid/base/client/base.js} +61 -53
  52. data/lib/netzke/{basepack/grid/javascripts → grid/base/client}/extensions.js +19 -13
  53. data/lib/netzke/{basepack/grid/javascripts → grid/base/client}/remember_selection.js +0 -1
  54. data/lib/netzke/grid/client.rb +8 -0
  55. data/lib/netzke/grid/components.rb +55 -0
  56. data/lib/netzke/grid/configuration.rb +72 -0
  57. data/lib/netzke/grid/endpoints.rb +99 -0
  58. data/lib/netzke/grid/permissions.rb +18 -0
  59. data/lib/netzke/grid/services.rb +141 -0
  60. data/lib/netzke/tree/base.rb +173 -0
  61. data/lib/netzke/{basepack/tree/javascripts/tree.js → tree/base/client/base.js} +55 -26
  62. data/lib/netzke/{basepack/tree/javascripts → tree/base/client}/extensions.js +7 -7
  63. data/lib/netzke/tree/endpoints.rb +34 -0
  64. data/lib/netzke/{basepack/viewport.rb → viewport/base.rb} +3 -3
  65. data/lib/netzke/{basepack/window.rb → window/base.rb} +7 -8
  66. data/lib/netzke/window/base/client/base.js +26 -0
  67. data/locales/de.yml +49 -33
  68. data/locales/en.yml +32 -39
  69. data/locales/es.yml +39 -25
  70. data/locales/nl.yml +39 -25
  71. data/locales/ru.yml +38 -25
  72. data/locales/uk.yml +40 -26
  73. data/stylesheets/basepack.css +10 -0
  74. metadata +48 -45
  75. data/javascripts/mixins/grid_event_handlers.js +0 -139
  76. data/lib/netzke/basepack/accordion.rb +0 -45
  77. data/lib/netzke/basepack/active_record/relation_extensions.rb +0 -27
  78. data/lib/netzke/basepack/form.rb +0 -131
  79. data/lib/netzke/basepack/form/endpoints.rb +0 -35
  80. data/lib/netzke/basepack/form/services.rb +0 -74
  81. data/lib/netzke/basepack/form/stylesheets/readonly_mode.css +0 -14
  82. data/lib/netzke/basepack/grid.rb +0 -570
  83. data/lib/netzke/basepack/grid/endpoints.rb +0 -111
  84. data/lib/netzke/basepack/grid/javascripts/edit_in_form.js +0 -51
  85. data/lib/netzke/basepack/grid/services.rb +0 -148
  86. data/lib/netzke/basepack/tab_panel.rb +0 -22
  87. data/lib/netzke/basepack/tab_panel/javascripts/tab_panel.js +0 -11
  88. data/lib/netzke/basepack/tree.rb +0 -269
  89. data/lib/netzke/basepack/window/javascripts/window.js +0 -26
  90. data/lib/netzke/basepack/wrap_lazy_loaded.rb +0 -29
@@ -1,12 +1,6 @@
1
- require 'netzke/basepack/active_record/relation_extensions'
2
-
3
1
  module Netzke
4
2
  module Basepack
5
3
  module ActiveRecord
6
4
  end
7
5
  end
8
6
  end
9
-
10
- ::ActiveRecord::Relation.class_eval do
11
- include ::Netzke::Basepack::ActiveRecord::RelationExtensions
12
- end
@@ -1,41 +1,50 @@
1
1
  module Netzke
2
2
  module Basepack
3
- # Common parts of FieldConfig and ColumnConfig
3
+ # Base for FieldConfig and ColumnConfig
4
4
  class AttrConfig < ActiveSupport::OrderedOptions
5
- def initialize(c, data_adapter)
5
+ def initialize(c, model_adapter)
6
6
  c = {name: c.to_s} if c.is_a?(Symbol) || c.is_a?(String)
7
7
  c[:name] = c[:name].to_s
8
8
  self.replace(c)
9
9
 
10
- @data_adapter = data_adapter || NullDataAdapter.new(nil)
10
+ @model_adapter = model_adapter
11
11
  end
12
12
 
13
13
  def primary?
14
- @data_adapter.primary_key_attr?(self)
14
+ @model_adapter.primary_key_attr?(self)
15
15
  end
16
16
 
17
17
  def association?
18
- @data_adapter.association_attr?(self)
18
+ @model_adapter.association_attr?(self)
19
19
  end
20
20
 
21
- def set_defaults!
22
- set_read_only! if read_only.nil?
21
+ def set_defaults
22
+ set_read_only if read_only.nil?
23
23
  end
24
24
 
25
- def set_read_only!
25
+ def set_read_only
26
26
  self.read_only = primary? ||
27
27
  !responded_to_by_model? &&
28
28
  !association?
29
+ self.delete(:read_only) if read_only == false
29
30
  end
30
31
 
31
32
  private
32
33
 
34
+ def default_label
35
+ if association?
36
+ @model_adapter.human_attribute_name(name.split("__").first)
37
+ else
38
+ @model_adapter.human_attribute_name(name)
39
+ end
40
+ end
41
+
33
42
  def responded_to_by_model?
34
43
  # if no model class is provided, assume the attribute is being responded to
35
- @data_adapter.model_class.nil? ||
44
+ @model_adapter.model.nil? ||
36
45
  !setter.nil? ||
37
- @data_adapter.model_class.instance_methods.include?(:"#{name}=") ||
38
- @data_adapter.model_class.attribute_names.include?(name)
46
+ @model_adapter.model.instance_methods.include?(:"#{name}=") ||
47
+ @model_adapter.model.attribute_names.include?(name)
39
48
  end
40
49
  end
41
50
  end
@@ -0,0 +1,10 @@
1
+ module Netzke
2
+ module Basepack
3
+ # TODO get rid
4
+ class AttributeConfig < ActiveSupport::OrderedOptions
5
+ def initialize(name)
6
+ self.name = name.to_s
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,196 @@
1
+ module Netzke
2
+ module Basepack
3
+ # This module is encluded in +Grid+, +Form+, and +Tree+. It allows configuring specific model attributes.
4
+ #
5
+ # To override default configuration for a model attribute (e.g. to change its label or read-only property) use the
6
+ # +attribute_overrides+ configuration option for the component, or the +attribute+ DSL method. This will have effect
7
+ # on both columns and form fields.
8
+ #
9
+ # For example, to make the address attribute read-only:
10
+ #
11
+ # class Users < Netzke::Grid::Base
12
+ # def configure(c)
13
+ # super
14
+ # c.model = User
15
+ # end
16
+ #
17
+ # attribute :address do |c|
18
+ # c.read_only = true
19
+ # end
20
+ # end
21
+ #
22
+ # Using the +attribute_overrides+ config option may be handy when building composite components. E.g. in a tab panel
23
+ # nesting multiple grids, you may want to override specific attributes for a specific grid:
24
+ #
25
+ # class ManagmentPanel < Netzke::Base
26
+ # client_class do |c|
27
+ # c.extend = "Ext.tab.Panel"
28
+ # end
29
+ #
30
+ # def configure(c)
31
+ # super
32
+ # c.items = [:users, :roles]
33
+ # end
34
+ #
35
+ # component :users do |c|
36
+ # c.attribute_overrides = {
37
+ # birth_date: {
38
+ # excluded: true # exclude this column from the grid and forms
39
+ # }
40
+ # }
41
+ # end
42
+ #
43
+ # component :roles
44
+ # end
45
+ #
46
+ # The following attribute config options are available:
47
+ #
48
+ # [read_only]
49
+ #
50
+ # A boolean that defines whether the attribute should be editable via grid/form.
51
+ #
52
+ # [getter]
53
+ #
54
+ # A lambda that receives a record as a parameter, and is expected to return the value used in the grid cell or
55
+ # form field, e.g.:
56
+ #
57
+ # getter: lambda {|r| [r.first_name, r.last_name].join }
58
+ #
59
+ # In case of relation used in relation, passes the last record to lambda, e.g.:
60
+ #
61
+ # name: author__books__first__name, getter: lambda {|r| r.title }
62
+ # r #=> author.books.first
63
+ #
64
+ # [setter]
65
+ #
66
+ # A lambda that receives a record as first parameter, and the value passed from the cell/field as the second parameter,
67
+ # and is expected to modify the record accordingly, e.g.:
68
+ #
69
+ # setter: lambda {|r,v| r.first_name, r.last_name = v.split(" ") }
70
+ #
71
+ # [scope]
72
+ #
73
+ # The scope for association attribute. Same syntax applies as for scoping out records for the grid.
74
+ #
75
+ # [filter_association_with]
76
+ #
77
+ # A Proc object that receives the relation and the value to filter by. Example:
78
+ #
79
+ # column :author__name do |c|
80
+ # c.filter_association_with = lambda {|rel, value| rel.where("first_name like ? or last_name like ?", "%#{value}%", "%#{value}%" ) }
81
+ # end
82
+ #
83
+ # [format]
84
+ #
85
+ # The format to display data in case of date and datetime attributes, e.g. 'Y-m-d g:i:s'.
86
+ #
87
+ # [excluded]
88
+ #
89
+ # When true, this attribute will not be used
90
+ #
91
+ # [meta]
92
+ #
93
+ # When set to +true+, the data for this column will be available in the grid store, but the actual column won't be
94
+ # created (as if +excluded+ were set to +true+).
95
+ #
96
+ # [type]
97
+ #
98
+ # When adding a virtual attribute to the grid, it may be useful to specify its type, so the column editor (and the
99
+ # form field) are configured properly.
100
+ #
101
+ # [column_config]
102
+ #
103
+ # Configuration specific for the corresponding grid column. For example:
104
+ #
105
+ # attribute :address do |c|
106
+ # c.column_config = { width: 200 }
107
+ # end
108
+ #
109
+ # [field_config]
110
+ #
111
+ # Configuration for the corresponding form field. For example:
112
+ #
113
+ # attribute :address do |c|
114
+ # c.field_config = { xtype: :displayfield }
115
+ # end
116
+ #
117
+ # [editor_config]
118
+ #
119
+ # Additional configuration for column editor and form field (which are usually represented by the same Ext field
120
+ # component). Any common Ext config option like `min_chars` and `format` are accepted. Besides, Netzke extends it
121
+ # with some extras:
122
+ #
123
+ # [blank_line]
124
+ #
125
+ # The blank line for one-to-many association columns, defaults to "---". Set to false to exclude completely.
126
+ #
127
+ # [date_format]
128
+ #
129
+ # In case of datetime type, the format date must be entered in the editor.
130
+ #
131
+ # [time_format]
132
+ #
133
+ # In case of datetime type, the format time must be entered in the editor.
134
+ module Attributes
135
+ extend ActiveSupport::Concern
136
+
137
+ ATTRIBUTE_METHOD_NAME = "%s_attribute"
138
+
139
+ included do
140
+ class_attribute :declared_attribute_names
141
+ self.declared_attribute_names = []
142
+ end
143
+
144
+ module ClassMethods
145
+ # Adds/overrides an attribute config, e.g.:
146
+ #
147
+ # attribute :price do |c|
148
+ # c.read_only = true
149
+ # end
150
+ def attribute(name, &block)
151
+ method_name = ATTRIBUTE_METHOD_NAME % name
152
+ define_method(method_name, &block)
153
+
154
+ # we *must* use a writer here
155
+ self.declared_attribute_names = declared_attribute_names + [name]
156
+ end
157
+ end
158
+
159
+ def attribute_overrides
160
+ return @attribute_overrides if @attribute_overrides
161
+
162
+ declared = self.class.declared_attribute_names.reduce({}) do |res, name|
163
+ c = AttributeConfig.new(name)
164
+ augment_attribute_config(c)
165
+ res.merge!(name => c)
166
+ end
167
+
168
+ @attribute_overrides = (config.attribute_overrides || {}).deep_merge(declared)
169
+ end
170
+
171
+ def augment_attribute_config(c)
172
+ send(ATTRIBUTE_METHOD_NAME % c.name, c)
173
+ end
174
+
175
+ def association_attr?(attr)
176
+ !!attr[:name].to_s.index("__")
177
+ end
178
+
179
+ # Returns a hash of association attribute default values. Used when creating new records with association attributes that have a default value.
180
+ def association_value_defaults(cols)
181
+ @_default_association_values ||= {}.tap do |values|
182
+ cols.each do |c|
183
+ next unless association_attr?(c) && c[:default_value]
184
+
185
+ assoc_name, assoc_method = c[:name].split '__'
186
+ assoc_class = model_adapter.class_for(assoc_name)
187
+ assoc_data_adapter = Netzke::Basepack::DataAdapters::AbstractAdapter.adapter_class(assoc_class).new(assoc_class)
188
+ ::Rails.logger.debug "\n!!! assoc_data_adapter.class: #{assoc_data_adapter.class.inspect}\n"
189
+ assoc_instance = assoc_data_adapter.find_record c[:default_value]
190
+ values[c[:name]] = assoc_instance.send(assoc_method)
191
+ end
192
+ end
193
+ end
194
+ end
195
+ end
196
+ end
@@ -1,6 +1,6 @@
1
1
  module Netzke
2
2
  module Basepack
3
- # Takes care of automatic column configuration in {Basepack::Grid}
3
+ # Takes care of automatic column configuration in {Grid::Base}
4
4
  class ColumnConfig < AttrConfig
5
5
  # These config options can be ommitted from config, as they are assumed by default at the JS side
6
6
  COMMON_DEFAULTS = {
@@ -12,20 +12,30 @@ module Netzke
12
12
  assoc: false
13
13
  }
14
14
 
15
- def set_defaults!
15
+ def merge_attribute(attr)
16
+ self.merge!(attr)
17
+
18
+ self.text = delete(:label) if self.has_key?(:label)
19
+
20
+ self.merge!(delete(:column_config)) if self.has_key?(:column_config)
21
+
22
+ self.delete(:field_config) if self.has_key?(:field_config)
23
+ end
24
+
25
+ def set_defaults
16
26
  super
17
27
 
18
- self.attr_type ||= @data_adapter.attr_type(name)
28
+ self.type ||= @model_adapter.attr_type(name)
19
29
 
20
- set_xtype! if xtype.nil?
30
+ set_xtype if xtype.nil?
21
31
 
22
- self.virtual = @data_adapter.virtual_attribute?(self)
32
+ self.virtual = @model_adapter.virtual_attribute?(self)
23
33
 
24
- self.text ||= label || @data_adapter.human_attribute_name(name)
34
+ self.text ||= label || default_label
25
35
 
26
- set_editor!
36
+ set_editor
27
37
 
28
- set_width! if width.nil?
38
+ set_width if width.nil?
29
39
 
30
40
  self.hidden = primary? if hidden.nil?
31
41
 
@@ -35,81 +45,79 @@ module Netzke
35
45
 
36
46
  self.assoc = association? # used at the JS side
37
47
 
38
- remove_defaults! # options that are implied by Ext JS by default, thus don't have to be passed
48
+ remove_defaults # options that are implied by Ext JS by default, thus don't have to be passed
39
49
  end
40
50
 
41
- def set_xtype!
51
+ def set_xtype
42
52
  # if user set those manually, we don't mess with column xtype
43
53
  return if renderer || editor
44
- xtype = xtype_for_attr_type(attr_type)
54
+ xtype = xtype_for_type(type)
45
55
  self.xtype = xtype unless xtype.nil?
46
56
  end
47
57
 
48
- def xtype_for_attr_type(type)
58
+ def xtype_for_type(type)
49
59
  { :boolean => :checkcolumn,
50
60
  :date => :datecolumn
51
61
  }[type]
52
62
  end
53
63
 
54
- def set_editor!
64
+ def set_editor
55
65
  # if shouldn't be editable, don't set any default editor
56
66
  return if read_only
57
67
 
58
68
  passed_editor = editor
59
69
 
60
70
  if association?
61
- set_default_association_editor!
71
+ set_default_association_editor
62
72
  else
63
- self.editor = editor_for_attr_type(attr_type)
73
+ self.editor = editor_for_type(type)
64
74
  end
65
75
 
66
76
  self.editor.merge!(passed_editor) if passed_editor
67
77
  end
68
78
 
69
79
  # Detects an association column and sets up the proper editor.
70
- def set_default_association_editor!
80
+ def set_default_association_editor
71
81
  assoc, assoc_method = name.split('__')
72
82
 
73
- assoc_method_type = @data_adapter.get_assoc_property_type assoc, assoc_method
83
+ assoc_method_type = @model_adapter.get_assoc_property_type assoc, assoc_method
74
84
 
75
85
  # if association column is boolean, display a checkbox (or alike), otherwise - a combobox (or alike)
76
86
  if nested_attribute
77
- self.editor = editor_for_attr_type(assoc_method_type)
87
+ self.editor = editor_for_type(assoc_method_type)
78
88
  else
79
- self.editor = assoc_method_type == :boolean ? editor_for_attr_type(:boolean) : {xtype: :netzkeremotecombo}
89
+ self.editor = assoc_method_type == :boolean ? editor_for_type(:boolean) : {xtype: :netzkeremotecombo}
80
90
  end
81
91
  end
82
92
 
83
93
  # Column editor config for attribute type.
84
- def editor_for_attr_type(type)
85
- {xtype: attr_type_to_editor_xtype_map(type)}
94
+ def editor_for_type(type)
95
+ {xtype: type_to_editor_xtype(type)}
96
+ end
97
+
98
+ def type_to_editor_xtype(type)
99
+ type_to_editor_xtype_map[type] || :textfield
86
100
  end
87
101
 
88
102
  # Hash that maps a column type to the editor xtype. Override if you want different editors.
89
- def attr_type_to_editor_xtype_map(type)
90
- { :integer => :numberfield,
91
- :boolean => :checkbox,
92
- :date => :datefield,
93
- :datetime => :xdatetime,
94
- :text => :textarea,
95
- :string => :textfield
96
- }[type] || :textfield
103
+ def type_to_editor_xtype_map
104
+ {
105
+ integer: :numberfield,
106
+ boolean: :checkbox,
107
+ date: :datefield,
108
+ datetime: :xdatetime,
109
+ text: :textarea,
110
+ string: :textfield
111
+ }
97
112
  end
98
113
 
99
- def set_width!
100
- self.width = case attr_type
101
- when :boolean
102
- 50
103
- when :datetime
104
- 150
105
- else
106
- 120
107
- end
114
+ def set_width
115
+ self.width = 150 if type == :datetime
108
116
  end
109
117
 
110
118
  ##
111
119
  # @return self
112
- def remove_defaults!
120
+ def remove_defaults
113
121
  COMMON_DEFAULTS.each_pair {|k,v| self.delete(k) if v == self[k]}
114
122
  self
115
123
  end
@@ -1,7 +1,48 @@
1
1
  module Netzke
2
2
  module Basepack
3
3
  # Takes care of grid column configuration, as well as the grid's default form fields
4
- # TODO: refactor using Netzke::Core::DslSupport
4
+ # +Grid::Base+ extends common Ext JS column options with the following ones:
5
+ #
6
+ # [sorting_scope]
7
+ #
8
+ # A Proc object used for sorting by the column. This can be useful for sorting by a virtual column. The Proc
9
+ # object will get the relation as the first parameter, and the sorting direction as the second. Example:
10
+ #
11
+ # columns => [{ name: "complete_user_name", sorting_scope: lambda {|rel, dir| order("users.first_name #{dir.to_s}, users.last_name #{dir.to_s}") }, ...]
12
+ #
13
+ # [filter_with]
14
+ #
15
+ # A Proc object that receives the relation, the value to filter by and the operator. This allows for more flexible
16
+ # handling of basic filters and enables filtering of virtual columns. Example:
17
+ #
18
+ # columns => [{ name: "complete_user_name", filter_with: lambda{|rel, value, op| rel.where("first_name like ? or last_name like ?", "%#{value}%", "%#{value}%" ) } }, ...]
19
+ #
20
+ # [filterable]
21
+ #
22
+ # Set to false to disable filtering on this column
23
+ #
24
+ # [editor]
25
+ #
26
+ # A hash that will override the automatic editor configuration. For example, for one-to-many association column
27
+ # you may set it to +{min_chars: 1}+, which will be passed to the combobox and make it query its remote data after
28
+ # entering 1 character (instead of default 4).
29
+ #
30
+ # === Configuring default filters on grid columns
31
+ #
32
+ # Default Filters can either be configured on the grid itself
33
+ #
34
+ # def configure(c)
35
+ # super
36
+ # c.default_filters = [{name: "Mark"}, {age: {gt: 10}}]
37
+ # end
38
+ #
39
+ # or as a component configuration
40
+ #
41
+ # component :tasks |c|
42
+ # c.klass = TaskGrid
43
+ # c.default_filters = [{due_date: {before: Time.now}}]
44
+ # end
45
+ #
5
46
  module Columns
6
47
  extend ActiveSupport::Concern
7
48
 
@@ -13,11 +54,6 @@ module Netzke
13
54
  end
14
55
 
15
56
  module ClassMethods
16
- def inherited(klass)
17
- klass.class_attribute :declared_columns
18
- klass.declared_columns = []
19
- end
20
-
21
57
  # Adds/overrides a column config, e.g.:
22
58
  #
23
59
  # column :title do |c|
@@ -28,53 +64,47 @@ module Netzke
28
64
  def column(name, &block)
29
65
  method_name = COLUMN_METHOD_NAME % name
30
66
  define_method(method_name, &block)
31
- self.declared_columns << name
67
+ self.declared_columns = [*declared_columns, name]
32
68
  end
33
69
  end
34
70
 
35
71
  # Returns the list of (non-normalized) columns to be used. By default returns the list of model column names and declared columns.
36
72
  # Can be overridden.
37
73
  def columns
38
- config.columns || default_columns
39
- end
40
-
41
- # Columns from model + columns declared with DSL
42
- def default_columns
43
- (data_adapter.model_attributes + self.class.declared_columns).uniq
74
+ config.columns || model_adapter.model_attributes
44
75
  end
45
76
 
46
77
  # An array of complete columns configs ready to be passed to the JS side.
47
- # The +options+ hash can have the following keys:
48
- # * :with_excluded - when true, include the columns that are marked as excluded
49
- # * :with_meta - when true, include the meta column
50
- def final_columns(options = {})
51
- # memoize
52
- @_final_columns ||= {}
53
- @_final_columns[options] ||= [].tap do |cols|
78
+ def final_columns
79
+ @final_columns ||= [].tap do |cols|
54
80
  has_primary_column = false
55
81
 
56
82
  columns.each do |c|
57
- c = Netzke::Basepack::ColumnConfig.new(c, data_adapter)
58
-
59
- # merge with column declaration
60
- send(:"#{c.name}_column", c) if respond_to?(:"#{c.name}_column")
83
+ c = build_column_config(c)
84
+ next if c.excluded
61
85
 
62
- # detect primary key column
63
86
  has_primary_column ||= c.primary?
64
-
65
- if (!c.excluded || options[:with_excluded]) && (!c.meta || options[:with_meta])
66
- # set the defaults as lowest priority
67
- augment_column_config(c)
68
-
69
- cols << c # if options[:with_excluded] || !c.excluded
70
- end
87
+ cols << c
71
88
  end
72
89
 
73
- insert_primary_column(cols) if !has_primary_column
74
- append_meta_column(cols) if options[:with_meta]
90
+ insert_primary_column(cols) unless has_primary_column
91
+ append_association_values_column(cols)
92
+ end
93
+ end
94
+
95
+ def build_column_config(c)
96
+ Netzke::Basepack::ColumnConfig.new(c, model_adapter).tap do |c|
97
+ attribute_config = attribute_overrides[c.name.to_sym]
98
+ c.merge_attribute(attribute_config) if attribute_config
99
+ augment_column_config(c)
75
100
  end
76
101
  end
77
102
 
103
+ # Array of complete config hashes for non-meta columns
104
+ def non_meta_columns
105
+ @non_meta_columns ||= final_columns.reject{|c| c[:meta]}
106
+ end
107
+
78
108
  # Columns as a hash, for easier access to a specific column
79
109
  def final_columns_hash
80
110
  @_final_columns_hash ||= final_columns.inject({}){|r,c| r.merge(c[:name].to_sym => c)}
@@ -82,89 +112,107 @@ module Netzke
82
112
 
83
113
  # Columns that have to be used by the JS side of the grid
84
114
  def js_columns
85
- final_columns(with_meta: true).map do |c|
115
+ final_columns.map do |c|
86
116
  # we are removing the editor on this last step, so that the editor config is still being passed from the
87
117
  # column config to the form editor; refactor!
88
- c.delete(:editor) if !config.enable_edit_inline
118
+ c.delete(:editor) unless config.edit_inline
89
119
  c
90
120
  end
91
121
  end
92
122
 
93
- def append_meta_column(cols)
94
- cols << {}.tap do |c|
95
- c.merge!(
96
- :name => "meta",
97
- :meta => true,
98
- :getter => lambda do |r|
99
- meta_data(r)
100
- end
101
- )
102
- c[:default_value] = meta_default_data if meta_default_data.present?
123
+ def append_association_values_column(cols)
124
+ cols << Netzke::Basepack::AttrConfig.new("association_values", model_adapter).tap do |c|
125
+ c.meta = true
126
+ c.getter = lambda do |r|
127
+ model_adapter.assoc_values(r, final_columns_hash).netzke_literalize_keys
128
+ end
129
+ defaults = association_value_defaults(cols).netzke_literalize_keys
130
+ c.default_value = defaults if defaults.present?
103
131
  end
104
132
  end
105
133
 
106
134
  def insert_primary_column(cols)
107
- primary_key = data_adapter.primary_key
108
- raise "Model #{data_adapter.model_class.name} does not have a primary column" if primary_key.blank?
109
- c = Netzke::Basepack::ColumnConfig.new(data_adapter.primary_key, data_adapter)
110
- send(:"#{c.name}_column", c) if respond_to?(:"#{c.name}_column")
135
+ primary_key = model_adapter.primary_key
136
+ raise "Model #{model_adapter.model.name} does not have a primary column" if primary_key.blank?
137
+ c = Netzke::Basepack::ColumnConfig.new(model_adapter.primary_key, model_adapter)
138
+ c.merge_attribute(attribute_overrides[c.name.to_sym]) if attribute_overrides.has_key?(c.name.to_sym)
111
139
  augment_column_config(c)
112
140
  cols.insert(0, c)
113
141
  end
114
142
 
115
- # default_value for the meta column; used when a new record is being created in the grid
116
- def meta_default_data
117
- default_association_values(final_columns_hash).present? ? { :association_values => default_association_values(final_columns_hash).netzke_literalize_keys } : {}
143
+ # Default form items (non-normalized) that will be displayed in the Add/Edit forms
144
+ def default_form_items
145
+ non_meta_columns.map{|c| c.name.to_sym}
118
146
  end
119
147
 
120
- # Override it when you need extra meta data to be passed through the meta column
121
- def meta_data(r)
122
- { :association_values => data_adapter.assoc_values(r, final_columns_hash).netzke_literalize_keys }
148
+ # ATM the same attributes are used as in forms
149
+ def attributes_for_search
150
+ non_meta_columns.map do |c|
151
+ {name: c.name, text: c.text, type: c.type}.tap do |a|
152
+ if c[:assoc]
153
+ a[:text].sub!(" ", " ")
154
+ end
155
+ end
156
+ end
123
157
  end
124
158
 
125
- protected
159
+ # Form items that will be used by the Add/Edit forms. May be useful overriding it.
160
+ def form_items
161
+ config.form_items || default_form_items
162
+ end
126
163
 
127
- # Default fields that will be displayed in the Add/Edit/Search forms
128
- # When overriding this method, keep in mind that the fields inside the layout must be expanded (each field represented by a hash, not just a symbol)
129
- def default_fields_for_forms
130
- columns_taken_over_to_forms.map do |c|
131
- (c[:editor] || {}).tap do |f|
132
- %w(name read_only setter getter scope format).each do |key|
133
- f[key.to_sym] = c[key.to_sym]
164
+ private
165
+
166
+ def populate_columns_with_filters(c)
167
+ c.default_filters.each do |filter|
168
+ c.columns[:items].each do |column|
169
+ if column[:name].to_sym == filter[:column].to_sym
170
+ extend_column_with_filter(column, filter)
134
171
  end
135
- f[:field_label] = c.text || c.header
136
172
  end
137
173
  end
174
+ c.delete(:default_filters)
138
175
  end
139
176
 
140
- # ATM the same attributes are used as in forms
141
- def attributes_for_search
142
- columns_taken_over_to_forms.map do |c|
143
- {name: c.name, text: c.text, attr_type: c.attr_type}.tap do |a|
144
- if c[:assoc]
145
- a[:text].sub!(" ", " ")
146
- end
177
+ def extend_column_with_filter(column, filter)
178
+ if filter[:value].is_a?(Hash)
179
+ val = {}
180
+ filter[:value].each do |k,v|
181
+ val[k] = (v.is_a?(Time) || v.is_a?(Date) || v.is_a?(ActiveSupport::TimeWithZone)) ? Netzke::Core::JsonLiteral.new("new Date('#{v.strftime("%m/%d/%Y")}')") : v
147
182
  end
183
+ else
184
+ val = filter[:value]
185
+ end
186
+ new_filter = {value: val, active: true}
187
+ if column[:filter]
188
+ column[:filter].merge! new_filter
189
+ else
190
+ column[:filter] = new_filter
148
191
  end
149
192
  end
150
193
 
151
- private
194
+ # Extends passed column config with DSL declaration for this column
195
+ def apply_column_dsl(c)
196
+ method_name = COLUMN_METHOD_NAME % c.name
197
+ send(method_name, c) if respond_to?(method_name)
198
+ end
152
199
 
153
200
  # Based on initial column config, e.g.:
154
201
  #
155
- # {:name=>"author__name", :attr_type=>:string}
202
+ # {:name=>"author__name", :type=>:string}
156
203
  #
157
204
  # augment it with additional configuration params, e.g.:
158
205
  #
159
- # {:name=>"author__name", :attr_type=>:string, :editor=>{:xtype=>:netzkeremotecombo}, :assoc=>true, :virtual=>true, :header=>"Author name", :sortable=>false, :filterable=>false}
206
+ # {:name=>"author__name", :type=>:string, :editor=>{:xtype=>:netzkeremotecombo}, :assoc=>true, :virtual=>true, :header=>"Author", :sortable=>false, :filterable=>false}
160
207
  #
161
208
  # It may be handy to override it.
162
209
  def augment_column_config(c)
163
- c.set_defaults!
210
+ apply_column_dsl(c)
211
+ c.set_defaults
164
212
  end
165
213
 
166
214
  def initial_columns_order
167
- final_columns.map do |c|
215
+ non_meta_columns.map do |c|
168
216
  # copy the values that are not null
169
217
  {name: c[:name]}.tap do |r|
170
218
  r[:width] = c[:width] if c[:width]
@@ -188,32 +236,14 @@ module Netzke
188
236
  init_column_names != stored_column_names
189
237
  end
190
238
 
191
- # Selects those columns that make sense to be shown in forms
192
- def columns_taken_over_to_forms
193
- final_columns.select {|c| include_in_forms?(c) && !exclude_from_forms?(c)}
194
- end
195
-
196
- def include_in_forms?(c)
197
- !c.getter.nil? ||
198
- !c.setter.nil? ||
199
- data_adapter.attribute_names.include?(c[:name]) ||
200
- data_class.instance_methods.include?(c[:name].to_sym) ||
201
- data_class.instance_methods.include?(:"#{c[:name]}=") ||
202
- association_attr?(c)
203
- end
204
-
205
- def exclude_from_forms?(c)
206
- c[:type] == :action
207
- end
208
-
209
239
  def columns_default_values
210
- final_columns.inject({}) do |r,c|
240
+ non_meta_columns.inject({}) do |r,c|
211
241
  assoc_name, assoc_method = c[:name].split '__'
212
242
  if c[:default_value].nil?
213
243
  r
214
244
  else
215
245
  if assoc_method
216
- r.merge(data_adapter.foreign_key_for(assoc_name) || data_adapter.foreign_key_for(assoc_name) => c[:default_value])
246
+ r.merge(model_adapter.foreign_key_for(assoc_name) || model_adapter.foreign_key_for(assoc_name) => c[:default_value])
217
247
  else
218
248
  r.merge(c[:name] => c[:default_value])
219
249
  end