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');
7 dojo.declare('openils.widget.AutoFieldWidget', null, {
15 * idlField -- Field description object from fieldmapper.IDL.fmclasses
16 * fmObject -- If available, the object being edited. This will be used
17 * to set the value of the widget.
18 * fmClass -- Class name (not required if idlField or fmObject is set)
19 * fmField -- Field name (not required if idlField)
20 * parentNode -- If defined, the widget will be appended to this DOM node
21 * dijitArgs -- Optional parameters object, passed directly to the dojo widget
22 * orgLimitPerms -- If this field defines a set of org units and an orgLimitPerms
23 * is defined, the code will limit the org units in the set to those
24 * allowed by the permission
26 constructor : function(args) {
30 // find the field description in the IDL if not provided
32 this.fmClass = this.fmObject.classname;
33 this.fmIDL = fieldmapper.IDL.fmclasses[this.fmClass];
36 this.fmIDL = fieldmapper.IDL.fmclasses[this.fmClass];
37 var fields = this.fmIDL.fields;
39 if(fields[f].name == this.fmField)
40 this.idlField = fields[f];
44 throw new Error("AutoFieldWidget could not determine which field to render. We need more information.");
48 * Turn the widget-stored value into a value oils understands
50 getFormattedValue : function() {
51 var value = this.baseWidgetValue();
52 switch(this.idlField.datatype) {
54 return (value) ? 't' : 'f'
56 return dojo.date.stamp.toISOString(value);
59 if(isNaN(value)) value = 0;
61 return (value === '') ? null : value;
65 baseWidgetValue : function(value) {
66 var attr = (this.readOnly) ? 'content' : 'value';
67 if(arguments.length) this.widget.attr(attr, value);
68 return this.widget.attr(attr);
72 * Turn the widget-stored value into something visually suitable
74 getDisplayString : function() {
75 var value = this.widgetValue;
76 switch(this.idlField.datatype) {
78 return (value) ? 'True' : 'False'; // XXX i18n!
80 dojo.require('dojo.date.locale');
81 dojo.require('dojo.date.stamp');
82 var date = dojo.date.stamp.fromISOString(value);
83 return dojo.date.locale.format(date, {formatLength:'short'});
85 if(value === null || value === undefined) return '';
86 return fieldmapper.aou.findOrgUnit(value).shortname();
89 if(isNaN(value)) value = 0;
91 if(value === undefined || value === null)
97 build : function(onload) {
100 // core widget provided for us, attach and move on
101 if(this.parentNode) // may already be in the "right" place
102 this.parentNode.appendChild(this.widget.domNode);
106 this.onload = onload;
107 if(this.widgetValue == null)
108 this.widgetValue = (this.fmObject) ? this.fmObject[this.idlField.name]() : null;
111 dojo.require('dijit.layout.ContentPane');
112 this.widget = new dijit.layout.ContentPane(this.dijitArgs, this.parentNode);
113 this._tryLinkedDisplayField();
115 } else if(this.widgetClass) {
116 dojo.require(this.widgetClass);
117 eval('this.widget = new ' + this.widgetClass + '(this.dijitArgs, this.parentNode);');
121 switch(this.idlField.datatype) {
124 dojo.require('dijit.form.TextBox');
125 this.widget = new dijit.form.TextBox(this.dijitArgs, this.parentNode);
126 this.widget.attr('disabled', true); // never allow editing of IDs
130 this._buildOrgSelector();
134 dojo.require('dijit.form.CurrencyTextBox');
135 this.widget = new dijit.form.CurrencyTextBox(this.dijitArgs, this.parentNode);
139 dojo.require('dijit.form.NumberTextBox');
140 this.dijitArgs = dojo.mixin(this.dijitArgs || {}, {constraints:{places:0}});
141 this.widget = new dijit.form.NumberTextBox(this.dijitArgs, this.parentNode);
145 dojo.require('dijit.form.NumberTextBox');
146 this.widget = new dijit.form.NumberTextBox(this.dijitArgs, this.parentNode);
150 dojo.require('dijit.form.DateTextBox');
151 dojo.require('dojo.date.stamp');
152 this.widget = new dijit.form.DateTextBox(this.dijitArgs, this.parentNode);
153 if(this.widgetValue != null)
154 this.widgetValue = dojo.date.stamp.fromISOString(this.widgetValue);
158 dojo.require('dijit.form.CheckBox');
159 this.widget = new dijit.form.CheckBox(this.dijitArgs, this.parentNode);
160 this.widgetValue = openils.Util.isTrue(this.widgetValue);
164 if(this._buildLinkSelector()) break;
167 dojo.require('dijit.form.TextBox');
168 this.widget = new dijit.form.TextBox(this.dijitArgs, this.parentNode);
172 if(!this.async) this._widgetLoaded();
176 // we want to display the value for our widget. However, instead of displaying
177 // an ID, for exmaple, display the value for the 'selector' field on the object
179 _tryLinkedDisplayField : function() {
181 if(this.idlField.datatype == 'org_unit')
182 return false; // we already handle org_units, no need to re-fetch
184 var linkInfo = this._getLinkSelector();
185 if(!linkInfo || !linkInfo.vfield) return false;
186 var lclass = linkInfo.linkClass;
188 // first try the object list cache
189 if(this.cache[lclass]) {
190 for(var k in this.cache[lclass]) {
191 var cc = this.cache[lclass][k];
192 if(cc[linkInfo.vfield.name]() == this.widgetValue) {
193 console.log("serving " + this.idlField.name + " from list cache");
194 this.widgetValue = cc[linkInfo.vfield.selector]();
200 // then try the single object cache
201 if(this.cacheSingle[lclass] && this.cacheSingle[lclass][this.widgetValue]) {
202 console.log("serving " + this.idlField.name + " from cacheSingle");
203 this.widgetValue = this.cacheSingle[lclass][this.widgetValue];
207 // if those fail, fetch the linked object
208 dojo.require('openils.PermaCrud');
211 new openils.PermaCrud().retrieve(lclass, this.widgetValue, {
213 oncomplete : function(r) {
214 var item = openils.Util.readResponse(r);
215 if(!self.cacheSingle[lclass])
216 self.cacheSingle[lclass] = {};
217 self.widgetValue = item[linkInfo.vfield.selector]();
218 self.cacheSingle[lclass][self.widgetValue] = item;
219 self.widget.startup();
220 self._widgetLoaded();
225 _getLinkSelector : function() {
226 var linkClass = this.idlField['class'];
227 if(this.idlField.reltype != 'has_a') return false;
228 if(!fieldmapper.IDL.fmclasses[linkClass].permacrud) return false;
229 if(!fieldmapper.IDL.fmclasses[linkClass].permacrud.retrieve) return false;
232 var rclassIdl = fieldmapper.IDL.fmclasses[linkClass];
234 for(var f in rclassIdl.fields) {
235 if(this.idlField.key == rclassIdl.fields[f].name) {
236 vfield = rclassIdl.fields[f];
242 throw new Error("'" + linkClass + "' has no '" + this.idlField.key + "' field!");
245 linkClass : linkClass,
250 _buildLinkSelector : function() {
251 var selectorInfo = this._getLinkSelector();
252 if(!selectorInfo) return false;
253 var linkClass = selectorInfo.linkClass;
254 var vfield = selectorInfo.vfield;
258 if(linkClass == 'pgt')
259 return this._buildPermGrpSelector();
261 this.widget = new dijit.form.FilteringSelect(this.dijitArgs, this.parentNode);
262 this.widget.searchAttr = this.widget.labelAttr = vfield.selector || vfield.name;
263 this.widget.valueAttr = vfield.name;
265 dojo.require('openils.PermaCrud');
266 dojo.require('dojo.data.ItemFileReadStore');
267 dojo.require('dijit.form.FilteringSelect');
270 var oncomplete = function(list) {
273 new dojo.data.ItemFileReadStore({data:fieldmapper[linkClass].toStoreData(list)});
274 self.cache[linkClass] = list;
276 self.widget.startup();
277 self._widgetLoaded();
280 if(this.cache[linkClass]) {
281 oncomplete(this.cache[linkClass]);
284 new openils.PermaCrud().retrieveAll(linkClass, {
286 oncomplete : function(r) {
287 var list = openils.Util.readResponse(r, false, true);
297 * For widgets that run asynchronously, provide a callback for finishing up
299 _widgetLoaded : function(value) {
301 this.baseWidgetValue(this.getDisplayString());
303 this.baseWidgetValue(this.widgetValue);
304 if(this.idlField.name == this.fmIDL.pkey && this.fmIDL.pkey_sequence)
305 this.widget.attr('disabled', true);
308 this.onload(this.widget, self);
311 _buildOrgSelector : function() {
312 dojo.require('fieldmapper.OrgUtils');
313 dojo.require('openils.widget.FilteringTreeSelect');
314 this.widget = new openils.widget.FilteringTreeSelect(this.dijitArgs, this.parentNode);
315 this.widget.searchAttr = 'shortname';
316 this.widget.labelAttr = 'shortname';
317 this.widget.parentField = 'parent_ou';
318 var user = new openils.User();
319 if(this.widgetValue == null)
320 this.widgetValue = user.user.ws_ou();
322 // if we have a limit perm, find the relevent orgs (async)
323 if(this.orgLimitPerms && this.orgLimitPerms.length > 0) {
326 user.getPermOrgList(this.orgLimitPerms,
328 self.widget.tree = orgList;
329 self.widget.startup();
330 self._widgetLoaded();
335 this.widget.tree = fieldmapper.aou.globalOrgTree;
336 this.widget.startup();
340 _buildPermGrpSelector : function() {
341 dojo.require('openils.widget.FilteringTreeSelect');
342 this.widget = new openils.widget.FilteringTreeSelect(this.dijitArgs, this.parentNode);
343 this.widget.searchAttr = 'name';
345 if(this.cache.permGrpTree) {
346 this.widget.tree = this.cache.permGrpTree;
347 this.widget.startup();
353 new openils.PermaCrud().retrieveAll('pgt', {
355 oncomplete : function(r) {
356 var list = openils.Util.readResponse(r, false, true);
361 map[list[l].id()] = list[l];
364 var pnode = map[node.parent()];
365 if(!pnode) {root = node; continue;}
366 if(!pnode.children()) pnode.children([]);
367 pnode.children().push(node);
369 self.widget.tree = self.cache.permGrpTree = root;
370 self.widget.startup();
371 self._widgetLoaded();