]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/web/js/dojo/openils/widget/AutoGrid.js
added onEditPane callback for munging edit/create panes
[working/Evergreen.git] / Open-ILS / web / js / dojo / openils / widget / AutoGrid.js
1 if(!dojo._hasResource['openils.widget.AutoGrid']) {
2     dojo.provide('openils.widget.AutoGrid');
3     dojo.require('dojox.grid.DataGrid');
4     dojo.require('openils.widget.AutoWidget');
5     dojo.require('openils.widget.AutoFieldWidget');
6     dojo.require('openils.widget.EditPane');
7     dojo.require('openils.widget.EditDialog');
8     dojo.require('openils.widget.GridColumnPicker');
9     dojo.require('openils.Util');
10
11     dojo.declare(
12         'openils.widget.AutoGrid',
13         [dojox.grid.DataGrid, openils.widget.AutoWidget],
14         {
15
16             /* if true, pop up an edit dialog when user hits Enter on a give row */
17             editOnEnter : false, 
18             defaultCellWidth : null,
19             editStyle : 'dialog',
20             suppressFields : null,
21             hideSelector : false,
22             selectorWidth : '1.5',
23             showColumnPicker : false,
24             columnPickerPrefix : null,
25
26             /* by default, don't show auto-generated (sequence) fields */
27             showSequenceFields : false, 
28
29             startup : function() {
30                 this.selectionMode = 'single';
31                 this.sequence = openils.widget.AutoGrid.sequence++;
32                 openils.widget.AutoGrid.gridCache[this.sequence] = this;
33                 this.inherited(arguments);
34                 this.initAutoEnv();
35                 this.attr('structure', this._compileStructure());
36                 this.setStore(this.buildAutoStore());
37
38                 if(this.showColumnPicker) {
39                     if(!this.columnPickerPrefix) {
40                         console.error("No columnPickerPrefix defined");
41                     } else {
42                         new openils.widget.GridColumnPicker(
43                             openils.User.authtoken, this.columnPickerPrefix, this).load();
44                     }
45                 }
46
47                 this.overrideEditWidgets = {};
48                 this.overrideEditWidgetClass = {};
49
50                 if(this.editOnEnter) 
51                     this._applyEditOnEnter();
52                 else if(this.singleEditStyle) 
53                     this._applySingleEditStyle();
54
55                 if(!this.hideSelector) {
56                     var header = this.layout.cells[0].view.getHeaderCellNode(0);
57                     var self = this;
58                     header.onclick = function() { self.toggleSelectAll(); }
59                 }
60             },
61
62             /* Don't allow sorting on the selector column */
63             canSort : function(rowIdx) {
64                 if(rowIdx == 1 && !this.hideSelector)
65                     return false;
66                 return true;
67             },
68
69             _compileStructure : function() {
70                 var existing = (this.structure && this.structure[0].cells[0]) ? 
71                     this.structure[0].cells[0] : [];
72                 var fields = [];
73
74                 var self = this;
75                 function pushEntry(entry) {
76                     if(self.suppressFields) {
77                         if(dojo.indexOf(self.suppressFields, entry.field) != -1)
78                             return;
79                     }
80                     if(!entry.get) 
81                         entry.get = openils.widget.AutoGrid.defaultGetter
82                     if(!entry.width && self.defaultCellWidth)
83                         entry.width = self.defaultCellWidth;
84                     fields.push(entry);
85                 }
86
87                 if(!this.hideSelector) {
88                     // insert the selector column
89                     pushEntry({
90                         field : '+selector',
91                         formatter : function(rowIdx) { return self._formatRowSelectInput(rowIdx); },
92                         get : function(rowIdx, item) { if(item) return rowIdx; },
93                         width : this.selectorWidth,
94                         name : '&#x2713',
95                         nonSelectable : true
96                     });
97                 }
98
99
100                 if(!this.fieldOrder) {
101                     /* no order defined, start with any explicit grid fields */
102                     for(var e in existing) {
103                         var entry = existing[e];
104                         var field = this.fmIDL.fields.filter(
105                             function(i){return (i.name == entry.field)})[0];
106                         if(field) entry.name = entry.name || field.label;
107                         pushEntry(entry);
108                     }
109                 }
110
111                 for(var f in this.sortedFieldList) {
112                     var field = this.sortedFieldList[f];
113                     if(!field || field.virtual) continue;
114                     
115                     // field was already added above
116                     if(fields.filter(function(i){return (i.field == field.name)})[0]) 
117                         continue;
118
119                     var entry = existing.filter(function(i){return (i.field == field.name)})[0];
120                     if(entry) {
121                         entry.name = field.label;
122                     } else {
123                         // unless specifically requested, hide sequence fields
124                         if(!this.showSequenceFields && field.name == this.fmIDL.pkey && this.fmIDL.pkey_sequence)
125                             continue; 
126
127                         entry = {field:field.name, name:field.label};
128                     }
129                     pushEntry(entry);
130                 }
131
132                 if(this.fieldOrder) {
133                     /* append any explicit non-IDL grid fields to the end */
134                     for(var e in existing) {
135                         var entry = existing[e];
136                         var field = fields.filter(
137                             function(i){return (i.field == entry.field)})[0];
138                         if(field) continue; // don't duplicate
139                         pushEntry(entry);
140                     }
141                 }
142
143                 return [{cells: [fields]}];
144             },
145
146             toggleSelectAll : function() {
147                 var selected = this.getSelectedRows();
148                 for(var i = 0; i < this.rowCount; i++) {
149                     if(selected[0])
150                         this.deSelectRow(i);
151                     else
152                         this.selectRow(i);
153                 }
154             },
155
156             getSelectedRows : function() {
157                 var rows = []; 
158                 dojo.forEach(
159                     dojo.query('[name=autogrid.selector]', this.domNode),
160                     function(input) {
161                         if(input.checked)
162                             rows.push(input.getAttribute('row'));
163                     }
164                 );
165                 return rows;
166             },
167
168             getFirstSelectedRow : function() {
169                 return this.getSelectedRows()[0];
170             },
171
172             getSelectedItems : function() {
173                 var items = [];
174                 var self = this;
175                 dojo.forEach(this.getSelectedRows(), function(idx) { items.push(self.getItem(idx)); });
176                 return items;
177             },
178
179             selectRow : function(rowIdx) {
180                 var inputs = dojo.query('[name=autogrid.selector]', this.domNode);
181                 for(var i = 0; i < inputs.length; i++) {
182                     if(inputs[i].getAttribute('row') == rowIdx) {
183                         inputs[i].checked = true;
184                         break;
185                     }
186                 }
187             },
188
189             deSelectRow : function(rowIdx) {
190                 var inputs = dojo.query('[name=autogrid.selector]', this.domNode);
191                 for(var i = 0; i < inputs.length; i++) {
192                     if(inputs[i].getAttribute('row') == rowIdx) {
193                         inputs[i].checked = false;
194                         break;
195                     }
196                 }
197             },
198
199             getAllObjects : function() {
200                 var objs = [];
201                 var self = this;
202                 this.store.fetch({
203                     onComplete : function(list) {
204                         dojo.forEach(list, 
205                             function(item) {
206                                 objs.push(new fieldmapper[self.fmClass]().fromStoreItem(item));
207                             }
208                         )
209                     }
210                 });
211                 return objs;
212             },
213
214             deleteSelected : function() {
215                 var items = this.getSelectedItems();
216                 var total = items.length;
217                 var self = this;
218                 dojo.require('openils.PermaCrud');
219                 var pcrud = new openils.PermaCrud();
220                 dojo.forEach(items,
221                     function(item) {
222                         var fmObject = new fieldmapper[self.fmClass]().fromStoreItem(item);
223                         pcrud['delete'](fmObject, {oncomplete : function(r) { self.store.deleteItem(item) }});
224                     }
225                 );
226             },
227
228             _formatRowSelectInput : function(rowIdx) {
229                 if(rowIdx === null || rowIdx === undefined) return '';
230                 return "<input type='checkbox' name='autogrid.selector' row='" + rowIdx + "'/>";
231             },
232
233             _applySingleEditStyle : function() {
234                 this.onMouseOverRow = function(e) {};
235                 this.onMouseOutRow = function(e) {};
236                 this.onCellFocus = function(cell, rowIndex) { 
237                     this.selection.deselectAll();
238                     this.selection.select(this.focus.rowIndex);
239                 };
240             },
241
242             /* capture keydown and launch edit dialog on enter */
243             _applyEditOnEnter : function() {
244                 this._applySingleEditStyle();
245
246                 dojo.connect(this, 'onRowDblClick',
247                     function(e) {
248                         if(this.editStyle == 'pane')
249                             this._drawEditPane(this.selection.getFirstSelected(), this.focus.rowIndex);
250                         else
251                             this._drawEditDialog(this.selection.getFirstSelected(), this.focus.rowIndex);
252                     }
253                 );
254
255                 dojo.connect(this, 'onKeyDown',
256                     function(e) {
257                         if(e.keyCode == dojo.keys.ENTER) {
258                             this.selection.deselectAll();
259                             this.selection.select(this.focus.rowIndex);
260                             if(this.editStyle == 'pane')
261                                 this._drawEditPane(this.selection.getFirstSelected(), this.focus.rowIndex);
262                             else
263                                 this._drawEditDialog(this.selection.getFirstSelected(), this.focus.rowIndex);
264                         }
265                     }
266                 );
267             },
268
269             _makeEditPane : function(storeItem, rowIndex, onPostSubmit, onCancel) {
270                 var grid = this;
271                 var fmObject = new fieldmapper[this.fmClass]().fromStoreItem(storeItem);
272                 var idents = grid.store.getIdentityAttributes();
273
274                 var pane = new openils.widget.EditPane({
275                     fmObject:fmObject,
276                     overrideWidgets : this.overrideEditWidgets,
277                     overrideWidgetClass : this.overrideEditWidgetClass,
278                     disableWidgetTest : this.disableWidgetTest,
279                     onPostSubmit : function() {
280                         for(var i in fmObject._fields) {
281                             var field = fmObject._fields[i];
282                             if(idents.filter(function(j){return (j == field)})[0])
283                                 continue; // don't try to edit an identifier field
284                             grid.store.setValue(storeItem, field, fmObject[field]());
285                         }
286                         if(self.onPostUpdate)
287                             self.onPostUpdate(storeItem, rowIndex);
288                         setTimeout(
289                             function(){
290                                 try { 
291                                     grid.views.views[0].getCellNode(rowIndex, 0).focus(); 
292                                 } catch (E) {}
293                             },200
294                         );
295                         if(onPostSubmit) onPostSubmit();
296                     },
297                     onCancel : function() {
298                         setTimeout(function(){
299                             grid.views.views[0].getCellNode(rowIndex, 0).focus();},200);
300                         if(onCancel) onCancel();
301                     }
302                 });
303
304                 pane.fieldOrder = this.fieldOrder;
305                 pane.mode = 'update';
306                 return pane;
307             },
308
309             _makeCreatePane : function(onPostSubmit, onCancel) {
310                 var grid = this;
311                 var pane = new openils.widget.EditPane({
312                     fmClass : this.fmClass,
313                     overrideWidgets : this.overrideEditWidgets,
314                     overrideWidgetClass : this.overrideEditWidgetClass,
315                     disableWidgetTest : this.disableWidgetTest,
316                     onPostSubmit : function(r) {
317                         var fmObject = openils.Util.readResponse(r);
318                         if(grid.onPostCreate)
319                             grid.onPostCreate(fmObject);
320                         if(fmObject) 
321                             grid.store.newItem(fmObject.toStoreItem());
322                         setTimeout(function(){
323                             try {
324                                 grid.selection.select(grid.rowCount-1);
325                                 grid.views.views[0].getCellNode(grid.rowCount-1, 1).focus();
326                             } catch (E) {}
327                         },200);
328                         if(onPostSubmit)
329                             onPostSubmit();
330                     },
331                     onCancel : function() {
332                         if(onCancel) onCancel();
333                     }
334                 });
335                 pane.fieldOrder = this.fieldOrder;
336                 pane.mode = 'create';
337                 return pane;
338             },
339
340             // .startup() is called within
341             _makeClonePane : function(storeItem, rowIndex, onPostSubmit, onCancel) {
342                 var clonePane = this._makeCreatePane(onPostSubmit, onCancel);
343                 var origPane = this._makeEditPane(storeItem, rowIndex);
344                 clonePane.startup();
345                 origPane.startup();
346                 dojo.forEach(origPane.fieldList,
347                     function(field) {
348                         if(field.widget.widget.attr('disabled')) return;
349                         var w = clonePane.fieldList.filter(
350                             function(i) { return (i.name == field.name) })[0];
351                         w.widget.baseWidgetValue(field.widget.widgetValue); // sync widgets
352                         w.widget.onload = function(){w.widget.baseWidgetValue(field.widget.widgetValue)}; // async widgets
353                     }
354                 );
355                 origPane.destroy();
356                 return clonePane;
357             },
358
359
360             _drawEditDialog : function(storeItem, rowIndex) {
361                 var self = this;
362                 var done = function() { self.hideDialog(); };
363                 var pane = this._makeEditPane(storeItem, rowIndex, done, done);
364                 this.editDialog = new openils.widget.EditDialog({editPane:pane});
365                 this.editDialog.startup();
366                 this.editDialog.show();
367             },
368
369             showCreateDialog : function() {
370                 var self = this;
371                 var done = function() { self.hideDialog(); };
372                 var pane = this._makeCreatePane(done, done);
373                 this.editDialog = new openils.widget.EditDialog({editPane:pane});
374                 this.editDialog.startup();
375                 this.editDialog.show();
376             },
377
378             _drawEditPane : function(storeItem, rowIndex) {
379                 var self = this;
380                 var done = function() { self.hidePane(); };
381                 dojo.style(this.domNode, 'display', 'none');
382                 this.editPane = this._makeEditPane(storeItem, rowIndex, done, done);
383                 this.editPane.startup();
384                 this.domNode.parentNode.insertBefore(this.editPane.domNode, this.domNode);
385                 if(this.onEditPane) this.onEditPane(this.editPane);
386             },
387
388             showClonePane : function() {
389                 var self = this;
390                 var done = function() { self.hidePane(); };
391                 var row = this.getFirstSelectedRow();
392                 if(!row) return;
393                 dojo.style(this.domNode, 'display', 'none');
394                 this.editPane = this._makeClonePane(this.getItem(row), row, done, done);
395                 this.domNode.parentNode.insertBefore(this.editPane.domNode, this.domNode);
396                 if(this.onEditPane) this.onEditPane(this.editPane);
397             },
398
399             showCreatePane : function() {
400                 var self = this;
401                 var done = function() { self.hidePane(); };
402                 dojo.style(this.domNode, 'display', 'none');
403                 this.editPane = this._makeCreatePane(done, done);
404                 this.editPane.startup();
405                 this.domNode.parentNode.insertBefore(this.editPane.domNode, this.domNode);
406                 if(this.onEditPane) this.onEditPane(this.editPane);
407             },
408
409             hideDialog : function() {
410                 this.editDialog.hide(); 
411                 this.editDialog.destroy(); 
412                 delete this.editDialog;
413                 this.update();
414             },
415
416             hidePane : function() {
417                 this.domNode.parentNode.removeChild(this.editPane.domNode);
418                 this.editPane.destroy();
419                 delete this.editPane;
420                 dojo.style(this.domNode, 'display', 'block');
421                 this.update();
422             },
423             
424             resetStore : function() {
425                 this.setStore(this.buildAutoStore());
426             },
427
428             loadAll : function(opts, search) {
429                 dojo.require('openils.PermaCrud');
430                 if(!opts) opts = {};
431                 var self = this;
432                 opts = dojo.mixin(opts, {
433                     async : true,
434                     streaming : true,
435                     onresponse : function(r) {
436                         var item = openils.Util.readResponse(r);
437                         self.store.newItem(item.toStoreItem());
438                     }
439                 });
440                 if(search)
441                     new openils.PermaCrud().search(this.fmClass, search, opts);
442                 else
443                     new openils.PermaCrud().retrieveAll(this.fmClass, opts);
444             }
445         } 
446     );
447
448     // static ID generater seed
449     openils.widget.AutoGrid.sequence = 0;
450     openils.widget.AutoGrid.gridCache = {};
451
452     openils.widget.AutoGrid.markupFactory = dojox.grid.DataGrid.markupFactory;
453
454     openils.widget.AutoGrid.defaultGetter = function(rowIndex, item) {
455         if(!item) return '';
456         var val = this.grid.store.getValue(item, this.field);
457         var autoWidget = new openils.widget.AutoFieldWidget({
458             fmClass: this.grid.fmClass,
459             fmField: this.field,
460             widgetValue : val,
461             readOnly : true,
462             forceSync : true
463         });
464         //autoWidget.build();
465         return autoWidget.getDisplayString();
466     }
467 }
468