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
@@ -0,0 +1,226 @@
1
+ module Netzke
2
+ class GridPanel < Base
3
+ module GridPanelColumns
4
+ module ClassMethods
5
+ # Columns to be displayed by the FieldConfigurator, "meta-columns". Each corresponds to a configuration
6
+ # option for each column in the grid.
7
+ def meta_columns
8
+ [
9
+ # Whether the column will be present in the grid, also in :hidden or :meta state. The value for this column will
10
+ # always be sent to/from the JS grid to the server
11
+ {:name => "included", :attr_type => :boolean, :width => 40, :header => "Incl", :default_value => true},
12
+
13
+ # The name of the column. May be any accessible method or attribute of the data_class.
14
+ {:name => "name", :attr_type => :string, :width => 200},
15
+
16
+ # The header for the column.
17
+ {:name => "label", :attr_type => :string, :width => 200, :header => "Header"},
18
+
19
+ # The default value of this column. Is used when a new row in the grid gets created.
20
+ {:name => "default_value", :attr_type => :string, :width => 200},
21
+
22
+ # Options for drop-downs
23
+ {:name => "combobox_options", :attr_type => :string, :editor => "textarea", :width => 200},
24
+
25
+ # Whether the column is editable in the grid.
26
+ {:name => "read_only", :attr_type => :boolean, :header => "R/O", :tooltip => "Read-only"},
27
+
28
+ # Whether the column will be in the hidden state (hide/show columns from the column menu, if it's enabled).
29
+ {:name => "hidden", :attr_type => :boolean},
30
+
31
+ # Whether the column should have "grid filters" enabled
32
+ # (see here: http://www.extjs.com/deploy/dev/examples/grid-filtering/grid-filter-local.html)
33
+ {:name => "with_filters", :attr_type => :boolean, :default_value => true, :header => "Filters"},
34
+
35
+ #
36
+ # Below some rarely used parameters, hidden by default (you can always un-hide them from the column menu).
37
+ #
38
+
39
+ # The column's width
40
+ {:name => "width", :attr_type => :integer, :hidden => true},
41
+
42
+ # Whether the column should be hideable
43
+ {:name => "hideable", :attr_type => :boolean, :default_value => true, :hidden => true},
44
+
45
+ # Whether the column should be sortable (why change it? normally it's hardcoded)
46
+ {:name => "sortable", :attr_type => :boolean, :default_value => true, :hidden => true},
47
+
48
+ #
49
+ # And finally some meta columns that we probably never want to see in the GUI
50
+ #
51
+ {:name => "editor", :attr_type => :string, :meta => true}
52
+ ]
53
+ end
54
+
55
+ end
56
+
57
+ module InstanceMethods
58
+
59
+ # Normalized columns for the grid, e.g.:
60
+ # [{:name => :id, :hidden => true, ...}, {:name => :name, :editable => false, ...}, ...]
61
+ def columns(only_included = true)
62
+ @columns ||= begin
63
+ if cols = load_columns
64
+ filter_out_excluded_columns(cols) if only_included
65
+ cols
66
+ else
67
+ initial_columns(only_included)
68
+ end
69
+ end
70
+ end
71
+
72
+ # Columns that we fall back to when neither persistent columns, nor configured columns are present.
73
+ # If there's a model-level field configuration, it's being used.
74
+ # Otherwise the defaults straight from the ActiveRecord model ("netzke_attributes").
75
+ # Override this method if you want to provide a fix set of columns in your subclass.
76
+ def default_columns
77
+ @default_columns ||= load_model_level_attrs || data_class.netzke_attributes
78
+ # @default_columns ||= load_model_level_attrs || data_class.netzke_attributes
79
+ end
80
+
81
+ # Columns that represent a smart merge of default_columns and columns passed during the configuration.
82
+ def initial_columns(only_included = true)
83
+ # Normalize here, as from the config we can get symbols (names) instead of hashes
84
+ columns_from_config = config[:columns] && normalize_attr_config(config[:columns])
85
+
86
+ if columns_from_config
87
+ # reverse-merge each column hash from config with each column hash from exposed_attributes (columns from config have higher priority)
88
+ for c in columns_from_config
89
+ corresponding_default_column = default_columns.find{ |k| k[:name] == c[:name] }
90
+ c.reverse_merge!(corresponding_default_column) if corresponding_default_column
91
+ end
92
+ columns_for_create = columns_from_config
93
+ else
94
+ # we didn't have columns configured in widget's config, so, use the columns from the data class
95
+ columns_for_create = default_columns
96
+ end
97
+
98
+ filter_out_excluded_columns(columns_for_create) if only_included
99
+
100
+ # Make the column config complete with the defaults
101
+ columns_for_create.each do |c|
102
+ detect_association(c)
103
+ set_default_header(c)
104
+ set_default_editor(c)
105
+ set_default_width(c)
106
+ set_default_hidden(c)
107
+ set_default_editable(c)
108
+ set_default_sortable(c)
109
+ set_default_filterable(c)
110
+ end
111
+
112
+ columns_for_create
113
+ end
114
+
115
+ end
116
+
117
+ private
118
+ def filter_out_excluded_columns(cols)
119
+ cols.reject!{ |c| c[:included] == false }
120
+ end
121
+
122
+ # Stores modified columns in persistent storage
123
+ def save_columns!
124
+ NetzkeFieldList.update_list_for_current_authority(global_id, columns(false), data_class.name)
125
+ end
126
+
127
+ def load_columns
128
+ NetzkeFieldList.read_list(global_id) if persistent_config_enabled?
129
+ end
130
+
131
+ def load_model_level_attrs
132
+ NetzkeModelAttrList.read_list(data_class.name)
133
+ end
134
+
135
+ # whether a column is bound to the primary_key
136
+ def reflects_primary_key?(c)
137
+ c[:name] == data_class.primary_key
138
+ end
139
+
140
+ def set_default_header(c)
141
+ c[:label] ||= c[:name].humanize
142
+ end
143
+
144
+ def set_default_editor(c)
145
+ c[:editor] ||= editor_for_attr_type(c[:attr_type])
146
+ end
147
+
148
+ def set_default_width(c)
149
+ c[:width] ||= 50 if c[:attr_type] == :boolean
150
+ c[:width] ||= 150 if c[:attr_type] == :datetime
151
+ end
152
+
153
+ def set_default_hidden(c)
154
+ c[:hidden] = true if reflects_primary_key?(c) && c[:hidden].nil?
155
+ end
156
+
157
+ def set_default_editable(c)
158
+ c[:editable] = c[:read_only].nil? ? !(reflects_primary_key?(c) || c[:virtual]) : !c[:read_only]
159
+ c.delete(:read_only)
160
+ end
161
+
162
+ def set_default_sortable(c)
163
+ c[:sortable] = !c[:virtual]
164
+ end
165
+
166
+ def set_default_filterable(c)
167
+ c[:filterable] = !c[:virtual]
168
+ end
169
+
170
+ # Returns editor's xtype for a column type
171
+ def editor_for_attr_type(type)
172
+ attr_type_to_editor_map[type]
173
+ end
174
+
175
+ def editor_for_association
176
+ :combobox
177
+ end
178
+
179
+ # Returns a hash that maps a column type to the editor xtype. Override if you want different editors.
180
+ def attr_type_to_editor_map
181
+ {
182
+ :integer => :numberfield,
183
+ :boolean => :checkbox,
184
+ :date => :datefield,
185
+ :datetime => :xdatetime,
186
+ :text => :textarea,
187
+ :string => :textfield
188
+ }
189
+ end
190
+
191
+ # Detects an association column and sets up the proper editor.
192
+ # If a column is a foreign key (e.g. "category_id"), also renames the column into "normalized" association column, e.g.:
193
+ # category__name
194
+ # If association doesn't respond to methods "name", "title" or "label", falls back to "id", e.g.:
195
+ # category__id
196
+ def detect_association(c)
197
+ # named as foreign key of some association?
198
+ assoc = data_class.reflect_on_all_associations.detect{|a| a.primary_key_name == c[:name]}
199
+
200
+ if assoc && !assoc.options[:polymorphic]
201
+ assoc_method = %w{name title label id}.detect{|m| (assoc.klass.instance_methods + assoc.klass.column_names).include?(m) } || assoc.klass.primary_key
202
+ c[:name] = "#{assoc.name}__#{assoc_method}"
203
+ end
204
+
205
+ # named with an double-underscore notation? surely an association column then
206
+ if !assoc && c[:name].index('__')
207
+ assoc_name, assoc_method = c[:name].split('__')
208
+ assoc = data_class.reflect_on_association(assoc_name.to_sym)
209
+ end
210
+
211
+ if assoc && assoc_method
212
+ assoc_column = assoc.klass.columns_hash[assoc_method]
213
+ assoc_method_type = assoc_column.try(:type)
214
+
215
+ # if association column is boolean, display a checkbox (or alike), otherwise - a combobox (or alike)
216
+ c[:editor] = assoc_method_type == :boolean ? editor_for_attr_type(:boolean) : editor_for_association
217
+ end
218
+ end
219
+
220
+ def self.included(receiver)
221
+ receiver.extend ClassMethods
222
+ receiver.send :include, InstanceMethods
223
+ end
224
+ end
225
+ end
226
+ end
@@ -1,26 +1,27 @@
1
1
  module Netzke
2
2
  class GridPanel < Base
3
+ # (Dynamic) JavaScript for GridPanel
3
4
  module GridPanelJs
4
- def self.included(base)
5
- base.extend ClassMethods
6
- end
7
-
5
+
6
+ # The result of this method (a hash) is converted to a JSON object and passed as the configuration parameter
7
+ # to the constructor of our JavaScript class. Override it when you want to pass any extra configuration
8
+ # to the JavaScript side.
8
9
  def js_config
9
- res = super
10
- res.merge!(:clmns => columns)
11
- res.merge!(:model => config[:model])
12
- res.merge!(:inline_data => get_data) if ext_config[:load_inline_data]
13
- res.merge!(:pri => data_class.primary_key)
14
- res
10
+ super.merge(
11
+ :clmns => columns, # columns
12
+ :model => config[:model], # the model name
13
+ :inline_data => (get_data if ext_config[:load_inline_data]), # inline data (loaded along with the grid panel)
14
+ :pri => data_class.primary_key # table primary key name
15
+ )
15
16
  end
16
17
 
17
18
  module ClassMethods
18
-
19
+
19
20
  def js_base_class
20
21
  'Ext.grid.EditorGridPanel'
21
22
  end
22
23
 
23
- # Ext.Component#initComponent, built up from pices (dependent on class configuration)
24
+ # Ext.Component#initComponent, built up from pices (dependent on class-level configuration)
24
25
  def js_init_component
25
26
 
26
27
  # Optional "edit in form"-related events
@@ -45,13 +46,11 @@ module Netzke
45
46
  // Normalize columns passed in the config
46
47
  var normClmns = [];
47
48
  Ext.each(this.clmns, function(c){
48
- if (!c.excluded) {
49
- // normalize columns
50
- if (typeof c == 'string') {
51
- normClmns.push({name:c});
52
- } else {
53
- normClmns.push(c);
54
- }
49
+ // normalize columns
50
+ if (typeof c == 'string') {
51
+ normClmns.push({name:c});
52
+ } else {
53
+ normClmns.push(c);
55
54
  }
56
55
  });
57
56
 
@@ -61,9 +60,12 @@ module Netzke
61
60
  this.plugins = []; // checkbox colums is a special case, being a plugin
62
61
 
63
62
  var filters = [];
64
-
65
- // Run through columns
63
+
64
+ // Run through columns and set up different configuration for each
66
65
  Ext.each(normClmns, function(c){
66
+ // We will not use meta columns as actual columns (not even hidden) - only to create the records
67
+ if (c.meta) return;
68
+
67
69
  // Apply default column config
68
70
  Ext.applyIf(c, this.defaultColumnConfig);
69
71
 
@@ -71,20 +73,24 @@ module Netzke
71
73
  c.dataIndex = c.name;
72
74
 
73
75
  // Automatically calculated default values
74
- if (!c.header) {c.header = c.name.humanize()}
76
+ if (!c.header) {c.header = c.label || c.name.humanize()}
75
77
 
76
78
  // normalize editor
77
79
  if (c.editor) {
78
80
  c.editor = Netzke.isObject(c.editor) ? c.editor : {xtype:c.editor};
79
81
  } else {
80
- c.editor = {xtype: 'textfield'}
82
+ c.editor = {xtype: this.attrTypeEditorMap[c.attrType] || 'textfield'}
81
83
  }
82
-
84
+
85
+ // if comboboxOptions are provided, we render a combobox instead of textfield
86
+ if (c.comboboxOptions && c.editor.xtype === "textfield") {
87
+ c.editor = {xtype: "combobox", options: c.comboboxOptions.split('\\n')}
88
+ }
89
+
83
90
  // collect filters
84
- // Not compatible with Ext 3.0
85
- //if (c.withFilters){
86
- // filters.push({type:Ext.netzke.filterMap[c.editor.xtype], dataIndex:c.name});
87
- //}
91
+ if (c.filterable){
92
+ filters.push({type:this.filterTypeForAttrType(c.attrType), dataIndex:c.name});
93
+ }
88
94
 
89
95
  if (c.editor && c.editor.xtype == 'checkbox') {
90
96
  // Special case of checkbox column
@@ -109,12 +115,17 @@ module Netzke
109
115
  if (c.renderer && !Ext.isArray(c.renderer) && c.renderer.match(/^\\s*function\\s*\\(/)) {
110
116
  // if the renderer is an inline function - eval it (double escaping because we are inside of the Ruby string here...)
111
117
  eval("c.renderer = " + c.renderer + ";");
118
+ } else if (Ext.isFunction(this[c.renderer])) {
119
+ // whether the renderer is defined in this.scope
120
+ c.renderer = this[c.renderer].createDelegate(this);
112
121
  } else {
113
122
  // othrewise it's a string representing the name of the renderer or an json-encoded array,
114
123
  // where the first parameter is the renderer's name, and the rest - parameters that should be
115
124
  // passed to the renderer at the moment of calling
116
125
  var renderer = Ext.netzke.normalizedRenderer(c.renderer);
117
- if (renderer != null) c.renderer = renderer;
126
+ if (renderer != null) {
127
+ c.renderer = renderer
128
+ };
118
129
  }
119
130
 
120
131
  // add to the list
@@ -132,14 +143,13 @@ module Netzke
132
143
  /* ... and done with columns */
133
144
 
134
145
  // Filters
135
- // Not compatible with Ext 3.0
136
- // if (this.enableColumnFilters) {
137
- // this.plugins.push(new Ext.grid.GridFilters({filters:filters}));
138
- // }
146
+ if (this.enableColumnFilters) {
147
+ this.plugins.push(new Ext.ux.grid.GridFilters({filters:filters}));
148
+ }
139
149
 
140
150
  // Create Ext.data.Record constructor specific for our particular column configuration
141
151
  this.recordConfig = [];
142
- Ext.each(normClmns, function(column){this.recordConfig.push({name:column.name});}, this);
152
+ Ext.each(normClmns, function(column){this.recordConfig.push({name:column.name, defaultValue:column.defaultValue});}, this);
143
153
  this.Row = Ext.data.Record.create(this.recordConfig);
144
154
 
145
155
  // Drag'n'Drop
@@ -200,8 +210,9 @@ module Netzke
200
210
  this.bbar = (this.enablePagination) ? new Ext.PagingToolbar({
201
211
  pageSize : this.rowsPerPage,
202
212
  items : this.bbar ? ["-"].concat(this.bbar) : [],
203
- store : this.store,
204
- emptyMsg: 'Empty'
213
+ store : this.store,
214
+ emptyMsg: 'Empty',
215
+ displayInfo: true
205
216
  }) : this.bbar;
206
217
 
207
218
  // Selection model
@@ -260,31 +271,60 @@ module Netzke
260
271
 
261
272
  end
262
273
 
274
+ # All the rest that makes our JavaScript class
263
275
  def js_extend_properties
264
276
  res = super
265
277
 
266
- # Generic (non-optional) functionality
267
278
  res.merge!(
268
279
  {
280
+ # all the options are overrideable in config, of course
269
281
  :track_mouse_over => true,
270
282
  :load_mask => true,
271
283
  :auto_scroll => true,
272
284
 
273
- :default_column_config => config_columns.inject({}){ |r, c| c.is_a?(Hash) ? r.merge(c[:name] => c[:default]) : r },
285
+ :default_column_config => meta_columns.inject({}){ |r, c| c.is_a?(Hash) ? r.merge(c[:name] => c[:default]) : r },
274
286
 
275
287
  :init_component => js_init_component.l,
276
288
 
289
+ :attr_type_editor_map => {
290
+ :integer => "numberfield",
291
+ :boolean => "checkbox",
292
+ :decimal => "numberfield",
293
+ :datetime => "xdatetime",
294
+ :date => "datefield",
295
+ :string => "textfield"
296
+ },
297
+
298
+ :filter_type_for_attr_type => <<-END_OF_JAVASCRIPT.l,
299
+ function(attrType){
300
+ var map = {
301
+ integer :'Numeric',
302
+ decimal :'Numeric',
303
+ datetime:'Date',
304
+ date :'Date',
305
+ string :'String',
306
+ };
307
+ map['boolean'] = "Boolean"; // "boolean" is a JS reserved word
308
+ return map[attrType] || 'String';
309
+ }
310
+ END_OF_JAVASCRIPT
311
+
277
312
  # Handlers for actions
278
313
  #
279
314
 
280
315
  :on_add => <<-END_OF_JAVASCRIPT.l,
281
316
  function(){
282
- var rowConfig = {};
283
- var r = new this.Row(rowConfig); // TODO: add default values
317
+ var r = new this.Row();
284
318
  r.isNew = true; // to distinguish new records
285
319
  // r.set('id', r.id); // otherwise later r.get('id') returns empty string
286
320
  this.stopEditing();
287
321
  this.getStore().add(r);
322
+
323
+ // Set default values
324
+ this.getStore().fields.each(function(field){
325
+ r.set(field.name, field.defaultValue);
326
+ });
327
+
288
328
  this.tryStartEditing(this.store.indexOf(r));
289
329
  }
290
330
  END_OF_JAVASCRIPT
@@ -466,11 +506,13 @@ module Netzke
466
506
  function(row){
467
507
  var editableIndex = 0;
468
508
  Ext.each(this.getColumnModel().config, function(c){
469
- if (!c.hidden && c.editable && c.editor && (c.editor.xtype !== 'checkbox')) {
509
+ // skip columns that cannot be edited
510
+ if (!(c.hidden == true || c.editable == false || !c.editor || c.attrType == 'boolean')) {
470
511
  return false;
471
512
  }
472
513
  editableIndex++;
473
514
  });
515
+
474
516
  if (editableIndex < this.getColumnModel().config.length) {this.startEditing(row, editableIndex);}
475
517
  }
476
518
  END_OF_JAVASCRIPT
@@ -575,84 +617,44 @@ module Netzke
575
617
  # Optional edit in form functionality
576
618
  res.merge!(
577
619
  {
578
- :on_successfull_record_creation => <<-END_OF_JAVASCRIPT.l,
579
- function(){
580
- this.formWindow.hide();
581
- this.getStore().reload();
582
- }
583
- END_OF_JAVASCRIPT
584
-
585
- :on_successfull_edit => <<-END_OF_JAVASCRIPT.l,
586
- function(){
587
- this.editFormWindow.close();
588
- delete this.editFormWindow;
589
- this.getStore().reload();
590
- }
591
- END_OF_JAVASCRIPT
592
-
593
620
  :on_edit_in_form => <<-END_OF_JAVASCRIPT.l,
594
621
  function(){
595
- // create the window
596
- delete this.editFormWindow;
597
- this.editFormWindow = new Ext.Window({
598
- title: 'Edit',
599
- layout: 'fit',
600
- modal: true,
601
- width: 400,
602
- height: Ext.lib.Dom.getViewHeight() *0.9,
603
- buttons:[{
604
- text: 'OK',
605
- handler: function(){
606
- this.ownerCt.ownerCt.getWidget().onApply();
607
- }
608
- },{
609
- text:'Cancel',
610
- handler:function(){
611
- this.ownerCt.ownerCt.hide();
612
- }
613
- }]
614
- });
615
-
616
- // show it and load the correct aggregatee in it
617
- this.editFormWindow.show(null, function(){
618
- var selModel = this.getSelectionModel();
619
- if (selModel.getCount() > 1) {
620
-
621
- // multiedit
622
- this.editFormWindow.setTitle('Multi-edit');
623
- this.loadAggregatee({
624
- id: "multiEditForm",
625
- container: this.editFormWindow.id,
626
- callback: function(aggr){
627
- // on apply attach ids of selected rows
628
- aggr.on('apply', function(){
629
- var ids = [];
630
- selModel.each(function(r){
631
- ids.push(r.id);
632
- });
633
- aggr.baseParams = {ids: Ext.encode(ids)}
634
- }, this);
635
- },
636
- scope: this
637
- });
638
- } else {
639
-
640
- // single edit
641
- this.editFormWindow.setTitle('Edit');
642
- var recordId = selModel.getSelected().id;
643
- this.loadAggregatee({
644
- id: "editForm",
645
- container: this.editFormWindow.id,
646
- params: {
647
- record_id: recordId
648
- }
649
- });
650
- }
651
- }, this);
652
-
622
+ var selModel = this.getSelectionModel();
623
+ if (selModel.getCount() > 1) {
624
+ var recordId = selModel.getSelected().id;
625
+ this.loadAggregatee({id: "multiEditForm",
626
+ params: {record_id: recordId},
627
+ callback: function(w){
628
+ var form = w.items.first();
629
+ form.on('apply', function(){
630
+ var ids = [];
631
+ selModel.each(function(r){
632
+ ids.push(r.id);
633
+ });
634
+ form.baseParams = {ids: Ext.encode(ids)}
635
+ }, this);
636
+
637
+ w.on('close', function(){
638
+ if (w.closeRes === "ok") {
639
+ this.store.reload();
640
+ }
641
+ }, this);
642
+ }, scope: this});
643
+ } else {
644
+ var recordId = selModel.getSelected().id;
645
+ this.loadAggregatee({id: "editForm",
646
+ params: {record_id: recordId},
647
+ callback: function(form){
648
+ form.on('close', function(){
649
+ if (form.closeRes === "ok") {
650
+ this.store.reload();
651
+ }
652
+ }, this);
653
+ }, scope: this});
654
+ }
653
655
  }
654
656
  END_OF_JAVASCRIPT
655
-
657
+
656
658
  :on_add_in_form => <<-END_OF_JAVASCRIPT.l,
657
659
  function(){
658
660
  this.loadAggregatee({id: "addForm", callback: function(form){
@@ -679,7 +681,7 @@ module Netzke
679
681
  modal: true,
680
682
  width: 400,
681
683
  height: Ext.lib.Dom.getViewHeight() *0.9,
682
- closeAction:'hide',
684
+ closeAction:'close',
683
685
  buttons:[{
684
686
  text: 'OK',
685
687
  handler: function(){
@@ -694,15 +696,15 @@ module Netzke
694
696
  closePositively : function(){
695
697
  this.conditions = this.getWidget().getForm().getValues();
696
698
  this.closeRes = 'OK';
697
- this.hide();
699
+ this.close();
698
700
  },
699
701
  closeNegatively: function(){
700
702
  this.closeRes = 'cancel';
701
- this.hide();
703
+ this.close();
702
704
  }
703
705
  });
704
706
 
705
- this.searchWindow.on('hide', function(){
707
+ this.searchWindow.on('close', function(){
706
708
  if (this.searchWindow.closeRes == 'OK'){
707
709
  var searchConditions = this.searchWindow.conditions;
708
710
  var filtered = false;
@@ -742,6 +744,11 @@ module Netzke
742
744
  res
743
745
  end
744
746
  end
747
+
748
+ def self.included(base)
749
+ base.extend ClassMethods
750
+ end
751
+
745
752
  end
746
753
  end
747
754
  end