]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/web/js/dojo/openils/widget/AutoFieldWidget.js
added an explicit error for a common occurence in autofieldwidget land
[working/Evergreen.git] / Open-ILS / web / js / dojo / openils / widget / AutoFieldWidget.js
1 if(!dojo._hasResource['openils.widget.AutoFieldWidget']) {
2     dojo.provide('openils.widget.AutoFieldWidget');
3     dojo.require('openils.Util');
4     dojo.require('openils.User');
5     dojo.require('fieldmapper.IDL');
6
7     dojo.declare('openils.widget.AutoFieldWidget', null, {
8
9         async : false,
10         cache : {},
11
12         /**
13          * args:
14          *  idlField -- Field description object from fieldmapper.IDL.fmclasses
15          *  fmObject -- If available, the object being edited.  This will be used 
16          *      to set the value of the widget.
17          *  fmClass -- Class name (not required if idlField or fmObject is set)
18          *  fmField -- Field name (not required if idlField)
19          *  parentNode -- If defined, the widget will be appended to this DOM node
20          *  dijitArgs -- Optional parameters object, passed directly to the dojo widget
21          *  orgLimitPerms -- If this field defines a set of org units and an orgLimitPerms 
22          *      is defined, the code will limit the org units in the set to those
23          *      allowed by the permission
24          */
25         constructor : function(args) {
26             for(var k in args)
27                 this[k] = args[k];
28
29             // find the field description in the IDL if not provided
30             if(this.fmObject) 
31                 this.fmClass = this.fmObject.classname;
32             this.fmIDL = fieldmapper.IDL.fmclasses[this.fmClass];
33
34             if(!this.idlField) {
35                 this.fmIDL = fieldmapper.IDL.fmclasses[this.fmClass];
36                 var fields = this.fmIDL.fields;
37                 for(var f in fields) 
38                     if(fields[f].name == this.fmField)
39                         this.idlField = fields[f];
40             }
41
42             if(!this.idlField) 
43                 throw new Error("AutoFieldWidget could not determine which field to render.  We need more information.");
44         },
45
46         /**
47          * Turn the widget-stored value into a value oils understands
48          */
49         getFormattedValue : function() {
50             var value = this.baseWidgetValue();
51             switch(this.idlField.datatype) {
52                 case 'bool':
53                     return (value) ? 't' : 'f'
54                 case 'timestamp':
55                     return dojo.date.stamp.toISOString(value);
56                 case 'int':
57                 case 'float':
58                     if(isNaN(value)) value = 0;
59                 default:
60                     return (value === '') ? null : value;
61             }
62         },
63
64         baseWidgetValue : function(value) {
65             var attr = (this.readOnly) ? 'content' : 'value';
66             if(arguments.length) this.widget.attr(attr, value);
67             return this.widget.attr(attr);
68         },
69         
70         /**
71          * Turn the widget-stored value into something visually suitable
72          */
73         getDisplayString : function() {
74             var value = this.widgetValue;
75             switch(this.idlField.datatype) {
76                 case 'bool':
77                     return (value) ? 'True' : 'False'; // XXX i18n!
78                 case 'timestamp':
79                     dojo.require('dojo.date.locale');
80                     dojo.require('dojo.date.stamp');
81                     var date = dojo.date.stamp.fromISOString(value);
82                     return dojo.date.locale.format(date, {formatLength:'short'});
83                 case 'org_unit':
84                     if(value === null || value === undefined) return '';
85                     return fieldmapper.aou.findOrgUnit(value).shortname();
86                 case 'int':
87                 case 'float':
88                     if(isNaN(value)) value = 0;
89                 default:
90                     if(value === undefined || value === null)
91                         value = '';
92                     return value+'';
93             }
94         },
95
96         build : function(onload) {
97
98             if(this.widget) {
99                 // core widget provided for us, attach and move on
100                 if(this.parentNode) // may already be in the "right" place
101                     this.parentNode.appendChild(this.widget.domNode);
102                 return;
103             }
104
105             this.onload = onload;
106             if(this.widgetValue == null)
107                 this.widgetValue = (this.fmObject) ? this.fmObject[this.idlField.name]() : null;
108
109             if(this.readOnly) {
110                 dojo.require('dijit.layout.ContentPane');
111                 this.widget = new dijit.layout.ContentPane(this.dijitArgs, this.parentNode);
112
113             } else if(this.widgetClass) {
114                 dojo.require(this.widgetClass);
115                 eval('this.widget = new ' + this.widgetClass + '(this.dijitArgs, this.parentNode);');
116
117             } else {
118
119                 switch(this.idlField.datatype) {
120                     
121                     case 'id':
122                         dojo.require('dijit.form.TextBox');
123                         this.widget = new dijit.form.TextBox(this.dijitArgs, this.parentNode);
124                         this.widget.attr('disabled', true); // never allow editing of IDs
125                         break;
126
127                     case 'org_unit':
128                         this._buildOrgSelector();
129                         break;
130
131                     case 'money':
132                         dojo.require('dijit.form.CurrencyTextBox');
133                         this.widget = new dijit.form.CurrencyTextBox(this.dijitArgs, this.parentNode);
134                         break;
135
136                     case 'int':
137                         dojo.require('dijit.form.NumberTextBox');
138                         this.dijitArgs = dojo.mixin(this.dijitArgs || {}, {constraints:{places:0}});
139                         this.widget = new dijit.form.NumberTextBox(this.dijitArgs, this.parentNode);
140                         break;
141
142                     case 'float':
143                         dojo.require('dijit.form.NumberTextBox');
144                         this.widget = new dijit.form.NumberTextBox(this.dijitArgs, this.parentNode);
145                         break;
146
147                     case 'timestamp':
148                         dojo.require('dijit.form.DateTextBox');
149                         dojo.require('dojo.date.stamp');
150                         this.widget = new dijit.form.DateTextBox(this.dijitArgs, this.parentNode);
151                         if(this.widgetValue != null) 
152                             this.widgetValue = dojo.date.stamp.fromISOString(this.widgetValue);
153                         break;
154
155                     case 'bool':
156                         dojo.require('dijit.form.CheckBox');
157                         this.widget = new dijit.form.CheckBox(this.dijitArgs, this.parentNode);
158                         this.widgetValue = openils.Util.isTrue(this.widgetValue);
159                         break;
160
161                     case 'link':
162                         if(this._buildLinkSelector()) break;
163
164                     default:
165                         dojo.require('dijit.form.TextBox');
166                         this.widget = new dijit.form.TextBox(this.dijitArgs, this.parentNode);
167                 }
168             }
169
170             if(!this.async) this._widgetLoaded();
171             return this.widget;
172         },
173
174         _buildLinkSelector : function() {
175
176             /* verify we can and should grab the related class */
177             var linkClass = this.idlField['class'];
178             if(this.idlField.reltype != 'has_a')  return false;
179             if(!fieldmapper.IDL.fmclasses[linkClass].permacrud) return false;
180             if(!fieldmapper.IDL.fmclasses[linkClass].permacrud.retrieve) return false;
181
182             dojo.require('openils.PermaCrud');
183             dojo.require('dojo.data.ItemFileReadStore');
184             dojo.require('dijit.form.FilteringSelect');
185
186             var self = this;
187             var vfield;
188             var rclassIdl = fieldmapper.IDL.fmclasses[linkClass];
189
190             if(linkClass == 'pgt')
191                 return self._buildPermGrpSelector();
192
193             this.async = true;
194             this.widget = new dijit.form.FilteringSelect(this.dijitArgs, this.parentNode);
195
196             for(var f in rclassIdl.fields) {
197                 if(self.idlField.key == rclassIdl.fields[f].name) {
198                     vfield = rclassIdl.fields[f];
199                     break;
200                 }
201             }
202
203             if(!vfield) 
204                 throw new Error("'" + linkClass + "' has no '" + self.idlField.key + "' field!");
205
206             this.widget.searchAttr = this.widget.labelAttr = vfield.selector || vfield.name;
207             this.widget.valueAttr = vfield.name;
208
209             var oncomplete = function(list) {
210                 if(list) {
211                     self.widget.store = 
212                         new dojo.data.ItemFileReadStore({data:fieldmapper[linkClass].toStoreData(list)});
213                     self.cache[linkClass] = list;
214                 }
215                 self.widget.startup();
216                 self._widgetLoaded();
217             };
218
219             if(this.cache[linkClass]) {
220                 oncomplete(this.cache[linkClass]);
221
222             } else {
223                 new openils.PermaCrud().retrieveAll(linkClass, {   
224                     async : true,
225                     oncomplete : function(r) {
226                         var list = openils.Util.readResponse(r, false, true);
227                         oncomplete(list);
228                     }
229                 });
230             }
231
232             return true;
233         },
234
235         /**
236          * For widgets that run asynchronously, provide a callback for finishing up
237          */
238         _widgetLoaded : function(value) {
239             if(this.readOnly) {
240                 this.baseWidgetValue(this.getDisplayString());
241             } else {
242                 this.baseWidgetValue(this.widgetValue);
243                 if(this.idlField.name == this.fmIDL.pkey && this.fmIDL.pkey_sequence)
244                     this.widget.attr('disabled', true); 
245             }
246             if(this.onload)
247                 this.onload(this.widget, self);
248         },
249
250         _buildOrgSelector : function() {
251             dojo.require('fieldmapper.OrgUtils');
252             dojo.require('openils.widget.FilteringTreeSelect');
253             this.widget = new openils.widget.FilteringTreeSelect(this.dijitArgs, this.parentNode);
254             this.widget.searchAttr = 'shortname';
255             this.widget.labelAttr = 'shortname';
256             this.widget.parentField = 'parent_ou';
257             var user = new openils.User();
258             if(this.widgetValue == null) 
259                 this.widgetValue = user.user.ws_ou();
260             
261             // if we have a limit perm, find the relevent orgs (async)
262             if(this.orgLimitPerms && this.orgLimitPerms.length > 0) {
263                 this.async = true;
264                 var self = this;
265                 user.getPermOrgList(this.orgLimitPerms, 
266                     function(orgList) {
267                         self.widget.tree = orgList;
268                         self.widget.startup();
269                         self._widgetLoaded();
270                     }
271                 );
272
273             } else {
274                 this.widget.tree = fieldmapper.aou.globalOrgTree;
275                 this.widget.startup();
276             }
277         },
278
279         _buildPermGrpSelector : function() {
280             dojo.require('openils.widget.FilteringTreeSelect');
281             this.widget = new openils.widget.FilteringTreeSelect(this.dijitArgs, this.parentNode);
282             this.widget.searchAttr = 'name';
283
284             if(this.cache.permGrpTree) {
285                 this.widget.tree = this.cache.permGrpTree;
286                 this.widget.startup();
287                 return;
288             } 
289
290             var self = this;
291             this.async = true;
292             new openils.PermaCrud().retrieveAll('pgt', {
293                 async : true,
294                 oncomplete : function(r) {
295                     var list = openils.Util.readResponse(r, false, true);
296                     if(!list) return;
297                     var map = {};
298                     var root = null;
299                     for(var l in list)
300                         map[list[l].id()] = list[l];
301                     for(var l in list) {
302                         var node = list[l];
303                         var pnode = map[node.parent()];
304                         if(!pnode) {root = node; continue;}
305                         if(!pnode.children()) pnode.children([]);
306                         pnode.children().push(node);
307                     }
308                     self.widget.tree = self.cache.permGrpTree = root;
309                     self.widget.startup();
310                     self._widgetLoaded();
311                 }
312             });
313
314             return true;
315         }
316     });
317 }
318