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.
- data/.autotest +1 -0
- data/.gitignore +6 -0
- data/{CHANGELOG → CHANGELOG.rdoc} +26 -0
- data/README.rdoc +11 -11
- data/Rakefile +37 -11
- data/TODO.rdoc +8 -0
- data/VERSION +1 -0
- data/javascripts/basepack.js +71 -28
- data/lib/app/models/netzke_auto_column.rb +56 -0
- data/lib/netzke-basepack.rb +5 -3
- data/lib/netzke/accordion_panel.rb +69 -67
- data/lib/netzke/active_record/basepack.rb +104 -0
- data/lib/netzke/active_record/data_accessor.rb +33 -0
- data/lib/netzke/basic_app.rb +233 -124
- data/lib/netzke/border_layout_panel.rb +97 -98
- data/lib/netzke/configuration_panel.rb +24 -0
- data/lib/netzke/data_accessor.rb +71 -0
- data/lib/netzke/ext.rb +6 -0
- data/lib/netzke/field_model.rb +1 -1
- data/lib/netzke/fields_configurator.rb +62 -37
- data/lib/netzke/form_panel.rb +161 -51
- data/lib/netzke/form_panel_api.rb +74 -0
- data/lib/netzke/form_panel_js.rb +129 -0
- data/lib/netzke/grid_panel.rb +385 -80
- data/lib/netzke/grid_panel_api.rb +352 -0
- data/lib/netzke/grid_panel_extras/javascripts/rows-dd.js +280 -0
- data/lib/netzke/grid_panel_js.rb +721 -0
- data/lib/netzke/masquerade_selector.rb +53 -0
- data/lib/netzke/panel.rb +9 -0
- data/lib/netzke/plugins/configuration_tool.rb +121 -0
- data/lib/netzke/property_editor.rb +95 -7
- data/lib/netzke/property_editor_extras/helper_model.rb +55 -34
- data/lib/netzke/search_panel.rb +62 -0
- data/lib/netzke/tab_panel.rb +97 -37
- data/lib/netzke/table_editor.rb +49 -44
- data/lib/netzke/tree_panel.rb +15 -16
- data/lib/netzke/wrapper.rb +29 -5
- data/netzke-basepack.gemspec +151 -19
- data/stylesheets/basepack.css +5 -0
- data/test/app_root/app/models/book.rb +1 -1
- data/test/app_root/db/migrate/20081222035855_create_netzke_preferences.rb +1 -1
- data/test/unit/accordion_panel_test.rb +1 -2
- data/test/unit/active_record_basepack_test.rb +54 -0
- data/test/unit/grid_panel_test.rb +8 -12
- data/test/unit/helper_model_test.rb +30 -0
- metadata +69 -78
- data/Manifest +0 -86
- data/TODO +0 -3
- data/lib/app/models/netzke_hash_record.rb +0 -180
- data/lib/app/models/netzke_layout_item.rb +0 -11
- data/lib/netzke/ar_ext.rb +0 -269
- data/lib/netzke/configuration_tool.rb +0 -80
- data/lib/netzke/container.rb +0 -77
- data/lib/netzke/db_fields.rb +0 -44
- data/lib/netzke/fields_configurator_old.rb +0 -62
- data/lib/netzke/form_panel_extras/interface.rb +0 -56
- data/lib/netzke/form_panel_extras/js_builder.rb +0 -134
- data/lib/netzke/grid_panel_extras/interface.rb +0 -206
- data/lib/netzke/grid_panel_extras/js_builder.rb +0 -352
- data/test/unit/ar_ext_test.rb +0 -53
- data/test/unit/netzke_hash_record_test.rb +0 -52
- 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
|
+
});
|