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