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, {
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];
34 this.suppressLinkedFields = args.suppressLinkedFields || [];
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 this.cache = openils.widget.AutoFieldWidget.cache;
50 this.cache[this.auth] = this.cache[this.auth] || {};
51 this.cache[this.auth].single = this.cache[this.auth].single || {};
52 this.cache[this.auth].list = this.cache[this.auth].list || {};
56 * Turn the widget-stored value into a value oils understands
58 getFormattedValue : function() {
59 var value = this.baseWidgetValue();
60 switch(this.idlField.datatype) {
62 return (value) ? 't' : 'f'
64 return dojo.date.stamp.toISOString(value);
68 if(isNaN(value)) value = 0;
70 return (value === '') ? null : value;
74 baseWidgetValue : function(value) {
75 var attr = (this.readOnly) ? 'content' : 'value';
76 if(arguments.length) this.widget.attr(attr, value);
77 return this.widget.attr(attr);
81 * Turn the widget-stored value into something visually suitable
83 getDisplayString : function() {
84 var value = this.widgetValue;
85 switch(this.idlField.datatype) {
87 return (openils.Util.isTrue(value)) ?
88 openils.widget.AutoFieldWidget.localeStrings.TRUE :
89 openils.widget.AutoFieldWidget.localeStrings.FALSE;
91 dojo.require('dojo.date.locale');
92 dojo.require('dojo.date.stamp');
93 var date = dojo.date.stamp.fromISOString(value);
94 return dojo.date.locale.format(date, {formatLength:'short'});
96 if(value === null || value === undefined) return '';
97 return fieldmapper.aou.findOrgUnit(value).shortname();
100 if(isNaN(value)) value = 0;
102 if(value === undefined || value === null)
108 build : function(onload) {
111 // core widget provided for us, attach and move on
112 if(this.parentNode) // may already be in the "right" place
113 this.parentNode.appendChild(this.widget.domNode);
117 if(!this.parentNode) // give it somewhere to live so that dojo won't complain
118 this.parentNode = dojo.create('div');
120 this.onload = onload;
121 if(this.widgetValue == null)
122 this.widgetValue = (this.fmObject) ? this.fmObject[this.idlField.name]() : null;
125 dojo.require('dijit.layout.ContentPane');
126 this.widget = new dijit.layout.ContentPane(this.dijitArgs, this.parentNode);
127 if(this.widgetValue !== null)
128 this._tryLinkedDisplayField();
130 } else if(this.widgetClass) {
131 dojo.require(this.widgetClass);
132 eval('this.widget = new ' + this.widgetClass + '(this.dijitArgs, this.parentNode);');
136 switch(this.idlField.datatype) {
139 dojo.require('dijit.form.TextBox');
140 this.widget = new dijit.form.TextBox(this.dijitArgs, this.parentNode);
144 this._buildOrgSelector();
148 dojo.require('dijit.form.CurrencyTextBox');
149 this.widget = new dijit.form.CurrencyTextBox(this.dijitArgs, this.parentNode);
153 dojo.require('dijit.form.NumberTextBox');
154 this.dijitArgs = dojo.mixin(this.dijitArgs || {}, {constraints:{places:0}});
155 this.widget = new dijit.form.NumberTextBox(this.dijitArgs, this.parentNode);
159 dojo.require('dijit.form.NumberTextBox');
160 this.widget = new dijit.form.NumberTextBox(this.dijitArgs, this.parentNode);
164 dojo.require('dijit.form.DateTextBox');
165 dojo.require('dojo.date.stamp');
166 this.widget = new dijit.form.DateTextBox(this.dijitArgs, this.parentNode);
167 if(this.widgetValue != null)
168 this.widgetValue = dojo.date.stamp.fromISOString(this.widgetValue);
172 dojo.require('dijit.form.CheckBox');
173 this.widget = new dijit.form.CheckBox(this.dijitArgs, this.parentNode);
174 this.widgetValue = openils.Util.isTrue(this.widgetValue);
178 if(this._buildLinkSelector()) break;
181 if(this.dijitArgs && (this.dijitArgs.required || this.dijitArgs.regExp)) {
182 dojo.require('dijit.form.ValidationTextBox');
183 this.widget = new dijit.form.ValidationTextBox(this.dijitArgs, this.parentNode);
185 dojo.require('dijit.form.TextBox');
186 this.widget = new dijit.form.TextBox(this.dijitArgs, this.parentNode);
191 if(!this.async) this._widgetLoaded();
195 // we want to display the value for our widget. However, instead of displaying
196 // an ID, for exmaple, display the value for the 'selector' field on the object
198 _tryLinkedDisplayField : function(noAsync) {
200 if(this.idlField.datatype == 'org_unit')
201 return false; // we already handle org_units, no need to re-fetch
203 // user opted to bypass fetching this linked data
204 if(this.suppressLinkedFields.indexOf(this.idlField.name) > -1)
207 var linkInfo = this._getLinkSelector();
208 if(!(linkInfo && linkInfo.vfield && linkInfo.vfield.selector))
210 var lclass = linkInfo.linkClass;
212 if(lclass == 'aou') {
213 this.widgetValue = fieldmapper.aou.findOrgUnit(this.widgetValue).shortname();
217 // first try the store cache
219 if(this.cache[this.auth].list[lclass]) {
220 var store = this.cache[this.auth].list[lclass];
222 query[linkInfo.vfield.name] = ''+this.widgetValue;
223 store.fetch({query:query, onComplete:
225 self.widgetValue = store.getValue(list[0], linkInfo.vfield.selector);
231 // then try the single object cache
232 if(this.cache[this.auth].single[lclass] && this.cache[this.auth].single[lclass][this.widgetValue]) {
233 this.widgetValue = this.cache[this.auth].single[lclass][this.widgetValue];
237 console.log("Fetching sync object " + lclass + " : " + this.widgetValue);
239 // if those fail, fetch the linked object
242 new openils.PermaCrud().retrieve(lclass, this.widgetValue, {
243 async : !this.forceSync,
244 oncomplete : function(r) {
245 var item = openils.Util.readResponse(r);
246 var newvalue = item[linkInfo.vfield.selector]();
248 if(!self.cache[self.auth].single[lclass])
249 self.cache[self.auth].single[lclass] = {};
250 self.cache[self.auth].single[lclass][self.widgetValue] = newvalue;
252 self.widgetValue = newvalue;
253 self.widget.startup();
254 self._widgetLoaded();
259 _getLinkSelector : function() {
260 var linkClass = this.idlField['class'];
261 if(this.idlField.reltype != 'has_a') return false;
262 if(!fieldmapper.IDL.fmclasses[linkClass].permacrud) return false;
263 if(!fieldmapper.IDL.fmclasses[linkClass].permacrud.retrieve) return false;
266 var rclassIdl = fieldmapper.IDL.fmclasses[linkClass];
268 for(var f in rclassIdl.fields) {
269 if(this.idlField.key == rclassIdl.fields[f].name) {
270 vfield = rclassIdl.fields[f];
276 throw new Error("'" + linkClass + "' has no '" + this.idlField.key + "' field!");
279 linkClass : linkClass,
284 _buildLinkSelector : function() {
285 var selectorInfo = this._getLinkSelector();
286 if(!selectorInfo) return false;
288 var linkClass = selectorInfo.linkClass;
289 var vfield = selectorInfo.vfield;
293 if(linkClass == 'pgt')
294 return this._buildPermGrpSelector();
295 if(linkClass == 'aou')
296 return this._buildOrgSelector();
297 if(linkClass == 'acpl')
298 return this._buildCopyLocSelector();
301 dojo.require('dojo.data.ItemFileReadStore');
302 dojo.require('dijit.form.FilteringSelect');
304 this.widget = new dijit.form.FilteringSelect(this.dijitArgs, this.parentNode);
305 this.widget.searchAttr = this.widget.labelAttr = vfield.selector || vfield.name;
306 this.widget.valueAttr = vfield.name;
309 var oncomplete = function(list) {
312 new dojo.data.ItemFileReadStore({data:fieldmapper[linkClass].toStoreData(list)});
313 self.cache[self.auth].list[linkClass] = self.widget.store;
315 self.widget.store = self.cache[self.auth].list[linkClass];
317 self.widget.startup();
318 self._widgetLoaded();
321 if(this.cache[self.auth].list[linkClass]) {
325 new openils.PermaCrud().retrieveAll(linkClass, {
326 async : !this.forceSync,
327 oncomplete : function(r) {
328 var list = openils.Util.readResponse(r, false, true);
338 * For widgets that run asynchronously, provide a callback for finishing up
340 _widgetLoaded : function(value) {
344 /* -------------------------------------------------------------
345 when using widgets in a grid, the cell may dissapear, which
346 kills the underlying DOM node, which causes this to fail.
347 For now, back out gracefully and let grid getters use
348 getDisplayString() instead
349 -------------------------------------------------------------*/
351 this.baseWidgetValue(this.getDisplayString());
356 this.baseWidgetValue(this.widgetValue);
357 if(this.idlField.name == this.fmIDL.pkey && this.fmIDL.pkey_sequence)
358 this.widget.attr('disabled', true);
359 if(this.disableWidgetTest && this.disableWidgetTest(this.idlField.name, this.fmObject))
360 this.widget.attr('disabled', true);
363 this.onload(this.widget, this);
366 _buildOrgSelector : function() {
367 dojo.require('fieldmapper.OrgUtils');
368 dojo.require('openils.widget.FilteringTreeSelect');
369 this.widget = new openils.widget.FilteringTreeSelect(this.dijitArgs, this.parentNode);
370 this.widget.searchAttr = 'shortname';
371 this.widget.labelAttr = 'shortname';
372 this.widget.parentField = 'parent_ou';
373 var user = new openils.User();
375 if(this.widgetValue == null)
376 this.widgetValue = user.user.ws_ou();
378 // if we have a limit perm, find the relevent orgs (async)
379 if(this.orgLimitPerms && this.orgLimitPerms.length > 0) {
382 user.getPermOrgList(this.orgLimitPerms,
384 self.widget.tree = orgList;
385 self.widget.startup();
386 self._widgetLoaded();
391 this.widget.tree = fieldmapper.aou.globalOrgTree;
392 this.widget.startup();
396 _buildPermGrpSelector : function() {
397 dojo.require('openils.widget.FilteringTreeSelect');
398 this.widget = new openils.widget.FilteringTreeSelect(this.dijitArgs, this.parentNode);
399 this.widget.searchAttr = 'name';
401 if(this.cache.permGrpTree) {
402 this.widget.tree = this.cache.permGrpTree;
403 this.widget.startup();
409 new openils.PermaCrud().retrieveAll('pgt', {
410 async : !this.forceSync,
411 oncomplete : function(r) {
412 var list = openils.Util.readResponse(r, false, true);
417 map[list[l].id()] = list[l];
420 var pnode = map[node.parent()];
421 if(!pnode) {root = node; continue;}
422 if(!pnode.children()) pnode.children([]);
423 pnode.children().push(node);
425 self.widget.tree = self.cache.permGrpTree = root;
426 self.widget.startup();
427 self._widgetLoaded();
434 _buildCopyLocSelector : function() {
435 dojo.require('dijit.form.FilteringSelect');
436 this.widget = new dijit.form.FilteringSelect(this.dijitArgs, this.parentNode);
437 this.widget.searchAttr = this.widget.labalAttr = 'name';
438 this.widget.valueAttr = 'id';
440 if(this.cache.copyLocStore) {
441 this.widget.store = this.cache.copyLocStore;
442 this.widget.startup();
448 var ws_ou = openils.User.user.ws_ou();
449 var orgs = fieldmapper.aou.findOrgUnit(ws_ou).orgNodeTrail().map(function (i) { return i.id() });
450 orgs = orgs.concat(fieldmapper.aou.descendantNodeList(ws_ou).map(function (i) { return i.id() }));
453 new openils.PermaCrud().search('acpl', {owning_lib : orgs}, {
454 async : !this.forceSync,
455 oncomplete : function(r) {
456 var list = openils.Util.readResponse(r, false, true);
459 new dojo.data.ItemFileReadStore({data:fieldmapper.acpl.toStoreData(list)});
460 self.cache.copyLocStore = self.widget.store;
461 self.widget.startup();
462 self._widgetLoaded();
470 openils.widget.AutoFieldWidget.localeStrings = dojo.i18n.getLocalization("openils.widget", "AutoFieldWidget");
471 openils.widget.AutoFieldWidget.cache = {};