]> git.evergreen-ils.org Git - Evergreen.git/blob - Evergreen/xul/staff_client/server/patron/ue_config.js
fixed the claims-returned count reset button
[Evergreen.git] / Evergreen / xul / staff_client / server / patron / ue_config.js
1 /* -----------------------------------------------------------------------
2         ----------------------------------------------------------------------- */
3 const SC_FETCH_ALL              = 'open-ils.circ:open-ils.circ.stat_cat.actor.retrieve.all';
4 const SC_CREATE_MAP             = 'open-ils.circ:open-ils.circ.stat_cat.actor.user_map.create';
5 const SV_FETCH_ALL              = 'open-ils.circ:open-ils.circ.survey.retrieve.all';
6 const FETCH_ID_TYPES            = 'open-ils.actor:open-ils.actor.user.ident_types.retrieve';
7 const FETCH_GROUPS              = 'open-ils.actor:open-ils.actor.groups.tree.retrieve';
8 const FETCH_NET_LEVELS  = 'open-ils.actor:open-ils.actor.net_access_level.retrieve.all';
9 const UPDATE_PATRON             = 'open-ils.actor:open-ils.actor.patron.update';
10 const PATRON_SEARCH             = 'open-ils.actor:open-ils.actor.patron.search.advanced';
11 const ZIP_SEARCH                        = 'open-ils.search:open-ils.search.zip';
12 const FETCH_ADDR_MEMS   = 'open-ils.actor:open-ils.actor.address.members';
13 const FETCH_GRP_MEMS            = 'open-ils.actor:open-ils.actor.usergroup.members.retrieve';
14 const CREATE_USER_NOTE  = 'open-ils.actor:open-ils.actor.note.create';
15 const CHECK_BARCODE             = 'open-ils.actor:open-ils.actor.barcode.exists';
16 const defaultState              = 'GA';
17 const defaultCountry            = 'USA';
18 const defaultNetAccess  = 'None';
19 const CSS_INVALID_DATA  = 'invalid_value';
20 const ADULT_AGE                 = 18;
21 //const GUARDIAN_NOTE           = 'SYSTEM: Parent/Guardian';
22
23 /* if they don't have these perms, they shouldn't be here */
24 var myPerms = [ 
25         'BAR_PATRON',
26         'group_application.user',
27         'group_application.user.patron',
28         'group_application.user.staff',
29         'group_application.user.staff.circ',
30         'group_application.user.staff.cat',
31         'group_application.user.staff.admin.global_admin',
32         'group_application.user.staff.admin.local_admin',
33         'group_application.user.staff.admin.lib_manager',
34         'group_application.user.staff.cat.cat1',
35         'group_application.user.staff.supercat',
36         'group_application.user.sip_client',
37         'group_application.user.vendor'
38         ];
39
40 var dataFields;
41 const numRegex          = /^\d+$/;
42 const wordRegex = /^\w+$/;
43 const ssnRegex          = /^\d{3}-\d{2}-\d{4}$/;
44 const dlRegex           = /^[a-zA-Z]{2}-\w+/; /* driver's license */
45 const phoneRegex        = /^\d{3}-\d{3}-\d{4}(| ex\d+)$/i;
46 const nonumRegex        = /^[a-zA-Z]\D*$/; /* no numbers, no beginning whitespace */
47 const dateRegex = /^\d{4}-\d{2}-\d{2}/;
48 const zipRegex          = /^\d{5}(-\d{4}|$)/; /* 12345 or 12345-6789 */
49
50 var barredAlerted = false;
51
52
53 function uEditUsrnameBlur(field) {
54         var usrname = uEditNodeVal(field);
55         if(!usrname) return;
56         var req = new Request(CHECK_USERNAME, SESSION, usrname);
57         req.callback( 
58                 function(r) {
59                         var res = r.getResultObject();
60                         if( res && res != patron.id() ) {
61                                 field.widget.onblur = null; /* prevent alert storm */
62                                 alertId('ue_dup_username');
63                                 field.widget.onblur = uEditUsrnameBlur;
64                                 setTimeout( 
65                                         function() {
66                                                 field.widget.node.focus();
67                                                 field.widget.node.select();
68                                         }, 10 
69                                 );
70                         }
71                 }
72         );
73         req.send();
74 }
75
76
77 function uEditBarcodeBlur(field) {
78         var barcode = uEditNodeVal(field);
79         if(!barcode) return;
80         var req = new Request(CHECK_BARCODE, SESSION, barcode);
81         req.callback( 
82                 function(r) {
83                         var res = r.getResultObject();
84                         if( res && res != patron.id() ) {
85                                 field.widget.onblur = null; /* prevent alert storm */
86                                 alertId('ue_dup_barcode');
87                                 field.widget.onblur = uEditBarcodeBlur;
88                                 setTimeout( 
89                                         function() {
90                                                 field.widget.node.focus();
91                                                 field.widget.node.select();
92                                         }, 10 
93                                 );
94                         } else {
95                                 var node = uEditFindFieldByWId("ue_username");
96                                 if(!node.widget.node.value) {
97                                         node.widget.node.value = barcode;
98                                         node.widget.node.onchange();
99                                 }
100                         }
101                 }
102         );
103         req.send();
104 }
105
106
107 function uEditDefineData(patron) {
108
109         var fields = [
110                 {
111                         required : true,
112                         object  : patron.card(),
113                         key             : 'barcode',
114                         errkey  : 'ue_bad_barcode',
115                         widget  : {
116                                 id              : 'ue_barcode',
117                                 regex   : wordRegex,
118                                 type    : 'input',
119                                 onblur : uEditBarcodeBlur
120                         }
121                 },
122                 {
123                         required : true,
124                         object  : patron,
125                         key             : 'usrname',
126                         errkey  : 'ue_bad_username',
127                         widget  : {
128                                 id              : 'ue_username',
129                                 regex   : wordRegex,
130                                 type    : 'input',
131                                 onblur : uEditUsrnameBlur
132                         }
133                 },
134                 {
135                         required : (patron.isnew()) ? true : false,
136                         object  : patron,
137                         key             : 'passwd',
138                         errkey  : 'ue_bad_password',
139                         widget  : {
140                                 id              : 'ue_password1',
141                                 type    : 'input',
142                                 onpostchange : function(field, newval) {
143                                         var pw2 = uEditFindFieldByWId('ue_password2');
144                                         /* tell the second passsword input to re-validate */
145                                         pw2.widget.node.onchange();
146                                 }
147
148                         }
149                 },
150                 {
151                         required : (patron.isnew()) ? true : false,
152                         object  : patron,
153                         key             : 'passwd',
154                         errkey  : 'ue_bad_password',
155                         widget  : {
156                                 id              : 'ue_password2',
157                                 type    : 'input',
158                                 onpostchange : function(field, newval) {
159                                         var pw1f = uEditFindFieldByWId('ue_password1');
160                                         var pw1 = uEditNodeVal(pw1f);
161                                         field.widget.regex = new RegExp('^'+pw1+'$');
162                                 }
163                         }
164                 },
165                 {
166                         required : true,
167                         object  : patron,
168                         key             : 'first_given_name',
169                         errkey  : 'ue_bad_firstname',
170                         widget  : {
171                                 id              : 'ue_firstname',
172                                 regex   : nonumRegex,
173                                 type    : 'input',
174                                 onblur : function(field) {
175                                         uEditCheckNamesDup('first', field );
176                                 }
177                         }
178                 },
179
180                 {
181                         required : false,
182                         object  : patron,
183                         key             : 'second_given_name',
184                         errkey  : 'ue_bad_middlename',
185                         widget  : {
186                                 id              : 'ue_middlename',
187                                 regex   : nonumRegex,
188                                 type    : 'input'
189                         }
190                 },
191                 {
192                         required : true,
193                         object  : patron,
194                         key             : 'family_name',
195                         errkey  : 'ue_bad_lastname',
196                         widget  : {
197                                 id              : 'ue_lastname',
198                                 regex   : nonumRegex,
199                                 type    : 'input',
200                                 onblur : function(field) {
201                                         uEditCheckNamesDup('last', field );
202                                 }
203                         }
204                 },
205                 {
206                         required : false,
207                         object  : patron,
208                         key             : 'suffix',
209                         widget  : {
210                                 id                      : 'ue_suffix',
211                                 type            : 'input',
212                                 onload  : function(val) {
213                                         setSelector($('ue_suffix_selector'), val);
214                                         $('ue_suffix_selector').onchange = function() {
215                                                 uEditFindFieldByKey('suffix').widget.node.onchange();
216                                         }
217                                 },
218                         }
219                 },
220                 {
221                         required : false,
222                         object  : patron,
223                         key             : 'dob',
224                         errkey  : 'ue_bad_dob',
225                         widget  : {
226                                 id                      : 'ue_dob',
227                                 regex           : dateRegex,
228                                 type            : 'input',
229                                 onpostchange    : function(field) { uEditCheckDOB(field); },
230                                 onblur  : function(field) { uEditCheckDOB(field); }
231                         }
232                 },
233                 {
234                         required : true,
235                         object  : patron,
236                         key             : 'ident_type',
237                         errkey  : 'ue_no_ident',
238                         widget  : {
239                                 id              : 'ue_primary_ident_type',
240                                 regex   : numRegex,
241                                 type    : 'select',
242                                 onpostchange : function(field, newval) 
243                                         { _uEditIdentPostchange('primary', field, newval); }
244                         }
245                 },
246                 {
247                         required : false,
248                         object  : patron,
249                         key             : 'ident_value',
250                         widget  : {
251                                 id                      : 'ue_primary_ident',
252                                 type            : 'input',
253                                 onblur : function(field) {
254                                         uEditCheckIdentDup(field);
255                                 }
256                         }
257                 },
258                 {
259                         required : false,
260                         object  : patron,
261                         key             : 'ident_value2',
262                         widget  : {
263                                 id                      : 'ue_secondary_ident',
264                                 type            : 'input'
265                         }
266                 },
267                 {
268                         required : false,
269                         object  : patron,
270                         key             : 'email',
271                         errkey  : 'ue_bad_email',
272                         widget  : {
273                                 id                      : 'ue_email',
274                                 type            : 'input',
275                                 regex           :  /.+\@.+\..+/,  /* make me better */
276                                 onblur  : function(field) {
277                                         var val = uEditNodeVal(field);
278                                         if( val && val != field.oldemail ) {
279                                                 uEditRunDupeSearch('email',
280                                                         { email : { value : val, group : 0 } });
281                                                 field.oldemail = val;
282                                         }
283                                 }
284                         }
285                 },
286                 {
287                         required : false,
288                         object  : patron,
289                         key             : 'day_phone',
290                         errkey  : 'ue_bad_phone',
291                         widget  : {
292                                 id                      : 'ue_day_phone',
293                                 type            : 'input',
294                                 regex           :  phoneRegex,
295                         }
296                 },
297                 {
298                         required : false,
299                         object  : patron,
300                         key             : 'evening_phone',
301                         errkey  : 'ue_bad_phone',
302                         widget  : {
303                                 id                      : 'ue_night_phone',
304                                 type            : 'input',
305                                 regex           :  phoneRegex,
306                         }
307                 },
308                 {
309                         required : false,
310                         object  : patron,
311                         key             : 'other_phone',
312                         errkey  : 'ue_bad_phone',
313                         widget  : {
314                                 id                      : 'ue_other_phone',
315                                 type            : 'input',
316                                 regex           :  phoneRegex,
317                         }
318                 },
319                 {
320                         required : true,
321                         object  : patron,
322                         key             : 'home_ou',
323                         widget  : {
324                                 id                      : 'ue_org_selector',
325                                 type            : 'select',
326                                 regex           :  numRegex,
327                         }
328                 },
329                 {
330                         required : true,
331                         object  : patron,
332                         key             : 'expire_date',
333                         errkey  : 'ue_bad_expire',
334                         widget  : {
335                                 id                      : 'ue_expire',
336                                 type            : 'input',
337                                 regex           :  dateRegex,
338                         }
339                 },
340                 {
341                         required : false,
342                         object  : patron,
343                         key             : 'active',
344                         widget  : {
345                                 id                      : 'ue_active',
346                                 type            : 'checkbox',
347                         }
348                 },
349                 {
350                         required : false,
351                         object  : patron,
352                         key             : 'barred',
353                         widget  : {
354                                 id                      : 'ue_barred',
355                                 type            : 'checkbox',
356                                 onpostchange : function(field, val) {
357                                         var afield = uEditFindFieldByKey('alert_message');
358                                         if( val ) {
359                                                 if( !barredAlerted ) {
360                                                         barredAlerted = true;
361                                                         alertId('ue_made_barred');
362                                                 }
363                                                 afield.required = true; 
364                                         } else {
365                                                 afield.required = false;
366                                         }
367                                 }
368                         }
369                 },
370                 {
371                         required : true,
372                         object  : patron,
373                         key             : 'profile',
374                         errkey  : 'ue_no_profile',
375                         widget  : {
376                                 id                      : 'ue_profile',
377                                 type            : 'select',
378                                 regex           : numRegex,
379                                 onpostchange : function(field, value) {
380                                         var type                        = groupsCache[value];
381                                         if(!type) return;
382                                         var interval    = type.perm_interval();
383
384                                         /* interval_to_seconds expects 'M' for months, 'm' for minutes */
385                                         interval                        = interval.replace(/mon/, 'Mon'); 
386                                         var intsecs             = parseInt(interval_to_seconds(interval));
387
388                                         var expdate             = new Date();
389                                         var exptime             = expdate.getTime();
390                                         exptime                 += intsecs * 1000;
391                                         expdate.setTime(exptime);
392
393                                         var year                        = expdate.getYear() + 1900;
394                                         var month               = (expdate.getMonth() + 1) + '';
395                                         var day                 = (expdate.getDate()) + '';
396
397                                         if(!month.match(/\d{2}/)) month = '0' + month;
398                                         if(!day.match(/\d{2}/)) day = '0' + day;
399
400                                         var node = $('ue_expire');
401                                         node.value = year+'-'+month+'-'+day;
402                                 }
403                         }
404                 },
405                 {
406                         required : false,
407                         object  : patron,
408                         key             : 'net_access_level',
409                         widget  : {
410                                 id              : 'ue_net_level',
411                                 type    : 'select'
412                         }
413                 },
414                 {
415                         required : false,
416                         object  : patron,
417                         key             : 'master_account',
418                         widget  : {
419                                 id                      : 'ue_group_lead',
420                                 type            : 'checkbox',
421                         }
422                 },
423                 {
424                         required : true,
425                         object  : patron,
426                         key             : 'claims_returned_count',
427                         widget  : {
428                                 id                      : 'ue_claims_returned',
429                                 type            : 'input',
430                                 regex           : numRegex,
431                                 disabled : true
432                         }
433                 },
434                 {
435                         required : false,
436                         object  : patron,
437                         key             : 'alert_message',
438                         widget  : {
439                                 id                      : 'ue_alert_message',
440                                 type            : 'input',
441                         }
442                 }
443         ];
444
445         for( var f in fields ) 
446                 dataFields.push(fields[f]);
447
448         uEditBuildAddrs(patron);
449         uEditBuildPatronSCM(patron);
450 }
451
452 var uEditOldFirstName;
453 var uEditOldMiddleName; /* future */
454 var uEditOldLastName;
455 function uEditCheckNamesDup(type, field) {
456         var newval = uEditNodeVal(field);
457         if(!newval) return;
458
459         var dosearch = false;
460
461         if(type =='first') {
462                 if( newval != uEditOldFirstName )
463                         dosearch = true;
464                 uEditOldFirstName = newval;
465         }
466
467         if(type =='last') {
468                 if( newval != uEditOldLastName )
469                         dosearch = true;
470                 uEditOldLastName = newval;
471         }
472
473         if( dosearch && uEditOldFirstName && uEditOldLastName ) {
474                 var search_hash = {};
475                 search_hash['first_given_name'] = { value : uEditOldFirstName, group : 0 };
476                 search_hash['family_name'] = { value : uEditOldLastName, group : 0 };
477                 uEditRunDupeSearch('names', search_hash);
478         }
479 }
480
481 var uEditOldIdentValue;
482 function uEditCheckIdentDup(field) {
483         var newval = uEditNodeVal(field);
484         if( newval && newval != uEditOldIdentValue ) {
485                 /* searches all ident_value fields */
486                 var search_hash  = { ident : { value : newval, group : 2 } };
487                 uEditRunDupeSearch('ident', search_hash);
488                 uEditOldIdentValue = newval;
489         }
490 }
491
492
493 /* Adds all of the addresses attached to the patron object
494         to the fields array */
495 var uEditAddrTemplate;
496 function uEditBuildAddrs(patron) {
497         var tbody = $('ue_address_tbody');
498         if(!uEditAddrTemplate)
499                 uEditAddrTemplate = tbody.removeChild($('ue_address_template'));
500         for( var a in patron.addresses() ) 
501                 uEditBuildAddrFields( patron, patron.addresses()[a]);
502 }
503
504
505 function uEditDeleteAddr( tbody, row, address, detach ) {
506         if(!confirm($('ue_delete_addr_warn').innerHTML)) return;
507         if(address.isnew()) { 
508                 patron.addresses(
509                         grep( patron.addresses(), 
510                                 function(i) {
511                                         return (i.id() != address.id());
512                                 }
513                         )
514                 );
515
516                 /* XXX */
517                 for( var f in dataFields ) {
518                         if( dataFields[f].object == address ) {
519                                 dataFields[f] = null;
520                         }
521                 }
522
523                 dataFields = compactArray(dataFields);
524
525         } else {
526
527                 if( detach ) { /* remove the offending address from the list */
528                         patron.addresses(
529                                 grep( 
530                                         patron.addresses(), 
531                                         function(i) {
532                                                 return (i.id() != address.id());
533                                         }
534                                 )
535                         );
536
537                 } else {
538                         address.isdeleted(1);
539                 }
540         }
541
542         tbody.removeChild(row);
543
544         var bid = patron.billing_address();
545         bid = (typeof bid == 'object') ? bid.id() : bid;
546
547         var mid = patron.mailing_address();
548         mid = (typeof mid == 'object') ? mid.id() : mid;
549
550
551         /* -----------------------------------------------------------------------
552                 if we're deleting a billing or mailing address 
553                 make sure some other address is automatically
554                 assigned as the billing or mailng address 
555                 ----------------------------------------------------------------------- */
556
557         if( bid == address.id() ) {
558                 for( var a in patron.addresses() ) {
559                         var addr = patron.addresses()[a];
560                         if(!addr.isdeleted() && addr.id() != address.id()) {
561                                 var node = uEditFindAddrInput('billing', addr.id());
562                                 node.checked = true;
563                                 uEditAddrTypeClick(node, 'billing');
564                                 break;
565                         }
566                 }
567         }
568
569         if( mid == address.id() ) {
570                 for( var a in patron.addresses() ) {
571                         var addr = patron.addresses()[a];
572                         if(!addr.isdeleted() && addr.id() != address.id()) {
573                                 var node = uEditFindAddrInput('mailing', addr.id());
574                                 node.checked = true;
575                                 uEditAddrTypeClick(node, 'mailing');
576                                 break;
577                         }
578                 }
579         }
580
581 }
582
583
584 function uEditFindAddrInput(type, id) {
585         var tbody = $('ue_address_tbody');
586         var rows = tbody.getElementsByTagName('tr');
587         for( var r in rows ) {
588                 var row = rows[r];
589                 if(row.parentNode != tbody) continue;
590                 var node = $n(row, 'ue_addr_'+type+'_yes');
591                 if( node.getAttribute('address') == id )
592                         return node;
593         }
594 }
595
596
597 function uEditAddrTypeClick(input, type) {
598         var tbody = $('ue_address_tbody');
599         var rows = tbody.getElementsByTagName('tr');
600         for( var r in rows ) {
601                 var row = rows[r];
602                 if(row.parentNode != tbody) continue;
603                 var node = $n(row, 'ue_addr_'+type+'_yes');
604                 removeCSSClass(node.parentNode,'addr_info_checked');
605         }
606
607         addCSSClass(input.parentNode,'addr_info_checked');
608         patron[type+'_address'](input.getAttribute('address'));
609         patron.ischanged(1);
610 }
611
612
613
614
615 /* Creates the field entries for an address object. */
616 function uEditBuildAddrFields(patron, address) {
617
618         var tbody = $('ue_address_tbody');
619
620         var row = tbody.appendChild(
621                 uEditAddrTemplate.cloneNode(true));
622
623         uEditCheckSharedAddr(patron, address, tbody, row);
624
625         $n(row, 'ue_addr_delete').onclick = 
626                 function() { uEditDeleteAddr(tbody, row, address); }
627
628         if( patron.billing_address() &&
629                         address.id() == patron.billing_address().id() ) 
630                 $n(row, 'ue_addr_billing_yes').checked = true;
631
632         if( patron.mailing_address() &&
633                         address.id() == patron.mailing_address().id() ) 
634                 $n(row, 'ue_addr_mailing_yes').checked = true;
635
636         $n(row, 'ue_addr_billing_yes').setAttribute('address', address.id());
637         $n(row, 'ue_addr_mailing_yes').setAttribute('address', address.id());
638
639         /* currently, non-owners cannot edit an address */
640         var disabled = (address.usr() != patron.id())
641
642         var fields = [
643                 { 
644                         required : false,
645                         object  : address, 
646                         key             : 'address_type', 
647                         widget  : {
648                                 base    : row,
649                                 name    : 'ue_addr_label',
650                                 type    : 'input',
651                                 disabled : disabled,
652                         }
653                 },
654                 { 
655                         required : true,
656                         object  : address, 
657                         key             : 'street1', 
658                         errkey  : 'ue_bad_addr_street',
659                         widget  : {
660                                 base    : row,
661                                 name    : 'ue_addr_street1',
662                                 type    : 'input',
663                                 disabled : disabled,
664                         }
665                 },
666                 { 
667                         required : false,
668                         object  : address, 
669                         key             : 'street2', 
670                         errkey  : 'ue_bad_addr_street',
671                         widget  : {
672                                 base    : row,
673                                 name    : 'ue_addr_street2',
674                                 type    : 'input',
675                                 disabled : disabled,
676                         }
677                 },
678                 { 
679                         required : true,
680                         object  : address, 
681                         key             : 'city', 
682                         errkey  : 'ue_bad_addr_city',
683                         widget  : {
684                                 base    : row,
685                                 name    : 'ue_addr_city',
686                                 type    : 'input',
687                                 disabled : disabled,
688                         }
689                 },
690                 { 
691                         required : false,
692                         object  : address, 
693                         key             : 'county', 
694                         widget  : {
695                                 base    : row,
696                                 name    : 'ue_addr_county',
697                                 type    : 'input',
698                                 disabled : disabled,
699                         }
700                 },
701                 { 
702                         required : true,
703                         object  : address, 
704                         key             : 'state', 
705                         errkey  : 'ue_bad_addr_state',
706                         widget  : {
707                                 base    : row,
708                                 name    : 'ue_addr_state',
709                                 type    : 'input',
710                                 disabled : disabled,
711                         }
712                 },
713                 { 
714                         required : true,
715                         object  : address, 
716                         key             : 'country', 
717                         errkey  : 'ue_bad_addr_country',
718                         widget  : {
719                                 base    : row,
720                                 name    : 'ue_addr_country',
721                                 type    : 'input',
722                                 disabled : disabled,
723                         }
724                 },
725                 { 
726                         required : true,
727                         object  : address, 
728                         key             : 'post_code',
729                         errkey  : 'ue_bad_addr_zip',
730                         widget  : {
731                                 base    : row,
732                                 name    : 'ue_addr_zip',
733                                 type    : 'input',
734                                 disabled : disabled,
735                                 regex   : zipRegex,
736                                 onblur : function(f) {
737                                         var v = uEditNodeVal(f);
738                                         var req = new Request(ZIP_SEARCH, v);
739                                         req.callback( 
740                                                 function(r) {
741                                                         var info = r.getResultObject();
742                                                         if(!info) return;
743                                                         var state = $n(f.widget.base, 'ue_addr_state');
744                                                         var county = $n(f.widget.base, 'ue_addr_county');
745                                                         var city = $n(f.widget.base, 'ue_addr_city');
746                                                         if(!state.value) {
747                                                                 state.value = info.state;
748                                                                 state.onchange();
749                                                         }
750                                                         if(!county.value) {
751                                                                 county.value = info.county;
752                                                                 county.onchange();
753                                                         }
754                                                         if(!city.value) {
755                                                                 city.value = info.city;
756                                                                 city.onchange();
757                                                         }
758                                                 }
759                                         );
760                                         req.send();
761                                 }
762                         }
763                 },
764                 { 
765                         required : false,
766                         object  : address, 
767                         key             : 'within_city_limits',
768                         widget  : {
769                                 base    : row,
770                                 name    : 'ue_addr_inc_yes',
771                                 type    : 'checkbox',
772                                 disabled : disabled,
773                         }
774                 },
775                 { 
776                         required : false,
777                         object  : address, 
778                         key             : 'valid',
779                         widget  : {
780                                 base    : row,
781                                 name    : 'ue_addr_valid_yes',
782                                 type    : 'checkbox',
783                                 disabled : disabled,
784                         }
785                 }
786         ];
787
788         for( var f in fields ) {
789                 dataFields.push(fields[f]);
790                 uEditActivateField(fields[f]);
791         }
792 }
793
794 function uEditBuildPatronSCM(patron) {
795         /* get the list of pre-defined maps */
796         var fields = uEditFindFieldsByKey('stat_cat_entry');
797         var map;
798         var newmaps = [];
799
800         /* for each user stat cat, pop it off the list,
801         updated the existing stat map field to match
802         the popped map and shove the existing stat
803         map field onto the user's list of stat maps */
804         while( (map = patron.stat_cat_entries().pop()) ) {
805
806                 var field = grep(fields, 
807                         function(item) {
808                                 return (item.object.stat_cat() == map.stat_cat());
809                         }
810                 );
811
812                 if(field) {
813                         var val = map.stat_cat_entry();
814                         field = field[0];
815                         $n(field.widget.base, field.widget.name).value = val;
816                         setSelector($n(field.widget.base, 'ue_stat_cat_selector'), val );
817                         field.object.stat_cat_entry(val);
818                         field.object.id(map.id());
819                         newmaps.push(field.object);
820                 }
821         }
822
823         for( var m in newmaps ) 
824                 patron.stat_cat_entries().push(newmaps[m]);
825 }
826
827
828 function uEditBuildSCMField(statcat, row) {
829
830         var map = new actscecm();
831         map.stat_cat(statcat.id());
832         map.target_usr(patron.id());
833
834         var field = {
835                 required : false,
836                 object  : map,
837                 key             : 'stat_cat_entry',
838                 widget  : {
839                         base    : row,
840                         name    : 'ue_stat_cat_newval',
841                         type    : 'input',
842
843                         onpostchange : function( field, newval ) {
844
845                                 /* see if the current map already resides in 
846                                         the patron entry list */
847                                 var exists = grep( patron.stat_cat_entries(),
848                                         function(item) {
849                                                 return (item.stat_cat() == statcat.id()); 
850                                         }
851                                 );
852
853                                 if(newval) {
854                                         map.isdeleted(0);
855                                         setSelector($n(row, 'ue_stat_cat_selector'), newval);
856                                 }
857
858                                 if(exists) {
859                                         if(!newval) {
860
861                                                 /* if the map is new but currently contains no value
862                                                         remove it from the set of new maps */
863                                                 if(map.isnew()) {
864                                                         patron.stat_cat_entries(
865                                                                 grep( patron.stat_cat_entries(),
866                                                                         function(item) {
867                                                                                 return (item.stat_cat() != map.stat_cat());
868                                                                         }
869                                                                 )
870                                                         );
871
872                                                 } else {
873                                                         map.isdeleted(1);
874                                                         map.ischanged(0);
875                                                 }
876                                         } 
877
878                                 } else {
879
880                                         /* map does not exist in the map array but now has data */
881                                         if(newval) { 
882                                                 map.isnew(1);
883                                                 patron.stat_cat_entries().push(map);
884                                         }
885                                 }
886                         }
887                 }
888         }
889
890         dataFields.push(field);
891 }
892
893
894
895 /** Run this after a new ident type is selected */
896 function _uEditIdentPostchange(type, field, newval) {
897
898         if(!newval) return;
899
900         /* When the ident type is changed, we change the
901         regex on the ident_value to match the selected type */
902         var vfname = 'ident_value';
903         if(type == 'secondary') vfname = 'ident_value2';
904         var vfield = uEditFindFieldByKey(vfname);
905         var name = identTypesCache[uEditNodeVal(field)].name();
906
907         hideMe($(type+'_ident_ssn_help'));
908         hideMe($(type+'_ident_dl_help'));
909
910         if(name.match(/ssn/i)) {
911                 vfield.widget.regex = ssnRegex;
912                 vfield.errkey = 'ue_bad_ident_ssn';
913                 unHideMe($(type+'_ident_ssn_help'));
914
915         } else {
916
917                 if(name.match(/driver/i)) {
918                         vfield.widget.regex = dlRegex;
919                         vfield.errkey = 'ue_bad_ident_dl';
920                         unHideMe($(type+'_ident_dl_help'));
921                         if(!uEditNodeVal(vfield))
922                                 vfield.widget.node.value = defaultState + '-';
923
924                 } else {
925                         vfield.widget.regex = null;
926                         vfield.errkey = null;
927                 }
928         }
929
930         /* focus then valdate the value field */
931         vfield.widget.node.onchange();
932         vfield.widget.node.focus();
933 }
934
935
936 /* checks to see if the given address is shared by others.
937  * if so, the address row is styled and ...
938  */
939
940 function uEditCheckSharedAddr(patron, address, tbody, row) {
941
942         if( address.isnew() || (patron.isnew() && !clone) ) return;
943
944         var req = new Request(FETCH_ADDR_MEMS, SESSION, address.id());
945         req.callback( 
946                 function(r) {
947
948                         var members = r.getResultObject();
949                         var shared = false;
950
951                         for( var m in members ) {
952                                 var id = members[m];
953
954                                 if( id != patron.id() ) {
955
956                                         addCSSClass(row.getElementsByTagName('table')[0], 'shared_address');
957                                         unHideMe($n(row, 'shared_row'));
958                                         $n(row, 'ue_addr_delete').disabled = true;
959
960                                         if( address.usr() != patron.id() ) {
961                                                 var button = $n(row, 'ue_addr_detach');
962                                                 unHideMe(button);
963                                                 button.onclick = 
964                                                         function() { uEditDeleteAddr( tbody, row, address, true ); }
965                                         }
966
967                                         shared = true;
968                                         break;
969                                 }
970                         }
971
972                         if( shared ) {
973
974                                 /* if this is a shared address, set the owner field and 
975                                         give the staff a chance to edit the owner if it's not this user */
976
977                                 var nnode = $n(row, 'addr_owner_name');
978                                 var link = $n(row, 'addr_owner');
979                                 var id = address.usr();
980                         
981                                 if( id == patron.id() ) {
982                         
983                                         nnode.appendChild(text(
984                                                 patron.first_given_name() + ' ' + patron.family_name()));
985                                         hideMe($n(row, 'owner_link_div'));
986                         
987                                 } else {
988                         
989                                         link.onclick = 
990                                                 function() { window.xulG.spawn_editor({ses:cgi.param('ses'),usr:id}) };
991                                 
992                                         if( userCache[id] ) {
993                                                 nnode.appendChild(text(
994                                                         usr.first_given_name() + ' ' +  usr.family_name()));
995                                 
996                                         } else {
997                                 
998                                                 fetchFleshedUser( id, 
999                                                         function(usr) {
1000                                                                 userCache[usr.id()] = usr;
1001                                                                 nnode.appendChild(text(
1002                                                                         usr.first_given_name() + ' ' + usr.family_name()));
1003                                                         }
1004                                                 );
1005                                         }
1006                                 }
1007                         }
1008                 }
1009         );
1010
1011         req.send();
1012 }
1013
1014
1015
1016
1017 var __lastdob;
1018 function uEditCheckDOB(field) {
1019
1020         var dob = uEditNodeVal(field);
1021
1022         /* don't bother if the data isn't valid */
1023         if(!dob || !dob.match(field.widget.regex)) 
1024                 return;
1025
1026         if( dob == __lastdob ) return;
1027
1028         __lastdob = dob;
1029
1030         var parts = dob.split(/-/);
1031         parts[2] = parts[2].replace(/[T ].*/,'');
1032         dob = buildDate( parts[0], parts[1], parts[2] );
1033
1034         var today = new Date();
1035
1036         if(!dob || dob > today) {
1037                 addCSSClass(field.widget.node, CSS_INVALID_DATA);
1038                 alertId('ue_bad_date');
1039                 return;
1040         }
1041
1042         var base = new Date();
1043         base.setYear( today.getYear() + 1900 - ADULT_AGE );
1044
1045         /* patron is at least 18 */
1046
1047         var f = uEditFindFieldByKey('ident_value2');
1048
1049         if( dob < base ) { /* patron is of age */
1050                 f.required = false;
1051                 hideMe(f.widget.node.parentNode.parentNode.parentNode);
1052                 return;
1053         }
1054
1055         unHideMe(f.widget.node.parentNode.parentNode.parentNode);
1056         f.required = true;
1057         uEditCheckErrors();
1058 }
1059
1060
1061