netzke-basepack 0.5.5.1 → 0.5.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. data/CHANGELOG.rdoc +16 -1
  2. data/README.rdoc +31 -56
  3. data/Rakefile +2 -2
  4. data/TODO.rdoc +3 -0
  5. data/javascripts/basepack.js +70 -30
  6. data/lib/app/models/netzke_auto_column.rb +1 -53
  7. data/lib/app/models/netzke_auto_field.rb +4 -0
  8. data/lib/app/models/netzke_auto_table.rb +61 -0
  9. data/lib/netzke-basepack.rb +13 -7
  10. data/lib/netzke/active_record/basepack.rb +28 -0
  11. data/lib/netzke/active_record/data_accessor.rb +2 -0
  12. data/lib/netzke/basic_app.rb +3 -4
  13. data/lib/netzke/{basic_app_extras → basic_app}/statusbar_ext.js +0 -0
  14. data/lib/netzke/data_accessor.rb +2 -0
  15. data/lib/netzke/ext.rb +1 -1
  16. data/lib/netzke/fields_configurator.rb +22 -6
  17. data/lib/netzke/form_panel.rb +20 -11
  18. data/lib/netzke/form_panel/form_panel_api.rb +78 -0
  19. data/lib/netzke/form_panel/form_panel_js.rb +143 -0
  20. data/lib/netzke/{form_panel_extras → form_panel}/javascripts/netzkefileupload.js +0 -0
  21. data/lib/netzke/{form_panel_extras → form_panel}/javascripts/xcheckbox.js +0 -0
  22. data/lib/netzke/grid_panel.rb +33 -24
  23. data/lib/netzke/grid_panel/grid_panel_api.rb +358 -0
  24. data/lib/netzke/grid_panel/grid_panel_js.rb +747 -0
  25. data/lib/netzke/{grid_panel_extras → grid_panel}/javascripts/filters.js +0 -0
  26. data/lib/netzke/{grid_panel_extras → grid_panel}/javascripts/rows-dd.js +0 -0
  27. data/lib/netzke/grid_panel/record_form_window.rb +44 -0
  28. data/lib/netzke/panel.rb +1 -3
  29. data/lib/netzke/property_editor.rb +2 -0
  30. data/lib/netzke/{property_editor_extras → property_editor}/helper_model.rb +2 -2
  31. data/lib/netzke/search_panel.rb +3 -3
  32. data/lib/netzke/window.rb +9 -3
  33. data/test/unit/grid_panel_test.rb +0 -2
  34. data/test/unit/helper_model_test.rb +2 -2
  35. metadata +16 -15
  36. data/lib/netzke/field_model.rb +0 -131
  37. data/lib/netzke/form_panel_api.rb +0 -78
  38. data/lib/netzke/form_panel_js.rb +0 -141
  39. data/lib/netzke/grid_panel_api.rb +0 -356
  40. data/lib/netzke/grid_panel_extras/record_form_window.rb +0 -46
  41. data/lib/netzke/grid_panel_js.rb +0 -725
@@ -0,0 +1,747 @@
1
+ module Netzke
2
+ class GridPanel < Base
3
+ module GridPanelJs
4
+ def self.included(base)
5
+ base.extend ClassMethods
6
+ end
7
+
8
+ def js_config
9
+ res = super
10
+ res.merge!(:clmns => columns)
11
+ res.merge!(:data_class_name => config[:data_class_name])
12
+ res.merge!(:inline_data => get_data) if ext_config[:load_inline_data]
13
+ res.merge!(:pri => data_class.primary_key)
14
+ res
15
+ end
16
+
17
+ module ClassMethods
18
+
19
+ def js_base_class
20
+ 'Ext.grid.EditorGridPanel'
21
+ end
22
+
23
+ # Ext.Component#initComponent, built up from pices (dependent on class configuration)
24
+ def js_init_component
25
+
26
+ # Optional "edit in form"-related events
27
+ edit_in_form_events = <<-END_OF_JAVASCRIPT if config[:edit_in_form_available]
28
+ if (this.enableEditInForm) {
29
+ this.getSelectionModel().on('selectionchange', function(selModel){
30
+ // Disable "edit in form" button if new record is present in selection
31
+ var disabled = !selModel.each(function(r){
32
+ if (r.isNew) { return false; }
33
+ });
34
+ this.actions.editInForm.setDisabled(disabled);
35
+ }, this);
36
+ }
37
+ END_OF_JAVASCRIPT
38
+
39
+ # Result
40
+ <<-END_OF_JAVASCRIPT
41
+ function(){
42
+ if (!this.clmns) {this.feedback('No columns defined for grid '+this.id);}
43
+
44
+ /* Process columns - all in sake of creating the column model */
45
+ // Normalize columns passed in the config
46
+ var normClmns = [];
47
+ Ext.each(this.clmns, function(c){
48
+ if (!c.excluded) {
49
+ // normalize columns
50
+ if (typeof c == 'string') {
51
+ normClmns.push({name:c});
52
+ } else {
53
+ normClmns.push(c);
54
+ }
55
+ }
56
+ });
57
+
58
+ delete this.clmns; // we don't need them anymore
59
+
60
+ var cmConfig = []; // column model config - we'll use it later to create the ColumnModel
61
+ this.plugins = []; // checkbox colums is a special case, being a plugin
62
+
63
+ var filters = [];
64
+
65
+ // Run through columns
66
+ Ext.each(normClmns, function(c){
67
+ // Apply default column config
68
+ Ext.applyIf(c, this.defaultColumnConfig);
69
+
70
+ // setting dataIndex separately
71
+ c.dataIndex = c.name;
72
+
73
+ // Automatically calculated default values
74
+ if (!c.header) {c.header = c.name.humanize()}
75
+
76
+ // normalize editor
77
+ if (c.editor) {
78
+ c.editor = Netzke.isObject(c.editor) ? c.editor : {xtype:c.editor};
79
+ } else {
80
+ c.editor = {xtype: 'textfield'}
81
+ }
82
+
83
+ // collect filters
84
+ // Not compatible with Ext 3.0
85
+ //if (c.withFilters){
86
+ // filters.push({type:Ext.netzke.filterMap[c.editor.xtype], dataIndex:c.name});
87
+ //}
88
+
89
+ if (c.editor && c.editor.xtype == 'checkbox') {
90
+ // Special case of checkbox column
91
+ var plugin = new Ext.ux.grid.CheckColumn(c);
92
+ this.plugins.push(plugin);
93
+ cmConfig.push(plugin);
94
+ } else {
95
+ // a "normal" column, not a plugin
96
+ if (!c.readOnly && !this.prohibitUpdate) {
97
+ // c.editor contains complete config of the editor
98
+ var xtype = c.editor.xtype;
99
+ c.editor = Ext.ComponentMgr.create(Ext.apply({
100
+ parentId: this.id,
101
+ name: c.name,
102
+ selectOnFocus:true
103
+ }, c.editor));
104
+ } else {
105
+ c.editor = null;
106
+ }
107
+
108
+ // set the renderer
109
+ if (c.renderer && c.renderer.match(/^\\s*function\\s*\\(/)) {
110
+ // if the renderer is an inline function - eval it (double escaping because we are inside of the Ruby string here...)
111
+ eval("c.renderer = " + c.renderer + ";");
112
+ } else {
113
+ // othrewise it's a string representing the name of the renderer or an json-encoded array,
114
+ // where the first parameter is the renderer's name, and the rest - parameters that should be
115
+ // passed to the renderer at the moment of calling
116
+ var renderer = Ext.netzke.normalizedRenderer(c.renderer);
117
+ if (renderer != null) c.renderer = renderer;
118
+ }
119
+
120
+ // add to the list
121
+ cmConfig.push(c);
122
+ }
123
+
124
+ }, this);
125
+
126
+ // Finally, create the ColumnModel based on processed columns
127
+ this.cm = new Ext.grid.ColumnModel(cmConfig);
128
+
129
+ // Hidden change event
130
+ if (this.persistentConfig) {this.cm.on('hiddenchange', this.onColumnHiddenChange, this);}
131
+
132
+ /* ... and done with columns */
133
+
134
+ // Filters
135
+ // Not compatible with Ext 3.0
136
+ // if (this.enableColumnFilters) {
137
+ // this.plugins.push(new Ext.grid.GridFilters({filters:filters}));
138
+ // }
139
+
140
+ // Create Ext.data.Record constructor specific for our particular column configuration
141
+ this.recordConfig = [];
142
+ Ext.each(normClmns, function(column){this.recordConfig.push({name:column.name});}, this);
143
+ this.Row = Ext.data.Record.create(this.recordConfig);
144
+
145
+ // Drag'n'Drop
146
+ if (this.enableRowsReordering){
147
+ this.ddPlugin = new Ext.ux.dd.GridDragDropRowOrder({
148
+ scrollable: true // enable scrolling support (default is false)
149
+ });
150
+ this.plugins.push(this.ddPlugin);
151
+ }
152
+
153
+ // Explicitely create the connection to get grid's data,
154
+ // because we don't want the app-wide Ext.Ajax to be used,
155
+ // as we are going to subscribe to its events
156
+ var connection = new Ext.data.Connection({
157
+ url: this.buildApiUrl("get_data"),
158
+ extraParams: {
159
+ authenticity_token : Netzke.authenticityToken
160
+ },
161
+
162
+ // inform Ext.Ajax about our events
163
+ listeners: {
164
+ beforerequest: function(){
165
+ Ext.Ajax.fireEvent('beforerequest', arguments);
166
+ },
167
+ requestexception: function(){
168
+ Ext.Ajax.fireEvent('requestexception', arguments);
169
+ },
170
+ requestcomplete: function(){
171
+ Ext.Ajax.fireEvent('requestcomplete', arguments);
172
+ }
173
+ }
174
+ });
175
+
176
+ // besides getting data into the store, we may also get commands to execute
177
+ connection.on('requestcomplete', function(conn, r){
178
+ var response = Ext.decode(r.responseText);
179
+
180
+ // delete data-related properties
181
+ Ext.each(['data', 'total', 'success'], function(property){delete response[property];});
182
+ this.bulkExecute(response);
183
+ }, this);
184
+
185
+ // HttpProxy that uses our custom connection
186
+ var httpProxy = new Ext.data.HttpProxy(connection);
187
+
188
+ // Data store
189
+ this.store = new Ext.data.Store({
190
+ proxy: this.proxy = httpProxy,
191
+ reader: new Ext.data.ArrayReader({root: "data", totalProperty: "total", successProperty: "success", id:0}, this.Row),
192
+ remoteSort: true,
193
+ listeners:{'loadexception':{
194
+ fn:this.loadExceptionHandler,
195
+ scope:this
196
+ }}
197
+ });
198
+
199
+ // Normalize bottom bar
200
+ this.bbar = (this.enablePagination) ? new Ext.PagingToolbar({
201
+ pageSize : this.rowsPerPage,
202
+ items : this.bbar ? ["-"].concat(this.bbar) : [],
203
+ store : this.store,
204
+ emptyMsg: 'Empty'
205
+ }) : this.bbar;
206
+
207
+ // Selection model
208
+ this.sm = new Ext.grid.RowSelectionModel();
209
+
210
+ // Now let Ext.grid.EditorGridPanel do the rest
211
+ // Original initComponent
212
+ #{js_full_class_name}.superclass.initComponent.call(this);
213
+
214
+ // Inform the server part about column operations
215
+ if (this.persistentConfig) {
216
+ this.on('columnresize', this.onColumnResize, this);
217
+ this.on('columnmove', this.onColumnMove, this);
218
+ }
219
+
220
+ // Context menu
221
+ if (this.enableContextMenu) {
222
+ this.on('rowcontextmenu', this.onRowContextMenu, this);
223
+ }
224
+
225
+ // Load data AFTER the toolbar is bound to the store, which will provide for correct page number
226
+ if (this.loadInlineData) {
227
+ this.getStore().loadData(this.inlineData);
228
+
229
+ // If rows per page specified, fake store.lastOptions as if the data was loaded
230
+ // by PagingToolbar (for correct functionning of refresh tool and extended search)
231
+ if (this.rowsPerPage) {
232
+ this.getStore().lastOptions = {params:{limit:this.rowsPerPage, start:0}}; // this is how PagingToolbar does it...
233
+ }
234
+
235
+ // inlineData may also contain commands (TODO: make it DRY)
236
+ // delete data-related properties
237
+ Ext.each(['data', 'total', 'success'], function(property){delete this.inlineData[property];}, this);
238
+ this.bulkExecute(this.inlineData);
239
+ }
240
+
241
+ // Process selectionchange event
242
+ this.getSelectionModel().on('selectionchange', function(selModel){
243
+ // enable/disable actions
244
+ this.actions.del.setDisabled(!selModel.hasSelection() || this.prohibitDelete);
245
+ this.actions.edit.setDisabled(selModel.getCount() != 1 || this.prohibitUpdate);
246
+ }, this);
247
+
248
+ // Drag n Drop event
249
+ if (this.enableRowsReordering){
250
+ this.ddPlugin.on('afterrowmove', this.onAfterRowMove, this);
251
+ }
252
+
253
+ // GridView
254
+ this.getView().getRowClass = this.defaultGetRowClass;
255
+
256
+ #{edit_in_form_events}
257
+ }
258
+
259
+ END_OF_JAVASCRIPT
260
+
261
+ end
262
+
263
+ def js_extend_properties
264
+ res = super
265
+
266
+ # Generic (non-optional) functionality
267
+ res.merge!(
268
+ {
269
+ :track_mouse_over => true,
270
+ :load_mask => true,
271
+ :auto_scroll => true,
272
+
273
+ :default_column_config => config_columns.inject({}){ |r, c| c.is_a?(Hash) ? r.merge(c[:name] => c[:default]) : r },
274
+
275
+ :init_component => js_init_component.l,
276
+
277
+ # Handlers for actions
278
+ #
279
+
280
+ :on_add => <<-END_OF_JAVASCRIPT.l,
281
+ function(){
282
+ var rowConfig = {};
283
+ var r = new this.Row(rowConfig); // TODO: add default values
284
+ r.isNew = true; // to distinguish new records
285
+ // r.set('id', r.id); // otherwise later r.get('id') returns empty string
286
+ this.stopEditing();
287
+ this.getStore().add(r);
288
+ this.tryStartEditing(this.store.indexOf(r));
289
+ }
290
+ END_OF_JAVASCRIPT
291
+
292
+ :on_edit => <<-END_OF_JAVASCRIPT.l,
293
+ function(){
294
+ var row = this.getSelectionModel().getSelected();
295
+ if (row){
296
+ this.tryStartEditing(this.store.indexOf(row));
297
+ }
298
+ }
299
+ END_OF_JAVASCRIPT
300
+
301
+ :on_del => <<-END_OF_JAVASCRIPT.l,
302
+ function() {
303
+ Ext.Msg.confirm('Confirm', 'Are you sure?', function(btn){
304
+ if (btn == 'yes') {
305
+ var records = [];
306
+ this.getSelectionModel().each(function(r){
307
+ if (r.isNew) {
308
+ // this record is not know to server - simply remove from store
309
+ this.store.remove(r);
310
+ } else {
311
+ records.push(r.id);
312
+ }
313
+ }, this);
314
+
315
+ if (records.length > 0){
316
+ // call API
317
+ this.deleteData({records: Ext.encode(records)});
318
+ }
319
+ }
320
+ }, this);
321
+ }
322
+ END_OF_JAVASCRIPT
323
+
324
+ :on_apply => <<-END_OF_JAVASCRIPT.l,
325
+ function(){
326
+ var newRecords = [];
327
+ var updatedRecords = [];
328
+ Ext.each(this.store.getModifiedRecords(),
329
+ function(r) {
330
+ if (r.isNew) {
331
+ newRecords.push(Ext.apply(r.getChanges(), {id:r.id}));
332
+ } else {
333
+ updatedRecords.push(Ext.apply(r.getChanges(), {id:r.id}));
334
+ }
335
+ },
336
+ this);
337
+
338
+ if (newRecords.length > 0 || updatedRecords.length > 0) {
339
+ var params = {};
340
+
341
+ if (newRecords.length > 0) {
342
+ params.created_records = Ext.encode(newRecords);
343
+ }
344
+
345
+ if (updatedRecords.length > 0) {
346
+ params.updated_records = Ext.encode(updatedRecords);
347
+ }
348
+
349
+ if (this.store.baseParams !== {}) {
350
+ params.base_params = Ext.encode(this.store.baseParams);
351
+ }
352
+
353
+ this.postData(params);
354
+ }
355
+
356
+ }
357
+ END_OF_JAVASCRIPT
358
+
359
+ # Handlers for tools
360
+ #
361
+
362
+ :on_refresh => <<-END_OF_JAVASCRIPT.l,
363
+ function() {
364
+ if (this.fireEvent('refresh', this) !== false) {
365
+ this.store.reload();
366
+ }
367
+ }
368
+ END_OF_JAVASCRIPT
369
+
370
+ # Event handlers
371
+ #
372
+
373
+ :on_column_resize => <<-END_OF_JAVASCRIPT.l,
374
+ function(index, size){
375
+ this.resizeColumn({
376
+ index:index,
377
+ size:size
378
+ });
379
+ }
380
+ END_OF_JAVASCRIPT
381
+
382
+ :on_column_hidden_change => <<-END_OF_JAVASCRIPT.l,
383
+ function(cm, index, hidden){
384
+ this.hideColumn({
385
+ index:index,
386
+ hidden:hidden
387
+ });
388
+ }
389
+ END_OF_JAVASCRIPT
390
+
391
+ :on_column_move => <<-END_OF_JAVASCRIPT.l,
392
+ function(oldIndex, newIndex){
393
+ this.moveColumn({
394
+ old_index:oldIndex,
395
+ new_index:newIndex
396
+ });
397
+
398
+ var newRecordConfig = [];
399
+ Ext.each(this.getColumnModel().config, function(c){newRecordConfig.push({name: c.name})});
400
+ delete this.Row; // old record constructor
401
+ this.Row = Ext.data.Record.create(newRecordConfig);
402
+ this.getStore().reader.recordType = this.Row;
403
+ }
404
+ END_OF_JAVASCRIPT
405
+
406
+ :on_row_context_menu => <<-END_OF_JAVASCRIPT.l,
407
+ function(grid, rowIndex, e){
408
+ e.stopEvent();
409
+ var coords = e.getXY();
410
+
411
+ if (!grid.getSelectionModel().isSelected(rowIndex)) {
412
+ grid.getSelectionModel().selectRow(rowIndex);
413
+ }
414
+
415
+ var menu = new Ext.menu.Menu({
416
+ items: this.contextMenu
417
+ });
418
+
419
+ menu.showAt(coords);
420
+ }
421
+ END_OF_JAVASCRIPT
422
+
423
+ :on_after_row_move => <<-END_OF_JAVASCRIPT.l,
424
+ function(dt, oldIndex, newIndex, records){
425
+ var ids = [];
426
+ // collect records ids
427
+ Ext.each(records, function(r){ids.push(r.id)});
428
+ // call GridPanel's API
429
+ this.moveRows({ids:Ext.encode(ids), new_index: newIndex});
430
+ }
431
+ END_OF_JAVASCRIPT
432
+
433
+ # Other methods
434
+ #
435
+
436
+ :load_exception_handler => <<-END_OF_JAVASCRIPT.l,
437
+ function(proxy, options, response, error){
438
+ if (response.status == 200 && (responseObject = Ext.decode(response.responseText)) && responseObject.flash){
439
+ this.feedback(responseObject.flash);
440
+ } else {
441
+ if (error){
442
+ this.feedback(error.message);
443
+ } else {
444
+ this.feedback(response.statusText);
445
+ }
446
+ }
447
+ }
448
+ END_OF_JAVASCRIPT
449
+
450
+ :update => <<-END_OF_JAVASCRIPT.l,
451
+ function(){
452
+ this.store.reload();
453
+ }
454
+ END_OF_JAVASCRIPT
455
+
456
+ :load_store_data => <<-END_OF_JAVASCRIPT.l,
457
+ function(data){
458
+ this.store.loadData(data);
459
+ Ext.each(['data', 'total', 'success'], function(property){delete data[property];}, this);
460
+ this.bulkExecute(data);
461
+ }
462
+ END_OF_JAVASCRIPT
463
+
464
+ # try editing the first editable (i.e. not hidden, not read-only) sell
465
+ :try_start_editing => <<-END_OF_JAVASCRIPT.l,
466
+ function(row){
467
+ var editableIndex = 0;
468
+ Ext.each(this.getColumnModel().config, function(c){
469
+ if (!c.hidden && c.editable && c.editor && (c.editor.xtype !== 'checkbox')) {
470
+ return false;
471
+ }
472
+ editableIndex++;
473
+ });
474
+ if (editableIndex < this.getColumnModel().config.length) {this.startEditing(row, editableIndex);}
475
+ }
476
+ END_OF_JAVASCRIPT
477
+
478
+ # Called by the server side to update newly created records
479
+ :update_new_records => <<-END_OF_JAVASCRIPT.l,
480
+ function(records){
481
+ this.updateRecords(records);
482
+ }
483
+ END_OF_JAVASCRIPT
484
+
485
+ # Called by the server side to update modified records
486
+ :update_mod_records => <<-END_OF_JAVASCRIPT.l,
487
+ function(records){
488
+ this.updateRecords(records, true);
489
+ }
490
+ END_OF_JAVASCRIPT
491
+
492
+ # Updates modified or newly created records, by record ID
493
+ # Example of the records argument (updated columns):
494
+ # {1098 => [1, 'value1', 'value2'], 1099 => [2, 'value1', 'value2']}
495
+ # Example of the records argument (new columns, id autogenerated by Ext):
496
+ # {"ext-record-200" => [1, 'value1', 'value2']}
497
+ :update_records => <<-END_OF_JAVASCRIPT.l,
498
+ function(records, mod){
499
+ if (!mod) {mod = false;}
500
+ var modRecordsInGrid = [].concat(this.store.getModifiedRecords()); // there must be a better way to clone an array...
501
+
502
+ // replace arrays of data in the args object with Ext.data.Record objects
503
+ for (var k in records){
504
+ records[k] = this.store.reader.readRecords([records[k]]).records[0];
505
+ }
506
+
507
+ // for each new record write the data returned by the server, and commit the record
508
+ Ext.each(modRecordsInGrid, function(recordInGrid){
509
+ if (mod ^ recordInGrid.isNew) {
510
+ // if record is new, we access its id by "id", otherwise, the id is in the primary key column
511
+ var recordId = recordInGrid.id;
512
+ // new data that the server sent us to update this record (identified by the id)
513
+ var newData = records[recordId];
514
+
515
+ if (newData){
516
+ for (var k in newData.data){
517
+ recordInGrid.set(k, newData.get(k));
518
+ }
519
+
520
+ recordInGrid.isNew = false;
521
+ recordInGrid.commit();
522
+ }
523
+
524
+ }
525
+ }, this);
526
+
527
+ // clear the selections
528
+ this.getSelectionModel().clearSelections();
529
+
530
+ // check if there are still records with errors
531
+ var modRecords = this.store.getModifiedRecords();
532
+ if (modRecords.length == 0) {
533
+ // if all records are accepted, reload the grid (so that eventual order/filtering is correct)
534
+ this.store.reload();
535
+
536
+ // ... and set default getRowClass function
537
+ this.getView().getRowClass = this.defaultGetRowClass;
538
+ } else {
539
+ this.getView().getRowClass = function(r){
540
+ return r.dirty ? "grid-dirty-record" : ""
541
+ }
542
+ }
543
+
544
+ this.getView().refresh();
545
+ }
546
+ END_OF_JAVASCRIPT
547
+
548
+ :default_get_row_class => <<-END_OF_JAVASCRIPT.l,
549
+ function(r){
550
+ return r.isNew ? "grid-dirty-record" : ""
551
+ }
552
+ END_OF_JAVASCRIPT
553
+
554
+ :select_first_row => <<-END_OF_JAVASCRIPT.l,
555
+ function(){
556
+ this.getSelectionModel().suspendEvents();
557
+ this.getSelectionModel().selectRow(0);
558
+ this.getSelectionModel().resumeEvents();
559
+ }
560
+ END_OF_JAVASCRIPT
561
+
562
+ # :reorder_columns => <<-END_OF_JAVASCRIPT.l,
563
+ # function(columns){
564
+ # columnsInNewShipment = [];
565
+ # Ext.each(columns, function(c){
566
+ # columnsInNewShipment.push({name:c});
567
+ # });
568
+ # newRecordType = Ext.data.Record.create(columnsInNewShipment);
569
+ # this.store.reader.recordType = newRecordType; // yes, recordType is a protected property, but that's the only way we can do it, and it seems to work for now
570
+ # }
571
+ # END_OF_JAVASCRIPT
572
+ }
573
+ )
574
+
575
+ # Optional edit in form functionality
576
+ res.merge!(
577
+ {
578
+ :on_successfull_record_creation => <<-END_OF_JAVASCRIPT.l,
579
+ function(){
580
+ this.formWindow.hide();
581
+ this.getStore().reload();
582
+ }
583
+ END_OF_JAVASCRIPT
584
+
585
+ :on_successfull_edit => <<-END_OF_JAVASCRIPT.l,
586
+ function(){
587
+ this.editFormWindow.close();
588
+ delete this.editFormWindow;
589
+ this.getStore().reload();
590
+ }
591
+ END_OF_JAVASCRIPT
592
+
593
+ :on_edit_in_form => <<-END_OF_JAVASCRIPT.l,
594
+ function(){
595
+ // create the window
596
+ delete this.editFormWindow;
597
+ this.editFormWindow = new Ext.Window({
598
+ title: 'Edit',
599
+ layout: 'fit',
600
+ modal: true,
601
+ width: 400,
602
+ height: Ext.lib.Dom.getViewHeight() *0.9,
603
+ buttons:[{
604
+ text: 'OK',
605
+ handler: function(){
606
+ this.ownerCt.ownerCt.getWidget().onApply();
607
+ }
608
+ },{
609
+ text:'Cancel',
610
+ handler:function(){
611
+ this.ownerCt.ownerCt.hide();
612
+ }
613
+ }]
614
+ });
615
+
616
+ // show it and load the correct aggregatee in it
617
+ this.editFormWindow.show(null, function(){
618
+ var selModel = this.getSelectionModel();
619
+ if (selModel.getCount() > 1) {
620
+
621
+ // multiedit
622
+ this.editFormWindow.setTitle('Multi-edit');
623
+ this.loadAggregatee({
624
+ id: "multiEditForm",
625
+ container: this.editFormWindow.id,
626
+ callback: function(aggr){
627
+ // on apply attach ids of selected rows
628
+ aggr.on('apply', function(){
629
+ var ids = [];
630
+ selModel.each(function(r){
631
+ ids.push(r.id);
632
+ });
633
+ aggr.baseParams = {ids: Ext.encode(ids)}
634
+ }, this);
635
+ },
636
+ scope: this
637
+ });
638
+ } else {
639
+
640
+ // single edit
641
+ this.editFormWindow.setTitle('Edit');
642
+ var recordId = selModel.getSelected().id;
643
+ this.loadAggregatee({
644
+ id: "editForm",
645
+ container: this.editFormWindow.id,
646
+ params: {
647
+ record_id: recordId
648
+ }
649
+ });
650
+ }
651
+ }, this);
652
+
653
+ }
654
+ END_OF_JAVASCRIPT
655
+
656
+ :on_add_in_form => <<-END_OF_JAVASCRIPT.l,
657
+ function(){
658
+ this.loadAggregatee({id: "addForm", callback: function(form){
659
+ form.on('close', function(){
660
+ if (form.closeRes === "ok") {
661
+ this.store.reload();
662
+ }
663
+ }, this);
664
+ }, scope: this});
665
+ }
666
+ END_OF_JAVASCRIPT
667
+ }
668
+ ) if config[:edit_in_form_available]
669
+
670
+ # Optional extended search functionality
671
+ res.merge!(
672
+ {
673
+ :on_search => <<-END_OF_JAVASCRIPT.l,
674
+ function(){
675
+ delete this.searchWindow;
676
+ this.searchWindow = new Ext.Window({
677
+ title:'Advanced search',
678
+ layout:'fit',
679
+ modal: true,
680
+ width: 400,
681
+ height: Ext.lib.Dom.getViewHeight() *0.9,
682
+ closeAction:'hide',
683
+ buttons:[{
684
+ text: 'OK',
685
+ handler: function(){
686
+ this.ownerCt.ownerCt.closePositively();
687
+ }
688
+ },{
689
+ text:'Cancel',
690
+ handler:function(){
691
+ this.ownerCt.ownerCt.closeNegatively();
692
+ }
693
+ }],
694
+ closePositively : function(){
695
+ this.conditions = this.getWidget().getForm().getValues();
696
+ this.closeRes = 'OK';
697
+ this.hide();
698
+ },
699
+ closeNegatively: function(){
700
+ this.closeRes = 'cancel';
701
+ this.hide();
702
+ }
703
+ });
704
+
705
+ this.searchWindow.on('hide', function(){
706
+ if (this.searchWindow.closeRes == 'OK'){
707
+ var searchConditions = this.searchWindow.conditions;
708
+ var filtered = false;
709
+ // check if there's any search condition set
710
+ for (var k in searchConditions) {
711
+ if (searchConditions[k].length > 0) {
712
+ filtered = true;
713
+ break;
714
+ }
715
+ }
716
+ this.actions.search.setText(filtered ? "Search *" : "Search");
717
+ this.getStore().baseParams = {extra_conditions: Ext.encode(this.searchWindow.conditions)};
718
+ this.getStore().load();
719
+ }
720
+ }, this);
721
+
722
+ this.searchWindow.on('add', function(container, searchPanel){
723
+ searchPanel.on('apply', function(widget){
724
+ this.searchWindow.closePositively();
725
+ return false; // stop the event
726
+ }, this);
727
+ }, this);
728
+
729
+ this.searchWindow.show(null, function(){
730
+ this.searchWindow.closeRes = 'cancel';
731
+ if (!this.searchWindow.getWidget()){
732
+ this.loadAggregatee({id:"searchPanel", container:this.searchWindow.id});
733
+ }
734
+ }, this);
735
+
736
+ }
737
+ END_OF_JAVASCRIPT
738
+
739
+ }
740
+ ) if config[:extended_search_available]
741
+
742
+ res
743
+ end
744
+ end
745
+ end
746
+ end
747
+ end