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');
8 dojo.declare('openils.widget.AutoFieldWidget', null, {
16 * idlField -- Field description object from fieldmapper.IDL.fmclasses
17 * fmObject -- If available, the object being edited. This will be used
18 * to set the value of the widget.
19 * fmClass -- Class name (not required if idlField or fmObject is set)
20 * fmField -- Field name (not required if idlField)
21 * parentNode -- If defined, the widget will be appended to this DOM node
22 * dijitArgs -- Optional parameters object, passed directly to the dojo widget
23 * orgLimitPerms -- If this field defines a set of org units and an orgLimitPerms
24 * is defined, the code will limit the org units in the set to those
25 * allowed by the permission
27 constructor : function(args) {
31 // find the field description in the IDL if not provided
33 this.fmClass = this.fmObject.classname;
34 this.fmIDL = fieldmapper.IDL.fmclasses[this.fmClass];
37 this.fmIDL = fieldmapper.IDL.fmclasses[this.fmClass];
38 var fields = this.fmIDL.fields;
40 if(fields[f].name == this.fmField)
41 this.idlField = fields[f];
45 throw new Error("AutoFieldWidget could not determine which field to render. We need more information. fmClass=" +
46 this.fmClass + ' fmField=' + this.fmField + ' fmObject=' + js2JSON(this.fmObject));
48 this.auth = openils.User.authtoken;
49 if(!this.cache[this.auth]) {
50 this.cache[this.auth] = {};
55 * Turn the widget-stored value into a value oils understands
57 getFormattedValue : function() {
58 var value = this.baseWidgetValue();
59 switch(this.idlField.datatype) {
61 return (value) ? 't' : 'f'
63 return dojo.date.stamp.toISOString(value);
67 if(isNaN(value)) value = 0;
69 return (value === '') ? null : value;
73 baseWidgetValue : function(value) {
74 var attr = (this.readOnly) ? 'content' : 'value';
75 if(arguments.length) this.widget.attr(attr, value);
76 return this.widget.attr(attr);
80 * Turn the widget-stored value into something visually suitable
82 getDisplayString : function() {
83 var value = this.widgetValue;
84 switch(this.idlField.datatype) {
86 return (openils.Util.isTrue(value)) ? 'True' : 'False'; // XXX i18n!
88 dojo.require('dojo.date.locale');
89 dojo.require('dojo.date.stamp');
90 var date = dojo.date.stamp.fromISOString(value);
91 return dojo.date.locale.format(date, {formatLength:'short'});
93 if(value === null || value === undefined) return '';
94 return fieldmapper.aou.findOrgUnit(value).shortname();
97 if(isNaN(value)) value = 0;
99 if(value === undefined || value === null)
105 build : function(onload) {
108 // core widget provided for us, attach and move on
109 if(this.parentNode) // may already be in the "right" place
110 this.parentNode.appendChild(this.widget.domNode);
114 if(!this.parentNode) // give it somewhere to live so that dojo won't complain
115 this.parentNode = document.createElement('div');
117 this.onload = onload;
118 if(this.widgetValue == null)
119 this.widgetValue = (this.fmObject) ? this.fmObject[this.idlField.name]() : null;
122 dojo.require('dijit.layout.ContentPane');
123 this.widget = new dijit.layout.ContentPane(this.dijitArgs, this.parentNode);
124 if(this.widgetValue !== null)
125 this._tryLinkedDisplayField();
127 } else if(this.widgetClass) {
128 dojo.require(this.widgetClass);
129 eval('this.widget = new ' + this.widgetClass + '(this.dijitArgs, this.parentNode);');
133 switch(this.idlField.datatype) {
136 dojo.require('dijit.form.TextBox');
137 this.widget = new dijit.form.TextBox(this.dijitArgs, this.parentNode);
141 this._buildOrgSelector();
145 dojo.require('dijit.form.CurrencyTextBox');
146 this.widget = new dijit.form.CurrencyTextBox(this.dijitArgs, this.parentNode);
150 dojo.require('dijit.form.NumberTextBox');
151 this.dijitArgs = dojo.mixin(this.dijitArgs || {}, {constraints:{places:0}});
152 this.widget = new dijit.form.NumberTextBox(this.dijitArgs, this.parentNode);
156 dojo.require('dijit.form.NumberTextBox');
157 this.widget = new dijit.form.NumberTextBox(this.dijitArgs, this.parentNode);
161 dojo.require('dijit.form.DateTextBox');
162 dojo.require('dojo.date.stamp');
163 this.widget = new dijit.form.DateTextBox(this.dijitArgs, this.parentNode);
164 if(this.widgetValue != null)
165 this.widgetValue = dojo.date.stamp.fromISOString(this.widgetValue);
169 dojo.require('dijit.form.CheckBox');
170 this.widget = new dijit.form.CheckBox(this.dijitArgs, this.parentNode);
171 this.widgetValue = openils.Util.isTrue(this.widgetValue);
175 if(this._buildLinkSelector()) break;
178 dojo.require('dijit.form.TextBox');
179 this.widget = new dijit.form.TextBox(this.dijitArgs, this.parentNode);
183 if(!this.async) this._widgetLoaded();
187 // we want to display the value for our widget. However, instead of displaying
188 // an ID, for exmaple, display the value for the 'selector' field on the object
190 _tryLinkedDisplayField : function(noAsync) {
192 if(this.idlField.datatype == 'org_unit')
193 return false; // we already handle org_units, no need to re-fetch
195 var linkInfo = this._getLinkSelector();
196 if(!(linkInfo && linkInfo.vfield && linkInfo.vfield.selector))
198 var lclass = linkInfo.linkClass;
200 if(lclass == 'aou') {
201 this.widgetValue = fieldmapper.aou.findOrgUnit(this.widgetValue).shortname();
205 // first try the store cache
207 if(this.cache[this.auth][lclass]) {
208 var store = this.cache[this.auth][lclass];
210 query[linkInfo.vfield.name] = ''+this.widgetValue;
211 store.fetch({query:query, onComplete:
213 self.widgetValue = store.getValue(list[0], linkInfo.vfield.selector);
219 // then try the single object cache
220 if(this.cacheSingle[lclass] && this.cacheSingle[lclass][this.widgetValue]) {
221 this.widgetValue = this.cacheSingle[lclass][this.widgetValue];
225 // if those fail, fetch the linked object
228 new openils.PermaCrud().retrieve(lclass, this.widgetValue, {
229 async : !this.forceSync,
230 oncomplete : function(r) {
231 var item = openils.Util.readResponse(r);
232 if(!self.cacheSingle[lclass])
233 self.cacheSingle[lclass] = {};
234 self.widgetValue = item[linkInfo.vfield.selector]();
235 self.cacheSingle[lclass][self.widgetValue] = item;
236 self.widget.startup();
237 self._widgetLoaded();
242 _getLinkSelector : function() {
243 var linkClass = this.idlField['class'];
244 if(this.idlField.reltype != 'has_a') return false;
245 if(!fieldmapper.IDL.fmclasses[linkClass].permacrud) return false;
246 if(!fieldmapper.IDL.fmclasses[linkClass].permacrud.retrieve) return false;
249 var rclassIdl = fieldmapper.IDL.fmclasses[linkClass];
251 for(var f in rclassIdl.fields) {
252 if(this.idlField.key == rclassIdl.fields[f].name) {
253 vfield = rclassIdl.fields[f];
259 throw new Error("'" + linkClass + "' has no '" + this.idlField.key + "' field!");
262 linkClass : linkClass,
267 _buildLinkSelector : function() {
268 var selectorInfo = this._getLinkSelector();
269 if(!selectorInfo) return false;
271 var linkClass = selectorInfo.linkClass;
272 var vfield = selectorInfo.vfield;
276 if(linkClass == 'pgt')
277 return this._buildPermGrpSelector();
278 if(linkClass == 'aou')
279 return this._buildOrgSelector();
280 if(linkClass == 'acpl')
281 return this._buildCopyLocSelector();
284 dojo.require('dojo.data.ItemFileReadStore');
285 dojo.require('dijit.form.FilteringSelect');
287 this.widget = new dijit.form.FilteringSelect(this.dijitArgs, this.parentNode);
288 this.widget.searchAttr = this.widget.labelAttr = vfield.selector || vfield.name;
289 this.widget.valueAttr = vfield.name;
292 var oncomplete = function(list) {
295 new dojo.data.ItemFileReadStore({data:fieldmapper[linkClass].toStoreData(list)});
296 self.cache[self.auth][linkClass] = self.widget.store;
298 self.widget.store = self.cache[self.auth][linkClass];
300 self.widget.startup();
301 self._widgetLoaded();
304 if(this.cache[self.auth][linkClass]) {
308 new openils.PermaCrud().retrieveAll(linkClass, {
309 async : !this.forceSync,
310 oncomplete : function(r) {
311 var list = openils.Util.readResponse(r, false, true);
321 * For widgets that run asynchronously, provide a callback for finishing up
323 _widgetLoaded : function(value) {
325 this.baseWidgetValue(this.getDisplayString());
327 this.baseWidgetValue(this.widgetValue);
328 if(this.idlField.name == this.fmIDL.pkey && this.fmIDL.pkey_sequence)
329 this.widget.attr('disabled', true);
330 if(this.disableWidgetTest && this.disableWidgetTest(this.idlField.name, this.fmObject))
331 this.widget.attr('disabled', true);
334 this.onload(this.widget, this);
337 _buildOrgSelector : function() {
338 dojo.require('fieldmapper.OrgUtils');
339 dojo.require('openils.widget.FilteringTreeSelect');
340 this.widget = new openils.widget.FilteringTreeSelect(this.dijitArgs, this.parentNode);
341 this.widget.searchAttr = 'shortname';
342 this.widget.labelAttr = 'shortname';
343 this.widget.parentField = 'parent_ou';
344 var user = new openils.User();
346 if(this.widgetValue == null)
347 this.widgetValue = user.user.ws_ou();
349 // if we have a limit perm, find the relevent orgs (async)
350 if(this.orgLimitPerms && this.orgLimitPerms.length > 0) {
353 user.getPermOrgList(this.orgLimitPerms,
355 self.widget.tree = orgList;
356 self.widget.startup();
357 self._widgetLoaded();
362 this.widget.tree = fieldmapper.aou.globalOrgTree;
363 this.widget.startup();
367 _buildPermGrpSelector : function() {
368 dojo.require('openils.widget.FilteringTreeSelect');
369 this.widget = new openils.widget.FilteringTreeSelect(this.dijitArgs, this.parentNode);
370 this.widget.searchAttr = 'name';
372 if(this.cache.permGrpTree) {
373 this.widget.tree = this.cache.permGrpTree;
374 this.widget.startup();
380 new openils.PermaCrud().retrieveAll('pgt', {
381 async : !this.forceSync,
382 oncomplete : function(r) {
383 var list = openils.Util.readResponse(r, false, true);
388 map[list[l].id()] = list[l];
391 var pnode = map[node.parent()];
392 if(!pnode) {root = node; continue;}
393 if(!pnode.children()) pnode.children([]);
394 pnode.children().push(node);
396 self.widget.tree = self.cache.permGrpTree = root;
397 self.widget.startup();
398 self._widgetLoaded();
405 _buildCopyLocSelector : function() {
406 dojo.require('dijit.form.FilteringSelect');
407 this.widget = new dijit.form.FilteringSelect(this.dijitArgs, this.parentNode);
408 this.widget.searchAttr = this.widget.labalAttr = 'name';
409 this.widget.valueAttr = 'id';
411 if(this.cache.copyLocStore) {
412 this.widget.store = this.cache.copyLocStore;
413 this.widget.startup();
419 var ws_ou = openils.User.user.ws_ou();
420 var orgs = fieldmapper.aou.findOrgUnit(ws_ou).orgNodeTrail().map(function (i) { return i.id() });
421 orgs = orgs.concat(fieldmapper.aou.descendantNodeList(ws_ou).map(function (i) { return i.id() }));
424 new openils.PermaCrud().search('acpl', {owning_lib : orgs}, {
425 async : !this.forceSync,
426 oncomplete : function(r) {
427 var list = openils.Util.readResponse(r, false, true);
430 new dojo.data.ItemFileReadStore({data:fieldmapper.acpl.toStoreData(list)});
431 self.cache.copyLocStore = self.widget.store;
432 self.widget.startup();
433 self._widgetLoaded();