netzke-basepack 0.4.2 → 0.5.1

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/.autotest +1 -0
  2. data/.gitignore +6 -0
  3. data/{CHANGELOG → CHANGELOG.rdoc} +26 -0
  4. data/README.rdoc +11 -11
  5. data/Rakefile +37 -11
  6. data/TODO.rdoc +8 -0
  7. data/VERSION +1 -0
  8. data/javascripts/basepack.js +71 -28
  9. data/lib/app/models/netzke_auto_column.rb +56 -0
  10. data/lib/netzke-basepack.rb +5 -3
  11. data/lib/netzke/accordion_panel.rb +69 -67
  12. data/lib/netzke/active_record/basepack.rb +104 -0
  13. data/lib/netzke/active_record/data_accessor.rb +33 -0
  14. data/lib/netzke/basic_app.rb +233 -124
  15. data/lib/netzke/border_layout_panel.rb +97 -98
  16. data/lib/netzke/configuration_panel.rb +24 -0
  17. data/lib/netzke/data_accessor.rb +71 -0
  18. data/lib/netzke/ext.rb +6 -0
  19. data/lib/netzke/field_model.rb +1 -1
  20. data/lib/netzke/fields_configurator.rb +62 -37
  21. data/lib/netzke/form_panel.rb +161 -51
  22. data/lib/netzke/form_panel_api.rb +74 -0
  23. data/lib/netzke/form_panel_js.rb +129 -0
  24. data/lib/netzke/grid_panel.rb +385 -80
  25. data/lib/netzke/grid_panel_api.rb +352 -0
  26. data/lib/netzke/grid_panel_extras/javascripts/rows-dd.js +280 -0
  27. data/lib/netzke/grid_panel_js.rb +721 -0
  28. data/lib/netzke/masquerade_selector.rb +53 -0
  29. data/lib/netzke/panel.rb +9 -0
  30. data/lib/netzke/plugins/configuration_tool.rb +121 -0
  31. data/lib/netzke/property_editor.rb +95 -7
  32. data/lib/netzke/property_editor_extras/helper_model.rb +55 -34
  33. data/lib/netzke/search_panel.rb +62 -0
  34. data/lib/netzke/tab_panel.rb +97 -37
  35. data/lib/netzke/table_editor.rb +49 -44
  36. data/lib/netzke/tree_panel.rb +15 -16
  37. data/lib/netzke/wrapper.rb +29 -5
  38. data/netzke-basepack.gemspec +151 -19
  39. data/stylesheets/basepack.css +5 -0
  40. data/test/app_root/app/models/book.rb +1 -1
  41. data/test/app_root/db/migrate/20081222035855_create_netzke_preferences.rb +1 -1
  42. data/test/unit/accordion_panel_test.rb +1 -2
  43. data/test/unit/active_record_basepack_test.rb +54 -0
  44. data/test/unit/grid_panel_test.rb +8 -12
  45. data/test/unit/helper_model_test.rb +30 -0
  46. metadata +69 -78
  47. data/Manifest +0 -86
  48. data/TODO +0 -3
  49. data/lib/app/models/netzke_hash_record.rb +0 -180
  50. data/lib/app/models/netzke_layout_item.rb +0 -11
  51. data/lib/netzke/ar_ext.rb +0 -269
  52. data/lib/netzke/configuration_tool.rb +0 -80
  53. data/lib/netzke/container.rb +0 -77
  54. data/lib/netzke/db_fields.rb +0 -44
  55. data/lib/netzke/fields_configurator_old.rb +0 -62
  56. data/lib/netzke/form_panel_extras/interface.rb +0 -56
  57. data/lib/netzke/form_panel_extras/js_builder.rb +0 -134
  58. data/lib/netzke/grid_panel_extras/interface.rb +0 -206
  59. data/lib/netzke/grid_panel_extras/js_builder.rb +0 -352
  60. data/test/unit/ar_ext_test.rb +0 -53
  61. data/test/unit/netzke_hash_record_test.rb +0 -52
  62. data/test/unit/netzke_layout_item_test.rb +0 -28
@@ -0,0 +1,352 @@
1
+ module Netzke
2
+ module GridPanelApi
3
+ def post_data(params)
4
+ success = true
5
+ mod_records = {}
6
+ [:create, :update].each do |operation|
7
+ data = ActiveSupport::JSON.decode(params["#{operation}d_records"]) if params["#{operation}d_records"]
8
+ if !data.nil? && !data.empty? # data may be nil for one of the operations
9
+ mod_records[operation] = process_data(data, operation)
10
+ mod_records[operation] = nil if mod_records[operation].empty?
11
+ end
12
+ break if !success
13
+ end
14
+ {
15
+ :update_new_records => mod_records[:create],
16
+ :update_mod_records => mod_records[:update] || {},
17
+ :feedback => @flash
18
+ }
19
+ end
20
+
21
+ def get_data(params = {})
22
+ if !ext_config[:prohibit_read]
23
+ records = get_records(params)
24
+ {:data => records.map{|r| r.to_array(normalized_columns, self)}, :total => ext_config[:enable_pagination] && records.total_entries}
25
+ else
26
+ flash :error => "You don't have permissions to read data"
27
+ {:feedback => @flash}
28
+ end
29
+ end
30
+
31
+ def delete_data(params = {})
32
+ if !ext_config[:prohibit_delete]
33
+ record_ids = ActiveSupport::JSON.decode(params[:records])
34
+ klass = config[:data_class_name].constantize
35
+ klass.delete(record_ids)
36
+ {:feedback => "Deleted #{record_ids.size} record(s)", :load_store_data => get_data}
37
+ else
38
+ {:feedback => "You don't have permissions to delete data"}
39
+ end
40
+ end
41
+
42
+ def resize_column(params)
43
+ raise "Called api_resize_column while not configured to do so" if ext_config[:enable_column_resize] == false
44
+ column_at(params[:index].to_i)[:width] = params[:size].to_i
45
+ save_columns!
46
+ {}
47
+ end
48
+
49
+ def hide_column(params)
50
+ raise "Called api_hide_column while not configured to do so" if ext_config[:enable_column_hide] == false
51
+ column_at(params[:index].to_i)[:hidden] = params[:hidden].to_b
52
+ save_columns!
53
+ {}
54
+ end
55
+
56
+ def move_column(params)
57
+ raise "Called api_move_column while not configured to do so" if ext_config[:enable_column_move] == false
58
+ column_to_move = columns.delete_at(params[:old_index].to_i)
59
+ columns.insert(params[:new_index].to_i, column_to_move)
60
+ save_columns!
61
+
62
+ # reorder the columns on the client side (still not sure if it's not an overkill)
63
+ # {:reorder_columns => columns.map(&:name)} # Well, I think it IS an overkill - commented out
64
+ # until proven to be necessary
65
+ {}
66
+ end
67
+
68
+ # Return the choices for the column
69
+ def get_combobox_options(params)
70
+ column = params[:column]
71
+ query = params[:query]
72
+
73
+ {:data => config[:data_class_name].constantize.options_for(column, query).map{|s| [s]}}
74
+ end
75
+
76
+ # Returns searchlogic's search with all the conditions
77
+ def get_search(params)
78
+ @search ||= begin
79
+ raise ArgumentError, "No data_class_name specified for widget '#{name}'" if !config[:data_class_name]
80
+
81
+ # make params coming from Ext grid filters understandable by searchlogic
82
+ search_params = normalize_params(params)
83
+
84
+ # merge with conditions coming from the config
85
+ search_params[:conditions].deep_merge!(config[:conditions] || {})
86
+
87
+ # merge with extra conditions (in searchlogic format, come from the extended search form)
88
+ search_params[:conditions].deep_merge!(
89
+ normalize_extra_conditions(ActiveSupport::JSON.decode(params[:extra_conditions]))
90
+ ) if params[:extra_conditions]
91
+
92
+ search = config[:data_class_name].constantize.search(search_params)
93
+
94
+ # applying scopes
95
+ scopes.each do |s|
96
+ if s.is_a?(Array)
97
+ scope_name, *args = s
98
+ search.send(scope_name, *args)
99
+ else
100
+ search.send(s)
101
+ end
102
+ end
103
+
104
+ search
105
+ end
106
+ end
107
+
108
+ def configuration_panel__columns__get_combobox_options(params)
109
+ query = params[:query]
110
+
111
+ data_arry = case params[:column]
112
+ when "name"
113
+ predefined_columns.map{ |c| c[:name].to_s }
114
+ else
115
+ raise RuntimeError, "Don't know about options for column '#{params[:column]}'"
116
+ end
117
+
118
+ {:data => data_arry.grep(/^#{query}/).map{ |n| [n] }}.to_nifty_json
119
+ end
120
+
121
+ protected
122
+
123
+ # operation => :update || :create
124
+ def process_data(data, operation)
125
+ success = true
126
+ # mod_record_ids = []
127
+ mod_records = {}
128
+ if !ext_config["prohibit_#{operation}".to_sym]
129
+ klass = config[:data_class_name].constantize
130
+ modified_records = 0
131
+ data.each do |record_hash|
132
+ id = record_hash.delete('id')
133
+ record = operation == :create ? klass.new : klass.find(id)
134
+ success = true
135
+
136
+ # merge with strong default attirbutes
137
+ record_hash.merge!(config[:strong_default_attrs]) if config[:strong_default_attrs]
138
+
139
+ # process all attirubutes for this record
140
+ record_hash.each_pair do |k,v|
141
+ begin
142
+ record.send("#{k}=",v)
143
+ rescue ArgumentError => exc
144
+ flash :error => exc.message
145
+ success = false
146
+ break
147
+ end
148
+ end
149
+
150
+ # try to save
151
+ # modified_records += 1 if success && record.save
152
+ mod_records[id] = record.to_array(columns, self) if success && record.save
153
+ # mod_record_ids << id if success && record.save
154
+
155
+ # flash eventual errors
156
+ if !record.errors.empty?
157
+ success = false
158
+ record.errors.each_full do |msg|
159
+ flash :error => msg
160
+ end
161
+ end
162
+ end
163
+ # flash :notice => "#{operation.to_s.capitalize}d #{modified_records} record(s)"
164
+ else
165
+ success = false
166
+ flash :error => "You don't have permissions to #{operation} data"
167
+ end
168
+ mod_records
169
+ end
170
+
171
+ # get records
172
+ def get_records(params)
173
+ # Restore params from widget_session if requested
174
+ if params[:with_last_params]
175
+ params = widget_session[:last_params]
176
+ else
177
+ # remember the last params
178
+ widget_session[:last_params] = params
179
+ end
180
+
181
+ search = get_search(params)
182
+
183
+ # sorting
184
+ if params[:sort]
185
+ assoc, method = params[:sort].split('__')
186
+ sort_string = method.nil? ? assoc : "#{assoc}_#{method}"
187
+ sort_string = (params[:dir] == "ASC" ? "ascend_by_" : "descend_by_") + sort_string
188
+ search.order(sort_string)
189
+ end
190
+
191
+ # pagination
192
+ if ext_config[:enable_pagination]
193
+ per_page = ext_config[:rows_per_page]
194
+ page = params[:limit] ? params[:start].to_i/params[:limit].to_i + 1 : 1
195
+ search.paginate(:per_page => per_page, :page => page)
196
+ else
197
+ search.all
198
+ end
199
+ end
200
+
201
+ # Create record with form
202
+ def create_new_record(params)
203
+ form_data = ActiveSupport::JSON.decode(params[:data])
204
+ res = aggregatee_instance(:new_record_form).create_or_update_record(form_data)
205
+
206
+ if res[:set_form_values]
207
+ # successful creation
208
+ res[:set_form_values] = nil
209
+ res[:on_successfull_record_creation] = true
210
+ end
211
+ res
212
+ end
213
+
214
+ # Move rows
215
+ def move_rows(params)
216
+ if defined?(ActsAsList) && data_class.ancestors.include?(ActsAsList::InstanceMethods)
217
+ ids = JSON.parse(params[:ids]).reverse
218
+ ids.each_with_index do |id, i|
219
+ r = data_class.find(id)
220
+ r.insert_at(params[:new_index].to_i + i + 1)
221
+ end
222
+ else
223
+ raise RuntimeError, "Data class should 'acts_as_list' to support moving rows"
224
+ end
225
+ {}
226
+ end
227
+
228
+ # When providing the edit_form aggregatee, fill in the form with the requested record
229
+ def load_aggregatee_with_cache(params)
230
+ if params[:id] == 'edit_form'
231
+ super(params.merge(:config => {:record_id => params[:record_id]}.to_json))
232
+ else
233
+ super
234
+ end
235
+ end
236
+
237
+ # Search scopes, in searchlogic format
238
+ def scopes
239
+ @scopes ||= config[:scopes] || []
240
+ end
241
+
242
+ # Converts Ext.grid.GridFilters filters to searchlogic conditions, e.g.
243
+ # {"0" => {
244
+ # "data" => {
245
+ # "type" => "numeric",
246
+ # "comparison" => "gt",
247
+ # "value" => 10 },
248
+ # "field" => "id"
249
+ # },
250
+ # "1" => {
251
+ # "data" => {
252
+ # "type" => "string",
253
+ # "value" => "pizza"
254
+ # },
255
+ # "field" => "food_name"
256
+ # }}
257
+ #
258
+ # =>
259
+ #
260
+ # {"id_gt" => 100, "food_name_contains" => "pizza"}
261
+ def convert_filters(column_filter)
262
+ res = {}
263
+ column_filter.each_pair do |k,v|
264
+ field = v["field"].dup
265
+ case v["data"]["type"]
266
+ when "string"
267
+ field << "_contains"
268
+ when "numeric"
269
+ field << "_#{v["data"]["comparison"]}"
270
+ end
271
+ value = v["data"]["value"]
272
+ res.merge!({field => value})
273
+ end
274
+ res
275
+ end
276
+
277
+ def normalize_extra_conditions(conditions)
278
+ conditions.convert_keys{|k| k.to_s.gsub("__", "_").to_sym}
279
+ end
280
+
281
+ # make params understandable to searchlogic
282
+ def normalize_params(params)
283
+ # filters
284
+ conditions = params[:filter] && convert_filters(params[:filter])
285
+
286
+ normalized_conditions = {}
287
+ conditions && conditions.each_pair do |k, v|
288
+ assoc, method = k.split('__')
289
+ normalized_conditions.merge!(method.nil? ? {assoc => v} : {assoc => {method => v}})
290
+ end
291
+
292
+ {:conditions => normalized_conditions}
293
+ end
294
+
295
+ ## Edit in form specific API
296
+ def new_record_form__submit(params)
297
+ form_data = ActiveSupport::JSON.decode(params[:data])
298
+
299
+ # merge with strong default attirbutes
300
+ form_data.merge!(config[:strong_default_attrs]) if config[:strong_default_attrs]
301
+
302
+ res = aggregatee_instance(:new_record_form).create_or_update_record(form_data)
303
+
304
+ if res[:set_form_values]
305
+ # successful creation
306
+ res[:set_form_values] = nil
307
+ res.merge!({
308
+ :parent => {:on_successfull_record_creation => true}
309
+ })
310
+ end
311
+ res.to_nifty_json
312
+ end
313
+
314
+ def check_for_positive_result(res)
315
+ if res[:set_form_values]
316
+ # successful creation
317
+ res[:set_form_values] = nil
318
+ res.merge!({
319
+ :parent => {:on_successfull_edit => true}
320
+ })
321
+ end
322
+ end
323
+
324
+ def edit_form__submit(params)
325
+ form_data = ActiveSupport::JSON.decode(params[:data])
326
+ res = aggregatee_instance(:new_record_form).create_or_update_record(form_data)
327
+
328
+ check_for_positive_result(res)
329
+
330
+ res.to_nifty_json
331
+ end
332
+
333
+ def multi_edit_form__submit(params)
334
+ form_data = ActiveSupport::JSON.decode(params[:data])
335
+ form_instance = aggregatee_instance(:new_record_form)
336
+
337
+ ids = ActiveSupport::JSON.decode(params[:ids])
338
+
339
+ res = {}
340
+ ids.each do |id|
341
+ res = form_instance.create_or_update_record(form_data.merge("id" => id))
342
+ break if !res[:set_form_values]
343
+ end
344
+
345
+ check_for_positive_result(res)
346
+
347
+ res.to_nifty_json
348
+ end
349
+
350
+
351
+ end
352
+ end
@@ -0,0 +1,280 @@
1
+ Ext.namespace('Ext.ux.dd');
2
+
3
+ Ext.ux.dd.GridDragDropRowOrder = Ext.extend(Ext.util.Observable,
4
+ {
5
+ copy: false,
6
+
7
+ scrollable: false,
8
+
9
+ constructor : function(config)
10
+ {
11
+ Ext.ux.dd.GridDragDropRowOrder.superclass.constructor.call(this);
12
+ if (config)
13
+ Ext.apply(this, config);
14
+
15
+ this.addEvents(
16
+ {
17
+ beforerowmove: true,
18
+ afterrowmove: true,
19
+ beforerowcopy: true,
20
+ afterrowcopy: true
21
+ });
22
+ },
23
+
24
+ init : function (grid)
25
+ {
26
+ this.grid = grid;
27
+ grid.enableDragDrop = true;
28
+
29
+ grid.on({
30
+ render: { fn: this.onGridRender, scope: this, single: true }
31
+ });
32
+ },
33
+
34
+ onGridRender : function (grid)
35
+ {
36
+ var self = this;
37
+
38
+ this.target = new Ext.dd.DropTarget(grid.getEl(),
39
+ {
40
+ ddGroup: grid.ddGroup || 'GridDD',
41
+ grid: grid,
42
+ gridDropTarget: this,
43
+
44
+ notifyDrop: function(dd, e, data)
45
+ {
46
+ // Remove drag lines. The 'if' condition prevents null error when drop occurs without dragging out of the selection area
47
+ if (this.currentRowEl)
48
+ {
49
+ this.currentRowEl.removeClass('grid-row-insert-below');
50
+ this.currentRowEl.removeClass('grid-row-insert-above');
51
+ }
52
+
53
+ // determine the row
54
+ var t = Ext.lib.Event.getTarget(e);
55
+ var rindex = this.grid.getView().findRowIndex(t);
56
+ if (rindex === false || rindex == data.rowIndex)
57
+ {
58
+ return false;
59
+ }
60
+ // fire the before move/copy event
61
+ if (this.gridDropTarget.fireEvent(self.copy ? 'beforerowcopy' : 'beforerowmove', this.gridDropTarget, data.rowIndex, rindex, data.selections, 123) === false)
62
+ {
63
+ return false;
64
+ }
65
+
66
+ // update the store
67
+ var ds = this.grid.getStore();
68
+
69
+ // Changes for multiselction by Spirit
70
+ var selections = new Array();
71
+ var keys = ds.data.keys;
72
+ for (var key in keys)
73
+ {
74
+ for (var i = 0; i < data.selections.length; i++)
75
+ {
76
+ if (keys[key] == data.selections[i].id)
77
+ {
78
+ // Exit to prevent drop of selected records on itself.
79
+ if (rindex == key)
80
+ {
81
+ return false;
82
+ }
83
+ selections.push(data.selections[i]);
84
+ }
85
+ }
86
+ }
87
+
88
+ // fix rowindex based on before/after move
89
+ if (rindex > data.rowIndex && this.rowPosition < 0)
90
+ {
91
+ rindex--;
92
+ }
93
+ if (rindex < data.rowIndex && this.rowPosition > 0)
94
+ {
95
+ rindex++;
96
+ }
97
+
98
+ // fix rowindex for multiselection
99
+ if (rindex > data.rowIndex && data.selections.length > 1)
100
+ {
101
+ rindex = rindex - (data.selections.length - 1);
102
+ }
103
+
104
+ // we tried to move this node before the next sibling, we stay in place
105
+ if (rindex == data.rowIndex)
106
+ {
107
+ return false;
108
+ }
109
+
110
+ // fire the before move/copy event
111
+ /* dupe - does it belong here or above???
112
+ if (this.gridDropTarget.fireEvent(self.copy ? 'beforerowcopy' : 'beforerowmove', this.gridDropTarget, data.rowIndex, rindex, data.selections, 123) === false)
113
+ {
114
+ return false;
115
+ }
116
+ */
117
+
118
+ if (!self.copy)
119
+ {
120
+ for (var i = 0; i < data.selections.length; i++)
121
+ {
122
+ ds.remove(ds.getById(data.selections[i].id));
123
+ }
124
+ }
125
+
126
+ for (var i = selections.length - 1; i >= 0; i--)
127
+ {
128
+ var insertIndex = rindex;
129
+ ds.insert(insertIndex, selections[i]);
130
+ }
131
+
132
+ // re-select the row(s)
133
+ var sm = this.grid.getSelectionModel();
134
+ if (sm)
135
+ {
136
+ sm.selectRecords(data.selections);
137
+ }
138
+
139
+ // console.info(this.gridDropTarget);
140
+
141
+ // fire the after move/copy event
142
+ this.gridDropTarget.fireEvent(self.copy ? 'afterrowcopy' : 'afterrowmove', this.gridDropTarget, data.rowIndex, rindex, data.selections);
143
+ return true;
144
+ },
145
+
146
+ notifyOver: function(dd, e, data)
147
+ {
148
+ var t = Ext.lib.Event.getTarget(e);
149
+ var rindex = this.grid.getView().findRowIndex(t);
150
+
151
+ // Similar to the code in notifyDrop. Filters for selected rows and quits function if any one row matches the current selected row.
152
+ var ds = this.grid.getStore();
153
+ var keys = ds.data.keys;
154
+ for (var key in keys)
155
+ {
156
+ for (var i = 0; i < data.selections.length; i++)
157
+ {
158
+ if (keys[key] == data.selections[i].id)
159
+ {
160
+ if (rindex == key)
161
+ {
162
+ if (this.currentRowEl)
163
+ {
164
+ this.currentRowEl.removeClass('grid-row-insert-below');
165
+ this.currentRowEl.removeClass('grid-row-insert-above');
166
+ }
167
+ return this.dropNotAllowed;
168
+ }
169
+ }
170
+ }
171
+ }
172
+
173
+ // If on first row, remove upper line. Prevents negative index error as a result of rindex going negative.
174
+ if (rindex < 0 || rindex === false)
175
+ {
176
+ this.currentRowEl.removeClass('grid-row-insert-above');
177
+ return this.dropNotAllowed;
178
+ }
179
+
180
+ try
181
+ {
182
+ var currentRow = this.grid.getView().getRow(rindex);
183
+ // Find position of row relative to page (adjusting for grid's scroll position)
184
+ var resolvedRow = new Ext.Element(currentRow).getY() - this.grid.getView().scroller.dom.scrollTop;
185
+ var rowHeight = currentRow.offsetHeight;
186
+
187
+ // Cursor relative to a row. -ve value implies cursor is above the row's middle and +ve value implues cursor is below the row's middle.
188
+ this.rowPosition = e.getPageY() - resolvedRow - (rowHeight/2);
189
+
190
+ // Clear drag line.
191
+ if (this.currentRowEl)
192
+ {
193
+ this.currentRowEl.removeClass('grid-row-insert-below');
194
+ this.currentRowEl.removeClass('grid-row-insert-above');
195
+ }
196
+
197
+ if (this.rowPosition > 0)
198
+ {
199
+ // If the pointer is on the bottom half of the row.
200
+ this.currentRowEl = new Ext.Element(currentRow);
201
+ this.currentRowEl.addClass('grid-row-insert-below');
202
+ }
203
+ else
204
+ {
205
+ // If the pointer is on the top half of the row.
206
+ if (rindex - 1 >= 0)
207
+ {
208
+ var previousRow = this.grid.getView().getRow(rindex - 1);
209
+ this.currentRowEl = new Ext.Element(previousRow);
210
+ this.currentRowEl.addClass('grid-row-insert-below');
211
+ }
212
+ else
213
+ {
214
+ // If the pointer is on the top half of the first row.
215
+ this.currentRowEl.addClass('grid-row-insert-above');
216
+ }
217
+ }
218
+ }
219
+ catch (err)
220
+ {
221
+ console.warn(err);
222
+ rindex = false;
223
+ }
224
+ return (rindex === false)? this.dropNotAllowed : this.dropAllowed;
225
+ },
226
+
227
+ notifyOut: function(dd, e, data)
228
+ {
229
+ // Remove drag lines when pointer leaves the gridView.
230
+ if (this.currentRowEl)
231
+ {
232
+ this.currentRowEl.removeClass('grid-row-insert-above');
233
+ this.currentRowEl.removeClass('grid-row-insert-below');
234
+ }
235
+ }
236
+ });
237
+
238
+ if (this.targetCfg)
239
+ {
240
+ Ext.apply(this.target, this.targetCfg);
241
+ }
242
+
243
+ if (this.scrollable)
244
+ {
245
+ Ext.dd.ScrollManager.register(grid.getView().getEditorParent());
246
+ grid.on({
247
+ beforedestroy: this.onBeforeDestroy,
248
+ scope: this,
249
+ single: true
250
+ });
251
+ }
252
+ },
253
+
254
+ getTarget: function()
255
+ {
256
+ return this.target;
257
+ },
258
+
259
+ getGrid: function()
260
+ {
261
+ return this.grid;
262
+ },
263
+
264
+ getCopy: function()
265
+ {
266
+ return this.copy ? true : false;
267
+ },
268
+
269
+ setCopy: function(b)
270
+ {
271
+ this.copy = b ? true : false;
272
+ },
273
+
274
+ onBeforeDestroy : function (grid)
275
+ {
276
+ // if we previously registered with the scroll manager, unregister
277
+ // it (if we don't it will lead to problems in IE)
278
+ Ext.dd.ScrollManager.unregister(grid.getView().getEditorParent());
279
+ }
280
+ });