]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/web/js/dojo/openils/widget/AutoFieldWidget.js
throw meaningful error when IDL link is invalid
[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
43         /**
44          * Turn the widget-stored value into a value oils understands
45          */
46         getFormattedValue : function() {
47             var value = this.baseWidgetValue();
48             switch(this.idlField.datatype) {
49                 case 'bool':
50                     return (value) ? 't' : 'f'
51                 case 'timestamp':
52                     return dojo.date.stamp.toISOString(value);
53                 default:
54                     return (value == '') ? null : value;
55             }
56         },
57
58         baseWidgetValue : function(value) {
59             var attr = (this.readOnly) ? 'content' : 'value';
60             if(arguments.length) this.widget.attr(attr, value);
61             return this.widget.attr(attr);
62         },
63         
64         /**
65          * Turn the widget-stored value into something visually suitable
66          */
67         getDisplayString : function() {
68             var value = this.widgetValue;
69             switch(this.idlField.datatype) {
70                 case 'bool':
71                     return (value) ? 'True' : 'False'; // XXX i18n!
72                 case 'timestamp':
73                     dojo.require('dojo.date.locale');
74                     dojo.require('dojo.date.stamp');
75                     var date = dojo.date.stamp.fromISOString(value);
76                     return dojo.date.locale.format(date, {formatLength:'short'});
77                 case 'org_unit':
78                     return fieldmapper.aou.findOrgUnit(value).shortname();
79                 default:
80                     return value+'';
81             }
82         },
83
84         build : function(onload) {
85
86             if(this.widget) {
87                 // core widget provided for us, attach and move on
88                 if(this.parentNode) // may already be in the "right" place
89                     this.parentNode.appendChild(this.widget.domNode);
90                 return;
91             }
92
93             this.onload = onload;
94             if(this.widgetValue == null)
95                 this.widgetValue = (this.fmObject) ? this.fmObject[this.idlField.name]() : null;
96
97             if(this.readOnly) {
98                 dojo.require('dijit.layout.ContentPane');
99                 this.widget = new dijit.layout.ContentPane(this.dijitArgs, this.parentNode);
100
101             } else if(this.widgetClass) {
102                 dojo.require(this.widgetClass);
103                 eval('this.widget = new ' + this.widgetClass + '(this.dijitArgs, this.parentNode);');
104
105             } else {
106
107                 switch(this.idlField.datatype) {
108                     
109                     case 'id':
110                         dojo.require('dijit.form.TextBox');
111                         this.widget = new dijit.form.TextBox(this.dijitArgs, this.parentNode);
112                         this.widget.attr('disabled', true); // never allow editing of IDs
113                         break;
114
115                     case 'org_unit':
116                         this._buildOrgSelector();
117                         break;
118
119                     case 'money':
120                         dojo.require('dijit.form.CurrencyTextBox');
121                         this.widget = new dijit.form.CurrencyTextBox(this.dijitArgs, this.parentNode);
122                         break;
123
124                     case 'int':
125                         dojo.require('dijit.form.NumberTextBox');
126                         this.dijitArgs = dojo.mixin(this.dijitArgs || {}, {constraints:{places:0}});
127                         this.widget = new dijit.form.NumberTextBox(this.dijitArgs, this.parentNode);
128                         break;
129
130                     case 'float':
131                         dojo.require('dijit.form.NumberTextBox');
132                         this.widget = new dijit.form.NumberTextBox(this.dijitArgs, this.parentNode);
133                         break;
134
135                     case 'timestamp':
136                         dojo.require('dijit.form.DateTextBox');
137                         dojo.require('dojo.date.stamp');
138                         this.widget = new dijit.form.DateTextBox(this.dijitArgs, this.parentNode);
139                         if(this.widgetValue != null) 
140                             this.widgetValue = dojo.date.stamp.fromISOString(this.widgetValue);
141                         break;
142
143                     case 'bool':
144                         dojo.require('dijit.form.CheckBox');
145                         this.widget = new dijit.form.CheckBox(this.dijitArgs, this.parentNode);
146                         this.widgetValue = openils.Util.isTrue(this.widgetValue);
147                         break;
148
149                     case 'link':
150                         if(this._buildLinkSelector()) break;
151
152                     default:
153                         dojo.require('dijit.form.TextBox');
154                         this.widget = new dijit.form.TextBox(this.dijitArgs, this.parentNode);
155                 }
156             }
157
158             if(!this.async) this._widgetLoaded();
159             return this.widget;
160         },
161
162         _buildLinkSelector : function() {
163
164             /* verify we can and should grab the related class */
165             var linkClass = this.idlField['class'];
166             if(this.idlField.reltype != 'has_a')  return false;
167             if(!fieldmapper.IDL.fmclasses[linkClass].permacrud) return false;
168             if(!fieldmapper.IDL.fmclasses[linkClass].permacrud.retrieve) return false;
169
170             dojo.require('openils.PermaCrud');
171             dojo.require('dojo.data.ItemFileReadStore');
172             dojo.require('dijit.form.FilteringSelect');
173
174             var self = this;
175             var vfield;
176             var rclassIdl = fieldmapper.IDL.fmclasses[linkClass];
177
178             if(linkClass == 'pgt')
179                 return self._buildPermGrpSelector();
180
181             this.async = true;
182             this.widget = new dijit.form.FilteringSelect(this.dijitArgs, this.parentNode);
183
184             for(var f in rclassIdl.fields) {
185                 if(self.idlField.key == rclassIdl.fields[f].name) {
186                     vfield = rclassIdl.fields[f];
187                     break;
188                 }
189             }
190
191             if(!vfield) 
192                 throw new Error("'" + linkClass + "' has no '" + self.idlField.key + "' field!");
193
194             this.widget.searchAttr = this.widget.labelAttr = vfield.selector || vfield.name;
195             this.widget.valueAttr = vfield.name;
196
197             new openils.PermaCrud().retrieveAll(linkClass, {   
198                 async : true,
199                 oncomplete : function(r) {
200                     var list = openils.Util.readResponse(r, false, true);
201                     if(list) {
202                         self.widget.store = 
203                             new dojo.data.ItemFileReadStore({data:fieldmapper[linkClass].toStoreData(list)});
204                     }
205                     self.widget.startup();
206                     self._widgetLoaded();
207                 }
208             });
209
210             return true;
211         },
212
213         /**
214          * For widgets that run asynchronously, provide a callback for finishing up
215          */
216         _widgetLoaded : function(value) {
217             if(this.readOnly) {
218                 this.baseWidgetValue(this.getDisplayString());
219             } else {
220                 this.baseWidgetValue(this.widgetValue);
221                 if(this.idlField.name == this.fmIDL.pkey && this.fmIDL.pkey_sequence)
222                     this.widget.attr('disabled', true); 
223             }
224             if(this.onload)
225                 this.onload(this.widget, self);
226         },
227
228         _buildOrgSelector : function() {
229             dojo.require('fieldmapper.OrgUtils');
230             dojo.require('openils.widget.FilteringTreeSelect');
231             this.widget = new openils.widget.FilteringTreeSelect(this.dijitArgs, this.parentNode);
232             this.widget.searchAttr = 'shortname';
233             this.widget.labelAttr = 'shortname';
234             this.widget.parentField = 'parent_ou';
235             
236             // if we have a limit perm, find the relevent orgs (async)
237             if(this.orgLimitPerms && this.orgLimitPerms.length > 0) {
238                 this.async = true;
239                 var user = new openils.User();
240                 var self = this;
241                 user.getPermOrgList(this.orgLimitPerms, 
242                     function(orgList) {
243                         self.widget.tree = orgList;
244                         self.widget.startup();
245                         self._widgetLoaded();
246                     }
247                 );
248
249             } else {
250                 this.widget.tree = fieldmapper.aou.globalOrgTree;
251                 this.widget.startup();
252             }
253         },
254
255         _buildPermGrpSelector : function() {
256             dojo.require('openils.widget.FilteringTreeSelect');
257             this.widget = new openils.widget.FilteringTreeSelect(this.dijitArgs, this.parentNode);
258             this.widget.searchAttr = 'name';
259
260             if(this.cache.permGrpTree) {
261                 this.widget.tree = this.cache.permGrpTree;
262                 this.widget.startup();
263                 return;
264             } 
265
266             var self = this;
267             this.async = true;
268             new openils.PermaCrud().retrieveAll('pgt', {
269                 async : true,
270                 oncomplete : function(r) {
271                     var list = openils.Util.readResponse(r, false, true);
272                     if(!list) return;
273                     var map = {};
274                     var root = null;
275                     for(var l in list)
276                         map[list[l].id()] = list[l];
277                     for(var l in list) {
278                         var node = list[l];
279                         var pnode = map[node.parent()];
280                         if(!pnode) {root = node; continue;}
281                         if(!pnode.children()) pnode.children([]);
282                         pnode.children().push(node);
283                     }
284                     self.widget.tree = self.cache.permGrpTree = root;
285                     self.widget.startup();
286                     self._widgetLoaded();
287                 }
288             });
289
290             return true;
291         }
292     });
293 }
294