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");
8 var localeStrings = dojo.i18n.getLocalization("openils.widget", "AutoFieldWidget");
10 dojo.declare('openils.widget.AutoFieldWidget', null, {
18 * idlField -- Field description object from fieldmapper.IDL.fmclasses
19 * fmObject -- If available, the object being edited. This will be used
20 * to set the value of the widget.
21 * fmClass -- Class name (not required if idlField or fmObject is set)
22 * fmField -- Field name (not required if idlField)
23 * parentNode -- If defined, the widget will be appended to this DOM node
24 * dijitArgs -- Optional parameters object, passed directly to the dojo widget
25 * orgLimitPerms -- If this field defines a set of org units and an orgLimitPerms
26 * is defined, the code will limit the org units in the set to those
27 * allowed by the permission
29 constructor : function(args) {
33 // find the field description in the IDL if not provided
35 this.fmClass = this.fmObject.classname;
36 this.fmIDL = fieldmapper.IDL.fmclasses[this.fmClass];
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)) ? localeStrings.TRUE : localeStrings.FALSE;
90 dojo.require('dojo.date.locale');
91 dojo.require('dojo.date.stamp');
92 var date = dojo.date.stamp.fromISOString(value);
93 return dojo.date.locale.format(date, {formatLength:'short'});
95 if(value === null || value === undefined) return '';
96 return fieldmapper.aou.findOrgUnit(value).shortname();
99 if(isNaN(value)) value = 0;
101 if(value === undefined || value === null)
107 build : function(onload) {
110 // core widget provided for us, attach and move on
111 if(this.parentNode) // may already be in the "right" place
112 this.parentNode.appendChild(this.widget.domNode);
116 if(!this.parentNode) // give it somewhere to live so that dojo won't complain
117 this.parentNode = document.createElement('div');
119 this.onload = onload;
120 if(this.widgetValue == null)
121 this.widgetValue = (this.fmObject) ? this.fmObject[this.idlField.name]() : null;
124 dojo.require('dijit.layout.ContentPane');
125 this.widget = new dijit.layout.ContentPane(this.dijitArgs, this.parentNode);
126 if(this.widgetValue !== null)
127 this._tryLinkedDisplayField();
129 } else if(this.widgetClass) {
130 dojo.require(this.widgetClass);
131 eval('this.widget = new ' + this.widgetClass + '(this.dijitArgs, this.parentNode);');
135 switch(this.idlField.datatype) {
138 dojo.require('dijit.form.TextBox');
139 this.widget = new dijit.form.TextBox(this.dijitArgs, this.parentNode);
143 this._buildOrgSelector();
147 dojo.require('dijit.form.CurrencyTextBox');
148 this.widget = new dijit.form.CurrencyTextBox(this.dijitArgs, this.parentNode);
152 dojo.require('dijit.form.NumberTextBox');
153 this.dijitArgs = dojo.mixin(this.dijitArgs || {}, {constraints:{places:0}});
154 this.widget = new dijit.form.NumberTextBox(this.dijitArgs, this.parentNode);
158 dojo.require('dijit.form.NumberTextBox');
159 this.widget = new dijit.form.NumberTextBox(this.dijitArgs, this.parentNode);
163 dojo.require('dijit.form.DateTextBox');
164 dojo.require('dojo.date.stamp');
165 this.widget = new dijit.form.DateTextBox(this.dijitArgs, this.parentNode);
166 if(this.widgetValue != null)
167 this.widgetValue = dojo.date.stamp.fromISOString(this.widgetValue);
171 dojo.require('dijit.form.CheckBox');
172 this.widget = new dijit.form.CheckBox(this.dijitArgs, this.parentNode);
173 this.widgetValue = openils.Util.isTrue(this.widgetValue);
177 if(this._buildLinkSelector()) break;
180 if(this.dijitArgs && (this.dijitArgs.required || this.dijitArgs.regExp)) {
181 dojo.require('dijit.form.ValidationTextBox');
182 this.widget = new dijit.form.ValidationTextBox(this.dijitArgs, this.parentNode);
184 dojo.require('dijit.form.TextBox');
185 this.widget = new dijit.form.TextBox(this.dijitArgs, this.parentNode);
190 if(!this.async) this._widgetLoaded();
194 // we want to display the value for our widget. However, instead of displaying
195 // an ID, for exmaple, display the value for the 'selector' field on the object
197 _tryLinkedDisplayField : function(noAsync) {
199 if(this.idlField.datatype == 'org_unit')
200 return false; // we already handle org_units, no need to re-fetch
202 var linkInfo = this._getLinkSelector();
203 if(!(linkInfo && linkInfo.vfield && linkInfo.vfield.selector))
205 var lclass = linkInfo.linkClass;
207 if(lclass == 'aou') {
208 this.widgetValue = fieldmapper.aou.findOrgUnit(this.widgetValue).shortname();
212 // first try the store cache
214 if(this.cache[this.auth][lclass]) {
215 var store = this.cache[this.auth][lclass];
217 query[linkInfo.vfield.name] = ''+this.widgetValue;
218 store.fetch({query:query, onComplete:
220 self.widgetValue = store.getValue(list[0], linkInfo.vfield.selector);
226 // then try the single object cache
227 if(this.cacheSingle[lclass] && this.cacheSingle[lclass][this.widgetValue]) {
228 this.widgetValue = this.cacheSingle[lclass][this.widgetValue];
232 // if those fail, fetch the linked object
235 new openils.PermaCrud().retrieve(lclass, this.widgetValue, {
236 async : !this.forceSync,
237 oncomplete : function(r) {
238 var item = openils.Util.readResponse(r);
239 if(!self.cacheSingle[lclass])
240 self.cacheSingle[lclass] = {};
241 self.widgetValue = item[linkInfo.vfield.selector]();
242 self.cacheSingle[lclass][self.widgetValue] = item;
243 self.widget.startup();
244 self._widgetLoaded();
249 _getLinkSelector : function() {
250 var linkClass = this.idlField['class'];
251 if(this.idlField.reltype != 'has_a') return false;
252 if(!fieldmapper.IDL.fmclasses[linkClass].permacrud) return false;
253 if(!fieldmapper.IDL.fmclasses[linkClass].permacrud.retrieve) return false;
256 var rclassIdl = fieldmapper.IDL.fmclasses[linkClass];
258 for(var f in rclassIdl.fields) {
259 if(this.idlField.key == rclassIdl.fields[f].name) {
260 vfield = rclassIdl.fields[f];
266 throw new Error("'" + linkClass + "' has no '" + this.idlField.key + "' field!");
269 linkClass : linkClass,
274 _buildLinkSelector : function() {
275 var selectorInfo = this._getLinkSelector();
276 if(!selectorInfo) return false;
278 var linkClass = selectorInfo.linkClass;
279 var vfield = selectorInfo.vfield;
283 if(linkClass == 'pgt')
284 return this._buildPermGrpSelector();
285 if(linkClass == 'aou')
286 return this._buildOrgSelector();
287 if(linkClass == 'acpl')
288 return this._buildCopyLocSelector();
291 dojo.require('dojo.data.ItemFileReadStore');
292 dojo.require('dijit.form.FilteringSelect');
294 this.widget = new dijit.form.FilteringSelect(this.dijitArgs, this.parentNode);
295 this.widget.searchAttr = this.widget.labelAttr = vfield.selector || vfield.name;
296 this.widget.valueAttr = vfield.name;
299 var oncomplete = function(list) {
302 new dojo.data.ItemFileReadStore({data:fieldmapper[linkClass].toStoreData(list)});
303 self.cache[self.auth][linkClass] = self.widget.store;
305 self.widget.store = self.cache[self.auth][linkClass];
307 self.widget.startup();
308 self._widgetLoaded();
311 if(this.cache[self.auth][linkClass]) {
315 new openils.PermaCrud().retrieveAll(linkClass, {
316 async : !this.forceSync,
317 oncomplete : function(r) {
318 var list = openils.Util.readResponse(r, false, true);
328 * For widgets that run asynchronously, provide a callback for finishing up
330 _widgetLoaded : function(value) {
332 this.baseWidgetValue(this.getDisplayString());
334 this.baseWidgetValue(this.widgetValue);
335 if(this.idlField.name == this.fmIDL.pkey && this.fmIDL.pkey_sequence)
336 this.widget.attr('disabled', true);
337 if(this.disableWidgetTest && this.disableWidgetTest(this.idlField.name, this.fmObject))
338 this.widget.attr('disabled', true);
341 this.onload(this.widget, this);
344 _buildOrgSelector : function() {
345 dojo.require('fieldmapper.OrgUtils');
346 dojo.require('openils.widget.FilteringTreeSelect');
347 this.widget = new openils.widget.FilteringTreeSelect(this.dijitArgs, this.parentNode);
348 this.widget.searchAttr = 'shortname';
349 this.widget.labelAttr = 'shortname';
350 this.widget.parentField = 'parent_ou';
351 var user = new openils.User();
353 if(this.widgetValue == null)
354 this.widgetValue = user.user.ws_ou();
356 // if we have a limit perm, find the relevent orgs (async)
357 if(this.orgLimitPerms && this.orgLimitPerms.length > 0) {
360 user.getPermOrgList(this.orgLimitPerms,
362 self.widget.tree = orgList;
363 self.widget.startup();
364 self._widgetLoaded();
369 this.widget.tree = fieldmapper.aou.globalOrgTree;
370 this.widget.startup();
374 _buildPermGrpSelector : function() {
375 dojo.require('openils.widget.FilteringTreeSelect');
376 this.widget = new openils.widget.FilteringTreeSelect(this.dijitArgs, this.parentNode);
377 this.widget.searchAttr = 'name';
379 if(this.cache.permGrpTree) {
380 this.widget.tree = this.cache.permGrpTree;
381 this.widget.startup();
387 new openils.PermaCrud().retrieveAll('pgt', {
388 async : !this.forceSync,
389 oncomplete : function(r) {
390 var list = openils.Util.readResponse(r, false, true);
395 map[list[l].id()] = list[l];
398 var pnode = map[node.parent()];
399 if(!pnode) {root = node; continue;}
400 if(!pnode.children()) pnode.children([]);
401 pnode.children().push(node);
403 self.widget.tree = self.cache.permGrpTree = root;
404 self.widget.startup();
405 self._widgetLoaded();
412 _buildCopyLocSelector : function() {
413 dojo.require('dijit.form.FilteringSelect');
414 this.widget = new dijit.form.FilteringSelect(this.dijitArgs, this.parentNode);
415 this.widget.searchAttr = this.widget.labalAttr = 'name';
416 this.widget.valueAttr = 'id';
418 if(this.cache.copyLocStore) {
419 this.widget.store = this.cache.copyLocStore;
420 this.widget.startup();
426 var ws_ou = openils.User.user.ws_ou();
427 var orgs = fieldmapper.aou.findOrgUnit(ws_ou).orgNodeTrail().map(function (i) { return i.id() });
428 orgs = orgs.concat(fieldmapper.aou.descendantNodeList(ws_ou).map(function (i) { return i.id() }));
431 new openils.PermaCrud().search('acpl', {owning_lib : orgs}, {
432 async : !this.forceSync,
433 oncomplete : function(r) {
434 var list = openils.Util.readResponse(r, false, true);
437 new dojo.data.ItemFileReadStore({data:fieldmapper.acpl.toStoreData(list)});
438 self.cache.copyLocStore = self.widget.store;
439 self.widget.startup();
440 self._widgetLoaded();