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 if(!value) return null;
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 = dojo.create('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].list[lclass]) {
221 var store = this.cache[this.auth].list[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.cache[this.auth].single[lclass] && this.cache[this.auth].single[lclass][this.widgetValue]) {
234 this.widgetValue = this.cache[this.auth].single[lclass][this.widgetValue];
238 console.log("Fetching sync object " + lclass + " : " + this.widgetValue);
240 // if those fail, fetch the linked object
243 new openils.PermaCrud().retrieve(lclass, this.widgetValue, {
244 async : !this.forceSync,
245 oncomplete : function(r) {
246 var item = openils.Util.readResponse(r);
247 var newvalue = item[linkInfo.vfield.selector]();
249 if(!self.cache[self.auth].single[lclass])
250 self.cache[self.auth].single[lclass] = {};
251 self.cache[self.auth].single[lclass][self.widgetValue] = newvalue;
253 self.widgetValue = newvalue;
254 self.widget.startup();
255 self._widgetLoaded();
260 _getLinkSelector : function() {
261 var linkClass = this.idlField['class'];
262 if(this.idlField.reltype != 'has_a') return false;
263 if(!fieldmapper.IDL.fmclasses[linkClass].permacrud) return false;
264 if(!fieldmapper.IDL.fmclasses[linkClass].permacrud.retrieve) return false;
267 var rclassIdl = fieldmapper.IDL.fmclasses[linkClass];
269 for(var f in rclassIdl.fields) {
270 if(this.idlField.key == rclassIdl.fields[f].name) {
271 vfield = rclassIdl.fields[f];
277 throw new Error("'" + linkClass + "' has no '" + this.idlField.key + "' field!");
280 linkClass : linkClass,
285 _buildLinkSelector : function() {
286 var selectorInfo = this._getLinkSelector();
287 if(!selectorInfo) return false;
289 var linkClass = selectorInfo.linkClass;
290 var vfield = selectorInfo.vfield;
294 if(linkClass == 'pgt')
295 return this._buildPermGrpSelector();
296 if(linkClass == 'aou')
297 return this._buildOrgSelector();
298 if(linkClass == 'acpl')
299 return this._buildCopyLocSelector();
302 dojo.require('dojo.data.ItemFileReadStore');
303 dojo.require('dijit.form.FilteringSelect');
305 this.widget = new dijit.form.FilteringSelect(this.dijitArgs, this.parentNode);
306 this.widget.searchAttr = this.widget.labelAttr = vfield.selector || vfield.name;
307 this.widget.valueAttr = vfield.name;
310 var oncomplete = function(list) {
313 new dojo.data.ItemFileReadStore({data:fieldmapper[linkClass].toStoreData(list)});
314 self.cache[self.auth].list[linkClass] = self.widget.store;
316 self.widget.store = self.cache[self.auth].list[linkClass];
318 self.widget.startup();
319 self._widgetLoaded();
322 if(this.cache[self.auth].list[linkClass]) {
326 new openils.PermaCrud().retrieveAll(linkClass, {
327 async : !this.forceSync,
328 oncomplete : function(r) {
329 var list = openils.Util.readResponse(r, false, true);
339 * For widgets that run asynchronously, provide a callback for finishing up
341 _widgetLoaded : function(value) {
345 /* -------------------------------------------------------------
346 when using widgets in a grid, the cell may dissapear, which
347 kills the underlying DOM node, which causes this to fail.
348 For now, back out gracefully and let grid getters use
349 getDisplayString() instead
350 -------------------------------------------------------------*/
352 this.baseWidgetValue(this.getDisplayString());
357 this.baseWidgetValue(this.widgetValue);
358 if(this.idlField.name == this.fmIDL.pkey && this.fmIDL.pkey_sequence)
359 this.widget.attr('disabled', true);
360 if(this.disableWidgetTest && this.disableWidgetTest(this.idlField.name, this.fmObject))
361 this.widget.attr('disabled', true);
364 this.onload(this.widget, this);
367 _buildOrgSelector : function() {
368 dojo.require('fieldmapper.OrgUtils');
369 dojo.require('openils.widget.FilteringTreeSelect');
370 this.widget = new openils.widget.FilteringTreeSelect(this.dijitArgs, this.parentNode);
371 this.widget.searchAttr = 'shortname';
372 this.widget.labelAttr = 'shortname';
373 this.widget.parentField = 'parent_ou';
374 var user = new openils.User();
376 if(this.widgetValue == null)
377 this.widgetValue = user.user.ws_ou();
379 // if we have a limit perm, find the relevent orgs (async)
380 if(this.orgLimitPerms && this.orgLimitPerms.length > 0) {
383 user.getPermOrgList(this.orgLimitPerms,
385 self.widget.tree = orgList;
386 self.widget.startup();
387 self._widgetLoaded();
392 this.widget.tree = fieldmapper.aou.globalOrgTree;
393 this.widget.startup();
397 _buildPermGrpSelector : function() {
398 dojo.require('openils.widget.FilteringTreeSelect');
399 this.widget = new openils.widget.FilteringTreeSelect(this.dijitArgs, this.parentNode);
400 this.widget.searchAttr = 'name';
402 if(this.cache.permGrpTree) {
403 this.widget.tree = this.cache.permGrpTree;
404 this.widget.startup();
410 new openils.PermaCrud().retrieveAll('pgt', {
411 async : !this.forceSync,
412 oncomplete : function(r) {
413 var list = openils.Util.readResponse(r, false, true);
418 map[list[l].id()] = list[l];
421 var pnode = map[node.parent()];
422 if(!pnode) {root = node; continue;}
423 if(!pnode.children()) pnode.children([]);
424 pnode.children().push(node);
426 self.widget.tree = self.cache.permGrpTree = root;
427 self.widget.startup();
428 self._widgetLoaded();
435 _buildCopyLocSelector : function() {
436 dojo.require('dijit.form.FilteringSelect');
437 this.widget = new dijit.form.FilteringSelect(this.dijitArgs, this.parentNode);
438 this.widget.searchAttr = this.widget.labalAttr = 'name';
439 this.widget.valueAttr = 'id';
441 if(this.cache.copyLocStore) {
442 this.widget.store = this.cache.copyLocStore;
443 this.widget.startup();
449 var ws_ou = openils.User.user.ws_ou();
450 var orgs = fieldmapper.aou.findOrgUnit(ws_ou).orgNodeTrail().map(function (i) { return i.id() });
451 orgs = orgs.concat(fieldmapper.aou.descendantNodeList(ws_ou).map(function (i) { return i.id() }));
454 new openils.PermaCrud().search('acpl', {owning_lib : orgs}, {
455 async : !this.forceSync,
456 oncomplete : function(r) {
457 var list = openils.Util.readResponse(r, false, true);
460 new dojo.data.ItemFileReadStore({data:fieldmapper.acpl.toStoreData(list)});
461 self.cache.copyLocStore = self.widget.store;
462 self.widget.startup();
463 self._widgetLoaded();
471 openils.widget.AutoFieldWidget.localeStrings = dojo.i18n.getLocalization("openils.widget", "AutoFieldWidget");
472 openils.widget.AutoFieldWidget.cache = {};