]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/web/js/ui/default/actor/user/register.js
indicate required widgets by checkin required-ness setting in the markup
[working/Evergreen.git] / Open-ILS / web / js / ui / default / actor / user / register.js
1 dojo.require('dojo.data.ItemFileReadStore');
2 dojo.require('dijit.form.Textarea');
3 dojo.require('dijit.form.FilteringSelect');
4 dojo.require('dijit.form.ComboBox');
5 dojo.require('fieldmapper.IDL');
6 dojo.require('openils.PermaCrud');
7 dojo.require('openils.widget.AutoGrid');
8 dojo.require('openils.widget.AutoFieldWidget');
9 dojo.require('dijit.form.CheckBox');
10 dojo.require('dijit.form.Button');
11 dojo.require('dojo.date');
12 dojo.require('openils.CGI');
13 dojo.require('openils.XUL');
14
15 var pcrud;
16 var fmClasses = ['au', 'ac', 'aua', 'actsc', 'asv', 'asvq', 'asva'];
17 var fieldDoc = {};
18 var statCats;
19 var statCatTempate;
20 var surveys;
21 var staff;
22 var patron;
23 var uEditUsePhonePw = false;
24 var widgetPile = [];
25 var uEditCardVirtId = -1;
26 var uEditAddrVirtId = -1;
27 var orgSettings = {};
28 var tbody;
29 var addrTemplateRows;
30 var cgi;
31 var cloneUser;
32
33 if(!window.xulG) var xulG = null;
34
35
36 function load() {
37     staff = new openils.User().user;
38     pcrud = new openils.PermaCrud();
39     cgi = new openils.CGI();
40     cloneUser = cgi.param('clone');
41     var userId = cgi.param('usr');
42
43     if(xulG) {
44             if(xulG.ses) openils.User.authtoken = xulG.ses;
45             if(xulG.clone !== null) cloneUser = xulG.clone;
46         if(xulG.usr !== null) userId = xulG.usr
47         if(xulG.params) {
48             var parms = xulG.params;
49                 if(parms.ses) 
50                 openils.User.authtoken = parms.ses;
51                 if(parms.clone) 
52                 cloneUser = parms.clone;
53             if(parms.usr !== null)
54                 userId = parms.usr
55         }
56     }
57
58     orgSettings = fieldmapper.aou.fetchOrgSettingBatch(staff.ws_ou(), [
59         'global.juvenile_age_threshold',
60         'patron.password.use_phone',
61         'ui.patron.default_inet_access_level'
62     ]);
63     for(k in orgSettings)
64         if(orgSettings[k])
65             orgSettings[k] = orgSettings[k].value;
66
67     uEditLoadUser(userId);
68
69     var list = pcrud.search('fdoc', {fm_class:fmClasses});
70     for(var i in list) {
71         var doc = list[i];
72         if(!fieldDoc[doc.fm_class()])
73             fieldDoc[doc.fm_class()] = {};
74         fieldDoc[doc.fm_class()][doc.field()] = doc;
75     }
76
77     tbody = dojo.byId('uedit-tbody');
78
79     addrTemplateRows = dojo.query('tr[type=addr-template]', tbody);
80     dojo.forEach(addrTemplateRows, function(row) { row.parentNode.removeChild(row); } );
81     statCatTemplate = tbody.removeChild(dojo.byId('stat-cat-row-template'));
82     surveyTemplate = tbody.removeChild(dojo.byId('survey-row-template'));
83     surveyQuestionTemplate = tbody.removeChild(dojo.byId('survey-question-row-template'));
84
85     loadStaticFields();
86     if(patron.isnew()) 
87         uEditNewAddr(null, uEditAddrVirtId);
88     else loadAllAddrs();
89     loadStatCats();
90     loadSurveys();
91 }
92
93 function uEditLoadUser(userId) {
94     if(!userId) return uEditNewPatron();
95     patron = fieldmapper.standardRequest(
96         ['open-ils.actor', 'open-ils.actor.user.fleshed.retrieve'],
97         {params : [openils.User.authtoken, userId]}
98     );
99 }
100
101 function loadStaticFields() {
102     for(var idx = 0; tbody.childNodes[idx]; idx++) {
103         var row = tbody.childNodes[idx];
104         if(row.nodeType != row.ELEMENT_NODE) continue;
105         var fmcls = row.getAttribute('fmclass');
106         if(!fmcls) continue;
107         fleshFMRow(row, fmcls);
108     }
109 }
110
111 function loadAllAddrs() {
112     dojo.forEach(patron.addresses(),
113         function(addr) {
114             uEditNewAddr(null, addr.id());
115         }
116     );
117 }
118
119 function loadStatCats() {
120
121     statCats = fieldmapper.standardRequest(
122         ['open-ils.circ', 'open-ils.circ.stat_cat.actor.retrieve.all'],
123         {params : [openils.User.authtoken, staff.ws_ou()]}
124     );
125
126     // draw stat cats
127     for(var idx in statCats) {
128         var stat = statCats[idx];
129         var row = statCatTemplate.cloneNode(true);
130         row.id = 'stat-cat-row-' + idx;
131         tbody.appendChild(row);
132         getByName(row, 'name').innerHTML = stat.name();
133         var valtd = getByName(row, 'widget');
134         var span = valtd.appendChild(document.createElement('span'));
135         var store = new dojo.data.ItemFileReadStore(
136                 {data:fieldmapper.actsc.toStoreData(stat.entries())});
137         var comboBox = new dijit.form.ComboBox({store:store}, span);
138         comboBox.labelAttr = 'value';
139         comboBox.searchAttr = 'value';
140
141         comboBox._wtype = 'statcat';
142         comboBox._statcat = stat.id();
143         widgetPile.push(comboBox); 
144
145         // populate existing cats
146         var map = patron.stat_cat_entries().filter(
147             function(mp) { return (mp.stat_cat() == stat.id()) })[0];
148         if(map) comboBox.attr('value', map.stat_cat_entry()); 
149
150     }
151 }
152
153 function loadSurveys() {
154
155     surveys = fieldmapper.standardRequest(
156         ['open-ils.circ', 'open-ils.circ.survey.retrieve.all'],
157         {params : [openils.User.authtoken]}
158     );
159
160     // draw surveys
161     for(var idx in surveys) {
162         var survey = surveys[idx];
163         var srow = surveyTemplate.cloneNode(true);
164         tbody.appendChild(srow);
165         getByName(srow, 'name').innerHTML = survey.name();
166
167         for(var q in survey.questions()) {
168             var quest = survey.questions()[q];
169             var qrow = surveyQuestionTemplate.cloneNode(true);
170             tbody.appendChild(qrow);
171             getByName(qrow, 'question').innerHTML = quest.question();
172
173             var span = getByName(qrow, 'answers').appendChild(document.createElement('span'));
174             var store = new dojo.data.ItemFileReadStore(
175                 {data:fieldmapper.asva.toStoreData(quest.answers())});
176             var select = new dijit.form.FilteringSelect({store:store}, span);
177             select.labelAttr = 'answer';
178             select.searchAttr = 'answer';
179
180             select._wtype = 'survey';
181             select._survey = survey.id();
182             select._question = quest.id();
183             widgetPile.push(select); 
184         }
185     }
186 }
187
188
189 function fleshFMRow(row, fmcls, args) {
190     var fmfield = row.getAttribute('fmfield');
191     var wclass = row.getAttribute('wclass');
192     var wstyle = row.getAttribute('wstyle');
193     var fieldIdl = fieldmapper.IDL.fmclasses[fmcls].field_map[fmfield];
194     if(!args) args = {};
195
196     var existing = dojo.query('td', row);
197     var htd = existing[0] || row.appendChild(document.createElement('td'));
198     var ltd = existing[1] || row.appendChild(document.createElement('td'));
199     var wtd = existing[2] || row.appendChild(document.createElement('td'));
200
201     openils.Util.addCSSClass(htd, 'uedit-help');
202     if(fieldDoc[fmcls] && fieldDoc[fmcls][fmfield]) {
203         var link = dojo.byId('uedit-help-template').cloneNode(true);
204         link.id = '';
205         link.onclick = function() { ueLoadContextHelp(fmcls, fmfield) };
206         openils.Util.removeCSSClass(link, 'hidden');
207         htd.appendChild(link);
208     }
209
210     if(!ltd.textContent) {
211         var span = document.createElement('span');
212         ltd.appendChild(document.createTextNode(fieldIdl.label));
213     }
214
215     span = document.createElement('span');
216     wtd.appendChild(span);
217
218     var fmObject = null;
219     switch(fmcls) {
220         case 'au' : fmObject = patron; break;
221         case 'ac' : fmObject = patron.card(); break;
222         case 'aua' : 
223             fmObject = patron.addresses().filter(
224                 function(i) { return (i.id() == args.addr) })[0];
225             break;
226     }
227     
228     var required = row.getAttribute('required') == 'required';
229     var widget = new openils.widget.AutoFieldWidget({
230         idlField : fieldIdl,
231         fmObject : fmObject,
232         fmClass : fmcls,
233         parentNode : span,
234         widgetClass : wclass,
235         dijitArgs : {
236             style: wstyle, 
237             required : required
238         },
239         orgLimitPerms : ['UPDATE_USER'],
240     });
241
242     widget.build();
243
244     widget._wtype = fmcls;
245     widget._fmfield = fmfield;
246     widget._addr = args.addr;
247     widgetPile.push(widget);
248     attachWidgetEvents(fmcls, fmfield, widget);
249     return widget;
250 }
251
252 function findWidget(wtype, fmfield, callback) {
253     return widgetPile.filter(
254         function(i){
255             if(i._wtype == wtype && i._fmfield == fmfield) {
256                 if(callback) return callback(i);
257                 return true;
258             }
259         }
260     ).pop();
261 }
262
263 function attachWidgetEvents(fmcls, fmfield, widget) {
264
265     if(fmcls == 'ac') {
266         if(fmfield == 'barcode') {
267             dojo.connect(widget.widget, 'onChange',
268                 function() {
269                     var un = findWidget('au', 'usrname');
270                     if(!un.widget.attr('value'))
271                         un.widget.attr('value', this.attr('value'));
272                 }
273             );
274             return;
275         }
276     }
277
278     if(fmcls == 'au') {
279         switch(fmfield) {
280
281             case 'profile': // when the profile changes, update the expire date
282                 dojo.connect(widget.widget, 'onChange', 
283                     function() {
284                         var self = this;
285                         var expireWidget = findWidget('au', 'expire_date');
286                         function found(items) {
287                             if(items.length == 0) return;
288                             var item = items[0];
289                             var interval = self.store.getValue(item, 'perm_interval');
290                             expireWidget.widget.attr('value', dojo.date.add(new Date(), 
291                                 'second', openils.Util.intervalToSeconds(interval)));
292                         }
293                         this.store.fetch({onComplete:found, query:{id:this.attr('value')}});
294                     }
295                 );
296                 return;
297
298             case 'dob':
299                 dojo.connect(widget.widget, 'onChange',
300                     function(newDob) {
301                         if(!newDob) return;
302                         var oldDob = patron.dob();
303                         if(dojo.date.stamp.fromISOString(oldDob) == newDob) return;
304
305                         var juvInterval = orgSettings['global.juvenile_age_threshold'] || '18 years';
306                         var juvWidget = findWidget('au', 'juvenile');
307                         var base = new Date();
308                         base.setTime(base.getTime() - Number(openils.Util.intervalToSeconds(juvInterval) + '000'));
309
310                         if(newDob <= base) // older than global.juvenile_age_threshold
311                             juvWidget.widget.attr('value', false);
312                         else
313                             juvWidget.widget.attr('value', true);
314                     }
315                 );
316                 return;
317         }
318     }
319
320     if(fmclass = 'aua') {
321         switch(fmfield) {
322             case 'post_code':
323                 dojo.connect(widget.widget, 'onChange',
324                     function(e) { 
325                         fieldmapper.standardRequest(
326                             ['open-ils.search', 'open-ils.search.zip'],
327                             {   async: true,
328                                 params: [e],
329                                 oncomplete : function(r) {
330                                     var res = openils.Util.readResponse(r);
331                                     var callback = function(w) { return w._addr == widget._addr; };
332                                     if(res.city) findWidget('aua', 'city', callback).widget.attr('value', res.city);
333                                     if(res.state) findWidget('aua', 'state', callback).widget.attr('value', res.state);
334                                     if(res.county) findWidget('aua', 'county', callback).widget.attr('value', res.county);
335                                     if(res.alert) alert(res.alert);
336                                 }
337                             }
338                         );
339                     }
340                 );
341                 return;
342         }
343     }
344 }
345
346 function getByName(node, name) {
347     return dojo.query('[name='+name+']', node)[0];
348 }
349
350
351 function ueLoadContextHelp(fmcls, fmfield) {
352     openils.Util.removeCSSClass(dojo.byId('uedit-help-div'), 'hidden');
353     dojo.byId('uedit-help-field').innerHTML = fieldmapper.IDL.fmclasses[fmcls].field_map[fmfield].label;
354     dojo.byId('uedit-help-text').innerHTML = fieldDoc[fmcls][fmfield].string();
355 }
356
357
358 /* creates a new patron object with card attached */
359 function uEditNewPatron() {
360     patron = new au();
361     patron.isnew(1);
362     patron.id(-1);
363     card = new ac();
364     card.id(uEditCardVirtId);
365     card.isnew(1);
366     patron.card(card);
367     patron.cards([card]);
368     patron.net_access_level(orgSettings['ui.patron.default_inet_access_level'] || 1);
369     patron.stat_cat_entries([]);
370     patron.survey_responses([]);
371     patron.addresses([]);
372     uEditMakeRandomPw(patron);
373 }
374
375 function uEditMakeRandomPw(patron) {
376     if(uEditUsePhonePw) return;
377     var rand  = Math.random();
378     rand = parseInt(rand * 10000) + '';
379     while(rand.length < 4) rand += '0';
380 /*
381     appendClear($('ue_password_plain'),text(rand));
382     unHideMe($('ue_password_gen'));
383 */
384     patron.passwd(rand);
385     return rand;
386 }
387
388 function uEditWidgetVal(w) {
389     var val = (w.getFormattedValue) ? w.getFormattedValue() : w.attr('value');
390     if(val === '') val = null;
391     return val;
392 }
393
394 function uEditSave() { _uEditSave(); }
395 function uEditSaveClone() { _uEditSave(true); }
396
397 function _uEditSave(doClone) {
398
399     for(var idx in widgetPile) {
400         var w = widgetPile[idx];
401         var val = uEditWidgetVal(w);
402
403         switch(w._wtype) {
404             case 'au':
405                 patron[w._fmfield](val);
406                 break;
407
408             case 'ac':
409                 patron.card()[w._fmfield](val);
410                 break;
411
412             case 'aua':
413                 var addr = patron.addresses().filter(function(i){return (i.id() == w._addr)})[0];
414                 if(!addr) {
415                     addr = new fieldmapper.aua();
416                     addr.id(w._addr);
417                     addr.isnew(1);
418                     addr.usr(patron.id());
419                     patron.addresses().push(addr);
420                 } else {
421                     if(addr[w._fmfield]() != val)
422                         addr.ischanged(1);
423                 }
424                 addr[w._fmfield](val);
425                 break;
426
427             case 'survey':
428                 if(val == null) break;
429                 var resp = new fieldmapper.asvr();
430                 resp.isnew(1);
431                 resp.survey(w._survey)
432                 resp.usr(patron.id());
433                 resp.question(w._question)
434                 resp.answer(val);
435                 patron.survey_responses().push(resp);
436                 break;
437
438             case 'statcat':
439                 if(val == null) break;
440
441                 var map = patron.stat_cat_entries().filter(
442                     function(m){
443                         return (m.stat_cat() == w._statcat) })[0];
444
445                 if(map) {
446                     if(map.stat_cat_entry() == val) 
447                         break;
448                     map.ischanged(1);
449                 } else {
450                     map = new fieldmapper.actscecm();
451                     map.isnew(1);
452                 }
453
454                 map.stat_cat(w._statcat);
455                 map.stat_cat_entry(val);
456                 map.target_usr(patron.id());
457                 patron.stat_cat_entries().push(map);
458                 break;
459         }
460     }
461
462     patron.ischanged(1);
463     fieldmapper.standardRequest(
464         ['open-ils.actor', 'open-ils.actor.patron.update'],
465         {   async: true,
466             params: [openils.User.authtoken, patron],
467             oncomplete: function(r) {
468                 newPatron = openils.Util.readResponse(r);
469                 if(newPatron) uEditFinishSave(newPatron, doClone);
470             }
471         }
472     );
473 }
474
475 function uEditFinishSave(newPatron, doClone) {
476
477     if(doClone &&cloneUser == null)
478         cloneUser = newPatron.id();
479
480         if( doClone ) {
481
482                 if(xulG && typeof xulG.spawn_editor == 'function' && !patron.isnew() ) {
483             window.xulG.spawn_editor({ses:openils.User.authtoken,clone:cloneUser});
484             uEditRefresh();
485
486                 } else {
487                         location.href = href.replace(/\?.*/, '') + '?clone=' + cloneUser;
488                 }
489
490         } else {
491
492                 uEditRefresh();
493         }
494
495         uEditRefreshXUL(newPatron);
496 }
497
498 function uEditRefresh() {
499     var usr = cgi.param('usr');
500     var href = location.href.replace(/\?.*/, '');
501     href += ((usr) ? '?usr=' + usr : '');
502     location.href = href;
503 }
504
505 function uEditRefreshXUL(newuser) {
506         if (window.xulG && typeof window.xulG.on_save == 'function') 
507                 window.xulG.on_save(newuser);
508 }
509
510
511 function uEditNewAddr(evt, id) {
512     if(id == null) id = --uEditAddrVirtId;
513     dojo.forEach(addrTemplateRows, 
514         function(row) {
515
516             row = tbody.insertBefore(row.cloneNode(true), dojo.byId('new-addr-row'));
517             row.setAttribute('type', '');
518             row.setAttribute('addr', id+'');
519
520             if(row.getAttribute('fmclass')) {
521                 fleshFMRow(row, 'aua', {addr:id});
522
523             } else if(row.getAttribute('name') == 'uedit-addr-pending-row') {
524
525                 var addr =  patron.addresses().filter(
526                     function(i) { return (i.id() == id) })[0];
527                 
528                 // if it's a pending address, show the 'approve' button
529                 if(addr && openils.Util.isTrue(addr.pending())) {
530                     openils.Util.show(row, 'table-row');
531                     dojo.query('[name=approve-button]', row)[0].onclick = 
532                         function() { uEditApproveAddress(addr); };
533
534                     if(addr.replaces()) {
535                         var div = dojo.query('[name=replaced-addr]', row)[0]
536                         div.innerHTML = addr.replaces();
537                     } else {
538                         openils.Util.hide(dojo.query('[name=replaced-addr-div]', row)[0]);
539                     }
540                 }
541
542             } else {
543                 var btn = dojo.query('[name=delete-button]', row)[0];
544                 if(btn) btn.onclick = function(){ uEditDeleteAddr(id) };
545             }
546         }
547     );
548 }
549
550 function uEditApproveAddress(addr) {
551     fieldmapper.standardRequest(
552         ['open-ils.actor', 'open-ils.actor.user.pending_address.approve'],
553         {   async: true,
554             params:  [openils.User.authtoken, addr],
555
556             oncomplete : function(r) {
557                 var oldId = openils.Util.readResponse(r);
558                     
559                 // remove addrs from UI
560                 dojo.forEach(
561                     patron.addresses(), 
562                     function(addr) { uEditDeleteAddr(addr.id(), true); }
563                 );
564
565                 if(oldId != null) {
566                     
567                     // remove the replaced address 
568                     if(oldId != addr.id()) {
569                                 patron.addresses(
570                             patron.addresses().filter(
571                                                 function(i) { return (i.id() != oldId); }
572                                         )
573                                 );
574                     }
575                     
576                     // fix the the new address
577                     addr.id(oldId);
578                     addr.replaces(null);
579                     addr.pending('f');
580
581                 }
582
583                 // redraw addrs
584                 loadAllAddrs();
585             }
586         }
587     );
588 }
589
590
591 function uEditDeleteAddr(id, noAlert) {
592     if(!noAlert) {
593         if(!confirm('Delete address ' + id)) return; /* XXX i18n */
594     }
595     var rows = dojo.query('tr[addr='+id+']', tbody);
596     for(var i = 0; i < rows.length; i++)
597         rows[i].parentNode.removeChild(rows[i]);
598     widgetPile = widgetPile.filter(function(w){return (w._addr != id)});
599 }
600
601 function uEditToggleRequired() {
602     if((tbody.className +'').match(/hide-non-required/)) 
603         openils.Util.removeCSSClass(tbody, 'hide-non-required');
604     else
605         openils.Util.addCSSClass(tbody, 'hide-non-required');
606     openils.Util.toggle('uedit-show-required');
607     openils.Util.toggle('uedit-show-all');
608 }
609
610
611
612 openils.Util.addOnLoad(load);