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