netzke-basepack 0.12.9 → 1.0.0.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +75 -44
- data/Gemfile +4 -2
- data/LICENSE +2 -6
- data/README.md +22 -24
- data/javascripts/basepack.js +0 -8
- data/javascripts/{columns.js → grid/columns.js} +59 -71
- data/javascripts/grid/event_handlers.js +218 -0
- data/javascripts/netzkeremotecombo.js +5 -13
- data/javascripts/tristate.js +62 -0
- data/javascripts/xdatetime.js +8 -37
- data/lib/netzke-basepack.rb +3 -2
- data/lib/netzke/basepack.rb +1 -1
- data/lib/netzke/basepack/action_column.rb +6 -23
- data/lib/netzke/basepack/active_record.rb +0 -6
- data/lib/netzke/basepack/attr_config.rb +20 -11
- data/lib/netzke/basepack/attribute_config.rb +10 -0
- data/lib/netzke/basepack/attributes.rb +196 -0
- data/lib/netzke/basepack/column_config.rb +47 -39
- data/lib/netzke/basepack/columns.rb +127 -97
- data/lib/netzke/basepack/data_accessor.rb +7 -48
- data/lib/netzke/basepack/data_adapters/abstract_adapter.rb +15 -17
- data/lib/netzke/basepack/data_adapters/active_record_adapter.rb +111 -90
- data/lib/netzke/basepack/dynamic_tab_panel.rb +3 -5
- data/lib/netzke/basepack/dynamic_tab_panel/{javascripts → client}/dynamic_tab_panel.js +6 -5
- data/lib/netzke/basepack/field_config.rb +30 -19
- data/lib/netzke/basepack/fields.rb +22 -12
- data/lib/netzke/basepack/grid_live_search.rb +1 -4
- data/lib/netzke/basepack/grid_live_search/{javascripts → client}/grid_live_search.js +9 -7
- data/lib/netzke/basepack/item_persistence.rb +3 -3
- data/lib/netzke/basepack/item_persistence/events_plugin.rb +8 -10
- data/lib/netzke/basepack/paging_form.rb +7 -11
- data/lib/netzke/basepack/paging_form/{javascripts → client}/paging_form.js +4 -4
- data/lib/netzke/basepack/query_builder.rb +12 -10
- data/lib/netzke/basepack/query_builder/{javascripts → client}/query_builder.js +14 -12
- data/lib/netzke/basepack/record_form_window.rb +8 -8
- data/lib/netzke/basepack/search_panel.rb +4 -6
- data/lib/netzke/basepack/search_panel/{javascripts → client}/condition_field.js +13 -16
- data/lib/netzke/basepack/search_panel/{javascripts → client}/search_panel.js +7 -7
- data/lib/netzke/basepack/search_window.rb +6 -6
- data/lib/netzke/basepack/simple_app/{javascripts → client}/statusbar_ext.js +0 -0
- data/lib/netzke/basepack/version.rb +1 -1
- data/lib/netzke/form/base.rb +166 -0
- data/lib/netzke/{basepack/form/javascripts/form.js → form/base/client/base.js} +77 -38
- data/lib/netzke/form/base/client/readonly_mode.css +4 -0
- data/lib/netzke/{basepack/form/javascripts → form/base/client}/readonly_mode.js +5 -5
- data/lib/netzke/form/endpoints.rb +33 -0
- data/lib/netzke/form/services.rb +74 -0
- data/lib/netzke/grid/actions.rb +52 -0
- data/lib/netzke/grid/base.rb +289 -0
- data/lib/netzke/{basepack/grid/javascripts → grid/base/client}/advanced_search.js +5 -1
- data/lib/netzke/{basepack/grid/javascripts/grid.js → grid/base/client/base.js} +61 -53
- data/lib/netzke/{basepack/grid/javascripts → grid/base/client}/extensions.js +19 -13
- data/lib/netzke/{basepack/grid/javascripts → grid/base/client}/remember_selection.js +0 -1
- data/lib/netzke/grid/client.rb +8 -0
- data/lib/netzke/grid/components.rb +55 -0
- data/lib/netzke/grid/configuration.rb +72 -0
- data/lib/netzke/grid/endpoints.rb +99 -0
- data/lib/netzke/grid/permissions.rb +18 -0
- data/lib/netzke/grid/services.rb +141 -0
- data/lib/netzke/tree/base.rb +173 -0
- data/lib/netzke/{basepack/tree/javascripts/tree.js → tree/base/client/base.js} +55 -26
- data/lib/netzke/{basepack/tree/javascripts → tree/base/client}/extensions.js +7 -7
- data/lib/netzke/tree/endpoints.rb +34 -0
- data/lib/netzke/{basepack/viewport.rb → viewport/base.rb} +3 -3
- data/lib/netzke/{basepack/window.rb → window/base.rb} +7 -8
- data/lib/netzke/window/base/client/base.js +26 -0
- data/locales/de.yml +49 -33
- data/locales/en.yml +32 -39
- data/locales/es.yml +39 -25
- data/locales/nl.yml +39 -25
- data/locales/ru.yml +38 -25
- data/locales/uk.yml +40 -26
- data/stylesheets/basepack.css +10 -0
- metadata +48 -45
- data/javascripts/mixins/grid_event_handlers.js +0 -139
- data/lib/netzke/basepack/accordion.rb +0 -45
- data/lib/netzke/basepack/active_record/relation_extensions.rb +0 -27
- data/lib/netzke/basepack/form.rb +0 -131
- data/lib/netzke/basepack/form/endpoints.rb +0 -35
- data/lib/netzke/basepack/form/services.rb +0 -74
- data/lib/netzke/basepack/form/stylesheets/readonly_mode.css +0 -14
- data/lib/netzke/basepack/grid.rb +0 -570
- data/lib/netzke/basepack/grid/endpoints.rb +0 -111
- data/lib/netzke/basepack/grid/javascripts/edit_in_form.js +0 -51
- data/lib/netzke/basepack/grid/services.rb +0 -148
- data/lib/netzke/basepack/tab_panel.rb +0 -22
- data/lib/netzke/basepack/tab_panel/javascripts/tab_panel.js +0 -11
- data/lib/netzke/basepack/tree.rb +0 -269
- data/lib/netzke/basepack/window/javascripts/window.js +0 -26
- data/lib/netzke/basepack/wrap_lazy_loaded.rb +0 -29
@@ -1,3 +1,7 @@
|
|
1
|
+
/**
|
2
|
+
* Client-side code for [Netzke::Form::Base](http://www.rubydoc.info/github/netzke/netzke-basepack/Netzke/Form/Base)
|
3
|
+
* @class Netzke.Form.Base
|
4
|
+
*/
|
1
5
|
{
|
2
6
|
bodyStyle : 'padding:5px 5px 0',
|
3
7
|
autoScroll : true,
|
@@ -33,35 +37,37 @@
|
|
33
37
|
// Now let Ext.form.Form do the rest
|
34
38
|
this.callParent(arguments);
|
35
39
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
if (event.getKey() == 13) this.up('form').onApply();
|
40
|
-
});
|
40
|
+
Ext.each(this.query('field'), function(field) {
|
41
|
+
field.on('specialkey', function(field, event) {
|
42
|
+
if (event.getKey() == 13) this.up('form').netzkeOnApply();
|
41
43
|
});
|
42
|
-
}
|
44
|
+
});
|
43
45
|
},
|
44
46
|
|
45
47
|
afterRender: function(){
|
46
48
|
this.callParent();
|
47
49
|
|
48
50
|
// have a record to be displayed?
|
49
|
-
if (this.record) { this.
|
51
|
+
if (this.record) { this.netzkeSetFormValues(this.record); }
|
50
52
|
|
51
53
|
// render in display mode?
|
52
|
-
if (this.locked || this.readOnly) this.
|
54
|
+
if (this.locked || this.readOnly) this.netzkeSetReadonlyMode(true);
|
53
55
|
},
|
54
56
|
|
55
|
-
|
56
|
-
this.
|
57
|
+
netzkeOnEdit: function(){
|
58
|
+
this.netzkeSetReadonlyMode(false);
|
57
59
|
},
|
58
60
|
|
59
|
-
|
61
|
+
netzkeOnCancel: function(){
|
60
62
|
this.getForm().reset();
|
61
|
-
this.
|
63
|
+
this.netzkeSetReadonlyMode(true, true);
|
62
64
|
},
|
63
65
|
|
64
|
-
|
66
|
+
/**
|
67
|
+
* In lockable mode, dynamically updates the toolbar depending on the read-only state.
|
68
|
+
* @method netzkeUpdateToolbar
|
69
|
+
*/
|
70
|
+
netzkeUpdateToolbar: function(){
|
65
71
|
var tbar = this.child('toolbar');
|
66
72
|
if (!tbar) return;
|
67
73
|
|
@@ -96,7 +102,11 @@
|
|
96
102
|
tbar.doLayout();
|
97
103
|
},
|
98
104
|
|
99
|
-
|
105
|
+
/**
|
106
|
+
* Handler for the `apply` action.
|
107
|
+
* @method netzkeOnApply
|
108
|
+
*/
|
109
|
+
netzkeOnApply: function() {
|
100
110
|
if (this.fireEvent('apply', this)) {
|
101
111
|
var values = this.getForm().getValues();
|
102
112
|
for (var fieldName in values) {
|
@@ -135,9 +145,10 @@
|
|
135
145
|
// We must use a different approach when the form is multipart, as we can't use the endpoint
|
136
146
|
if (this.getForm().hasUpload()) {
|
137
147
|
this.getForm().submit({ // normal submit
|
138
|
-
url: this.netzkeEndpointUrl("
|
148
|
+
url: this.netzkeEndpointUrl("submit"),
|
139
149
|
params: {
|
140
|
-
data: Ext.encode(values) // here are the correct values that may be different from display values
|
150
|
+
data: Ext.encode(values), // here are the correct values that may be different from display values
|
151
|
+
configs: Ext.encode(this.netzkeBuildParentConfigs())
|
141
152
|
},
|
142
153
|
failure: function(form, action){
|
143
154
|
var respObj = Ext.decode(action.response.responseText);
|
@@ -153,27 +164,33 @@
|
|
153
164
|
scope: this
|
154
165
|
});
|
155
166
|
} else {
|
156
|
-
this.
|
167
|
+
this.server.submit(Ext.apply((this.baseParams || {}), { data:Ext.encode(values) }), function(){ this.setLoading(false); });
|
157
168
|
}
|
158
169
|
}
|
159
170
|
this.fireEvent('afterApply', this);
|
160
171
|
},
|
161
172
|
|
162
|
-
|
163
|
-
|
173
|
+
/**
|
174
|
+
* Called by the server on successful submit.
|
175
|
+
* @method netzkeOnSubmitSuccess
|
176
|
+
*/
|
177
|
+
netzkeOnSubmitSuccess: function() {
|
164
178
|
this.fireEvent("submitsuccess");
|
165
|
-
if (this.mode == "lockable") this.
|
179
|
+
if (this.mode == "lockable") this.netzkeSetReadonlyMode(true);
|
166
180
|
this.setLoading(false);
|
167
181
|
},
|
168
182
|
|
169
|
-
|
183
|
+
/**
|
184
|
+
* Sets form values (including associations).
|
185
|
+
* @method netzkeSetFormValues
|
186
|
+
*/
|
187
|
+
netzkeSetFormValues: function(values){
|
170
188
|
var assocValues = values.meta.associationValues || {};
|
171
189
|
for (var assocFieldName in assocValues) {
|
172
190
|
|
173
191
|
var assocField = this.getForm().getFields().filter('name', assocFieldName).first();
|
174
192
|
if (assocField.isXType('combobox')) {
|
175
|
-
|
176
|
-
assocField.store.loadData([[values[assocFieldName], assocValues[assocFieldName]]]);
|
193
|
+
assocField.getStore().loadData([[values[assocFieldName], assocValues[assocFieldName]]]);
|
177
194
|
delete assocField.lastQuery; // force loading the store next time user clicks the trigger
|
178
195
|
} else {
|
179
196
|
assocField.setValue(assocValues[assocFieldName]);
|
@@ -184,42 +201,64 @@
|
|
184
201
|
this.getForm().setValues(values);
|
185
202
|
},
|
186
203
|
|
187
|
-
|
204
|
+
/**
|
205
|
+
* Dynamically changes form's read-only state.
|
206
|
+
* @method netzkeSetReadonlyMode
|
207
|
+
* @param {Boolean} onOff
|
208
|
+
*/
|
209
|
+
netzkeSetReadonlyMode: function(onOff){
|
188
210
|
if (this.inReadonlyMode == onOff) return;
|
189
211
|
this.getForm().getFields().each(function(i){
|
190
|
-
if (i.
|
212
|
+
if (i.netzkeSetReadonlyMode) i.netzkeSetReadonlyMode(onOff);
|
191
213
|
});
|
192
214
|
|
193
215
|
// this.getForm().cleanDestroyed(); // because fields inside of composite fields are not auto-cleaned!
|
194
216
|
this.doLayout();
|
195
217
|
this.inReadonlyMode = onOff;
|
196
|
-
if (this.mode == "lockable") this.
|
218
|
+
if (this.mode == "lockable") this.netzkeUpdateToolbar();
|
197
219
|
},
|
198
220
|
|
199
|
-
|
200
|
-
|
221
|
+
/**
|
222
|
+
* Recursively extract field names from `items`.
|
223
|
+
* @method netzkeExtractFields
|
224
|
+
* @param {Array} items
|
225
|
+
*/
|
226
|
+
netzkeExtractFields: function(items){
|
201
227
|
Ext.each(items, function(i){
|
202
|
-
if (i.items) {this.
|
228
|
+
if (i.items) {this.netzkeExtractFields(i.items);}
|
203
229
|
else if (i.name) {this.fieldNames.push(i.name);}
|
204
230
|
}, this);
|
205
231
|
},
|
206
232
|
|
207
|
-
|
233
|
+
/**
|
234
|
+
* Called by the server to display varidation errors.
|
235
|
+
* @method netzkeApplyFormErrors
|
236
|
+
* @param {Array} errors Array of errors as provided by the `submit` endpoint
|
237
|
+
*/
|
238
|
+
netzkeApplyFormErrors: function(errors) {
|
208
239
|
var field;
|
209
240
|
Ext.iterate(errors, function(fieldName, message){
|
210
241
|
fieldName = fieldName.underscore();
|
211
|
-
if ( field = this.getForm().findField(fieldName) ||
|
212
|
-
this.getForm().findField(fieldName.replace(/([a-z]+)([0-9])/g, '$1_$2')) ||
|
213
|
-
this.getForm().getFields().findBy(function(f){ return fieldName == f.getName().replace(/(.+)__.+/g, '$1'); }) ||
|
214
|
-
this.getForm().getFields().findBy(function(f){
|
215
|
-
str = f.getName().camelize();
|
216
|
-
first = str.substring(0,1);
|
217
|
-
matchingName = (first.toLowerCase()+str.substring(1)).underscore();
|
242
|
+
if ( field = this.getForm().findField(fieldName) ||
|
243
|
+
this.getForm().findField(fieldName.replace(/([a-z]+)([0-9])/g, '$1_$2')) ||
|
244
|
+
this.getForm().getFields().findBy(function(f){ return fieldName == f.getName().replace(/(.+)__.+/g, '$1'); }) ||
|
245
|
+
this.getForm().getFields().findBy(function(f){
|
246
|
+
str = f.getName().camelize();
|
247
|
+
first = str.substring(0,1);
|
248
|
+
matchingName = (first.toLowerCase()+str.substring(1)).underscore();
|
218
249
|
return fieldName == matchingName;
|
219
250
|
})
|
220
251
|
) {
|
221
252
|
field.markInvalid(message.join('<br/>'));
|
222
253
|
}
|
223
254
|
}, this);
|
224
|
-
}
|
255
|
+
},
|
256
|
+
|
257
|
+
netzkeDisplayFormErrors: function(errors){
|
258
|
+
var body = "";
|
259
|
+
Ext.each(errors, function(error){
|
260
|
+
body += error.msg + "<br/>"
|
261
|
+
});
|
262
|
+
this.netzkeNotify(body);
|
263
|
+
},
|
225
264
|
}
|
@@ -1,8 +1,8 @@
|
|
1
|
-
// Overrides that implement
|
1
|
+
// Overrides that implement netzkeSetReadonlyMode for form fields.
|
2
2
|
//
|
3
3
|
|
4
4
|
Ext.form.field.Base.override({
|
5
|
-
|
5
|
+
netzkeSetReadonlyMode: function(onOff){
|
6
6
|
if (this.hidden) return;
|
7
7
|
|
8
8
|
if (!this.initialConfig.readOnly) {
|
@@ -21,15 +21,15 @@ Ext.form.field.Base.override({
|
|
21
21
|
|
22
22
|
// Also the FieldContainer
|
23
23
|
Ext.form.FieldContainer.override({
|
24
|
-
|
24
|
+
netzkeSetReadonlyMode: function(onOff){
|
25
25
|
this.items.each(function(i){
|
26
|
-
i.
|
26
|
+
i.netzkeSetReadonlyMode(onOff);
|
27
27
|
});
|
28
28
|
}
|
29
29
|
});
|
30
30
|
|
31
31
|
Ext.form.field.Checkbox.override({
|
32
|
-
|
32
|
+
netzkeSetReadonlyMode: function(onOff){
|
33
33
|
this.setDisabled(onOff);
|
34
34
|
}
|
35
35
|
});
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Netzke
|
2
|
+
module Form
|
3
|
+
module Endpoints
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
# Called when the form gets submitted (e.g. by pressing the Apply button)
|
8
|
+
endpoint :submit do |params|
|
9
|
+
data = ActiveSupport::JSON.decode(params[:data])
|
10
|
+
submit(data, client)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Can be called when the form needs to load a record with given ID. E.g.:
|
14
|
+
#
|
15
|
+
# someForm.server.load({id: 100});
|
16
|
+
endpoint :load do |params|
|
17
|
+
@record = model && model_adapter.find_record(params[:id])
|
18
|
+
client.netzke_set_form_values js_record_data
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns options for a combobox
|
22
|
+
# params receive:
|
23
|
+
# +attr+ - column's name
|
24
|
+
# +query+ - what's typed-in in the combobox
|
25
|
+
# +id+ - selected record id
|
26
|
+
endpoint :get_combobox_options do |params|
|
27
|
+
attr = fields[params[:attr].to_sym]
|
28
|
+
client.data = model_adapter.combo_data(attr, params[:query])
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module Netzke
|
2
|
+
module Form
|
3
|
+
module Services
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
def submit(data, client)
|
7
|
+
# File uploads are in raw params instead of "data" hash, so, mix them in into "data"
|
8
|
+
controller.params.each_pair do |k,v|
|
9
|
+
data[k] = v if v.is_a?(ActionDispatch::Http::UploadedFile)
|
10
|
+
end
|
11
|
+
|
12
|
+
success = create_or_update_record(data)
|
13
|
+
|
14
|
+
if success
|
15
|
+
client.netzke_set_form_values(js_record_data)
|
16
|
+
client.success = true # respond to classic form submission with {success: true}
|
17
|
+
client.netzke_on_submit_success # inform the Netzke endpoint caller about success
|
18
|
+
else
|
19
|
+
errors = model_adapter.errors_array(@record).map do |error|
|
20
|
+
{level: :error, msg: error}
|
21
|
+
end
|
22
|
+
client.netzke_display_form_errors(errors)
|
23
|
+
client.netzke_apply_form_errors(build_form_errors(record))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def values
|
28
|
+
record && record.netzke_hash(fields)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
# Builds the form errors
|
34
|
+
def build_form_errors(record)
|
35
|
+
form_errors = {}
|
36
|
+
foreign_keys = model_adapter.hash_fk_model
|
37
|
+
record.errors.to_hash.map{|field, error|
|
38
|
+
# some ORM return an array for error
|
39
|
+
error = error.join ', ' if error.kind_of? Array
|
40
|
+
# Get the correct field name for the errors on foreign keys
|
41
|
+
if foreign_keys.has_key?(field)
|
42
|
+
fields.each do |k, v|
|
43
|
+
# Hack to stop to_nifty_json from camalizing model__field
|
44
|
+
field = k.to_s.gsub('__', '____') if k.to_s.split('__').first == foreign_keys[field].to_s
|
45
|
+
end
|
46
|
+
end
|
47
|
+
form_errors[field] ||= []
|
48
|
+
form_errors[field] << error
|
49
|
+
}
|
50
|
+
form_errors
|
51
|
+
end
|
52
|
+
|
53
|
+
# Creates/updates a record from hash
|
54
|
+
def create_or_update_record(hsh)
|
55
|
+
hsh.merge!(config[:strong_values]) if config[:strong_values]
|
56
|
+
|
57
|
+
# only pick the record specified in the params if it was not provided in the configuration
|
58
|
+
@record ||= model_adapter.find_record hsh.delete(model.primary_key.to_s)
|
59
|
+
|
60
|
+
#model.find(:first, :conditions => model.primary_key => hsh.delete(model.primary_key)})
|
61
|
+
success = true
|
62
|
+
|
63
|
+
@record = model.new if @record.nil?
|
64
|
+
|
65
|
+
hsh.each_pair do |k,v|
|
66
|
+
model_adapter.set_record_value_for_attribute(@record, fields[k.to_sym].nil? ? {:name => k} : fields[k.to_sym], v)
|
67
|
+
end
|
68
|
+
|
69
|
+
# did we have complete success?
|
70
|
+
success && model_adapter.save_record(@record)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Netzke
|
2
|
+
module Grid
|
3
|
+
module Actions
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
action :add do |a|
|
8
|
+
a.icon = :add
|
9
|
+
end
|
10
|
+
|
11
|
+
action :edit do |a|
|
12
|
+
a.disabled = true # initial
|
13
|
+
a.icon = :table_edit
|
14
|
+
end
|
15
|
+
|
16
|
+
action :delete do |a|
|
17
|
+
a.disabled = true # initial
|
18
|
+
a.icon = :table_row_delete
|
19
|
+
end
|
20
|
+
|
21
|
+
action :apply do |a|
|
22
|
+
a.icon = :tick
|
23
|
+
end
|
24
|
+
|
25
|
+
action :search do |a|
|
26
|
+
a.enable_toggle = true
|
27
|
+
a.icon = :magnifier
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def has_add_action?
|
32
|
+
allowed_to?(:create)
|
33
|
+
end
|
34
|
+
|
35
|
+
def has_edit_action?
|
36
|
+
allowed_to?(:update)
|
37
|
+
end
|
38
|
+
|
39
|
+
def has_apply_action?
|
40
|
+
config.edit_inline && (allowed_to?(:create) || allowed_to?(:update))
|
41
|
+
end
|
42
|
+
|
43
|
+
def has_delete_action?
|
44
|
+
allowed_to?(:delete)
|
45
|
+
end
|
46
|
+
|
47
|
+
def has_search_action?
|
48
|
+
true
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,289 @@
|
|
1
|
+
module Netzke
|
2
|
+
module Grid
|
3
|
+
# Ext.grid.Panel-based component with the following features:
|
4
|
+
#
|
5
|
+
# * infinite scrolling or pagination
|
6
|
+
# * automatic default attribute configuration (overridable via config)
|
7
|
+
# * multi-line CRUD operations
|
8
|
+
# * adding/editing records via a form
|
9
|
+
# * editing multiple records simultaneously
|
10
|
+
# * one-to-many association support
|
11
|
+
# * server-side sorting and filtering
|
12
|
+
# * permissions
|
13
|
+
# * persistent column resizing, moving and toggling
|
14
|
+
# * complex query search with preset management
|
15
|
+
#
|
16
|
+
# Client-side methods are documented here: http://api.netzke.org/client/classes/Netzke.Grid.Base.html.
|
17
|
+
#
|
18
|
+
# == Configuration
|
19
|
+
#
|
20
|
+
# The following config options are supported:
|
21
|
+
#
|
22
|
+
# [model]
|
23
|
+
#
|
24
|
+
# Name of the ActiveRecord model that provides data to this Grid (e.g. "User") or the model's class (e.g. User).
|
25
|
+
# Required.
|
26
|
+
#
|
27
|
+
# [columns]
|
28
|
+
#
|
29
|
+
# Explicit list of columns to be displayed in the grid; each column may be represented by a symbol (attribute name),
|
30
|
+
# or a hash, which contains the +name+ key pointing to the attribute name and additional configuration keys (see
|
31
|
+
# the "Configuring attributes" section below). For example:
|
32
|
+
#
|
33
|
+
# class Users < Netzke::Grid::Base
|
34
|
+
# def configure(c)
|
35
|
+
# super
|
36
|
+
# c.model = User
|
37
|
+
# c.columns = [
|
38
|
+
# :first_name,
|
39
|
+
# :last_name,
|
40
|
+
# { name: :salary, with: 50 }
|
41
|
+
# ]
|
42
|
+
# end
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# Defaults to model attribute list.
|
46
|
+
#
|
47
|
+
# Note, that you can also individually override column configs (e.g. setting a column's width) by using the
|
48
|
+
# +column+ DSL method (see +Basepack::Columns+), and override attributes (e.g. making an attribute read-only) by
|
49
|
+
# using the +attribute+ DSL method (see +Basepack::Attributes+).
|
50
|
+
#
|
51
|
+
# [form_items]
|
52
|
+
#
|
53
|
+
# Array of form items. This may define arbitrary form layout. An item that represents a specific attribute, should
|
54
|
+
# be specified as either a symbol (attribute name), or a hash containing the +name+ key pointing to the attribute
|
55
|
+
# name, as well as additional configuration keys.
|
56
|
+
#
|
57
|
+
# class Users < Netzke::Basepack::Grid
|
58
|
+
# def configure(c)
|
59
|
+
# super
|
60
|
+
# c.model = User
|
61
|
+
# c.form_items = [
|
62
|
+
# {
|
63
|
+
# xtype: 'fieldset', title: 'Name', items: [:first_name, :last_name]
|
64
|
+
# },
|
65
|
+
# { name: :salary, disabled: true }
|
66
|
+
# ]
|
67
|
+
# end
|
68
|
+
# end
|
69
|
+
#
|
70
|
+
# Defaults to model attribute list.
|
71
|
+
#
|
72
|
+
# [attribute_overrides]
|
73
|
+
#
|
74
|
+
# Hash of per-attribute configurations. This allows overriding attributes configs that will be reflected by both
|
75
|
+
# corresponding grid column and form field.
|
76
|
+
#
|
77
|
+
# Using this option may be convenient when building composite components containing multiple grids. From inside a
|
78
|
+
# given grid class it's easier to use the +attribute+ DSL method (see "Configuring attributes").
|
79
|
+
#
|
80
|
+
# [scope]
|
81
|
+
#
|
82
|
+
# A Proc object used to scope out grid data. Receives the current relation as a parameter and must return the
|
83
|
+
# modified relation. For example:
|
84
|
+
#
|
85
|
+
# class Books < Netzke::Basepack::Grid
|
86
|
+
# def configure(c)
|
87
|
+
# c.model = "Book"
|
88
|
+
# super
|
89
|
+
# c.scope = lambda {|r| r.where(author_id: 1) }
|
90
|
+
# end
|
91
|
+
# end
|
92
|
+
#
|
93
|
+
# [strong_values]
|
94
|
+
#
|
95
|
+
# A hash of attributes to be merged atop of every created/updated record, e.g. +role_id: 1+
|
96
|
+
#
|
97
|
+
# [edit_inline]
|
98
|
+
# Whether record editing should happen inline (as opposed to using a form). When set to +true+, automatically sets
|
99
|
+
# +paging+ to +true+. Defaults to +false+.
|
100
|
+
#
|
101
|
+
# [context_menu]
|
102
|
+
#
|
103
|
+
# An array of actions (e.g. [:edit, "-", :delete] - see the Actions section) or +false+ to disable the context menu.
|
104
|
+
#
|
105
|
+
# [paging]
|
106
|
+
#
|
107
|
+
# Set to +true+ to use pagination instead of infinite scrolling. Is automatically set to
|
108
|
+
# +true+ if +edit_inline+ is +true+. Defaults to +false+.
|
109
|
+
#
|
110
|
+
# [store_config]
|
111
|
+
#
|
112
|
+
# Extra configuration for the JS class's internal store (Ext.data.ProxyStore), which will override Netzke's
|
113
|
+
# defaults. For example, to modify amount of records per page (defaults to 25), do:
|
114
|
+
#
|
115
|
+
# def configure(c)
|
116
|
+
# c.paging = true
|
117
|
+
# c.store_config = {page_size: 100}
|
118
|
+
# super
|
119
|
+
# end
|
120
|
+
#
|
121
|
+
# Another example, enable (multi) sorting initially:
|
122
|
+
#
|
123
|
+
# def configure(c)
|
124
|
+
# c.store_config = {sorters: [:title, {property: :author__first_name, direction: :DESC}]}
|
125
|
+
# super
|
126
|
+
# end
|
127
|
+
#
|
128
|
+
# [disable_dirty_page_warning]
|
129
|
+
#
|
130
|
+
# Do not warn the user about dirty records on the page when changing the page. Defaults to +false+.
|
131
|
+
#
|
132
|
+
# [permissions]
|
133
|
+
#
|
134
|
+
# Hash that can have a combination of the following boolean keys: +create+, +read+, +update+, +delete+ that
|
135
|
+
# set corresponding permissions on the grid. For example, to disable deleting records:
|
136
|
+
#
|
137
|
+
# c.permissions = {delete: false}
|
138
|
+
#
|
139
|
+
# == Configuring attributes (columns and form fields)
|
140
|
+
#
|
141
|
+
# === Overriding individual attributes
|
142
|
+
#
|
143
|
+
# To override configuration for a specific attribute, you may either use the +attribute_overrides+ configuration
|
144
|
+
# option (see above), or the +attribute+ DSL method, for example:
|
145
|
+
#
|
146
|
+
# class Books < Netzke::Grid::Base
|
147
|
+
# attribute :price do |c|
|
148
|
+
# c.read_only = true
|
149
|
+
# end
|
150
|
+
#
|
151
|
+
# def configure(c)
|
152
|
+
# c.model = Book
|
153
|
+
# super
|
154
|
+
# end
|
155
|
+
# end
|
156
|
+
#
|
157
|
+
# This will make the 'price' column (as well as corresponding form field) read-only.
|
158
|
+
#
|
159
|
+
# The same DSL method may be used for defining virtual attributes. For details, refer to +Basepack::Attributes+.
|
160
|
+
#
|
161
|
+
# === Overriding individual column settings
|
162
|
+
#
|
163
|
+
# To override configuration for a column (like making the column hidden or specyfing its initial width), either add
|
164
|
+
# the +column_config+ key to the +attribute_overrides+ (see above), or use the +column+ DSL method, for example:
|
165
|
+
#
|
166
|
+
# column :full_name do |c|
|
167
|
+
# c.width = 200
|
168
|
+
# end
|
169
|
+
#
|
170
|
+
# For details, refer to +Basepack::Columns+.
|
171
|
+
#
|
172
|
+
# === Specifying column list
|
173
|
+
#
|
174
|
+
# To explicitely specify columns in the grid, use the +columns+ config option, or override +Grid#columns+:
|
175
|
+
#
|
176
|
+
# def columns
|
177
|
+
# super + [:extra_column]
|
178
|
+
# end
|
179
|
+
#
|
180
|
+
# == One-to-many association support
|
181
|
+
#
|
182
|
+
# If the model bound to a grid +belongs_to+ another model, Grid can display an "assocition column" - where the user
|
183
|
+
# can select the associated record from a drop-down box. You can specify which method of the association should be
|
184
|
+
# used as the display value for the drop-down box options by using the double-underscore notation on the column
|
185
|
+
# name, where the association name is separated from the association method by "__" (double underscore). For
|
186
|
+
# example, let's say we have a Book that +belongs_to+ model Author, and Author responds to +first_name+. This way,
|
187
|
+
# the book grid can have a column defined as follows:
|
188
|
+
#
|
189
|
+
# {name: "author__first_name"}
|
190
|
+
#
|
191
|
+
# Grid will detect it to be an association column, and will use the drop-down box for selecting an author, where the
|
192
|
+
# list of authors will be represented by the author's first name.
|
193
|
+
#
|
194
|
+
# In order to scope out the records displayed in the drop-down box, the +scope+ column option can be used, e.g.:
|
195
|
+
#
|
196
|
+
# {name: "author__first_name", scope: lambda {|relation| relation.where(popular: true).limit(10)}
|
197
|
+
#
|
198
|
+
# == Add/Edit forms
|
199
|
+
#
|
200
|
+
# Add/Edit forms are each wrapped in a separate +Window::Base+-descending component (called +RecordFormWindow+
|
201
|
+
# for the add/edit forms, and can be overridden individually as any other child component.
|
202
|
+
#
|
203
|
+
# === Overriding form windows
|
204
|
+
#
|
205
|
+
# Override the following direct child components to change the looks of the pop-up windows: +:add_window+,
|
206
|
+
# +:edit_window+, +:multiedit_window+, and +:search_window+. For example, to override the title of the Add form,
|
207
|
+
# do:
|
208
|
+
#
|
209
|
+
# component :add_window do |c|
|
210
|
+
# super c
|
211
|
+
# c.title = "Adding new record"
|
212
|
+
# c.width = "90%"
|
213
|
+
# end
|
214
|
+
#
|
215
|
+
# === Modifying forms
|
216
|
+
#
|
217
|
+
# The forms will by default display the fields that correspond to the configured columns, taking over meaningful
|
218
|
+
# configuration options (e.g. +text+ will be converted into +fieldLabel+).
|
219
|
+
# You may override the default fields displayed in the all add/edit forms by overriding the
|
220
|
+
# +default_form_items+ method, which should return an array understood by the +items+ config property of the
|
221
|
+
# +Form+. If you need to use a custom +Form::Base+-descending class instead of +Form+, you need to override the
|
222
|
+
# +configure_form_window+ method:
|
223
|
+
#
|
224
|
+
# def configure_form_window(c)
|
225
|
+
# super
|
226
|
+
# c.form_config.klass = UserForm
|
227
|
+
# end
|
228
|
+
#
|
229
|
+
# To individually override forms, you should override the wrapping window components, as shown in the previous
|
230
|
+
# session. E.g., to modify the set of fields in the Add form:
|
231
|
+
#
|
232
|
+
# component :add_window do |c|
|
233
|
+
# super c
|
234
|
+
# c.form_config.items = [:title]
|
235
|
+
# end
|
236
|
+
#
|
237
|
+
# == Actions
|
238
|
+
#
|
239
|
+
# You can override Grid's actions to change their text, icons, and tooltips (see
|
240
|
+
# http://rdoc.info/github/netzke/netzke-core/Netzke/Core/Actions).
|
241
|
+
#
|
242
|
+
# Grid implements the following actions:
|
243
|
+
#
|
244
|
+
# [add]
|
245
|
+
#
|
246
|
+
# Add record
|
247
|
+
#
|
248
|
+
# [delete]
|
249
|
+
#
|
250
|
+
# Delete record(s)
|
251
|
+
#
|
252
|
+
# [edit]
|
253
|
+
#
|
254
|
+
# Edit record(s)
|
255
|
+
#
|
256
|
+
# [apply]
|
257
|
+
#
|
258
|
+
# Applying inline changes (after inline adding/editing of record)
|
259
|
+
#
|
260
|
+
# [search]
|
261
|
+
#
|
262
|
+
# Show advanced search query builder
|
263
|
+
class Base < Netzke::Base
|
264
|
+
include Netzke::Grid::Configuration
|
265
|
+
include Netzke::Grid::Endpoints
|
266
|
+
include Netzke::Grid::Services
|
267
|
+
include Netzke::Grid::Actions
|
268
|
+
include Netzke::Grid::Components
|
269
|
+
include Netzke::Grid::Permissions
|
270
|
+
include Netzke::Grid::Client
|
271
|
+
include Netzke::Basepack::Attributes
|
272
|
+
include Netzke::Basepack::Columns
|
273
|
+
include Netzke::Basepack::DataAccessor
|
274
|
+
|
275
|
+
client_class do |c|
|
276
|
+
c.extend = "Ext.grid.Panel"
|
277
|
+
c.include :advanced_search
|
278
|
+
c.include :remember_selection
|
279
|
+
|
280
|
+
c.mixins << "Netzke.Grid.Columns"
|
281
|
+
c.mixins << "Netzke.Grid.EventHandlers"
|
282
|
+
|
283
|
+
c.translate :are_you_sure, :confirmation, :proceed_with_unapplied_changes
|
284
|
+
|
285
|
+
c.require :extensions
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|