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) {
342 this.baseWidgetValue(this.widgetValue);
343 if(this.idlField.name == this.fmIDL.pkey && this.fmIDL.pkey_sequence)
344 this.widget.attr('disabled', true);
345 if(this.disableWidgetTest && this.disableWidgetTest(this.idlField.name, this.fmObject))
346 this.widget.attr('disabled', true);
349 this.onload(this.widget, this);
352 _buildOrgSelector : function() {
353 dojo.require('fieldmapper.OrgUtils');
354 dojo.require('openils.widget.FilteringTreeSelect');
355 this.widget = new openils.widget.FilteringTreeSelect(this.dijitArgs, this.parentNode);
356 this.widget.searchAttr = 'shortname';
357 this.widget.labelAttr = 'shortname';
358 this.widget.parentField = 'parent_ou';
359 var user = new openils.User();
361 if(this.widgetValue == null)
362 this.widgetValue = user.user.ws_ou();
364 // if we have a limit perm, find the relevent orgs (async)
365 if(this.orgLimitPerms && this.orgLimitPerms.length > 0) {
368 user.getPermOrgList(this.orgLimitPerms,
370 self.widget.tree = orgList;
371 self.widget.startup();
372 self._widgetLoaded();
377 this.widget.tree = fieldmapper.aou.globalOrgTree;
378 this.widget.startup();
382 _buildPermGrpSelector : function() {
383 dojo.require('openils.widget.FilteringTreeSelect');
384 this.widget = new openils.widget.FilteringTreeSelect(this.dijitArgs, this.parentNode);
385 this.widget.searchAttr = 'name';
387 if(this.cache.permGrpTree) {
388 this.widget.tree = this.cache.permGrpTree;
389 this.widget.startup();
395 new openils.PermaCrud().retrieveAll('pgt', {
396 async : !this.forceSync,
397 oncomplete : function(r) {
398 var list = openils.Util.readResponse(r, false, true);
403 map[list[l].id()] = list[l];
406 var pnode = map[node.parent()];
407 if(!pnode) {root = node; continue;}
408 if(!pnode.children()) pnode.children([]);
409 pnode.children().push(node);
411 self.widget.tree = self.cache.permGrpTree = root;
412 self.widget.startup();
413 self._widgetLoaded();
420 _buildCopyLocSelector : function() {
421 dojo.require('dijit.form.FilteringSelect');
422 this.widget = new dijit.form.FilteringSelect(this.dijitArgs, this.parentNode);
423 this.widget.searchAttr = this.widget.labalAttr = 'name';
424 this.widget.valueAttr = 'id';
426 if(this.cache.copyLocStore) {
427 this.widget.store = this.cache.copyLocStore;
428 this.widget.startup();
434 var ws_ou = openils.User.user.ws_ou();
435 var orgs = fieldmapper.aou.findOrgUnit(ws_ou).orgNodeTrail().map(function (i) { return i.id() });
436 orgs = orgs.concat(fieldmapper.aou.descendantNodeList(ws_ou).map(function (i) { return i.id() }));
439 new openils.PermaCrud().search('acpl', {owning_lib : orgs}, {
440 async : !this.forceSync,
441 oncomplete : function(r) {
442 var list = openils.Util.readResponse(r, false, true);
445 new dojo.data.ItemFileReadStore({data:fieldmapper.acpl.toStoreData(list)});
446 self.cache.copyLocStore = self.widget.store;
447 self.widget.startup();
448 self._widgetLoaded();
456 openils.widget.AutoFieldWidget.localeStrings = dojo.i18n.getLocalization("openils.widget", "AutoFieldWidget");
457 openils.widget.AutoFieldWidget.cache = {};