netzke-basepack 0.4.2 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
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
+ });