a3d36c0df216190af684d3de396f9b2b80979191
[working/Evergreen.git] / Open-ILS / web / js / dojo / openils / widget / EditPane.js
1 if(!dojo._hasResource['openils.widget.EditPane']) {
2     dojo.provide('openils.widget.EditPane');
3     dojo.require('openils.widget.AutoWidget');
4     dojo.require('openils.widget.AutoFieldWidget');
5     dojo.require('fieldmapper.Fieldmapper');
6     dojo.require('dijit.layout.ContentPane');
7     dojo.require('openils.Util');
8     dojo.require('openils.PermaCrud');
9     dojo.require('dijit.form.Button');
10     dojo.requireLocalization('openils.widget', 'AutoFieldWidget');
11
12     dojo.declare(
13         'openils.widget.EditPane',
14         [dijit.layout.ContentPane, openils.widget.AutoWidget],
15         {
16             mode : 'update',
17             onPostSubmit : null, // apply callback
18             onCancel : null, // cancel callback
19             hideActionButtons : false,
20             fieldDocs : null,
21             existingTable : null,
22             suppressFields : null,
23             requiredFields : null,
24             paneStackCount : 1, // how many fields to add to each row, for compressing display
25
26             constructor : function(args) {
27                 this.fieldList = [];
28                 for(var k in args)
29                     this[k] = args[k];
30             },
31
32             /**
33              * Builds a basic table of key / value pairs.  Keys are IDL display labels.
34              * Values are dijit's, when values set
35              */
36             startup : function() {
37                 this.inherited(arguments);
38                 this.initAutoEnv();
39                 if(this.readOnly)
40                     this.hideSaveButton = true;
41
42                 // grab any field-level docs
43                 /*
44                 var pcrud = new openils.PermaCrud();
45                 this.fieldDocs = pcrud.search('fdoc', {fm_class:this.fmClass});
46                 */
47
48                 this.nls = dojo.i18n.getLocalization('openils.widget', 'AutoFieldWidget');
49
50                 var table = this.existingTable;
51                 if(!table) {
52                     var table = this.table = document.createElement('table');
53                     this.domNode.appendChild(table);
54                 }
55                 var tbody = document.createElement('tbody');
56                 table.appendChild(tbody);
57
58                 this.limitPerms = [];
59                 if(this.fmIDL.permacrud && this.fmIDL.permacrud[this.mode])
60                     this.limitPerms = this.fmIDL.permacrud[this.mode].perms;
61
62                 if(!this.overrideWidgets)
63                     this.overrideWidgets = {};
64
65                 if(!this.overrideWidgetClass)
66                     this.overrideWidgetClass = {};
67
68                 if(!this.overrideWidgetArgs)
69                     this.overrideWidgetArgs = {};
70
71                 var idx = 0;
72                 var currentRow;
73                 for(var f in this.sortedFieldList) {
74                     var field = this.sortedFieldList[f];
75                     if(!field || field.virtual || field.nonIdl) continue;
76
77                     if(this.suppressFields && this.suppressFields.indexOf(field.name) > -1)
78                         continue;
79
80                     if(field.name == this.fmIDL.pkey && this.mode == 'create' && this.fmIDL.pkey_sequence)
81                         continue; /* don't show auto-generated fields on create */
82
83                     if(!this.overrideWidgetArgs[field.name])
84                         this.overrideWidgetArgs[field.name] = {};
85
86                     if(this.overrideWidgetArgs[field.name].hrbefore && this.paneStackCount <= 1) {
87                         var hrTr = document.createElement('tr');
88                         var hrTd = document.createElement('td');
89                         var hr = document.createElement('hr');
90                         hrTd.colSpan = 2;
91                         dojo.addClass(hrTd, 'openils-widget-editpane-hr-cell');
92                         hrTd.appendChild(hr);
93                         hrTr.appendChild(hrTd);
94                         tbody.appendChild(hrTr);
95                     }
96
97                     if((idx++ % this.paneStackCount) == 0 || !currentRow) {
98                         // time to start a new row
99                         currentRow = document.createElement('tr');
100                         tbody.appendChild(currentRow);
101                     }
102
103                     //var docTd = document.createElement('td');
104                     var nameTd = document.createElement('td');
105                     var valTd = document.createElement('td');
106                     var valSpan = document.createElement('span');
107                     valTd.appendChild(valSpan);
108                     dojo.addClass(nameTd, 'openils-widget-editpane-name-cell');
109                     dojo.addClass(valTd, 'openils-widget-editpane-value-cell');
110
111                     /*
112                     if(this.fieldDocs[field]) {
113                         var helpLink = dojo.create('a');
114                         var helpImg = dojo.create('img', {src:'/opac/images/advancedsearch-icon.png'}); // TODO Config
115                         helpLink.appendChild(helpImg);
116                         docTd.appendChild(helpLink);
117                     }
118                     */
119
120                     nameTd.appendChild(document.createTextNode(field.label));
121                     currentRow.setAttribute('fmfield', field.name);
122                     //currentRow.appendChild(docTd);
123                     currentRow.appendChild(nameTd);
124                     currentRow.appendChild(valTd);
125                     //dojo.addClass(docTd, 'oils-fm-edit-pane-help');
126
127                     var args = dojo.mixin(
128                         {   // defaults
129                             idlField : field, 
130                             fmObject : this.fmObject,
131                             fmClass : this.fmClass,
132                             parentNode : valSpan,
133                             orgLimitPerms : this.limitPerms,
134                             readOnly : this.readOnly,
135                             widget : this.overrideWidgets[field.name],
136                             widgetClass : this.overrideWidgetClass[field.name],
137                             disableWidgetTest : this.disableWidgetTest
138                         },
139                         this.overrideWidgetArgs[field.name] // per-field overrides
140                     );
141
142                     if (this.overrideWidgets[field.name]) {
143                         if (this.overrideWidgets[field.name].shove) {
144                             args.shove = dojo.mixin(
145                                 {"mode": this.mode},
146                                 this.overrideWidgets[field.name].shove
147                             );
148                         }
149                     }
150
151                     if(args.readOnly) {
152                         dojo.addClass(nameTd, 'openils-widget-editpane-ro-name-cell');
153                         dojo.addClass(valTd, 'openils-widget-editpane-ro-value-cell');
154                     }
155
156                     if(this.requiredFields && this.requiredFields.indexOf(field.name) >= 0) {
157                         if(!args.dijitArgs) args.dijitArgs = {};
158                         args.dijitArgs.required = true;
159                     }
160
161                     var widget = new openils.widget.AutoFieldWidget(args);
162
163                     widget.build();
164                     this.fieldList.push({name:field.name, widget:widget});
165                 }
166                 if(!this.hideActionButtons)
167                     this.buildActionButtons(tbody);
168
169                 openils.Util.addCSSClass(table, 'oils-fm-edit-pane');
170             },
171
172             applySaveOnEnter : function(widget) {
173                 var self = this;
174                 dojo.connect(this, 'onKeyDown',
175                     function(e) {
176                         if(e.keyCode == dojo.keys.ENTER) 
177                             self.performAutoEditAction();
178                     }
179                 );
180             },
181
182             buildActionButtons : function(tbody) {
183                 var row = document.createElement('tr');
184                 var cancelTd = document.createElement('td');
185                 var applyTd = document.createElement('td');
186                 var cancelSpan = document.createElement('span');
187                 var applySpan = document.createElement('span');
188                 row.appendChild(cancelTd);
189                 row.appendChild(applyTd);
190                 cancelTd.appendChild(cancelSpan);
191                 applyTd.appendChild(applySpan);
192                 tbody.appendChild(row);
193
194                 var self = this;
195                 new dijit.form.Button({
196                     label: this.nls.CANCEL,
197                     onClick : this.onCancel
198                 }, cancelSpan);
199
200                 if(this.hideSaveButton) return;
201
202                 new dijit.form.Button({
203                     label:this.nls.SAVE,
204                     onClick: function() {self.performAutoEditAction();}
205                 }, applySpan);
206             },
207
208             getFields : function() {
209                 return this.fieldList.map(function(a) { return a.name });
210             },
211
212             // Apply a function for the name and formatted value of each field
213             // in this edit pane.  If any required value is null, then return
214             // an error object.
215             mapValues: function (fn) {
216                 var e = 0, msg = '', lbl = this.fmIDL.label;
217                 dojo.forEach(this.fieldList, function (f) {
218                     var v, w = f.widget;
219                     if ((v = w.getFormattedValue()) === null && w.isRequired()) { e++; }
220                     fn(f.name, v);
221                 });
222                 if (e > 0) {
223                     return new Error(dojo.string.substitute(this.nls.REQ_FIELDS_EMPTY, [lbl, e]));
224                 }
225             },
226
227             getFieldValue : function(field, checkRequired) {
228                 for(var i in this.fieldList) {
229                     if(field == this.fieldList[i].name) {
230                         var val = this.fieldList[i].widget.getFormattedValue();
231                         if (checkRequired &&
232                             val == null && /* XXX stricter check needed? */
233                             this.fieldList[i].widget.isRequired()) {
234                             throw new Error("req");
235                         }
236                         return val;
237
238                     }
239                 }
240             },
241
242             getFieldWidget : function(field) {
243                 for (var i in this.fieldList)
244                     if (field == this.fieldList[i].name)
245                         return this.fieldList[i].widget;
246             },
247
248             setFieldValue : function(field, val) {
249                 for(var i in this.fieldList) {
250                     if(field == this.fieldList[i].name) {
251                         this.fieldList[i].widget.widget.attr('value', val);
252                     }
253                 }
254             },
255
256
257             performAutoEditAction : function() {
258                 var self = this;
259                 self.performEditAction({
260                     oncomplete:function(req, cudResults) {
261                         if(self.onPostSubmit)
262                             self.onPostSubmit(req, cudResults);
263                     }
264                 });
265             },
266
267             performEditAction : function(opts) {
268                 var self = this;
269                 var fields = this.getFields();
270                 if(this.mode == 'create')
271                     this.fmObject = new fieldmapper[this.fmClass]();
272                 try {
273                     for(var idx in fields) {
274                         this.fmObject[fields[idx]](
275                             this.getFieldValue(fields[idx], true)
276                         );
277                     }
278                 } catch (E) {
279                     if (E.message == "req") /* req'd field set to null. bail. */
280                         return;
281                     else /* something else went wrong? */
282                         throw E;
283                 }
284                 if(this.mode == 'create' && this.fmIDL.pkey_sequence)
285                     this.fmObject[this.fmIDL.pkey](null);
286                 if (typeof(this.onSubmit) == "function") {
287                     this.onSubmit(this.fmObject, opts, self);
288                 } else {
289                     (new openils.PermaCrud())[this.mode](this.fmObject, opts);
290                 }
291             }
292         }
293     );
294 }
295