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");
9 dojo.declare('openils.widget.AutoFieldWidget', null, {
17 * idlField -- Field description object from fieldmapper.IDL.fmclasses
18 * fmObject -- If available, the object being edited. This will be used
19 * to set the value of the widget.
20 * fmClass -- Class name (not required if idlField or fmObject is set)
21 * fmField -- Field name (not required if idlField)
22 * parentNode -- If defined, the widget will be appended to this DOM node
23 * dijitArgs -- Optional parameters object, passed directly to the dojo widget
24 * orgLimitPerms -- If this field defines a set of org units and an orgLimitPerms
25 * is defined, the code will limit the org units in the set to those
26 * allowed by the permission
28 constructor : function(args) {
32 // find the field description in the IDL if not provided
34 this.fmClass = this.fmObject.classname;
35 this.fmIDL = fieldmapper.IDL.fmclasses[this.fmClass];
36 this.suppressLinkedFields = args.suppressLinkedFields || [];
39 this.fmIDL = fieldmapper.IDL.fmclasses[this.fmClass];
40 var fields = this.fmIDL.fields;
42 if(fields[f].name == this.fmField)
43 this.idlField = fields[f];
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));
50 this.auth = openils.User.authtoken;
51 if(!this.cache[this.auth]) {
52 this.cache[this.auth] = {};
57 * Turn the widget-stored value into a value oils understands
59 getFormattedValue : function() {
60 var value = this.baseWidgetValue();
61 switch(this.idlField.datatype) {
63 return (value) ? 't' : 'f'
65 return dojo.date.stamp.toISOString(value);
69 if(isNaN(value)) value = 0;
71 return (value === '') ? null : value;
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);
82 * Turn the widget-stored value into something visually suitable
84 getDisplayString : function() {
85 var value = this.widgetValue;
86 switch(this.idlField.datatype) {
88 return (openils.Util.isTrue(value)) ?
89 openils.widget.AutoFieldWidget.localeStrings.TRUE :
90 openils.widget.AutoFieldWidget.localeStrings.FALSE;
92 dojo.require('dojo.date.locale');
93 dojo.require('dojo.date.stamp');
94 var date = dojo.date.stamp.fromISOString(value);
95 return dojo.date.locale.format(date, {formatLength:'short'});
97 if(value === null || value === undefined) return '';
98 return fieldmapper.aou.findOrgUnit(value).shortname();
101 if(isNaN(value)) value = 0;
103 if(value === undefined || value === null)
109 build : function(onload) {
112 // core widget provided for us, attach and move on
113 if(this.parentNode) // may already be in the "right" place
114 this.parentNode.appendChild(this.widget.domNode);
118 if(!this.parentNode) // give it somewhere to live so that dojo won't complain
119 this.parentNode = document.createElement('div');
121 this.onload = onload;
122 if(this.widgetValue == null)
123 this.widgetValue = (this.fmObject) ? this.fmObject[this.idlField.name]() : null;
126 dojo.require('dijit.layout.ContentPane');
127 this.widget = new dijit.layout.ContentPane(this.dijitArgs, this.parentNode);
128 if(this.widgetValue !== null)
129 this._tryLinkedDisplayField();
131 } else if(this.widgetClass) {
132 dojo.require(this.widgetClass);
133 eval('this.widget = new ' + this.widgetClass + '(this.dijitArgs, this.parentNode);');
137 switch(this.idlField.datatype) {
140 dojo.require('dijit.form.TextBox');
141 this.widget = new dijit.form.TextBox(this.dijitArgs, this.parentNode);
145 this._buildOrgSelector();
149 dojo.require('dijit.form.CurrencyTextBox');
150 this.widget = new dijit.form.CurrencyTextBox(this.dijitArgs, this.parentNode);
154 dojo.require('dijit.form.NumberTextBox');
155 this.dijitArgs = dojo.mixin(this.dijitArgs || {}, {constraints:{places:0}});
156 this.widget = new dijit.form.NumberTextBox(this.dijitArgs, this.parentNode);
160 dojo.require('dijit.form.NumberTextBox');
161 this.widget = new dijit.form.NumberTextBox(this.dijitArgs, this.parentNode);
165 dojo.require('dijit.form.DateTextBox');
166 dojo.require('dojo.date.stamp');
167 this.widget = new dijit.form.DateTextBox(this.dijitArgs, this.parentNode);
168 if(this.widgetValue != null)
169 this.widgetValue = dojo.date.stamp.fromISOString(this.widgetValue);
173 dojo.require('dijit.form.CheckBox');
174 this.widget = new dijit.form.CheckBox(this.dijitArgs, this.parentNode);
175 this.widgetValue = openils.Util.isTrue(this.widgetValue);
179 if(this._buildLinkSelector()) break;
182 if(this.dijitArgs && (this.dijitArgs.required || this.dijitArgs.regExp)) {
183 dojo.require('dijit.form.ValidationTextBox');
184 this.widget = new dijit.form.ValidationTextBox(this.dijitArgs, this.parentNode);
186 dojo.require('dijit.form.TextBox');
187 this.widget = new dijit.form.TextBox(this.dijitArgs, this.parentNode);
192 if(!this.async) this._widgetLoaded();
196 // we want to display the value for our widget. However, instead of displaying
197 // an ID, for exmaple, display the value for the 'selector' field on the object
199 _tryLinkedDisplayField : function(noAsync) {
201 if(this.idlField.datatype == 'org_unit')
202 return false; // we already handle org_units, no need to re-fetch
204 // user opted to bypass fetching this linked data
205 if(this.suppressLinkedFields.indexOf(this.idlField.name) > -1)
208 var linkInfo = this._getLinkSelector();
209 if(!(linkInfo && linkInfo.vfield && linkInfo.vfield.selector))
211 var lclass = linkInfo.linkClass;
213 if(lclass == 'aou') {
214 this.widgetValue = fieldmapper.aou.findOrgUnit(this.widgetValue).shortname();
218 // first try the store cache
220 if(this.cache[this.auth][lclass]) {
221 var store = this.cache[this.auth][lclass];
223 query[linkInfo.vfield.name] = ''+this.widgetValue;
224 store.fetch({query:query, onComplete:
226 self.widgetValue = store.getValue(list[0], linkInfo.vfield.selector);
232 // then try the single object cache
233 if(this.cacheSingle[lclass] && this.cacheSingle[lclass][this.widgetValue]) {
234 this.widgetValue = this.cacheSingle[lclass][this.widgetValue];
238 // if those fail, fetch the linked object
241 new openils.PermaCrud().retrieve(lclass, this.widgetValue, {
242 async : !this.forceSync,
243 oncomplete : function(r) {
244 var item = openils.Util.readResponse(r);
245 if(!self.cacheSingle[lclass])
246 self.cacheSingle[lclass] = {};
247 self.widgetValue = item[linkInfo.vfield.selector]();
248 self.cacheSingle[lclass][self.widgetValue] = item;
249 self.widget.startup();
250 self._widgetLoaded();
255 _getLinkSelector : function() {
256 var linkClass = this.idlField['class'];
257 if(this.idlField.reltype != 'has_a') return false;
258 if(!fieldmapper.IDL.fmclasses[linkClass].permacrud) return false;
259 if(!fieldmapper.IDL.fmclasses[linkClass].permacrud.retrieve) return false;
262 var rclassIdl = fieldmapper.IDL.fmclasses[linkClass];
264 for(var f in rclassIdl.fields) {
265 if(this.idlField.key == rclassIdl.fields[f].name) {
266 vfield = rclassIdl.fields[f];
272 throw new Error("'" + linkClass + "' has no '" + this.idlField.key + "' field!");
275 linkClass : linkClass,
280 _buildLinkSelector : function() {
281 var selectorInfo = this._getLinkSelector();
282 if(!selectorInfo) return false;
284 var linkClass = selectorInfo.linkClass;
285 var vfield = selectorInfo.vfield;
289 if(linkClass == 'pgt')
290 return this._buildPermGrpSelector();
291 if(linkClass == 'aou')
292 return this._buildOrgSelector();
293 if(linkClass == 'acpl')
294 return this._buildCopyLocSelector();
297 dojo.require('dojo.data.ItemFileReadStore');
298 dojo.require('dijit.form.FilteringSelect');
300 this.widget = new dijit.form.FilteringSelect(this.dijitArgs, this.parentNode);
301 this.widget.searchAttr = this.widget.labelAttr = vfield.selector || vfield.name;
302 this.widget.valueAttr = vfield.name;
305 var oncomplete = function(list) {
308 new dojo.data.ItemFileReadStore({data:fieldmapper[linkClass].toStoreData(list)});
309 self.cache[self.auth][linkClass] = self.widget.store;
311 self.widget.store = self.cache[self.auth][linkClass];
313 self.widget.startup();
314 self._widgetLoaded();
317 if(this.cache[self.auth][linkClass]) {
321 new openils.PermaCrud().retrieveAll(linkClass, {
322 async : !this.forceSync,
323 oncomplete : function(r) {
324 var list = openils.Util.readResponse(r, false, true);
334 * For widgets that run asynchronously, provide a callback for finishing up
336 _widgetLoaded : function(value) {
338 this.baseWidgetValue(this.getDisplayString());
340 this.baseWidgetValue(this.widgetValue);
341 if(this.idlField.name == this.fmIDL.pkey && this.fmIDL.pkey_sequence)
342 this.widget.attr('disabled', true);
343 if(this.disableWidgetTest && this.disableWidgetTest(this.idlField.name, this.fmObject))
344 this.widget.attr('disabled', true);
347 this.onload(this.widget, this);
350 _buildOrgSelector : function() {
351 dojo.require('fieldmapper.OrgUtils');
352 dojo.require('openils.widget.FilteringTreeSelect');
353 this.widget = new openils.widget.FilteringTreeSelect(this.dijitArgs, this.parentNode);
354 this.widget.searchAttr = 'shortname';
355 this.widget.labelAttr = 'shortname';
356 this.widget.parentField = 'parent_ou';
357 var user = new openils.User();
359 if(this.widgetValue == null)
360 this.widgetValue = user.user.ws_ou();
362 // if we have a limit perm, find the relevent orgs (async)
363 if(this.orgLimitPerms && this.orgLimitPerms.length > 0) {
366 user.getPermOrgList(this.orgLimitPerms,
368 self.widget.tree = orgList;
369 self.widget.startup();
370 self._widgetLoaded();
375 this.widget.tree = fieldmapper.aou.globalOrgTree;
376 this.widget.startup();
380 _buildPermGrpSelector : function() {
381 dojo.require('openils.widget.FilteringTreeSelect');
382 this.widget = new openils.widget.FilteringTreeSelect(this.dijitArgs, this.parentNode);
383 this.widget.searchAttr = 'name';
385 if(this.cache.permGrpTree) {
386 this.widget.tree = this.cache.permGrpTree;
387 this.widget.startup();
393 new openils.PermaCrud().retrieveAll('pgt', {
394 async : !this.forceSync,
395 oncomplete : function(r) {
396 var list = openils.Util.readResponse(r, false, true);
401 map[list[l].id()] = list[l];
404 var pnode = map[node.parent()];
405 if(!pnode) {root = node; continue;}
406 if(!pnode.children()) pnode.children([]);
407 pnode.children().push(node);
409 self.widget.tree = self.cache.permGrpTree = root;
410 self.widget.startup();
411 self._widgetLoaded();
418 _buildCopyLocSelector : function() {
419 dojo.require('dijit.form.FilteringSelect');
420 this.widget = new dijit.form.FilteringSelect(this.dijitArgs, this.parentNode);
421 this.widget.searchAttr = this.widget.labalAttr = 'name';
422 this.widget.valueAttr = 'id';
424 if(this.cache.copyLocStore) {
425 this.widget.store = this.cache.copyLocStore;
426 this.widget.startup();
432 var ws_ou = openils.User.user.ws_ou();
433 var orgs = fieldmapper.aou.findOrgUnit(ws_ou).orgNodeTrail().map(function (i) { return i.id() });
434 orgs = orgs.concat(fieldmapper.aou.descendantNodeList(ws_ou).map(function (i) { return i.id() }));
437 new openils.PermaCrud().search('acpl', {owning_lib : orgs}, {
438 async : !this.forceSync,
439 oncomplete : function(r) {
440 var list = openils.Util.readResponse(r, false, true);
443 new dojo.data.ItemFileReadStore({data:fieldmapper.acpl.toStoreData(list)});
444 self.cache.copyLocStore = self.widget.store;
445 self.widget.startup();
446 self._widgetLoaded();
454 openils.widget.AutoFieldWidget.localeStrings = dojo.i18n.getLocalization("openils.widget", "AutoFieldWidget");