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