]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/web/js/dojo/openils/widget/AutoFieldWidget.js
one small step for i18n
[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     dojo.require('openils.PermaCrud');
7         dojo.requireLocalization("openils.widget", "AutoFieldWidget");
8     var localeStrings = dojo.i18n.getLocalization("openils.widget", "AutoFieldWidget");
9
10     dojo.declare('openils.widget.AutoFieldWidget', null, {
11
12         async : false,
13         cache : {},
14         cacheSingle : {},
15
16         /**
17          * args:
18          *  idlField -- Field description object from fieldmapper.IDL.fmclasses
19          *  fmObject -- If available, the object being edited.  This will be used 
20          *      to set the value of the widget.
21          *  fmClass -- Class name (not required if idlField or fmObject is set)
22          *  fmField -- Field name (not required if idlField)
23          *  parentNode -- If defined, the widget will be appended to this DOM node
24          *  dijitArgs -- Optional parameters object, passed directly to the dojo widget
25          *  orgLimitPerms -- If this field defines a set of org units and an orgLimitPerms 
26          *      is defined, the code will limit the org units in the set to those
27          *      allowed by the permission
28          */
29         constructor : function(args) {
30             for(var k in args)
31                 this[k] = args[k];
32
33             // find the field description in the IDL if not provided
34             if(this.fmObject) 
35                 this.fmClass = this.fmObject.classname;
36             this.fmIDL = fieldmapper.IDL.fmclasses[this.fmClass];
37
38             if(!this.idlField) {
39                 this.fmIDL = fieldmapper.IDL.fmclasses[this.fmClass];
40                 var fields = this.fmIDL.fields;
41                 for(var f in fields) 
42                     if(fields[f].name == this.fmField)
43                         this.idlField = fields[f];
44             }
45
46             if(!this.idlField) 
47                 throw new Error("AutoFieldWidget could not determine which field to render.  We need more information. fmClass=" + 
48                     this.fmClass + ' fmField=' + this.fmField + ' fmObject=' + js2JSON(this.fmObject));
49
50             this.auth = openils.User.authtoken;
51             if(!this.cache[this.auth]) {
52                 this.cache[this.auth] = {};
53             }
54         },
55
56         /**
57          * Turn the widget-stored value into a value oils understands
58          */
59         getFormattedValue : function() {
60             var value = this.baseWidgetValue();
61             switch(this.idlField.datatype) {
62                 case 'bool':
63                     return (value) ? 't' : 'f'
64                 case 'timestamp':
65                     return dojo.date.stamp.toISOString(value);
66                 case 'int':
67                 case 'float':
68                 case 'money':
69                     if(isNaN(value)) value = 0;
70                 default:
71                     return (value === '') ? null : value;
72             }
73         },
74
75         baseWidgetValue : function(value) {
76             var attr = (this.readOnly) ? 'content' : 'value';
77             if(arguments.length) this.widget.attr(attr, value);
78             return this.widget.attr(attr);
79         },
80         
81         /**
82          * Turn the widget-stored value into something visually suitable
83          */
84         getDisplayString : function() {
85             var value = this.widgetValue;
86             switch(this.idlField.datatype) {
87                 case 'bool':
88                     return (openils.Util.isTrue(value)) ? localeStrings.TRUE : localeStrings.FALSE;
89                 case 'timestamp':
90                     dojo.require('dojo.date.locale');
91                     dojo.require('dojo.date.stamp');
92                     var date = dojo.date.stamp.fromISOString(value);
93                     return dojo.date.locale.format(date, {formatLength:'short'});
94                 case 'org_unit':
95                     if(value === null || value === undefined) return '';
96                     return fieldmapper.aou.findOrgUnit(value).shortname();
97                 case 'int':
98                 case 'float':
99                     if(isNaN(value)) value = 0;
100                 default:
101                     if(value === undefined || value === null)
102                         value = '';
103                     return value+'';
104             }
105         },
106
107         build : function(onload) {
108
109             if(this.widget) {
110                 // core widget provided for us, attach and move on
111                 if(this.parentNode) // may already be in the "right" place
112                     this.parentNode.appendChild(this.widget.domNode);
113                 return;
114             }
115             
116             if(!this.parentNode) // give it somewhere to live so that dojo won't complain
117                 this.parentNode = document.createElement('div');
118
119             this.onload = onload;
120             if(this.widgetValue == null)
121                 this.widgetValue = (this.fmObject) ? this.fmObject[this.idlField.name]() : null;
122
123             if(this.readOnly) {
124                 dojo.require('dijit.layout.ContentPane');
125                 this.widget = new dijit.layout.ContentPane(this.dijitArgs, this.parentNode);
126                 if(this.widgetValue !== null)
127                     this._tryLinkedDisplayField();
128
129             } else if(this.widgetClass) {
130                 dojo.require(this.widgetClass);
131                 eval('this.widget = new ' + this.widgetClass + '(this.dijitArgs, this.parentNode);');
132
133             } else {
134
135                 switch(this.idlField.datatype) {
136                     
137                     case 'id':
138                         dojo.require('dijit.form.TextBox');
139                         this.widget = new dijit.form.TextBox(this.dijitArgs, this.parentNode);
140                         break;
141
142                     case 'org_unit':
143                         this._buildOrgSelector();
144                         break;
145
146                     case 'money':
147                         dojo.require('dijit.form.CurrencyTextBox');
148                         this.widget = new dijit.form.CurrencyTextBox(this.dijitArgs, this.parentNode);
149                         break;
150
151                     case 'int':
152                         dojo.require('dijit.form.NumberTextBox');
153                         this.dijitArgs = dojo.mixin(this.dijitArgs || {}, {constraints:{places:0}});
154                         this.widget = new dijit.form.NumberTextBox(this.dijitArgs, this.parentNode);
155                         break;
156
157                     case 'float':
158                         dojo.require('dijit.form.NumberTextBox');
159                         this.widget = new dijit.form.NumberTextBox(this.dijitArgs, this.parentNode);
160                         break;
161
162                     case 'timestamp':
163                         dojo.require('dijit.form.DateTextBox');
164                         dojo.require('dojo.date.stamp');
165                         this.widget = new dijit.form.DateTextBox(this.dijitArgs, this.parentNode);
166                         if(this.widgetValue != null) 
167                             this.widgetValue = dojo.date.stamp.fromISOString(this.widgetValue);
168                         break;
169
170                     case 'bool':
171                         dojo.require('dijit.form.CheckBox');
172                         this.widget = new dijit.form.CheckBox(this.dijitArgs, this.parentNode);
173                         this.widgetValue = openils.Util.isTrue(this.widgetValue);
174                         break;
175
176                     case 'link':
177                         if(this._buildLinkSelector()) break;
178
179                     default:
180                         dojo.require('dijit.form.TextBox');
181                         this.widget = new dijit.form.TextBox(this.dijitArgs, this.parentNode);
182                 }
183             }
184
185             if(!this.async) this._widgetLoaded();
186             return this.widget;
187         },
188
189         // we want to display the value for our widget.  However, instead of displaying
190         // an ID, for exmaple, display the value for the 'selector' field on the object
191         // the ID points to
192         _tryLinkedDisplayField : function(noAsync) {
193
194             if(this.idlField.datatype == 'org_unit')
195                 return false; // we already handle org_units, no need to re-fetch
196
197             var linkInfo = this._getLinkSelector();
198             if(!(linkInfo && linkInfo.vfield && linkInfo.vfield.selector)) 
199                 return false;
200             var lclass = linkInfo.linkClass;
201
202             if(lclass == 'aou') {
203                 this.widgetValue = fieldmapper.aou.findOrgUnit(this.widgetValue).shortname();
204                 return;
205             }
206
207             // first try the store cache
208             var self = this;
209             if(this.cache[this.auth][lclass]) {
210                 var store = this.cache[this.auth][lclass];
211                 var query = {};
212                 query[linkInfo.vfield.name] = ''+this.widgetValue;
213                 store.fetch({query:query, onComplete:
214                     function(list) {
215                         self.widgetValue = store.getValue(list[0], linkInfo.vfield.selector);
216                     }
217                 });
218                 return;
219             }
220
221             // then try the single object cache
222             if(this.cacheSingle[lclass] && this.cacheSingle[lclass][this.widgetValue]) {
223                 this.widgetValue = this.cacheSingle[lclass][this.widgetValue];
224                 return;
225             }
226
227             // if those fail, fetch the linked object
228             this.async = true;
229             var self = this;
230             new openils.PermaCrud().retrieve(lclass, this.widgetValue, {   
231                 async : !this.forceSync,
232                 oncomplete : function(r) {
233                     var item = openils.Util.readResponse(r);
234                     if(!self.cacheSingle[lclass])
235                         self.cacheSingle[lclass] = {};
236                     self.widgetValue = item[linkInfo.vfield.selector]();
237                     self.cacheSingle[lclass][self.widgetValue] = item;
238                     self.widget.startup();
239                     self._widgetLoaded();
240                 }
241             });
242         },
243
244         _getLinkSelector : function() {
245             var linkClass = this.idlField['class'];
246             if(this.idlField.reltype != 'has_a')  return false;
247             if(!fieldmapper.IDL.fmclasses[linkClass].permacrud) return false;
248             if(!fieldmapper.IDL.fmclasses[linkClass].permacrud.retrieve) return false;
249
250             var vfield;
251             var rclassIdl = fieldmapper.IDL.fmclasses[linkClass];
252
253             for(var f in rclassIdl.fields) {
254                 if(this.idlField.key == rclassIdl.fields[f].name) {
255                     vfield = rclassIdl.fields[f];
256                     break;
257                 }
258             }
259
260             if(!vfield) 
261                 throw new Error("'" + linkClass + "' has no '" + this.idlField.key + "' field!");
262
263             return {
264                 linkClass : linkClass,
265                 vfield : vfield
266             };
267         },
268
269         _buildLinkSelector : function() {
270             var selectorInfo = this._getLinkSelector();
271             if(!selectorInfo) return false;
272
273             var linkClass = selectorInfo.linkClass;
274             var vfield = selectorInfo.vfield;
275
276             this.async = true;
277
278             if(linkClass == 'pgt')
279                 return this._buildPermGrpSelector();
280             if(linkClass == 'aou')
281                 return this._buildOrgSelector();
282             if(linkClass == 'acpl')
283                 return this._buildCopyLocSelector();
284
285
286             dojo.require('dojo.data.ItemFileReadStore');
287             dojo.require('dijit.form.FilteringSelect');
288
289             this.widget = new dijit.form.FilteringSelect(this.dijitArgs, this.parentNode);
290             this.widget.searchAttr = this.widget.labelAttr = vfield.selector || vfield.name;
291             this.widget.valueAttr = vfield.name;
292
293             var self = this;
294             var oncomplete = function(list) {
295                 if(list) {
296                     self.widget.store = 
297                         new dojo.data.ItemFileReadStore({data:fieldmapper[linkClass].toStoreData(list)});
298                     self.cache[self.auth][linkClass] = self.widget.store;
299                 } else {
300                     self.widget.store = self.cache[self.auth][linkClass];
301                 }
302                 self.widget.startup();
303                 self._widgetLoaded();
304             };
305
306             if(this.cache[self.auth][linkClass]) {
307                 oncomplete();
308
309             } else {
310                 new openils.PermaCrud().retrieveAll(linkClass, {   
311                     async : !this.forceSync,
312                     oncomplete : function(r) {
313                         var list = openils.Util.readResponse(r, false, true);
314                         oncomplete(list);
315                     }
316                 });
317             }
318
319             return true;
320         },
321
322         /**
323          * For widgets that run asynchronously, provide a callback for finishing up
324          */
325         _widgetLoaded : function(value) {
326             if(this.readOnly) {
327                 this.baseWidgetValue(this.getDisplayString());
328             } else {
329                 this.baseWidgetValue(this.widgetValue);
330                 if(this.idlField.name == this.fmIDL.pkey && this.fmIDL.pkey_sequence)
331                     this.widget.attr('disabled', true); 
332                 if(this.disableWidgetTest && this.disableWidgetTest(this.idlField.name, this.fmObject))
333                     this.widget.attr('disabled', true); 
334             }
335             if(this.onload)
336                 this.onload(this.widget, this);
337         },
338
339         _buildOrgSelector : function() {
340             dojo.require('fieldmapper.OrgUtils');
341             dojo.require('openils.widget.FilteringTreeSelect');
342             this.widget = new openils.widget.FilteringTreeSelect(this.dijitArgs, this.parentNode);
343             this.widget.searchAttr = 'shortname';
344             this.widget.labelAttr = 'shortname';
345             this.widget.parentField = 'parent_ou';
346             var user = new openils.User();
347
348             if(this.widgetValue == null) 
349                 this.widgetValue = user.user.ws_ou();
350             
351             // if we have a limit perm, find the relevent orgs (async)
352             if(this.orgLimitPerms && this.orgLimitPerms.length > 0) {
353                 this.async = true;
354                 var self = this;
355                 user.getPermOrgList(this.orgLimitPerms, 
356                     function(orgList) {
357                         self.widget.tree = orgList;
358                         self.widget.startup();
359                         self._widgetLoaded();
360                     }
361                 );
362
363             } else {
364                 this.widget.tree = fieldmapper.aou.globalOrgTree;
365                 this.widget.startup();
366             }
367         },
368
369         _buildPermGrpSelector : function() {
370             dojo.require('openils.widget.FilteringTreeSelect');
371             this.widget = new openils.widget.FilteringTreeSelect(this.dijitArgs, this.parentNode);
372             this.widget.searchAttr = 'name';
373
374             if(this.cache.permGrpTree) {
375                 this.widget.tree = this.cache.permGrpTree;
376                 this.widget.startup();
377                 return true;
378             } 
379
380             var self = this;
381             this.async = true;
382             new openils.PermaCrud().retrieveAll('pgt', {
383                 async : !this.forceSync,
384                 oncomplete : function(r) {
385                     var list = openils.Util.readResponse(r, false, true);
386                     if(!list) return;
387                     var map = {};
388                     var root = null;
389                     for(var l in list)
390                         map[list[l].id()] = list[l];
391                     for(var l in list) {
392                         var node = list[l];
393                         var pnode = map[node.parent()];
394                         if(!pnode) {root = node; continue;}
395                         if(!pnode.children()) pnode.children([]);
396                         pnode.children().push(node);
397                     }
398                     self.widget.tree = self.cache.permGrpTree = root;
399                     self.widget.startup();
400                     self._widgetLoaded();
401                 }
402             });
403
404             return true;
405         },
406
407         _buildCopyLocSelector : function() {
408             dojo.require('dijit.form.FilteringSelect');
409             this.widget = new dijit.form.FilteringSelect(this.dijitArgs, this.parentNode);
410             this.widget.searchAttr = this.widget.labalAttr = 'name';
411             this.widget.valueAttr = 'id';
412
413             if(this.cache.copyLocStore) {
414                 this.widget.store = this.cache.copyLocStore;
415                 this.widget.startup();
416                 this.async = false;
417                 return true;
418             } 
419
420             // my orgs
421             var ws_ou = openils.User.user.ws_ou();
422             var orgs = fieldmapper.aou.findOrgUnit(ws_ou).orgNodeTrail().map(function (i) { return i.id() });
423             orgs = orgs.concat(fieldmapper.aou.descendantNodeList(ws_ou).map(function (i) { return i.id() }));
424
425             var self = this;
426             new openils.PermaCrud().search('acpl', {owning_lib : orgs}, {
427                 async : !this.forceSync,
428                 oncomplete : function(r) {
429                     var list = openils.Util.readResponse(r, false, true);
430                     if(!list) return;
431                     self.widget.store = 
432                         new dojo.data.ItemFileReadStore({data:fieldmapper.acpl.toStoreData(list)});
433                     self.cache.copyLocStore = self.widget.store;
434                     self.widget.startup();
435                     self._widgetLoaded();
436                 }
437             });
438
439             return true;
440         }
441     });
442 }
443