netzke-basepack 0.12.0 → 0.12.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -547
- data/Gemfile +4 -1
- data/README.md +2 -1
- data/javascripts/basepack.js +9 -2
- data/javascripts/columns.js +224 -0
- data/{lib/netzke/basepack/grid/javascripts/event_handling.js → javascripts/mixins/grid_event_handlers.js} +58 -9
- data/lib/netzke/basepack.rb +1 -3
- data/lib/netzke/basepack/columns.rb +0 -2
- data/lib/netzke/basepack/data_adapters/abstract_adapter.rb +18 -0
- data/lib/netzke/basepack/data_adapters/active_record_adapter.rb +26 -29
- data/lib/netzke/basepack/form.rb +1 -2
- data/lib/netzke/basepack/form/endpoints.rb +35 -0
- data/lib/netzke/basepack/form/services.rb +18 -61
- data/lib/netzke/basepack/grid.rb +6 -7
- data/lib/netzke/basepack/grid/endpoints.rb +0 -1
- data/lib/netzke/basepack/grid/javascripts/extensions.js +2 -0
- data/lib/netzke/basepack/grid/javascripts/grid.js +2 -203
- data/lib/netzke/basepack/grid/services.rb +3 -1
- data/lib/netzke/basepack/search_panel.rb +7 -5
- data/lib/netzke/basepack/search_panel/javascripts/condition_field.js +1 -2
- data/lib/netzke/basepack/tree.rb +223 -0
- data/lib/netzke/basepack/tree/javascripts/extensions.js +101 -0
- data/lib/netzke/basepack/tree/javascripts/tree.js +112 -0
- data/lib/netzke/basepack/version.rb +1 -1
- data/locales/en.yml +18 -0
- metadata +8 -3
@@ -128,7 +128,9 @@ module Netzke
|
|
128
128
|
attrs.merge!(config[:strong_default_attrs]) if config[:strong_default_attrs]
|
129
129
|
|
130
130
|
attrs.each_pair do |k,v|
|
131
|
-
|
131
|
+
attr = final_columns_hash[k.to_sym]
|
132
|
+
next if attr.nil?
|
133
|
+
data_adapter.set_record_value_for_attribute(record, attr, v)
|
132
134
|
end
|
133
135
|
|
134
136
|
if record.save
|
@@ -9,24 +9,24 @@ module Netzke
|
|
9
9
|
i18n_path = "netzke.basepack.search_panel.%s"
|
10
10
|
|
11
11
|
ATTRIBUTE_OPERATORS_MAP = {
|
12
|
-
:
|
12
|
+
integer: [
|
13
13
|
["eq", I18n.t(i18n_path % 'equals')],
|
14
14
|
["gt", I18n.t(i18n_path % 'greater_than')],
|
15
15
|
["lt", I18n.t(i18n_path % 'less_than')]
|
16
16
|
],
|
17
|
-
:
|
17
|
+
text: [
|
18
18
|
["contains", I18n.t(i18n_path % 'contains')] # same as matches => %string%
|
19
19
|
],
|
20
|
-
:
|
20
|
+
string: [
|
21
21
|
["contains", I18n.t(i18n_path % 'contains')], # same as matches => %string%
|
22
22
|
["matches", I18n.t(i18n_path % 'matches')]
|
23
23
|
],
|
24
|
-
:
|
24
|
+
boolean: [
|
25
25
|
["is_any", I18n.t(i18n_path % 'is_true')],
|
26
26
|
["is_true", I18n.t(i18n_path % 'is_true')],
|
27
27
|
["is_false", I18n.t(i18n_path % 'is_false')]
|
28
28
|
],
|
29
|
-
:
|
29
|
+
date: [
|
30
30
|
["eq", I18n.t(i18n_path % 'date_equals')],
|
31
31
|
["gt", I18n.t(i18n_path % 'after')],
|
32
32
|
["lt", I18n.t(i18n_path % 'before')],
|
@@ -36,6 +36,8 @@ module Netzke
|
|
36
36
|
}
|
37
37
|
|
38
38
|
ATTRIBUTE_OPERATORS_MAP[:datetime] = ATTRIBUTE_OPERATORS_MAP[:date]
|
39
|
+
ATTRIBUTE_OPERATORS_MAP[:decimal] = ATTRIBUTE_OPERATORS_MAP[:integer]
|
40
|
+
ATTRIBUTE_OPERATORS_MAP[:float] = ATTRIBUTE_OPERATORS_MAP[:integer]
|
39
41
|
|
40
42
|
js_configure do |c|
|
41
43
|
c.extend = "Ext.form.FormPanel"
|
@@ -142,9 +142,8 @@ Ext.define('Netzke.classes.Netzke.Basepack.SearchPanel.ConditionField', {
|
|
142
142
|
var idx = this.ownerCt.items.indexOf(this);
|
143
143
|
var owner = this.ownerCt;
|
144
144
|
var newSelf = Ext.createByAlias('widget.netzkebasepacksearchpanelconditionfield', Ext.apply(this.initialConfig, {name: attr, attrType: attrType, attr: attr.underscore(), ownerCt: this.ownerCt, operator: null}));
|
145
|
-
owner.remove(this);
|
146
145
|
owner.insert(idx, newSelf);
|
147
|
-
|
146
|
+
setTimeout(function() { this.destroy(); }.bind(this), 1); // this gives time for pending events to get handled without errors
|
148
147
|
},
|
149
148
|
|
150
149
|
// Returns true if it should be in the query
|
@@ -0,0 +1,223 @@
|
|
1
|
+
module Netzke
|
2
|
+
module Basepack
|
3
|
+
# Ext.tree.Panel-based component with the following features:
|
4
|
+
#
|
5
|
+
# * CRUD operations (only R is implemented atm)
|
6
|
+
#
|
7
|
+
# == Simple example
|
8
|
+
#
|
9
|
+
# class Files < Netzke::Basepack::Tree
|
10
|
+
# def configure(c)
|
11
|
+
# super
|
12
|
+
# c.model = "FileRecord"
|
13
|
+
# c.columns = [
|
14
|
+
# {name: :name, xtype: :treecolumn},
|
15
|
+
# :size
|
16
|
+
# ]
|
17
|
+
# end
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# == Instance configuration
|
21
|
+
#
|
22
|
+
# The following config options are supported:
|
23
|
+
#
|
24
|
+
# [model]
|
25
|
+
#
|
26
|
+
# Name of the ActiveRecord model that provides data to this Tree, e.g. "FileRecord"
|
27
|
+
# The model must respond to the following methods:
|
28
|
+
#
|
29
|
+
# * TreeModel.root - the root record
|
30
|
+
# * TreeModel#children - child records
|
31
|
+
#
|
32
|
+
# Note that the awesome_nested_set gem implements the above, so, feel free to use it.
|
33
|
+
#
|
34
|
+
# [columns]
|
35
|
+
#
|
36
|
+
# An array of columns to be displayed in the tree. See the "Columns" section in the `Netzke::Basepack::Grid`.
|
37
|
+
# Additionally, you probably will want to specify which column will have the tree nodes UI by providing the
|
38
|
+
# `xtype` config option set to `:treecolumn`.
|
39
|
+
#
|
40
|
+
# [root]
|
41
|
+
#
|
42
|
+
# By default, the component will pick whatever record is returned by `TreeModel.root`, and use it as the root
|
43
|
+
# record. However, sometimes the model table has multiple root records (which `parent_id` set to `nil`), and all
|
44
|
+
# of them should be shown in the panel. To achive this, you can define the `root` config option,
|
45
|
+
# which will serve as a virtual root record for those records. You may set it to `true`, or a hash of
|
46
|
+
# attributes, e.g.:
|
47
|
+
#
|
48
|
+
# c.root = {name: 'Root', size: 1000}
|
49
|
+
#
|
50
|
+
# Note, that the root record can be hidden from the tree by specifying the `Ext.tree.Panel`'s `root_visible`
|
51
|
+
# config option set to `false`, which is probably what you want when you have multiple root records.
|
52
|
+
class Tree < Netzke::Base
|
53
|
+
NODE_ATTRS = {
|
54
|
+
boolean: %w[leaf checked expanded expandable qtip qtitle],
|
55
|
+
string: %w[icon icon_cls href href_target qtip qtitle]
|
56
|
+
}
|
57
|
+
|
58
|
+
include Netzke::Basepack::Grid::Endpoints
|
59
|
+
include Netzke::Basepack::Grid::Services
|
60
|
+
include Netzke::Basepack::Columns
|
61
|
+
include Netzke::Basepack::DataAccessor
|
62
|
+
|
63
|
+
js_configure do |c|
|
64
|
+
c.extend = "Ext.tree.Panel"
|
65
|
+
c.mixin
|
66
|
+
c.mixins << "Netzke.mixins.Basepack.Columns"
|
67
|
+
c.mixins << "Netzke.mixins.Basepack.GridEventHandlers"
|
68
|
+
c.translate *%w[are_you_sure confirmation]
|
69
|
+
c.require :extensions
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.server_side_config_options
|
73
|
+
super + [:model]
|
74
|
+
end
|
75
|
+
|
76
|
+
def configure(c)
|
77
|
+
set_defaults(c)
|
78
|
+
super
|
79
|
+
end
|
80
|
+
|
81
|
+
def columns
|
82
|
+
add_node_interface_methods(super)
|
83
|
+
end
|
84
|
+
|
85
|
+
def get_records(params)
|
86
|
+
if params[:id] == 'root'
|
87
|
+
data_adapter.find_root_records
|
88
|
+
else
|
89
|
+
data_adapter.find_record_children(data_adapter.find_record(params[:id]))
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# Override Grid::Services#read so we send records as key-value JSON (instead of array)
|
94
|
+
def read(params = {})
|
95
|
+
{}.tap do |res|
|
96
|
+
records = get_records(params)
|
97
|
+
res[:data] = records.map{|r| data_adapter.record_to_hash(r, final_columns(:with_meta => true)).netzke_literalize_keys}
|
98
|
+
res[:total] = count_records(params) if config[:enable_pagination]
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def js_configure(c)
|
103
|
+
super
|
104
|
+
|
105
|
+
c.title = c.title || self.class.js_config.properties[:title] || data_class.name.pluralize
|
106
|
+
c.bbar = bbar
|
107
|
+
# c.context_menu = context_menu
|
108
|
+
c.columns = js_columns
|
109
|
+
c.columns_order = columns_order
|
110
|
+
c.inline_data = read if c.load_inline_data
|
111
|
+
c.pri = data_adapter.primary_key
|
112
|
+
|
113
|
+
if c.default_filters
|
114
|
+
populate_cols_with_filters(c)
|
115
|
+
end
|
116
|
+
|
117
|
+
c.root ||= data_adapter.record_to_hash(data_adapter.root, final_columns(with_meta: true)).netzke_literalize_keys
|
118
|
+
end
|
119
|
+
|
120
|
+
action :add do |a|
|
121
|
+
a.handler = "onAddRecord" # overriding naming conventions as Ext 4 grid has its own onAdd method
|
122
|
+
a.icon = :add
|
123
|
+
end
|
124
|
+
|
125
|
+
action :edit do |a|
|
126
|
+
# a.disabled = true
|
127
|
+
a.handler = :onEdit
|
128
|
+
a.icon = :table_edit
|
129
|
+
end
|
130
|
+
|
131
|
+
action :apply do |a|
|
132
|
+
a.disabled = config[:prohibit_update] && config[:prohibit_create]
|
133
|
+
a.icon = :tick
|
134
|
+
end
|
135
|
+
|
136
|
+
action :del do |a|
|
137
|
+
# a.disabled = true
|
138
|
+
a.icon = :table_row_delete
|
139
|
+
end
|
140
|
+
|
141
|
+
component :add_window do |c|
|
142
|
+
preconfigure_record_window(c)
|
143
|
+
c.title = "Add #{data_class.model_name.human}"
|
144
|
+
c.items = [:add_form]
|
145
|
+
c.form_config.record = data_class.new(columns_default_values)
|
146
|
+
end
|
147
|
+
|
148
|
+
component :edit_window do |c|
|
149
|
+
preconfigure_record_window(c)
|
150
|
+
c.title = "Edit #{data_class.model_name.human}"
|
151
|
+
c.items = [:edit_form]
|
152
|
+
end
|
153
|
+
|
154
|
+
component :multi_edit_window do |c|
|
155
|
+
preconfigure_record_window(c)
|
156
|
+
c.title = "Edit #{data_class.model_name.human.pluralize}"
|
157
|
+
c.items = [:multi_edit_form]
|
158
|
+
end
|
159
|
+
|
160
|
+
endpoint :add_window__add_form__netzke_submit do |params, this|
|
161
|
+
data = ActiveSupport::JSON.decode(params[:data])
|
162
|
+
data["parent_id"] = params["parent_id"]
|
163
|
+
this.merge!(component_instance(:add_window).
|
164
|
+
component_instance(:add_form).
|
165
|
+
submit(data, this))
|
166
|
+
on_data_changed if this.set_form_values.present?
|
167
|
+
this.delete(:set_form_values)
|
168
|
+
end
|
169
|
+
|
170
|
+
protected
|
171
|
+
|
172
|
+
def bbar
|
173
|
+
config.has_key?(:bbar) ? config[:bbar] : default_bbar
|
174
|
+
end
|
175
|
+
|
176
|
+
# Override to change the default bottom toolbar
|
177
|
+
def default_bbar
|
178
|
+
%i[add edit apply del]
|
179
|
+
end
|
180
|
+
|
181
|
+
def preconfigure_record_window(c)
|
182
|
+
c.klass = RecordFormWindow
|
183
|
+
|
184
|
+
c.form_config = ActiveSupport::OrderedOptions.new.tap do |f|
|
185
|
+
f.model = config[:model]
|
186
|
+
f.persistent_config = config[:persistent_config]
|
187
|
+
f.strong_default_attrs = config[:strong_default_attrs]
|
188
|
+
f.mode = config[:mode]
|
189
|
+
f.items = default_fields_for_forms
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
private
|
194
|
+
|
195
|
+
# Adds attributes known to Ext.data.NodeInterface as meta columns (only those our model responds to)
|
196
|
+
def add_node_interface_methods(columns)
|
197
|
+
columns.clone.tap do |columns|
|
198
|
+
NODE_ATTRS.each do |type, attrs|
|
199
|
+
add_node_interface_methods_by_type!(columns, attrs, type)
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
def add_node_interface_methods_by_type!(columns, attrs, type)
|
205
|
+
attrs.each do |a|
|
206
|
+
next unless data_adapter.model_respond_to?(a.to_sym)
|
207
|
+
columns << {attr_type: type, name: a, meta: true}
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
def set_defaults(c)
|
212
|
+
# The nil? checks are needed because these can be already set in a subclass
|
213
|
+
c.enable_edit_in_form = true if c.enable_edit_in_form.nil?
|
214
|
+
c.enable_edit_inline = true if c.enable_edit_inline.nil?
|
215
|
+
c.enable_extended_search = true if c.enable_extended_search.nil?
|
216
|
+
c.enable_column_filters = true if c.enable_column_filters.nil?
|
217
|
+
c.enable_pagination = true if c.enable_pagination.nil?
|
218
|
+
c.rows_per_page = 30 if c.rows_per_page.nil?
|
219
|
+
c.tools = %w{ refresh } if c.tools.nil?
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
Ext.define('Netzke.classes.Basepack.Tree.Proxy', {
|
2
|
+
extend: 'Ext.data.proxy.Server',
|
3
|
+
|
4
|
+
batch: function(options) {
|
5
|
+
if (!options) return;
|
6
|
+
for (operation in options.operations) {
|
7
|
+
var op = new Ext.data.Operation({action: operation, records: options.operations[operation]});
|
8
|
+
this[op.action](op, Ext.emptyFn, this);
|
9
|
+
}
|
10
|
+
},
|
11
|
+
|
12
|
+
read: function(operation, callback, scope) {
|
13
|
+
this.grid.serverRead(this.paramsFromOperation(operation), function(res) {
|
14
|
+
this.processResponse(true, operation, {}, res, callback, scope);
|
15
|
+
}, this);
|
16
|
+
return {};
|
17
|
+
},
|
18
|
+
|
19
|
+
update: function(op, callback, scope) {
|
20
|
+
var data = Ext.Array.map(op.getRecords(), function(r) { return r.getData(); });
|
21
|
+
|
22
|
+
this.grid.serverUpdate(data, function(res) {
|
23
|
+
var errors = [];
|
24
|
+
Ext.each(op.records, function(r) {
|
25
|
+
var rid = r.getId(),
|
26
|
+
recordData = res[rid].record,
|
27
|
+
error = res[rid].error;
|
28
|
+
if (recordData) {
|
29
|
+
serverRecord = this.getReader().read({data: [res[rid].record]}).records[0];
|
30
|
+
r.copyFrom(serverRecord);
|
31
|
+
r.commit();
|
32
|
+
}
|
33
|
+
if (error) { errors.push(error); }
|
34
|
+
}, this);
|
35
|
+
|
36
|
+
if (errors.length == 0) {
|
37
|
+
// this.grid.getStore().load();
|
38
|
+
} else {
|
39
|
+
this.grid.netzkeFeedback(errors);
|
40
|
+
}
|
41
|
+
}, this);
|
42
|
+
},
|
43
|
+
|
44
|
+
destroy: function(op, callback, scope) {
|
45
|
+
var data = Ext.Array.map(op.getRecords(), function(r) { return r.getData().id; });
|
46
|
+
var store = this.grid.getStore();
|
47
|
+
this.grid.serverDelete(data, function(res){
|
48
|
+
var errors = [];
|
49
|
+
for (id in res) {
|
50
|
+
var error;
|
51
|
+
if (error = res[id].error) {
|
52
|
+
errors.push(error);
|
53
|
+
store.getRemovedRecords().forEach(function(record, i){
|
54
|
+
if (record.getId() == id) {
|
55
|
+
store.insert(record.index, record);
|
56
|
+
}
|
57
|
+
});
|
58
|
+
}
|
59
|
+
}
|
60
|
+
|
61
|
+
// clear store state
|
62
|
+
store.commitChanges();
|
63
|
+
|
64
|
+
if (errors.length > 0) {
|
65
|
+
this.grid.netzkeFeedback([errors]);
|
66
|
+
}
|
67
|
+
|
68
|
+
// this.grid.getStore().load();
|
69
|
+
|
70
|
+
}, this);
|
71
|
+
},
|
72
|
+
// Build consistent request params
|
73
|
+
paramsFromOperation: function(operation) {
|
74
|
+
var params = Ext.apply({id: operation.getId()}, this.getParams(operation));
|
75
|
+
|
76
|
+
if (params.filter) {
|
77
|
+
params.filters = Ext.decode(params.filter);
|
78
|
+
delete params.filter;
|
79
|
+
}
|
80
|
+
|
81
|
+
if (params.sort) {
|
82
|
+
params.sorters = Ext.decode(params.sort);
|
83
|
+
delete params.sort;
|
84
|
+
}
|
85
|
+
|
86
|
+
Ext.apply(params, this.extraParams);
|
87
|
+
|
88
|
+
return params;
|
89
|
+
}
|
90
|
+
});
|
91
|
+
|
92
|
+
/**
|
93
|
+
* A fix for CheckColumn
|
94
|
+
*/
|
95
|
+
Ext.override(Ext.ux.CheckColumn, {
|
96
|
+
processEvent: function(type) {
|
97
|
+
// by returning true, we'll allow event propagation, so it reacts similarly to other columns
|
98
|
+
if (this.readOnly && type == 'mousedown') return true;
|
99
|
+
else return this.callOverridden(arguments);
|
100
|
+
}
|
101
|
+
});
|
@@ -0,0 +1,112 @@
|
|
1
|
+
{
|
2
|
+
multiSelect: true,
|
3
|
+
|
4
|
+
initComponent: function(){
|
5
|
+
this.netzkeProcessColumns();
|
6
|
+
this.netzkeBuildModel('Ext.data.TreeModel');
|
7
|
+
this.netzkeBuildStore();
|
8
|
+
|
9
|
+
delete this.root;
|
10
|
+
|
11
|
+
this.plugins = [];
|
12
|
+
this.plugins.push(Ext.create('Ext.grid.plugin.CellEditing', {pluginId: 'celleditor'}));
|
13
|
+
|
14
|
+
this.callParent();
|
15
|
+
|
16
|
+
this.setDynamicActionProperties(); // enable/disable actions (buttons) depending on selection
|
17
|
+
},
|
18
|
+
|
19
|
+
// Process selectionchange event to enable/disable actions
|
20
|
+
setDynamicActionProperties: function() {
|
21
|
+
this.getSelectionModel().on('selectionchange', function(selModel){
|
22
|
+
// if (this.actions.add) this.actions.add.setDisabled(selModel.getCount() != 1);
|
23
|
+
if (this.actions.edit) this.actions.edit.setDisabled(selModel.getCount() != 1);
|
24
|
+
}, this);
|
25
|
+
},
|
26
|
+
|
27
|
+
netzkeBuildStore: function() {
|
28
|
+
var store = Ext.create('Ext.data.TreeStore', Ext.apply({
|
29
|
+
proxy: this.netzkeBuildProxy(),
|
30
|
+
pruneModifiedRecords: true,
|
31
|
+
remoteSort: true,
|
32
|
+
remoteFilter: true,
|
33
|
+
pageSize: this.rowsPerPage,
|
34
|
+
root: this.root
|
35
|
+
}, this.dataStore));
|
36
|
+
|
37
|
+
delete this.dataStore;
|
38
|
+
|
39
|
+
store.getProxy().getReader().on('endpointcommands', function(commands) {
|
40
|
+
this.netzkeBulkExecute(commands);
|
41
|
+
}, this);
|
42
|
+
|
43
|
+
this.store = store;
|
44
|
+
return store; // for backward compatibility
|
45
|
+
},
|
46
|
+
|
47
|
+
netzkeBuildProxy: function() {
|
48
|
+
return Ext.create('Netzke.classes.Basepack.Tree.Proxy', {
|
49
|
+
reader: this.netzkeBuildReader(),
|
50
|
+
grid: this
|
51
|
+
});
|
52
|
+
},
|
53
|
+
|
54
|
+
netzkeBuildReader: function() {
|
55
|
+
var modelName = Netzke.modelName(this.id);
|
56
|
+
return Ext.create('Ext.data.reader.Json', {
|
57
|
+
model: modelName,
|
58
|
+
rootProperty: 'data'
|
59
|
+
});
|
60
|
+
},
|
61
|
+
|
62
|
+
// overriding
|
63
|
+
onAddRecord: function(){
|
64
|
+
var selected = this.getSelection()[0]
|
65
|
+
|
66
|
+
this.netzkeLoadComponent("add_window", {
|
67
|
+
callback: function(w){
|
68
|
+
w.show();
|
69
|
+
var form = w.items.first();
|
70
|
+
form.on('apply', function(){
|
71
|
+
if (!form.baseParams) form.baseParams = {};
|
72
|
+
form.baseParams.parent_id = (selected || {}).id;
|
73
|
+
}, this);
|
74
|
+
|
75
|
+
w.on('close', function(){
|
76
|
+
if (w.closeRes === "ok") {
|
77
|
+
if (selected) {
|
78
|
+
if (selected.isExpanded()) {
|
79
|
+
this.store.load({node: selected});
|
80
|
+
} else {
|
81
|
+
selected.expand();
|
82
|
+
}
|
83
|
+
} else {
|
84
|
+
this.store.load()
|
85
|
+
}
|
86
|
+
}
|
87
|
+
}, this);
|
88
|
+
}, scope: this
|
89
|
+
});
|
90
|
+
},
|
91
|
+
|
92
|
+
// overriding
|
93
|
+
onApply: function(){
|
94
|
+
var topModified = this.store.getModifiedRecords()[0]; // the most top-level modified record
|
95
|
+
this.store.sync();
|
96
|
+
this.store.load({node: topModified.parentNode});
|
97
|
+
},
|
98
|
+
|
99
|
+
// overriding
|
100
|
+
onDel: function() {
|
101
|
+
Ext.Msg.confirm(this.i18n.confirmation, this.i18n.areYouSure, function(btn){
|
102
|
+
if (btn == 'yes') {
|
103
|
+
var toDelete = this.getSelectionModel().getSelection();
|
104
|
+
store = this.getStore();
|
105
|
+
store.remove(toDelete);
|
106
|
+
store.removedNodes = toDelete; // HACK
|
107
|
+
store.sync();
|
108
|
+
}
|
109
|
+
}, this);
|
110
|
+
}
|
111
|
+
|
112
|
+
}
|