netzke-basepack 0.5.8 → 0.5.9

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.
Files changed (62) hide show
  1. data/CHANGELOG.rdoc +18 -0
  2. data/README.rdoc +11 -4
  3. data/Rakefile +19 -3
  4. data/TODO.rdoc +1 -1
  5. data/generators/netzke_basepack/netzke_basepack_generator.rb +13 -0
  6. data/generators/netzke_basepack/templates/create_netzke_field_lists.rb +18 -0
  7. data/generators/netzke_basepack/templates/public_assets/ts-checkbox.gif +0 -0
  8. data/install.rb +1 -1
  9. data/javascripts/basepack.js +124 -30
  10. data/lib/app/models/netzke_field_list.rb +261 -0
  11. data/lib/app/models/netzke_model_attr_list.rb +21 -0
  12. data/lib/app/models/netzke_persistent_array_auto_model.rb +58 -0
  13. data/lib/netzke-basepack.rb +17 -2
  14. data/lib/netzke/active_record.rb +10 -0
  15. data/lib/netzke/active_record/association_attributes.rb +102 -0
  16. data/lib/netzke/active_record/attributes.rb +100 -0
  17. data/lib/netzke/active_record/combobox_options.rb +43 -0
  18. data/lib/netzke/active_record/data_accessor.rb +9 -12
  19. data/lib/netzke/attributes_configurator.rb +195 -0
  20. data/lib/netzke/basic_app.rb +47 -4
  21. data/lib/netzke/configuration_panel.rb +1 -1
  22. data/lib/netzke/data_accessor.rb +7 -30
  23. data/lib/netzke/fields_configurator.rb +106 -41
  24. data/lib/netzke/form_panel.rb +28 -125
  25. data/lib/netzke/form_panel/form_panel_api.rb +2 -3
  26. data/lib/netzke/form_panel/form_panel_fields.rb +147 -0
  27. data/lib/netzke/form_panel/form_panel_js.rb +35 -15
  28. data/lib/netzke/grid_panel.rb +130 -213
  29. data/lib/netzke/grid_panel/grid_panel_api.rb +254 -257
  30. data/lib/netzke/grid_panel/grid_panel_columns.rb +226 -0
  31. data/lib/netzke/grid_panel/grid_panel_js.rb +126 -119
  32. data/lib/netzke/grid_panel/record_form_window.rb +7 -1
  33. data/lib/netzke/json_array_editor.rb +61 -0
  34. data/lib/netzke/plugins/configuration_tool.rb +1 -1
  35. data/lib/netzke/property_editor.rb +3 -3
  36. data/lib/netzke/search_panel.rb +164 -27
  37. data/lib/netzke/tab_panel.rb +14 -12
  38. data/stylesheets/basepack.css +43 -2
  39. data/test/app_root/app/models/book.rb +1 -1
  40. data/test/app_root/app/models/role.rb +3 -0
  41. data/test/app_root/app/models/user.rb +3 -0
  42. data/test/app_root/config/database.yml +1 -1
  43. data/test/app_root/db/migrate/20090102223630_create_netzke_field_lists.rb +18 -0
  44. data/test/app_root/db/migrate/20090423214303_create_roles.rb +11 -0
  45. data/test/app_root/db/migrate/20090423222114_create_users.rb +12 -0
  46. data/test/fixtures/books.yml +4 -2
  47. data/test/fixtures/categories.yml +2 -2
  48. data/test/fixtures/genres.yml +6 -6
  49. data/test/fixtures/roles.yml +8 -0
  50. data/test/fixtures/users.yml +11 -0
  51. data/test/test_helper.rb +2 -0
  52. data/test/unit/active_record_basepack_test.rb +2 -2
  53. data/test/unit/fields_configuration_test.rb +18 -0
  54. data/test/unit/grid_panel_test.rb +29 -27
  55. metadata +41 -16
  56. data/lib/app/models/netzke_auto_column.rb +0 -4
  57. data/lib/app/models/netzke_auto_field.rb +0 -4
  58. data/lib/app/models/netzke_auto_table.rb +0 -61
  59. data/lib/netzke/active_record/basepack.rb +0 -134
  60. data/lib/netzke/grid_panel/javascripts/filters.js +0 -7
  61. data/test/app_root/db/migrate/20090102223630_create_netzke_layouts.rb +0 -14
  62. data/test/unit/helper_model_test.rb +0 -30
@@ -29,7 +29,6 @@ module Netzke
29
29
  begin
30
30
  @record.send("#{k}=",v)
31
31
  rescue StandardError => exc
32
- logger.debug "!!! FormPanelApi#create_or_update_record exception: #{exc.inspect}\n"
33
32
  flash :error => exc.message
34
33
  success = false
35
34
  break
@@ -66,12 +65,12 @@ module Netzke
66
65
 
67
66
  def configuration_panel__fields__get_combobox_options(params)
68
67
  query = params[:query]
69
- {:data => (predefined_columns.map{ |c| c[:name].to_s }).grep(/^#{query}/).map{ |n| [n] }}.to_nifty_json
68
+ {:data => (default_columns.map{ |c| c[:name].to_s }).grep(/^#{query}/).map{ |n| [n] }}.to_nifty_json
70
69
  end
71
70
 
72
71
  # Returns array of form values according to the configured columns
73
72
  def array_of_values
74
- @record && @record.to_array(columns, self)
73
+ @record && @record.to_array(fields, self)
75
74
  end
76
75
  end
77
76
  end
@@ -0,0 +1,147 @@
1
+ module Netzke
2
+ class FormPanel < Base
3
+ module FormPanelFields
4
+ module ClassMethods
5
+ # Columns to be displayed by the FieldConfigurator, "meta-columns". Each corresponds to a configuration
6
+ # option for each field in the form.
7
+ def meta_columns
8
+ [
9
+ {:name => "included", :attr_type => :boolean, :width => 40, :header => "Incl", :default_value => true},
10
+ {:name => "name", :attr_type => :string, :editor => :combobox, :width => 200},
11
+ {:name => "label", :attr_type => :string, :header => "Label"},
12
+ {:name => "default_value", :attr_type => :string}
13
+ ]
14
+ end
15
+ end
16
+
17
+ module InstanceMethods
18
+ def fields
19
+ @fields ||= begin
20
+ flds = load_fields
21
+ flds ||= initial_fields
22
+
23
+ flds.map! do |c|
24
+ value = record.send(c[:name])
25
+ value.nil? ? c : c.merge(:value => value)
26
+ end if record
27
+
28
+ flds
29
+ end
30
+ end
31
+
32
+ def default_fields
33
+ @default_fields ||= load_model_level_attrs || (data_class && data_class.netzke_attributes) || []
34
+ end
35
+
36
+ def initial_fields(only_included = true)
37
+ ::ActiveSupport::Deprecation.warn("The :columns option for FormPanel is deprecated. Use :fields instead", caller) if config[:columns]
38
+
39
+ # Normalize here, as from the config we can get symbols (names) instead of hashes
40
+ fields_from_config = (config[:columns] || config[:fields]) && normalize_attr_config(config[:columns] || config[:fields])
41
+
42
+ if fields_from_config
43
+ # reverse-merge each column hash from config with each column hash from exposed_attributes (fields from config have higher priority)
44
+ for c in fields_from_config
45
+ corresponding_exposed_column = default_fields.find{ |k| k[:name] == c[:name] }
46
+ c.reverse_merge!(corresponding_exposed_column) if corresponding_exposed_column
47
+ end
48
+ fields_for_create = fields_from_config
49
+ elsif default_fields
50
+ # we didn't have fields configured in widget's config, so, use the fields from the data class
51
+ fields_for_create = default_fields
52
+ else
53
+ raise ArgumentError, "No fields specified for widget '#{global_id}'"
54
+ end
55
+
56
+ fields_for_create.reject!{ |c| c[:included] == false }
57
+
58
+ fields_for_create.map! do |c|
59
+ if data_class
60
+
61
+ detect_association_with_method(c)
62
+
63
+ # detect association column (e.g. :category_id)
64
+ if assoc = data_class.reflect_on_all_associations.detect{|a| a.primary_key_name == c[:name]}
65
+ c[:xtype] ||= xtype_for_association
66
+ assoc_method = %w{name title label id}.detect{|m| (assoc.klass.instance_methods + assoc.klass.column_names).include?(m) } || assoc.klass.primary_key
67
+ c[:name] = "#{assoc.name}__#{assoc_method}"
68
+ end
69
+
70
+ c[:hidden] = true if c[:name] == data_class.primary_key && c[:hidden].nil? # hide ID column by default
71
+ end
72
+
73
+ set_default_field_label(c)
74
+
75
+ c[:xtype] ||= xtype_for_attr_type(c[:attr_type]) # unless xtype_map[type].nil?
76
+ c
77
+ end
78
+
79
+ fields_for_create
80
+
81
+ end
82
+ end
83
+
84
+ private
85
+ # Stores modified fields in persistent storage (not used in forms, as we can't modify them on the fly, only via FieldsConfigurator)
86
+ # def save_fields!
87
+ # NetzkeFieldList.update_list_for_current_authority(global_id, fields, data_class.name)
88
+ # end
89
+
90
+ def load_fields
91
+ NetzkeFieldList.read_list(global_id) if persistent_config_enabled?
92
+ end
93
+
94
+ def load_model_level_attrs
95
+ NetzkeModelAttrList.read_list(data_class.name) if data_class
96
+ end
97
+
98
+ def set_default_field_label(c)
99
+ c[:label] ||= c[:name].humanize
100
+ end
101
+
102
+ def attr_type_to_xtype_map
103
+ {
104
+ :integer => :numberfield,
105
+ :boolean => :xcheckbox,
106
+ :date => :datefield,
107
+ :datetime => :xdatetime,
108
+ :text => :textarea,
109
+ :json => :jsonfield
110
+ # :string => :textfield
111
+ }
112
+ end
113
+
114
+ def xtype_for_attr_type(type)
115
+ attr_type_to_xtype_map[type]
116
+ end
117
+
118
+ def xtype_for_association
119
+ :combobox
120
+ end
121
+
122
+ def detect_association_with_method(c)
123
+ if c[:name].to_s.index('__')
124
+ assoc_name, method = c[:name].split('__').map(&:to_sym)
125
+ if assoc = data_class.reflect_on_association(assoc_name)
126
+ assoc_column = assoc.klass.columns_hash[method.to_s]
127
+ assoc_method_type = assoc_column.try(:type)
128
+ if assoc_method_type
129
+ c[:xtype] ||= assoc_method_type == :boolean ? xtype_for_attr_type(assoc_method_type) : :combobox
130
+ end
131
+ end
132
+ end
133
+
134
+ end
135
+
136
+
137
+ def self.included(receiver)
138
+ receiver.extend ClassMethods
139
+ receiver.send :include, InstanceMethods
140
+
141
+ receiver.class_eval do
142
+ alias :initial_columns :initial_fields
143
+ end
144
+ end
145
+ end
146
+ end
147
+ end
@@ -1,8 +1,13 @@
1
1
  module Netzke
2
2
  class FormPanel < Base
3
3
  module FormPanelJs
4
- def self.included(base)
5
- base.extend ClassMethods
4
+ # parameters used to instantiate the JS object
5
+ def js_config
6
+ res = super
7
+ res.merge!(:fields => fields)
8
+ res.merge!(:model => data_class.name) if data_class
9
+ res.merge!(:pri => data_class.primary_key) if data_class
10
+ res
6
11
  end
7
12
 
8
13
  module ClassMethods
@@ -24,21 +29,22 @@ module Netzke
24
29
  var index = 0;
25
30
 
26
31
  // Process columns
27
- Ext.each(this.clmns, function(field){
28
- if (typeof field == 'string') field = {name:field}; // normalize field
32
+ Ext.each(this.fields, function(field){
29
33
  if (!field.hidden || field.name == this.pri) {
30
34
  recordFields.push({name:field.name, mapping:index++});
31
-
35
+
32
36
  var defaultColumnConfig = Ext.apply({}, this.defaultColumnConfig);
33
37
  var columnConfig = Ext.apply(defaultColumnConfig, field);
34
38
 
35
39
  // apply dynamically defined properties
36
- Ext.apply(columnConfig, {
37
- fieldLabel: columnConfig.fieldLabel || columnConfig.name.humanize(),
38
- hideLabel: columnConfig.hidden, // completely hide fields marked "hidden"
39
- parentId: this.id,
40
- name: columnConfig.name,
41
- checked: columnConfig.xtype == "xcheckbox" ? columnConfig.value : null // checkbox state
40
+ Ext.applyIf(columnConfig, {
41
+ xtype : this.attrTypeEditorMap[columnConfig.attrType],
42
+ fieldLabel: columnConfig.fieldLabel || columnConfig.label || columnConfig.name.humanize(),
43
+ hideLabel : columnConfig.hidden, // completely hide fields marked "hidden"
44
+ parentId : this.id,
45
+ name : columnConfig.name,
46
+ value : columnConfig.value || columnConfig.defaultValue,
47
+ checked : columnConfig.attrType == "boolean" ? columnConfig.value : null // checkbox state
42
48
  });
43
49
 
44
50
  this.items.push(columnConfig);
@@ -48,7 +54,7 @@ module Netzke
48
54
  var Record = Ext.data.Record.create(recordFields);
49
55
  this.reader = new Ext.data.RecordArrayReader({root:"data"}, Record);
50
56
 
51
- delete this.clmns; // we don't need them anymore
57
+ delete this.fields; // we don't need them anymore
52
58
 
53
59
  // Now let Ext.form.FormPanel do the rest
54
60
  #{js_full_class_name}.superclass.initComponent.call(this);
@@ -58,6 +64,15 @@ module Netzke
58
64
  }
59
65
  END_OF_JAVASCRIPT
60
66
 
67
+ :attr_type_editor_map => {
68
+ :integer => "numberfield",
69
+ :boolean => "checkbox",
70
+ :decimal => "numberfield",
71
+ :datetime => "xdatetime",
72
+ :date => "datefield",
73
+ :string => "textfield"
74
+ },
75
+
61
76
  # Defaults for each field
62
77
  :defaults => {
63
78
  :anchor => '-20', # to leave some space for the scrollbar
@@ -74,9 +89,9 @@ module Netzke
74
89
  }
75
90
  },
76
91
 
77
- :default_column_config => config_columns.inject({}){ |r, c| r.merge!({
78
- c[:name] => c[:default]
79
- }) },
92
+ # :default_column_config => meta_columns.inject({}){ |r, c| r.merge!({
93
+ # c[:name] => c[:default_value]
94
+ # })},
80
95
 
81
96
  :set_form_values => <<-END_OF_JAVASCRIPT.l,
82
97
  function(values){
@@ -138,6 +153,11 @@ module Netzke
138
153
  end
139
154
 
140
155
  end
156
+
157
+ def self.included(base)
158
+ base.extend ClassMethods
159
+ end
160
+
141
161
  end
142
162
  end
143
163
  end
@@ -1,5 +1,6 @@
1
1
  require "netzke/grid_panel/grid_panel_js"
2
2
  require "netzke/grid_panel/grid_panel_api"
3
+ require "netzke/grid_panel/grid_panel_columns"
3
4
  require "netzke/plugins/configuration_tool"
4
5
  require "netzke/data_accessor"
5
6
 
@@ -58,13 +59,45 @@ module Netzke
58
59
  # * <tt>:mode</tt> - when set to <tt>:config</tt>, GridPanel loads in configuration mode
59
60
  #
60
61
  # Additionally supports Netzke::Base config options.
62
+ #
63
+ # == Column
64
+ # Here's how the GridPanel decides which columns in which sequence and with which configuration to display.
65
+ # First, the column configs are aquired from this GridPanel's persistent storage, as an array of hashes, each
66
+ # representing a column configuration, such as:
67
+ #
68
+ # {:name => :created_at, :header => "Created", :tooltip => "When the record was created"}
69
+ #
70
+ # This hash *overrides* (deep_merge) the hard-coded configuration, an example of which can be specifying
71
+ # columns for a GridPanel instance, e.g.:
72
+ #
73
+ # :columns => [{:name => :created_at, :sortable => false}]
74
+ #
75
+ # ... which in its turn overrides the defaults provided by persistent storage managed by the AttributesConfigurator
76
+ # that provides *model-level* (as opposed to a widget-level) configuration of a database model
77
+ # (which is used by both grids and forms in Netzke).
78
+ # And lastly, the defaults for AttributesConfigurator are calculated from the database model itself, powered by Netzke.
79
+ # For example, in the model you can specify virtual attributes and their types that will be picked up by Netzke, the default
80
+ # order of columns, or excluded columns. For details see <tt>Netzke::ActiveRecord::Attributes</tt>.
81
+ #
82
+ # The columns are displayed in the order specified by what's found first in the following sequence:
83
+ # GridPanel instance's persistent storage
84
+ # hardcoded config
85
+ # AttributesConfigurator persistent storage
86
+ # netzke_expose_attributes in the database model
87
+ # database columns + (eventually) virtual attributes specified with netzke_attribute
61
88
  class GridPanel < Base
62
- # javascript (client-side)
89
+ # javascript (client-side)
63
90
  include GridPanelJs
64
- # API (server-side)
91
+
92
+ # API (server-side)
65
93
  include GridPanelApi
66
- # Code shared between GridPanel, FormPanel, and other widgets that serve as interface to database tables
94
+
95
+ # Columns
96
+ include GridPanelColumns
97
+
98
+ # Code shared between GridPanel, FormPanel, and other widgets that serve as interface to database tables
67
99
  include Netzke::DataAccessor
100
+
68
101
 
69
102
  def self.enforce_config_consistency
70
103
  config[:default_config][:ext_config][:enable_edit_in_form] &&= config[:edit_in_form_available]
@@ -111,24 +144,19 @@ module Netzke
111
144
  # Checkcolumn
112
145
  ext_examples = Netzke::Base.config[:ext_location] + "/examples/"
113
146
  res << ext_examples + "ux/CheckColumn.js"
114
- # res << "#{File.dirname(__FILE__)}/grid_panel/javascripts/check-column.js"
115
-
116
147
 
117
148
  # Filters
118
- # Not compatible with Ext 3.0
119
- # if config[:column_filters_available]
120
- # ext_examples = Netzke::Base.config[:ext_location] + "/examples/"
121
- # res << ext_examples + "grid-filtering/menu/EditableItem.js"
122
- # res << ext_examples + "grid-filtering/menu/RangeMenu.js"
123
- # res << ext_examples + "grid-filtering/grid/GridFilters.js"
124
- #
125
- # %w{Boolean Date List Numeric String}.unshift("").each do |f|
126
- # res << ext_examples + "grid-filtering/grid/filter/#{f}Filter.js"
127
- # end
128
- #
129
- # res << "#{File.dirname(__FILE__)}/grid_panel/javascripts/filters.js"
130
- #
131
- # end
149
+ if config[:column_filters_available]
150
+ ext_examples = Netzke::Base.config[:ext_location] + "/examples/"
151
+ res << ext_examples + "ux/gridfilters/menu/ListMenu.js"
152
+ res << ext_examples + "ux/gridfilters/menu/RangeMenu.js"
153
+ res << ext_examples + "ux/gridfilters/GridFilters.js"
154
+
155
+ %w{Boolean Date List Numeric String}.unshift("").each do |f|
156
+ res << ext_examples + "ux/gridfilters/filter/#{f}Filter.js"
157
+ end
158
+
159
+ end
132
160
 
133
161
  # DD
134
162
  if config[:rows_reordering_available]
@@ -137,7 +165,7 @@ module Netzke
137
165
 
138
166
  res
139
167
  end
140
-
168
+
141
169
  # Define connection points between client side and server side of GridPanel.
142
170
  # See implementation of equally named methods in the GridPanelApi module.
143
171
  api :get_data, :post_data, :delete_data, :resize_column, :move_column, :hide_column, :get_combobox_options, :move_rows
@@ -147,9 +175,14 @@ module Netzke
147
175
 
148
176
  # (We can't memoize this method because at some point we extend it, e.g. in Netzke::DataAccessor)
149
177
  def data_class
150
- ::ActiveSupport::Deprecation.warn("data_class_name option is deprecated. Use model instead", caller) if config[:data_class_name]
151
- model_name = config[:model] || config[:data_class_name]
152
- @data_class ||= model_name.nil? ? raise(ArgumentError, "No model specified for widget #{global_id}") : model_name.constantize
178
+ @data_class ||= begin
179
+ klass = "Netzke::ModelExtensions::#{config[:model]}For#{short_widget_class_name}".constantize rescue nil
180
+ klass || begin
181
+ ::ActiveSupport::Deprecation.warn("data_class_name option is deprecated. Use model instead", caller) if config[:data_class_name]
182
+ model_name = config[:model] || config[:data_class_name]
183
+ model_name.nil? ? raise(ArgumentError, "No model specified for widget #{global_id}") : model_name.constantize
184
+ end
185
+ end
153
186
  end
154
187
 
155
188
  def initialize(config = {}, parent = nil)
@@ -158,52 +191,31 @@ module Netzke
158
191
  apply_helpers
159
192
  end
160
193
 
161
- # Columns to be displayed by the FieldConfigurator.
162
- def self.config_columns
163
- [
164
- {:name => :name, :type => :string, :editor => :combobox, :width => 200},
165
- {:name => :excluded, :type => :boolean, :editor => :checkbox, :width => 40, :header => "Excl"},
166
- {:name => :value},
167
- {:name => :header},
168
- {:name => :hidden, :type => :boolean, :editor => :checkbox},
169
- {:name => :editable, :type => :boolean, :editor => :checkbox, :header => "Editable", :default => true},
170
- {:name => :editor, :type => :string, :editor => {:xtype => :combobox, :options => Netzke::Ext::FORM_FIELD_XTYPES}},
171
- {:name => :renderer, :type => :string},
172
-
173
- # maybe later
174
- # {:name => :xtype, :type => :string, :editor => {:xtype => :combobox, :options => Netzke::Ext::COLUMN_XTYPES}},
175
-
176
- # {:name => :renderer, :type => :string, :editor => {:xtype => :jsonfield}},
177
-
178
- # Filters not supported in Ext 3.0
179
- # {:name => :with_filters, :type => :boolean, :editor => :checkbox, :default => true, :header => "Filters"},
180
-
181
- # some rarely used configurations, hidden
182
- {:name => :width, :type => :integer, :editor => :numberfield, :hidden => true},
183
- {:name => :hideable, :type => :boolean, :editor => :checkbox, :default => true, :hidden => true},
184
- {:name => :sortable, :type => :boolean, :editor => :checkbox, :default => true, :hidden => true},
185
- ]
186
- end
194
+ # def data_class
195
+ # klass = "Netzke::ModelExtensions::#{data_class.name}#{short_widget_class_name}Ext".constantize rescue nil
196
+ # klass || data_class
197
+ # end
187
198
 
199
+ # Fields to be displayed in the "General" tab of the configuration panel
188
200
  def self.property_fields
189
201
  res = [
190
202
  {:name => :ext_config__title, :type => :string},
191
203
  {:name => :ext_config__header, :type => :boolean, :default => true},
192
204
  {:name => :ext_config__enable_context_menu, :type => :boolean, :default => true},
193
- {:name => :ext_config__context_menu, :type => :json},
205
+ # {:name => :ext_config__context_menu, :type => :json},
194
206
  {:name => :ext_config__enable_pagination, :type => :boolean, :default => true},
195
207
  {:name => :ext_config__rows_per_page, :type => :integer},
196
- {:name => :ext_config__bbar, :type => :json},
208
+ # {:name => :ext_config__bbar, :type => :json},
197
209
  {:name => :ext_config__prohibit_create, :type => :boolean},
198
210
  {:name => :ext_config__prohibit_update, :type => :boolean},
199
211
  {:name => :ext_config__prohibit_delete, :type => :boolean},
200
212
  {:name => :ext_config__prohibit_read, :type => :boolean}
201
213
  ]
202
214
 
203
- res << {:name => :ext_config__enable_extended_search, :type => :boolean} if config[:extended_search_available]
204
- res << {:name => :ext_config__enable_edit_in_form, :type => :boolean} if config[:edit_in_form_available]
215
+ # res << {:name => :ext_config__enable_extended_search, :type => :boolean} if config[:extended_search_available]
216
+ # res << {:name => :ext_config__enable_edit_in_form, :type => :boolean} if config[:edit_in_form_available]
205
217
 
206
- # TODO: buggy thing
218
+ # TODO: a buggy thing
207
219
  # res << {:name => :layout__columns, :type => :json}
208
220
 
209
221
  res
@@ -237,9 +249,9 @@ module Netzke
237
249
  res << {
238
250
  :persistent_config => true,
239
251
  :name => 'columns',
240
- :class_name => "FieldsConfigurator",
252
+ :class_name => "FieldsConfigurator",
241
253
  :active => true,
242
- :widget => self
254
+ :owner => self
243
255
  }
244
256
  res << {
245
257
  :name => 'general',
@@ -252,15 +264,30 @@ module Netzke
252
264
 
253
265
  def actions
254
266
  # Defaults
255
- {
256
- :add => {:text => 'Add', :disabled => ext_config[:prohibit_create]},
257
- :edit => {:text => 'Edit', :disabled => true},
258
- :del => {:text => 'Delete', :disabled => true},
259
- :apply => {:text => 'Apply', :disabled => ext_config[:prohibit_update] && ext_config[:prohibit_create]},
260
- :add_in_form => {:text => 'Add in form', :disabled => !ext_config[:enable_edit_in_form]},
267
+ actions = {
268
+ :add => {:text => 'Add', :disabled => ext_config[:prohibit_create]},
269
+ :edit => {:text => 'Edit', :disabled => true},
270
+ :del => {:text => 'Delete', :disabled => true},
271
+ :apply => {:text => 'Apply', :disabled => ext_config[:prohibit_update] && ext_config[:prohibit_create]},
272
+ :add_in_form => {:text => 'Add in form', :disabled => !ext_config[:enable_edit_in_form]},
261
273
  :edit_in_form => {:text => 'Edit in form', :disabled => true},
262
- :search => {:text => 'Search', :disabled => !ext_config[:enable_extended_search], :checked => true}
274
+ :search => {:text => 'Search', :disabled => !ext_config[:enable_extended_search], :checked => true}
263
275
  }
276
+
277
+ if Netzke::Base.config[:with_icons]
278
+ icons_uri = Netzke::Base.config[:icons_uri]
279
+ actions.deep_merge!(
280
+ :add => {:icon => icons_uri + "add.png"},
281
+ :edit => {:icon => icons_uri + "table_edit.png"},
282
+ :del => {:icon => icons_uri + "table_row_delete.png"},
283
+ :apply => {:icon => icons_uri + "tick.png"},
284
+ :add_in_form => {:icon => icons_uri + "application_form_add.png"},
285
+ :edit_in_form => {:icon => icons_uri + "application_form_edit.png"},
286
+ :search => {:icon => icons_uri + "find.png"}
287
+ )
288
+ end
289
+
290
+ actions
264
291
  end
265
292
 
266
293
  def initial_late_aggregatees
@@ -276,7 +303,7 @@ module Netzke
276
303
  },
277
304
  :item => {
278
305
  :class_name => "FormPanel",
279
- :model => data_class.name,
306
+ :model => config[:model],
280
307
  :persistent_config => config[:persistent_config],
281
308
  :strong_default_attrs => config[:strong_default_attrs],
282
309
  :ext_config => {
@@ -290,38 +317,50 @@ module Netzke
290
317
  },
291
318
 
292
319
  :edit_form => {
293
- :class_name => "FormPanel",
294
- :model => data_class.name,
295
- :persistent_config => config[:persistent_config],
320
+ :class_name => "GridPanel::RecordFormWindow",
296
321
  :ext_config => {
297
- :bbar => false,
298
- :header => false,
299
- :mode => ext_config[:mode]
300
- }
322
+ :title => "Edit #{data_class.name.humanize}",
323
+ :button_align => "right"
324
+ },
325
+ :item => {
326
+ :class_name => "FormPanel",
327
+ :model => config[:model],
328
+ :persistent_config => config[:persistent_config],
329
+ :ext_config => {
330
+ :bbar => false,
331
+ :header => false,
332
+ :mode => ext_config[:mode]
333
+ }
334
+ },
301
335
  },
302
336
 
303
- :multi_edit_form => {
304
- :class_name => "FormPanel",
305
- :model => data_class.name,
306
- :persistent_config => config[:persistent_config],
307
- :ext_config => {
308
- :bbar => false,
309
- :header => false,
310
- :mode => ext_config[:mode]
311
- }
312
- },
337
+ # :edit_form => {
338
+ # :class_name => "FormPanel",
339
+ # :model => data_class.name,
340
+ # :persistent_config => config[:persistent_config],
341
+ # :ext_config => {
342
+ # :bbar => false,
343
+ # :header => false,
344
+ # :mode => ext_config[:mode]
345
+ # }
346
+ # },
313
347
 
314
- :new_record_form => {
315
- :class_name => "FormPanel",
316
- :model => data_class.name,
317
- :persistent_config => config[:persistent_config],
318
- :strong_default_attrs => config[:strong_default_attrs],
348
+ :multi_edit_form => {
349
+ :class_name => "GridPanel::RecordFormWindow",
319
350
  :ext_config => {
320
- :bbar => false,
321
- :header => false,
322
- :mode => ext_config[:mode]
351
+ :title => "Edit #{data_class.name.humanize}",
352
+ :button_align => "right"
323
353
  },
324
- :record => data_class.new
354
+ :item => {
355
+ :class_name => "FormPanel",
356
+ :model => config[:model],
357
+ :persistent_config => config[:persistent_config],
358
+ :ext_config => {
359
+ :bbar => false,
360
+ :header => false,
361
+ :mode => ext_config[:mode]
362
+ }
363
+ }
325
364
  }
326
365
  }) if ext_config[:enable_edit_in_form]
327
366
 
@@ -329,7 +368,7 @@ module Netzke
329
368
  res.merge!({
330
369
  :search_panel => {
331
370
  :class_name => "SearchPanel",
332
- :search_class_name => data_class.name,
371
+ :search_class_name => config[:model],
333
372
  :persistent_config => config[:persistent_config],
334
373
  :ext_config => {
335
374
  :header => false,
@@ -342,129 +381,7 @@ module Netzke
342
381
  res
343
382
  end
344
383
 
345
-
346
384
  include Plugins::ConfigurationTool if config[:config_tool_available] # it will load ConfigurationPanel into a modal window
347
385
 
348
- def columns
349
- @columns ||= get_columns
350
- end
351
-
352
- # Normalized columns
353
- def normalized_columns
354
- @normalized_columns ||= normalize_columns(columns)
355
- end
356
-
357
- def get_columns
358
- if persistent_config_enabled?
359
- columns = persistent_config['layout__columns'] || default_columns
360
- res = normalize_array_of_columns(columns)
361
- else
362
- res = default_columns
363
- end
364
-
365
- # denormalize
366
- res.map{ |c| c.is_a?(Hash) && c.reject{ |k,v| k == :name }.empty? ? c[:name].to_sym : c }
367
- end
368
-
369
- # Normalizes the column at position +index+ and returns it.
370
- def column_at(index)
371
- if columns[index].is_a?(Hash)
372
- columns[index]
373
- else
374
- column_name = columns.delete_at(index)
375
- normalized_column = normalize_column(column_name)
376
- columns.insert(index, normalized_column)
377
- normalized_column
378
- end
379
- end
380
-
381
- # Stores modified columns in persistent storage
382
- def save_columns!
383
- persistent_config[:layout__columns] = columns
384
- end
385
-
386
- TYPE_EDITOR_MAP = {
387
- :integer => :numberfield,
388
- :boolean => :checkbox,
389
- :date => :datefield,
390
- :datetime => :xdatetime,
391
- :text => :textarea
392
- # :string => :textfield
393
- }
394
-
395
- def default_columns
396
- # columns specified in widget's config
397
- columns_from_config = config[:columns] && normalize_columns(config[:columns])
398
-
399
- if columns_from_config
400
- # reverse-merge each column hash from config with each column hash from exposed_attributes (columns from config have higher priority)
401
- for c in columns_from_config
402
- corresponding_exposed_column = predefined_columns.find{ |k| k[:name] == c[:name] }
403
- c.reverse_merge!(corresponding_exposed_column) if corresponding_exposed_column
404
- end
405
- columns_for_create = columns_from_config
406
- else
407
- # we didn't have columns configured in widget's config, so, use the columns from the data class
408
- columns_for_create = predefined_columns
409
- end
410
-
411
- columns_for_create.map! do |c|
412
- # detect ActiveRecord column type (if the column is "real") or fall back to :virtual
413
- type = (data_class.columns_hash[c[:name].to_s] && data_class.columns_hash[c[:name].to_s].type) || :virtual
414
-
415
- # detect :assoc__method columns
416
- if c[:name].to_s.index('__')
417
- assoc_name, method = c[:name].to_s.split('__').map(&:to_sym)
418
- if assoc = data_class.reflect_on_association(assoc_name)
419
- assoc_column = assoc.klass.columns_hash[method.to_s]
420
- assoc_method_type = assoc_column.try(:type)
421
- if assoc_method_type
422
- c[:editor] ||= TYPE_EDITOR_MAP[assoc_method_type] == :checkbox ? :checkbox : :combobox
423
- end
424
- type = :association
425
- end
426
- end
427
-
428
- # detect association column (e.g. :category_id)
429
- assoc = data_class.reflect_on_all_associations.detect{|a| a.primary_key_name.to_sym == c[:name]}
430
- if assoc && !assoc.options[:polymorphic]
431
- c[:editor] ||= :combobox
432
- assoc_method = %w{name title label id}.detect{|m| (assoc.klass.instance_methods + assoc.klass.column_names).include?(m) } || assoc.klass.primary_key
433
- c[:name] = "#{assoc.name}__#{assoc_method}".to_sym
434
- type = :association
435
- end
436
-
437
- # Some smart defaults
438
-
439
- # default editor, dependent on column type
440
- c[:editor] ||= TYPE_EDITOR_MAP[type] unless TYPE_EDITOR_MAP[type].nil?
441
- # narrow column for checkbox
442
- c[:width] ||= 50 if c[:editor] == :checkbox
443
- # wider column for xdatetime
444
- c[:width] ||= 120 if c[:editor] == :xdatetime
445
- # hide ID column
446
- c[:hidden] = true if c[:name] == data_class.primary_key.to_sym && c[:hidden].nil?
447
- # make ID column read-only
448
- c[:editable] = false if c[:name] == data_class.primary_key.to_sym && c[:editable].nil?
449
-
450
- # Some default limitations for virtual columns
451
- if type == :virtual
452
- # disable filters
453
- # c[:with_filters].nil? && c[:with_filters] = false
454
- # disable sorting
455
- c[:sortable].nil? && c[:sortable] = false
456
- # read-only
457
- # c[:read_only].nil? && c[:read_only] = true
458
- c[:editable].nil? && c[:editable] = false
459
- end
460
-
461
- # denormalize column (save space)
462
- c.reject{ |k,v| k == :name }.empty? ? c[:name] : c
463
- end
464
-
465
- columns_for_create
466
-
467
- end
468
-
469
386
  end
470
387
  end