netzke-basepack 0.7.7 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (192) hide show
  1. data/.travis.yml +15 -10
  2. data/{CHANGELOG.rdoc → CHANGELOG.md} +146 -110
  3. data/LICENSE +7 -1
  4. data/README.md +47 -56
  5. data/Rakefile +5 -5
  6. data/config/before-travis.sh +10 -0
  7. data/javascripts/basepack.js +0 -130
  8. data/javascripts/netzkeremotecombo.js +59 -0
  9. data/lib/netzke/basepack.rb +9 -14
  10. data/lib/netzke/basepack/accordion.rb +45 -0
  11. data/lib/netzke/basepack/active_record.rb +12 -0
  12. data/lib/netzke/basepack/active_record/relation_extensions.rb +27 -0
  13. data/lib/netzke/basepack/columns.rb +309 -0
  14. data/lib/netzke/basepack/data_accessor.rb +22 -12
  15. data/lib/netzke/basepack/data_adapters/abstract_adapter.rb +75 -11
  16. data/lib/netzke/basepack/data_adapters/active_record_adapter.rb +154 -49
  17. data/lib/netzke/basepack/fields.rb +162 -0
  18. data/lib/netzke/basepack/form.rb +136 -0
  19. data/lib/netzke/basepack/{form_panel → form}/javascripts/comma_list_cbg.js +0 -1
  20. data/lib/netzke/basepack/{form_panel/javascripts/form_panel.js → form/javascripts/form.js} +20 -26
  21. data/lib/netzke/basepack/{form_panel → form}/javascripts/n_radio_group.js +0 -1
  22. data/lib/netzke/basepack/{form_panel → form}/javascripts/readonly_mode.js +0 -0
  23. data/lib/netzke/basepack/form/services.rb +115 -0
  24. data/lib/netzke/basepack/{form_panel → form}/stylesheets/readonly_mode.css +0 -0
  25. data/lib/netzke/basepack/grid.rb +355 -0
  26. data/lib/netzke/basepack/{grid_panel → grid}/javascripts/advanced_search.js +1 -1
  27. data/lib/netzke/basepack/{grid_panel → grid}/javascripts/check_column_fix.js +0 -0
  28. data/lib/netzke/basepack/{grid_panel → grid}/javascripts/edit_in_form.js +3 -3
  29. data/lib/netzke/basepack/{grid_panel → grid}/javascripts/event_handling.js +5 -2
  30. data/lib/netzke/basepack/{grid_panel/javascripts/grid_panel.js → grid/javascripts/grid.js} +120 -132
  31. data/lib/netzke/basepack/{grid_panel → grid}/javascripts/misc.js +0 -0
  32. data/lib/netzke/basepack/grid/services.rb +216 -0
  33. data/lib/netzke/basepack/item_persistence.rb +44 -0
  34. data/lib/netzke/basepack/item_persistence/events_plugin.rb +47 -0
  35. data/lib/netzke/basepack/{paging_form_panel.rb → paging_form.rb} +24 -30
  36. data/lib/netzke/basepack/{paging_form_panel/javascripts/paging_form_panel.js → paging_form/javascripts/paging_form.js} +2 -4
  37. data/lib/netzke/basepack/query_builder.rb +44 -73
  38. data/lib/netzke/basepack/query_builder/javascripts/query_builder.js +16 -2
  39. data/lib/netzke/basepack/record_form_window.rb +67 -0
  40. data/lib/netzke/basepack/search_panel.rb +22 -24
  41. data/lib/netzke/basepack/search_panel/javascripts/condition_field.js +2 -2
  42. data/lib/netzke/basepack/search_window.rb +47 -53
  43. data/lib/netzke/basepack/simple_app.rb +10 -13
  44. data/lib/netzke/basepack/simple_app/javascripts/simple_app.js +2 -8
  45. data/lib/netzke/basepack/tab_panel.rb +5 -4
  46. data/lib/netzke/basepack/tab_panel/javascripts/tab_panel.js +5 -5
  47. data/lib/netzke/basepack/version.rb +2 -2
  48. data/lib/netzke/basepack/viewport.rb +16 -0
  49. data/lib/netzke/basepack/window.rb +27 -18
  50. data/lib/netzke/basepack/window/javascripts/window.js +7 -1
  51. data/lib/netzke/basepack/wrap_lazy_loaded.rb +18 -18
  52. data/locales/en.yml +40 -24
  53. data/netzke-basepack.gemspec +51 -82
  54. data/stylesheets/basepack.css +0 -41
  55. data/test/basepack_test_app/Gemfile +9 -46
  56. data/test/basepack_test_app/Gemfile.lock +61 -96
  57. data/test/basepack_test_app/app/components/author_form.rb +8 -5
  58. data/test/basepack_test_app/app/components/author_grid.rb +2 -2
  59. data/test/basepack_test_app/app/components/book_form.rb +34 -31
  60. data/test/basepack_test_app/app/components/book_form_with_defaults.rb +6 -7
  61. data/test/basepack_test_app/app/components/book_form_with_file_upload.rb +10 -0
  62. data/test/basepack_test_app/app/components/book_form_with_nested_attributes.rb +5 -6
  63. data/test/basepack_test_app/app/components/book_grid.rb +19 -8
  64. data/test/basepack_test_app/app/components/book_grid_filtering.rb +4 -7
  65. data/test/basepack_test_app/app/components/book_grid_loader.rb +28 -15
  66. data/test/basepack_test_app/app/components/book_grid_with_custom_columns.rb +45 -21
  67. data/test/basepack_test_app/app/components/book_grid_with_default_values.rb +26 -8
  68. data/test/basepack_test_app/app/components/book_grid_with_excluded_columns.rb +11 -0
  69. data/test/basepack_test_app/app/components/book_grid_with_extra_feedback.rb +2 -2
  70. data/test/basepack_test_app/app/components/book_grid_with_extra_filters.rb +7 -6
  71. data/test/basepack_test_app/app/components/book_grid_with_mass_assignment_security.rb +9 -0
  72. data/test/basepack_test_app/app/components/book_grid_with_nested_attributes.rb +9 -9
  73. data/test/basepack_test_app/app/components/book_grid_with_overridden_columns.rb +5 -3
  74. data/test/basepack_test_app/app/components/book_grid_with_paging.rb +6 -8
  75. data/test/basepack_test_app/app/components/book_grid_with_persistence.rb +6 -4
  76. data/test/basepack_test_app/app/components/book_grid_with_scope.rb +6 -0
  77. data/test/basepack_test_app/app/components/book_grid_with_scoped_authors.rb +10 -7
  78. data/test/basepack_test_app/app/components/book_grid_with_virtual_attributes.rb +21 -13
  79. data/test/basepack_test_app/app/components/book_paging_form.rb +21 -0
  80. data/test/basepack_test_app/app/components/book_query_builder.rb +7 -6
  81. data/test/basepack_test_app/app/components/book_with_custom_primary_key_grid.rb +6 -7
  82. data/test/basepack_test_app/app/components/books_bound_to_author.rb +9 -7
  83. data/test/basepack_test_app/app/components/border_layout_panel_with_persistence.rb +12 -0
  84. data/test/basepack_test_app/app/components/double_book_grid.rb +19 -14
  85. data/test/basepack_test_app/app/components/form_without_model.rb +15 -16
  86. data/test/basepack_test_app/app/components/grid_with_initial_sorting.rb +7 -0
  87. data/test/basepack_test_app/app/components/grid_with_inline_data.rb +7 -0
  88. data/test/basepack_test_app/app/components/paging_form_with_search.rb +2 -2
  89. data/test/basepack_test_app/app/components/panel_with_persistent_regions.rb +35 -0
  90. data/test/basepack_test_app/app/components/query_builder.rb +7 -0
  91. data/test/basepack_test_app/app/components/simple_panel.rb +16 -11
  92. data/test/basepack_test_app/app/components/simple_window.rb +7 -6
  93. data/test/basepack_test_app/app/components/some_accordion.rb +18 -0
  94. data/test/basepack_test_app/app/components/some_auth_app.rb +5 -5
  95. data/test/basepack_test_app/app/components/some_border_layout.rb +20 -20
  96. data/test/basepack_test_app/app/components/some_search_panel.rb +6 -0
  97. data/test/basepack_test_app/app/components/some_simple_app.rb +30 -16
  98. data/test/basepack_test_app/app/components/some_tab_panel.rb +18 -15
  99. data/test/basepack_test_app/app/components/user_form.rb +18 -16
  100. data/test/basepack_test_app/app/components/user_form_with_default_fields.rb +5 -6
  101. data/test/basepack_test_app/app/components/user_grid.rb +11 -6
  102. data/test/basepack_test_app/app/components/user_grid_with_customized_form_fields.rb +5 -3
  103. data/test/basepack_test_app/app/components/window_component_loader.rb +25 -21
  104. data/test/basepack_test_app/app/models/address.rb +0 -26
  105. data/test/basepack_test_app/app/models/author.rb +0 -31
  106. data/test/basepack_test_app/app/models/book.rb +1 -42
  107. data/test/basepack_test_app/app/models/book_with_custom_primary_key.rb +1 -23
  108. data/test/basepack_test_app/app/models/role.rb +0 -21
  109. data/test/basepack_test_app/app/models/user.rb +0 -24
  110. data/test/basepack_test_app/app/views/layouts/components.html.erb +1 -1
  111. data/test/basepack_test_app/config/application.rb +1 -1
  112. data/test/basepack_test_app/config/database.yml.travis +2 -6
  113. data/test/basepack_test_app/config/initializers/netzke.rb +1 -6
  114. data/test/basepack_test_app/db/schema.rb +14 -14
  115. data/test/basepack_test_app/features/accordion_panel.feature +2 -2
  116. data/test/basepack_test_app/features/form_panel.feature +7 -7
  117. data/test/basepack_test_app/features/grid_panel.feature +93 -39
  118. data/test/basepack_test_app/features/grid_panel_with_custom_primary_key.feature +2 -1
  119. data/test/basepack_test_app/features/grid_sorting.feature +30 -6
  120. data/test/basepack_test_app/features/paging_form_panel.feature +7 -7
  121. data/test/basepack_test_app/features/persistent_regions.feature +30 -0
  122. data/test/basepack_test_app/features/search_in_grid.feature +5 -5
  123. data/test/basepack_test_app/features/simple_app.feature +6 -7
  124. data/test/basepack_test_app/features/step_definitions/form_panel_steps.rb +1 -1
  125. data/test/basepack_test_app/features/step_definitions/generic_steps.rb +109 -4
  126. data/test/basepack_test_app/features/step_definitions/grid_panel_steps.rb +8 -10
  127. data/test/basepack_test_app/features/step_definitions/window_steps.rb +27 -0
  128. data/test/basepack_test_app/features/tab_panel.feature +1 -1
  129. data/test/basepack_test_app/features/window.feature +17 -0
  130. data/test/unit/accordion_panel_test.rb +2 -2
  131. data/test/unit/grid_panel_test.rb +4 -4
  132. metadata +57 -83
  133. data/TODO.rdoc +0 -8
  134. data/lib/generators/netzke/basepack_generator.rb +0 -10
  135. data/lib/generators/netzke/templates/assets/ts-checkbox.gif +0 -0
  136. data/lib/generators/netzke/templates/create_netzke_field_lists.rb +0 -18
  137. data/lib/netzke/active_record.rb +0 -20
  138. data/lib/netzke/active_record/attributes.rb +0 -259
  139. data/lib/netzke/active_record/combobox_options.rb +0 -16
  140. data/lib/netzke/active_record/relation_extensions.rb +0 -37
  141. data/lib/netzke/basepack/accordion_panel.rb +0 -39
  142. data/lib/netzke/basepack/action_column.rb +0 -68
  143. data/lib/netzke/basepack/action_column/javascripts/action_column.js +0 -61
  144. data/lib/netzke/basepack/auth_app.rb +0 -159
  145. data/lib/netzke/basepack/basic_app.rb +0 -7
  146. data/lib/netzke/basepack/border_layout_panel.rb +0 -53
  147. data/lib/netzke/basepack/border_layout_panel/javascripts/border_layout_panel.js +0 -40
  148. data/lib/netzke/basepack/data_adapters/data_mapper_adapter.rb +0 -264
  149. data/lib/netzke/basepack/data_adapters/sequel_adapter.rb +0 -260
  150. data/lib/netzke/basepack/form_panel.rb +0 -144
  151. data/lib/netzke/basepack/form_panel/fields.rb +0 -208
  152. data/lib/netzke/basepack/form_panel/javascripts/misc.js +0 -4
  153. data/lib/netzke/basepack/form_panel/services.rb +0 -142
  154. data/lib/netzke/basepack/grid_panel.rb +0 -441
  155. data/lib/netzke/basepack/grid_panel/columns.rb +0 -400
  156. data/lib/netzke/basepack/grid_panel/javascripts/rows-dd.js +0 -281
  157. data/lib/netzke/basepack/grid_panel/record_form_window.rb +0 -41
  158. data/lib/netzke/basepack/grid_panel/services.rb +0 -235
  159. data/lib/netzke/basepack/panel.rb +0 -11
  160. data/lib/netzke/basepack/wrapper.rb +0 -28
  161. data/lib/netzke/data_mapper.rb +0 -18
  162. data/lib/netzke/data_mapper/attributes.rb +0 -273
  163. data/lib/netzke/data_mapper/combobox_options.rb +0 -11
  164. data/lib/netzke/data_mapper/relation_extensions.rb +0 -38
  165. data/lib/netzke/sequel.rb +0 -18
  166. data/lib/netzke/sequel/attributes.rb +0 -274
  167. data/lib/netzke/sequel/combobox_options.rb +0 -10
  168. data/lib/netzke/sequel/relation_extensions.rb +0 -40
  169. data/locales/zh-cn.yml +0 -79
  170. data/test/basepack_test_app/app/components/book_form_with_custom_fields.rb +0 -21
  171. data/test/basepack_test_app/app/components/book_grid_with_column_actions.rb +0 -15
  172. data/test/basepack_test_app/app/components/book_grid_with_defaults.rb +0 -6
  173. data/test/basepack_test_app/app/components/book_paging_form_panel.rb +0 -22
  174. data/test/basepack_test_app/app/components/generic_user_form.rb +0 -12
  175. data/test/basepack_test_app/app/components/simple_accordion.rb +0 -11
  176. data/test/basepack_test_app/app/components/simple_tab_panel.rb +0 -11
  177. data/test/basepack_test_app/app/components/simple_wrapper.rb +0 -7
  178. data/test/basepack_test_app/app/components/some_accordion_panel.rb +0 -22
  179. data/test/basepack_test_app/app/presenters/forms/generic_user.rb +0 -6
  180. data/test/basepack_test_app/app/views/components/loadable_window.html.erb +0 -9
  181. data/test/basepack_test_app/app/views/components/simple_panel.html.erb +0 -1
  182. data/test/basepack_test_app/features/components_in_view.feature +0 -11
  183. data/test/basepack_test_app/features/simple_panel.feature +0 -11
  184. data/test/basepack_test_app/features/validations_in_grid.feature +0 -13
  185. data/test/basepack_test_app/features/virtual_attributes.feature +0 -16
  186. data/test/basepack_test_app/spec/components/form_panel_spec.rb +0 -53
  187. data/test/basepack_test_app/spec/components/grid_panel_spec.rb +0 -10
  188. data/test/basepack_test_app/spec/data_adapter/adapter_spec.rb +0 -68
  189. data/test/basepack_test_app/spec/data_adapter/attributes_spec.rb +0 -56
  190. data/test/basepack_test_app/spec/data_adapter/relation_extensions_spec.rb +0 -125
  191. data/test/basepack_test_app/spec/factories.rb +0 -28
  192. data/test/basepack_test_app/spec/spec_helper.rb +0 -39
@@ -0,0 +1,12 @@
1
+ require 'netzke/basepack/active_record/relation_extensions'
2
+
3
+ module Netzke
4
+ module Basepack
5
+ module ActiveRecord
6
+ end
7
+ end
8
+ end
9
+
10
+ ::ActiveRecord::Relation.class_eval do
11
+ include ::Netzke::Basepack::ActiveRecord::RelationExtensions
12
+ end
@@ -0,0 +1,27 @@
1
+ module Netzke
2
+ module Basepack
3
+ module ActiveRecord
4
+ module RelationExtensions
5
+ def extend_with(*params)
6
+ scope = params.shift
7
+ case scope.class.name
8
+ when "Symbol" # model's scope
9
+ self.send(scope, *params)
10
+ when "String" # SQL query or SQL query with params (e.g. ["created_at < ?", 1.day.ago])
11
+ params.empty? ? self.where(scope) : self.where([scope, *params])
12
+ when "Array"
13
+ self.extend_with(*scope)
14
+ when "Hash" # conditions hash
15
+ self.where(scope)
16
+ when "ActiveSupport::HashWithIndifferentAccess" # conditions hash
17
+ self.where(scope)
18
+ when "Proc" # receives a relation, must return a relation
19
+ scope.call(self)
20
+ else
21
+ raise ArgumentError, "Wrong parameter type for ActiveRecord::Relation#extend_with"
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,309 @@
1
+ module Netzke
2
+ module Basepack
3
+ module Columns
4
+ extend ActiveSupport::Concern
5
+
6
+ COLUMN_METHOD_NAME = "%s_column"
7
+
8
+ module ClassMethods
9
+ # Overrides a column config, e.g.:
10
+ #
11
+ # column :title do |c|
12
+ # c.flex = 1
13
+ # end
14
+ def column(name, &block)
15
+ method_name = COLUMN_METHOD_NAME % name
16
+ define_method(method_name, &block)
17
+ end
18
+ end
19
+
20
+ # Returns the list of (non-normalized) columns to be used. By default returns the list of model column names.
21
+ # Can be overridden.
22
+ def columns
23
+ config.columns || data_adapter.model_attributes
24
+ end
25
+
26
+ # An array of complete columns configs ready to be passed to the JS side.
27
+ # The +options+ hash can have the following keys:
28
+ # * :with_excluded - when true, include the columns that are marked as excluded
29
+ # * :with_meta - when true, include the meta column
30
+ def final_columns(options = {})
31
+ @_final_columns ||= {}
32
+ @_final_columns[options] ||= [].tap do |cols|
33
+ initial_columns(true).each do |c|
34
+ name = c.name
35
+
36
+ # merge with column declaration
37
+ send(:"#{name}_column", c) if respond_to?(:"#{name}_column")
38
+
39
+ # set the defaults as lowest priority
40
+ augment_column_config(c)
41
+
42
+ cols << c if options[:with_excluded] || !c.excluded
43
+ end
44
+
45
+ append_meta_column(cols) if options[:with_meta]
46
+ end
47
+ end
48
+
49
+ # Columns as a hash, for easier access to a specific column
50
+ def final_columns_hash
51
+ @_final_columns_hash ||= final_columns.inject({}){|r,c| r.merge(c[:name].to_sym => c)}
52
+ end
53
+
54
+ # Columns from config.columns or the `columns` method, after normalization
55
+ def initial_columns(with_excluded = false)
56
+ @_initial_columns ||= {}
57
+ @_initial_columns[with_excluded] ||= [].tap do |cols|
58
+ has_primary_column = false
59
+
60
+ columns.each do |c|
61
+ # normalize:
62
+ # * :title => {name: 'title'}
63
+ # * {name: :some_column} => {name: 'some_column'}
64
+ c = ActiveSupport::OrderedOptions.new.replace(c.is_a?(Symbol) ? {name: c.to_s} : c.merge(name: c[:name].to_s))
65
+
66
+ cols << c if with_excluded || !c.excluded
67
+
68
+ # detect primary key column
69
+ has_primary_column ||= c.name == data_adapter.primary_key_name
70
+ end
71
+
72
+ # automatically add a column that reflects the primary key
73
+ cols.insert(0, ActiveSupport::OrderedOptions.new.replace(:name => data_adapter.primary_key_name)) unless has_primary_column
74
+ end
75
+ end
76
+
77
+ def append_meta_column(cols)
78
+ cols << {}.tap do |c|
79
+ c.merge!(
80
+ :name => "meta",
81
+ :meta => true,
82
+ :getter => lambda do |r|
83
+ meta_data(r)
84
+ end
85
+ )
86
+ c[:default_value] = meta_default_data if meta_default_data.present?
87
+ end
88
+ end
89
+
90
+ # default_value for the meta column; used when a new record is being created in the grid
91
+ def meta_default_data
92
+ default_association_values(final_columns_hash).present? ? { :association_values => default_association_values(final_columns_hash).literalize_keys } : {}
93
+ end
94
+
95
+ # Override it when you need extra meta data to be passed through the meta column
96
+ def meta_data(r)
97
+ { :association_values => data_adapter.assoc_values(r, final_columns_hash).literalize_keys }
98
+ end
99
+
100
+ private
101
+
102
+ # Based on initial column config, e.g.:
103
+ #
104
+ # {:name=>"author__name", :attr_type=>:string}
105
+ #
106
+ # augment it with additional configuration params, e.g.:
107
+ #
108
+ # {:name=>"author__name", :attr_type=>:string, :editor=>{:xtype=>:netzkeremotecombo}, :assoc=>true, :virtual=>true, :header=>"Author name", :editable=>true, :sortable=>false, :filterable=>false}
109
+ #
110
+ # It may be handy to override it.
111
+ def augment_column_config(c)
112
+ set_default_attr_type(c)
113
+ set_default_xtype(c)
114
+ set_default_virtual(c)
115
+ set_default_text(c)
116
+ set_default_editable(c)
117
+ set_default_editor(c)
118
+ set_default_width(c)
119
+ set_default_hidden(c)
120
+ set_default_sortable(c)
121
+ set_default_filterable(c)
122
+ c[:assoc] = association_attr?(c) # needed on the JS side
123
+ end
124
+
125
+ def set_default_attr_type(c)
126
+ c[:attr_type] ||= association_attr?(c) ? :integer : data_adapter.attr_type(c.name)
127
+ end
128
+
129
+ def set_default_xtype(c)
130
+ return if c[:renderer] || c[:editor] # if user set those manually, we don't mess with column xtype
131
+ c[:xtype] ||= attr_type_to_xtype_map[c[:attr_type]]
132
+ end
133
+
134
+ def set_default_text(c)
135
+ c[:text] ||= c[:label] || data_adapter.human_attribute_name(c[:name])
136
+ end
137
+
138
+ def set_default_editor(c)
139
+ # if shouldn't be editable, don't set any default editor; also, specifying xtype takes care of the editor
140
+ return if c[:read_only] || c[:editable] == false
141
+
142
+ if association_attr?(c)
143
+ set_default_association_editor(c)
144
+ else
145
+ c[:editor] ||= editor_for_attr_type(c[:attr_type])
146
+ end
147
+
148
+ end
149
+
150
+ def set_default_width(c)
151
+ c[:width] ||= 50 if c[:attr_type] == :boolean
152
+ c[:width] ||= 150 if c[:attr_type] == :datetime
153
+ end
154
+
155
+ def set_default_hidden(c)
156
+ c[:hidden] = true if data_adapter.primary_key_attr?(c) && c[:hidden].nil?
157
+ end
158
+
159
+ def set_default_editable(c)
160
+ if c[:editable].nil?
161
+ c[:editable] = is_editable_column?(c)
162
+ end
163
+ end
164
+
165
+ def set_default_sortable(c)
166
+ # this *has* to be set to false if we don't want the column to be sortable (it's sortable by default in Ext)
167
+ c[:sortable] = !(c[:virtual] && !c[:sorting_scope]) if c[:sortable].nil?
168
+ end
169
+
170
+ def set_default_filterable(c)
171
+ c[:filterable] = !c[:virtual] if c[:filterable].nil?
172
+ end
173
+
174
+
175
+ # Detects an association column and sets up the proper editor.
176
+ def set_default_association_editor(c)
177
+ assoc, assoc_method = c[:name].split('__')
178
+ return unless assoc
179
+
180
+ assoc_method_type = data_adapter.get_assoc_property_type assoc, assoc_method
181
+
182
+ # if association column is boolean, display a checkbox (or alike), otherwise - a combobox (or alike)
183
+ if c[:nested_attribute]
184
+ c[:editor] ||= editor_for_attr_type(assoc_method_type)
185
+ else
186
+ c[:editor] ||= assoc_method_type == :boolean ? editor_for_attr_type(:boolean) : editor_for_association
187
+ end
188
+ end
189
+
190
+ # If the column should be editable
191
+ def is_editable_column?(c)
192
+ not_editable_if = data_adapter.primary_key_attr?(c)
193
+ not_editable_if ||= c[:virtual] && !association_attr?(c[:name])
194
+ not_editable_if ||= c[:read_only]
195
+
196
+ editable_if = data_adapter.attribute_names.include?(c[:name])
197
+ editable_if ||= data_class.instance_methods.map(&:to_s).include?("#{c[:name]}=")
198
+ editable_if ||= association_attr?(c[:name])
199
+
200
+ editable_if && !not_editable_if
201
+ end
202
+
203
+ def initial_columns_order
204
+ final_columns.map do |c|
205
+ # copy the values that are not null
206
+ {name: c[:name]}.tap do |r|
207
+ r[:width] = c[:width] if c[:width]
208
+ r[:hidden] = c[:hidden] if c[:hidden]
209
+ end
210
+ end
211
+ end
212
+
213
+ def columns_order
214
+ if config[:persistence]
215
+ state[:columns_order] = initial_columns_order if columns_have_changed?
216
+ state[:columns_order] || initial_columns_order
217
+ else
218
+ initial_columns_order
219
+ end
220
+ end
221
+
222
+ def columns_have_changed?
223
+ init_column_names = initial_columns_order.map{ |c| c[:name].to_s }.sort
224
+ stored_column_names = (state[:columns_order] || initial_columns_order).map{ |c| c[:name].to_s }.sort
225
+ init_column_names != stored_column_names
226
+ end
227
+
228
+ # Column editor config for attribute type.
229
+ def editor_for_attr_type(type)
230
+ {:xtype => attr_type_to_editor_xtype_map[type] || :textfield}
231
+ end
232
+
233
+ # Column editor config for one-to-many association
234
+ def editor_for_association
235
+ {:xtype => :netzkeremotecombo}
236
+ end
237
+
238
+ # Hash that maps a column type to the editor xtype. Override if you want different editors.
239
+ def attr_type_to_editor_xtype_map
240
+ {
241
+ :integer => :numberfield,
242
+ :boolean => :checkbox,
243
+ :date => :datefield,
244
+ :datetime => :xdatetime,
245
+ :text => :textarea,
246
+ :string => :textfield
247
+ }
248
+ end
249
+
250
+ def attr_type_to_xtype_map
251
+ {
252
+ # :integer => :numbercolumn, # don't like the default formatter
253
+ :boolean => :checkcolumn,
254
+ :date => :datecolumn,
255
+ #:datetime => :datecolumn # TODO: replace with datetimepicker
256
+ }
257
+ end
258
+
259
+ # Default fields that will be displayed in the Add/Edit/Search forms
260
+ # 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)
261
+ def default_fields_for_forms
262
+ selected_columns = final_columns.select do |c|
263
+ data_adapter.attribute_names.include?(c[:name]) ||
264
+ data_class.instance_methods.include?("#{c[:name]}=") ||
265
+ association_attr?(c[:name])
266
+ end
267
+
268
+ selected_columns.map do |c|
269
+ field_config = {
270
+ :name => c[:name],
271
+ :field_label => c[:text] || c[:header]
272
+ }
273
+
274
+ # scopes for combobox options
275
+ field_config[:scopes] = c[:editor][:scopes] if c[:editor].is_a?(Hash)
276
+
277
+ field_config.merge!(c[:editor] || {})
278
+
279
+ field_config
280
+ end
281
+ end
282
+
283
+ def columns_default_values
284
+ final_columns.inject({}) do |r,c|
285
+ assoc_name, assoc_method = c[:name].split '__'
286
+ if c[:default_value].nil?
287
+ r
288
+ else
289
+ if assoc_method
290
+ r.merge(data_adapter.foreign_key_for(assoc_name) || data_adapter.foreign_key_for(assoc_name) => c[:default_value])
291
+ else
292
+ r.merge(c[:name] => c[:default_value])
293
+ end
294
+ end
295
+ end
296
+ end
297
+
298
+ # Recursively traversess items (an array) and yields each found field (a hash with :name set)
299
+ def each_attr_in(items)
300
+ items.each do |item|
301
+ if item.is_a?(Hash)
302
+ each_attr_in(item[:items]) if item[:items].is_a?(Array)
303
+ yield(item) if item[:name]
304
+ end
305
+ end
306
+ end
307
+ end
308
+ end
309
+ end
@@ -1,18 +1,14 @@
1
1
  module Netzke
2
2
  module Basepack
3
- # This module is included into such data-driven components as GridPanel, FormPanel, PagingFormPanel, etc.
3
+ # This module is included into such data-driven components as Grid, Form, PagingForm, etc.
4
4
  module DataAccessor
5
-
6
-
7
-
8
5
  # Returns options for comboboxes in grids/forms
9
6
  def combobox_options_for_column(column, method_options = {})
10
7
  data_adapter.combobox_options_for_column column, method_options
11
8
  end
12
9
 
13
10
  # Normalize array of attributes
14
- # [:col1, "col2", {:name => :col3}] =>
15
- # [{:name => "col1"}, {:name => "col2"}, {:name => "col3"}]
11
+ # [:col1, "col2", {:name => :col3}] #=> [{:name => "col1"}, {:name => "col2"}, {:name => "col3"}]
16
12
  def normalize_attrs(attrs)
17
13
  attrs.map{ |a| normalize_attr(a) }
18
14
  end
@@ -35,19 +31,33 @@ module Netzke
35
31
 
36
32
  # Data adapter responsible for all DB-related operations
37
33
  def data_adapter
38
- @data_adapter ||= Netzke::Basepack::DataAdapters::AbstractAdapter.adapter_class(data_class).new(data_class)
34
+ @data_adapter ||= data_class && Netzke::Basepack::DataAdapters::AbstractAdapter.adapter_class(data_class).new(data_class)
39
35
  end
40
36
 
41
- # whether a column is bound to the primary_key
42
- def primary_key_attr?(a)
43
- data_class && a[:name].to_s == data_class.primary_key.to_s
44
- end
37
+ # whether a column/field is bound to the primary_key
38
+ # def primary_key_attr?(a)
39
+ # data_class && a[:name].to_s == data_class.primary_key.to_s
40
+ # end
45
41
 
46
42
  # Mark an attribute as "virtual" by default, when it doesn't reflect a model column, or a model column of an association
47
43
  def set_default_virtual(c)
48
- c[:virtual] = data_adapter.column_virtual?(c) if c[:virtual].nil?
44
+ c[:virtual] = data_adapter.virtual_attribute?(c) if c[:virtual].nil?
49
45
  end
50
46
 
47
+ # Returns a hash of association attribute default values. Used when creating new records with association attributes that have a default value
48
+ def default_association_values(attr_hash) #:nodoc:
49
+ @_default_association_values ||= {}.tap do |values|
50
+ attr_hash.each_pair do |name,c|
51
+ next unless association_attr?(c) && c[:default_value]
52
+
53
+ assoc_name, assoc_method = c[:name].split '__'
54
+ assoc_class = data_adapter.class_for(assoc_name)
55
+ assoc_data_adapter = Netzke::Basepack::DataAdapters::AbstractAdapter.adapter_class(assoc_class).new(assoc_class)
56
+ assoc_instance = assoc_data_adapter.find_record c[:default_value]
57
+ values[name] = assoc_instance.send(assoc_method)
58
+ end
59
+ end
60
+ end
51
61
  end
52
62
  end
53
63
  end
@@ -2,6 +2,23 @@ module Netzke::Basepack::DataAdapters
2
2
  # A concrete adapter should implement all the public instance methods of this adapter in order to support all the functionality of Basepack components.
3
3
  class AbstractAdapter
4
4
 
5
+ # Returns primary key name of the model
6
+ def primary_key_name
7
+ "id"
8
+ end
9
+
10
+ # Returns a list of model attribute hashes, each containing `name`, `attr_type` and `default_value` (if set in the schema).
11
+ # For association columns the name can have the double-underscore format, e.g.: `author__first_name`.
12
+ # These attributes will be used by grids and forms to display default columns/fields.
13
+ def model_attributes
14
+ raise NotImplementedError
15
+ end
16
+
17
+ # Returns attribute type (as Symbol) given its name.
18
+ def attr_type(attr_name)
19
+ raise NotImplementedError
20
+ end
21
+
5
22
  # Returns records based on passed params. Implements:
6
23
  # * pagination
7
24
  # * filtering
@@ -14,7 +31,7 @@ module Netzke::Basepack::DataAdapters
14
31
  # * :direction - "asc" or "desc"
15
32
  # * :limit - rows per page in pagination
16
33
  # * :start - page number in pagination
17
- # * :scope - the scope as described in Netzke::Basepack::GridPanel
34
+ # * :scope - the scope as described in Netzke::Basepack::Grid
18
35
  # * :filter - Ext filters
19
36
  #
20
37
  # The `columns` parameter may be used to use joins to address the n+1 query problem, and receives an array of column configurations
@@ -33,7 +50,7 @@ module Netzke::Basepack::DataAdapters
33
50
  #
34
51
  # `params` is a hash that contains the following keys:
35
52
  #
36
- # * :scope - the scope as described in Netzke::Basepack::GridPanel
53
+ # * :scope - the scope as described in Netzke::Basepack::Grid
37
54
  # * :filter - Ext filters
38
55
  #
39
56
  # The `columns` parameter may be used to use joins to address the n+1 query problem, and receives an array of column configurations
@@ -74,14 +91,18 @@ module Netzke::Basepack::DataAdapters
74
91
  def get_property_type column
75
92
  column.type
76
93
  end
77
-
94
+
78
95
  # should return true if column is virtual
79
- def column_virtual? c
96
+ def virtual_attribute? c
80
97
  raise NotImplementedError
81
98
  end
82
99
 
83
100
  # Returns options for comboboxes in grids/forms
84
- def combobox_options_for_column(column, method_options = {})
101
+ # +attr+ - column/field configuration; note that it will in its turn provide:
102
+ # * +name+ - attribute name
103
+ # * +scope+ - searching scope (optional)
104
+ # +query+ - whatever is entered in the combobox
105
+ def combo_data(attr, query = "")
85
106
  raise NotImplementedError
86
107
  end
87
108
 
@@ -99,6 +120,16 @@ module Netzke::Basepack::DataAdapters
99
120
  def destroy(ids)
100
121
  end
101
122
 
123
+ # Finds a record by id, return nil if not found
124
+ def find_record(id)
125
+ @model_class.find(id)
126
+ end
127
+
128
+ # Build a hash of foreign keys and the associated model
129
+ def hash_fk_model
130
+ raise NotImplementedError
131
+ end
132
+
102
133
  # Changes records position (e.g. when acts_as_list is used in ActiveRecord).
103
134
  #
104
135
  # `params` is a hash with the following keys:
@@ -125,22 +156,55 @@ module Netzke::Basepack::DataAdapters
125
156
  record.errors.to_a
126
157
  end
127
158
 
128
- # Finds a record by id, return nil if not found
129
- def find_record(id)
130
- @model_class.find(id)
159
+ # Whether an attribute is mass assignable. As second argument optionally takes the role.
160
+ def attribute_mass_assignable?(attr_name, role = :default)
161
+ true
131
162
  end
132
163
 
133
- # Build a hash of foreign keys and the associated model
134
- def hash_fk_model
135
- raise NotImplementedError
164
+ # Whether an attribute (by name) is an association one
165
+ def association_attr?(attr_name)
166
+ !!attr_name.to_s.index("__")
167
+ end
168
+
169
+ # Transforms a record to an array of values according to the passed attributes
170
+ # +attrs+ - array of attribute config hashes
171
+ def record_to_array(r, attrs)
172
+ []
136
173
  end
137
174
 
175
+ # Transforms a record to a hash of values according to the passed attributes
176
+ # +attrs+ - array of attribute config hashes
177
+ def record_to_hash(r, attrs)
178
+ {}
179
+ end
138
180
 
181
+ # Returns a hash of association values for given record, e.g.:
182
+ #
183
+ # {author__first_name: "Michael"}
184
+ def assoc_values(r, attr_hash) #:nodoc:
185
+ {}.tap do |values|
186
+ attr_hash.each_pair do |name,c|
187
+ values[name] = record_value_for_attribute(r, c, true) if association_attr?(c)
188
+ end
189
+ end
190
+ end
191
+
192
+ # Fetches the value specified by an (association) attribute
193
+ # If +through_association+ is true, get the value of the association by provided method, *not* the associated record's id
194
+ # E.g., author__name with through_association set to true may return "Vladimir Nabokov", while with through_association set to false, it'll return author_id for the current record
195
+ def record_value_for_attribute(r, a, through_association = false)
196
+ end
197
+
198
+ # Assigns new value to an (association) attribute in a given record
199
+ # +role+ - role provided for mass assignment protection
200
+ def set_record_value_for_attribute(record, attr, value, role = :default)
201
+ end
139
202
 
140
203
  # -- End of overridable methods
141
204
 
142
205
  # Abstract-adapter specifics
143
206
  #
207
+ #
144
208
 
145
209
  # Used to determine if the given adapter should be used for the passed in class.
146
210
  def self.for_class?(member_class)