1 if(!dojo._hasResource['openils.widget.AutoGrid']) {
2 dojo.provide('openils.widget.AutoGrid');
3 dojo.require('dojox.grid.DataGrid');
4 dojo.require('dijit.layout.ContentPane');
5 dojo.require('openils.widget.AutoWidget');
6 dojo.require('openils.widget.AutoFieldWidget');
7 dojo.require('openils.widget.EditPane');
8 dojo.require('openils.widget.EditDialog');
9 dojo.require('openils.widget.GridColumnPicker');
10 dojo.require('openils.Util');
13 'openils.widget.AutoGrid',
14 [dojox.grid.DataGrid, openils.widget.AutoWidget],
17 /* if true, pop up an edit dialog when user hits Enter on a give row */
19 defaultCellWidth : null,
21 suppressFields : null,
23 selectorWidth : '1.5',
24 showColumnPicker : false,
25 columnPickerPrefix : null,
28 showPaginator : false,
29 suppressLinkedFields : null, // list of fields whose linked display data should not be fetched from the server
31 /* by default, don't show auto-generated (sequence) fields */
32 showSequenceFields : false,
34 startup : function() {
35 this.selectionMode = 'single';
36 this.sequence = openils.widget.AutoGrid.sequence++;
37 openils.widget.AutoGrid.gridCache[this.sequence] = this;
38 this.inherited(arguments);
40 this.attr('structure', this._compileStructure());
41 this.setStore(this.buildAutoStore());
42 this.cachedQueryOpts = {};
44 if(this.showColumnPicker) {
45 if(!this.columnPickerPrefix) {
46 console.error("No columnPickerPrefix defined");
48 var picker = new openils.widget.GridColumnPicker(
49 openils.User.authtoken, this.columnPickerPrefix, this);
50 if(openils.User.authtoken) {
53 openils.Util.addOnLoad(function() { picker.load() });
58 this.overrideEditWidgets = {};
59 this.overrideEditWidgetClass = {};
62 this._applyEditOnEnter();
63 else if(this.singleEditStyle)
64 this._applySingleEditStyle();
66 if(!this.hideSelector) {
67 dojo.connect(this, 'onHeaderCellClick',
70 this.toggleSelectAll();
75 if(this.showPaginator) {
77 this.paginator = new dijit.layout.ContentPane();
80 var back = dojo.create('a', {
82 style : 'padding-right:6px;',
83 href : 'javascript:void(0);',
84 onclick : function() {
86 self.cachedQueryOpts.offset = self.displayOffset -= self.displayLimit;
90 self.loadAll(self.cachedQueryOpts, self.cachedQuerySearch);
94 var forw = dojo.create('a', {
96 style : 'padding-right:6px;',
97 href : 'javascript:void(0);',
98 onclick : function() {
100 self.cachedQueryOpts.offset = self.displayOffset += self.displayLimit;
104 self.loadAll(self.cachedQueryOpts, self.cachedQuerySearch);
108 dojo.place(this.paginator.domNode, this.domNode, 'before');
109 dojo.place(back, this.paginator.domNode);
110 dojo.place(forw, this.paginator.domNode);
111 this.loadProgressIndicator = dojo.create('img', {
112 src:'/opac/images/progressbar_green.gif',
113 style:'height:16px;width:16px;'
115 dojo.place(this.loadProgressIndicator, this.paginator.domNode);
119 hideLoadProgressIndicator : function() {
120 dojo.style(this.loadProgressIndicator, 'visibility', 'hidden');
123 showLoadProgressIndicator : function() {
124 dojo.style(this.loadProgressIndicator, 'visibility', 'visible');
127 /* Don't allow sorting on the selector column */
128 canSort : function(rowIdx) {
129 if(rowIdx == 1 && !this.hideSelector)
134 _compileStructure : function() {
135 var existing = (this.structure && this.structure[0].cells[0]) ?
136 this.structure[0].cells[0] : [];
140 function pushEntry(entry) {
141 if(self.suppressFields) {
142 if(dojo.indexOf(self.suppressFields, entry.field) != -1)
146 entry.get = openils.widget.AutoGrid.defaultGetter
147 if(!entry.width && self.defaultCellWidth)
148 entry.width = self.defaultCellWidth;
152 if(!this.hideSelector) {
153 // insert the selector column
156 formatter : function(rowIdx) { return self._formatRowSelectInput(rowIdx); },
157 get : function(rowIdx, item) { if(item) return rowIdx; },
158 width : this.selectorWidth,
165 if(!this.fieldOrder) {
166 /* no order defined, start with any explicit grid fields */
167 for(var e in existing) {
168 var entry = existing[e];
169 var field = this.fmIDL.fields.filter(
170 function(i){return (i.name == entry.field)})[0];
171 if(field) entry.name = entry.name || field.label;
176 for(var f in this.sortedFieldList) {
177 var field = this.sortedFieldList[f];
178 if(!field || field.virtual) continue;
180 // field was already added above
181 if(fields.filter(function(i){return (i.field == field.name)})[0])
184 var entry = existing.filter(function(i){return (i.field == field.name)})[0];
186 entry.name = field.label;
188 // unless specifically requested, hide sequence fields
189 if(!this.showSequenceFields && field.name == this.fmIDL.pkey && this.fmIDL.pkey_sequence)
192 entry = {field:field.name, name:field.label};
197 if(this.fieldOrder) {
198 /* append any explicit non-IDL grid fields to the end */
199 for(var e in existing) {
200 var entry = existing[e];
201 var field = fields.filter(
202 function(i){return (i.field == entry.field)})[0];
203 if(field) continue; // don't duplicate
208 return [{cells: [fields]}];
211 toggleSelectAll : function() {
212 var selected = this.getSelectedRows();
213 for(var i = 0; i < this.rowCount; i++) {
221 getSelectedRows : function() {
224 dojo.query('[name=autogrid.selector]', this.domNode),
227 rows.push(input.getAttribute('row'));
233 getFirstSelectedRow : function() {
234 return this.getSelectedRows()[0];
237 getSelectedItems : function() {
240 dojo.forEach(this.getSelectedRows(), function(idx) { items.push(self.getItem(idx)); });
244 selectRow : function(rowIdx) {
245 var inputs = dojo.query('[name=autogrid.selector]', this.domNode);
246 for(var i = 0; i < inputs.length; i++) {
247 if(inputs[i].getAttribute('row') == rowIdx) {
248 if(!inputs[i].disabled)
249 inputs[i].checked = true;
255 deSelectRow : function(rowIdx) {
256 var inputs = dojo.query('[name=autogrid.selector]', this.domNode);
257 for(var i = 0; i < inputs.length; i++) {
258 if(inputs[i].getAttribute('row') == rowIdx) {
259 inputs[i].checked = false;
265 getAllObjects : function() {
269 onComplete : function(list) {
272 objs.push(new fieldmapper[self.fmClass]().fromStoreItem(item));
280 deleteSelected : function() {
281 var items = this.getSelectedItems();
282 var total = items.length;
284 dojo.require('openils.PermaCrud');
285 var pcrud = new openils.PermaCrud();
288 var fmObject = new fieldmapper[self.fmClass]().fromStoreItem(item);
289 pcrud['delete'](fmObject, {oncomplete : function(r) { self.store.deleteItem(item) }});
294 _formatRowSelectInput : function(rowIdx) {
295 if(rowIdx === null || rowIdx === undefined) return '';
296 var s = "<input type='checkbox' name='autogrid.selector' row='" + rowIdx + "'";
297 if(this.disableSelectorForRow && this.disableSelectorForRow(rowIdx))
298 s += " disabled='disabled'";
302 _applySingleEditStyle : function() {
303 this.onMouseOverRow = function(e) {};
304 this.onMouseOutRow = function(e) {};
305 this.onCellFocus = function(cell, rowIndex) {
306 this.selection.deselectAll();
307 this.selection.select(this.focus.rowIndex);
311 /* capture keydown and launch edit dialog on enter */
312 _applyEditOnEnter : function() {
313 this._applySingleEditStyle();
315 dojo.connect(this, 'onRowDblClick',
317 if(this.editStyle == 'pane')
318 this._drawEditPane(this.selection.getFirstSelected(), this.focus.rowIndex);
320 this._drawEditDialog(this.selection.getFirstSelected(), this.focus.rowIndex);
324 dojo.connect(this, 'onKeyDown',
326 if(e.keyCode == dojo.keys.ENTER) {
327 this.selection.deselectAll();
328 this.selection.select(this.focus.rowIndex);
329 if(this.editStyle == 'pane')
330 this._drawEditPane(this.selection.getFirstSelected(), this.focus.rowIndex);
332 this._drawEditDialog(this.selection.getFirstSelected(), this.focus.rowIndex);
338 _makeEditPane : function(storeItem, rowIndex, onPostSubmit, onCancel) {
340 var fmObject = new fieldmapper[this.fmClass]().fromStoreItem(storeItem);
341 var idents = grid.store.getIdentityAttributes();
343 var pane = new openils.widget.EditPane({
345 overrideWidgets : this.overrideEditWidgets,
346 overrideWidgetClass : this.overrideEditWidgetClass,
347 disableWidgetTest : this.disableWidgetTest,
348 onPostSubmit : function() {
349 for(var i in fmObject._fields) {
350 var field = fmObject._fields[i];
351 if(idents.filter(function(j){return (j == field)})[0])
352 continue; // don't try to edit an identifier field
353 grid.store.setValue(storeItem, field, fmObject[field]());
355 if(self.onPostUpdate)
356 self.onPostUpdate(storeItem, rowIndex);
360 grid.views.views[0].getCellNode(rowIndex, 0).focus();
364 if(onPostSubmit) onPostSubmit();
366 onCancel : function() {
367 setTimeout(function(){
368 grid.views.views[0].getCellNode(rowIndex, 0).focus();},200);
369 if(onCancel) onCancel();
373 pane.fieldOrder = this.fieldOrder;
374 pane.mode = 'update';
378 _makeCreatePane : function(onPostSubmit, onCancel) {
380 var pane = new openils.widget.EditPane({
381 fmClass : this.fmClass,
382 overrideWidgets : this.overrideEditWidgets,
383 overrideWidgetClass : this.overrideEditWidgetClass,
384 disableWidgetTest : this.disableWidgetTest,
385 onPostSubmit : function(r) {
386 var fmObject = openils.Util.readResponse(r);
387 if(grid.onPostCreate)
388 grid.onPostCreate(fmObject);
390 grid.store.newItem(fmObject.toStoreItem());
391 setTimeout(function(){
393 grid.selection.select(grid.rowCount-1);
394 grid.views.views[0].getCellNode(grid.rowCount-1, 1).focus();
400 onCancel : function() {
401 if(onCancel) onCancel();
404 pane.fieldOrder = this.fieldOrder;
405 pane.mode = 'create';
409 // .startup() is called within
410 _makeClonePane : function(storeItem, rowIndex, onPostSubmit, onCancel) {
411 var clonePane = this._makeCreatePane(onPostSubmit, onCancel);
412 var origPane = this._makeEditPane(storeItem, rowIndex);
415 dojo.forEach(origPane.fieldList,
417 if(field.widget.widget.attr('disabled')) return;
418 var w = clonePane.fieldList.filter(
419 function(i) { return (i.name == field.name) })[0];
420 w.widget.baseWidgetValue(field.widget.widgetValue); // sync widgets
421 w.widget.onload = function(){w.widget.baseWidgetValue(field.widget.widgetValue)}; // async widgets
429 _drawEditDialog : function(storeItem, rowIndex) {
431 var done = function() { self.hideDialog(); };
432 var pane = this._makeEditPane(storeItem, rowIndex, done, done);
433 this.editDialog = new openils.widget.EditDialog({editPane:pane});
434 this.editDialog.startup();
435 this.editDialog.show();
438 showCreateDialog : function() {
440 var done = function() { self.hideDialog(); };
441 var pane = this._makeCreatePane(done, done);
442 this.editDialog = new openils.widget.EditDialog({editPane:pane});
443 this.editDialog.startup();
444 this.editDialog.show();
447 _drawEditPane : function(storeItem, rowIndex) {
449 var done = function() { self.hidePane(); };
450 dojo.style(this.domNode, 'display', 'none');
451 this.editPane = this._makeEditPane(storeItem, rowIndex, done, done);
452 this.editPane.startup();
453 this.domNode.parentNode.insertBefore(this.editPane.domNode, this.domNode);
454 if(this.onEditPane) this.onEditPane(this.editPane);
457 showClonePane : function() {
459 var done = function() { self.hidePane(); };
460 var row = this.getFirstSelectedRow();
462 dojo.style(this.domNode, 'display', 'none');
463 this.editPane = this._makeClonePane(this.getItem(row), row, done, done);
464 this.domNode.parentNode.insertBefore(this.editPane.domNode, this.domNode);
465 if(this.onEditPane) this.onEditPane(this.editPane);
468 showCreatePane : function() {
470 var done = function() { self.hidePane(); };
471 dojo.style(this.domNode, 'display', 'none');
472 this.editPane = this._makeCreatePane(done, done);
473 this.editPane.startup();
474 this.domNode.parentNode.insertBefore(this.editPane.domNode, this.domNode);
475 if(this.onEditPane) this.onEditPane(this.editPane);
478 hideDialog : function() {
479 this.editDialog.hide();
480 this.editDialog.destroy();
481 delete this.editDialog;
485 hidePane : function() {
486 this.domNode.parentNode.removeChild(this.editPane.domNode);
487 this.editPane.destroy();
488 delete this.editPane;
489 dojo.style(this.domNode, 'display', 'block');
493 resetStore : function() {
494 this.setStore(this.buildAutoStore());
497 loadAll : function(opts, search) {
498 dojo.require('openils.PermaCrud');
499 if(this.loadProgressIndicator)
500 dojo.style(this.loadProgressIndicator, 'visibility', 'visible');
503 {limit : this.displayLimit, offset : this.displayOffset},
506 opts = dojo.mixin(opts, {
509 onresponse : function(r) {
510 var item = openils.Util.readResponse(r);
511 self.store.newItem(item.toStoreItem());
513 oncomplete : function() {
514 if(self.loadProgressIndicator)
515 dojo.style(self.loadProgressIndicator, 'visibility', 'hidden');
519 this.cachedQuerySearch = search;
520 this.cachedQueryOpts = opts;
522 new openils.PermaCrud().search(this.fmClass, search, opts);
524 new openils.PermaCrud().retrieveAll(this.fmClass, opts);
529 // static ID generater seed
530 openils.widget.AutoGrid.sequence = 0;
531 openils.widget.AutoGrid.gridCache = {};
533 openils.widget.AutoGrid.markupFactory = dojox.grid.DataGrid.markupFactory;
535 openils.widget.AutoGrid.defaultGetter = function(rowIndex, item) {
537 var val = this.grid.store.getValue(item, this.field);
538 var autoWidget = new openils.widget.AutoFieldWidget({
539 fmClass: this.grid.fmClass,
543 suppressLinkedFields : this.grid.suppressLinkedFields
549 var node = _this.grid.getCell(_this.index).view.getCellNode(rowIndex, _this.index);
551 node.innerHTML = ww.getDisplayString();
556 return autoWidget.getDisplayString();