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