netzke-basepack 0.4.2 → 0.5.1

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