/* Check age and category entered on registration form against the age category requirements * Script requires two elements from the form; one with an id that contains'yearBorn', * and one with a name that contains 'Category'. Both inputs must be assigned a class of 'target'. * * eventYear is exposed in the document by customization to the php code, * the customization must be added to components\com_eventbooking\view\register\html.php after * '$event = EventbookingHelperDatabase::getEvent($eventId);' around line 34 * OR to components\com_eventbooking\view\override\register\html.php to void overwrite on upgrade * /* Customization to add javascript variable store event year * $eventYear = JHtml::_('date', $event->event_date, 'Y', null); * $document = JFactory::getDocument(); * $document->addScriptDeclaration(' * const eventYear = $eventYear; * '); ************************************************************************************************************************************** */ Ready(); function Ready() { //add listener on document when document ready if (document.readyState !== 'loading'){ FormListener(); } else { document.addEventListener('DOMContentLoaded', FormListener); } } function FormListener() { //set event listener on form member information parent as form elements for individuals in group registration are created after page load; event will bubble up to parent document.getElementById("t3-content").addEventListener("focusout", DetectChildFocusOut); //prevent event bubbling event.stopPropagation(); } function DetectChildFocusOut() { //check for desired event trigger element by checking for class if (event.target.classList.contains('target')) { CategoryAgeValidate(); }; } //end DetectChildFocusOut function CategoryAgeValidate() { let categoryElementId = ""; let yearBornElementId = ""; const targetId = event.target.id; const birthYearEnteredElementName = "yearBorn" IdElements(); ValidateAge(); function IdElements() { //get name and sequence number of target let sequenceNumber = targetId.match(/\d+$/); //identifies individual in group registration const categoryName = document.querySelector('[id^="Category_"]').id.match(/[a-zA-Z_]+/).toString(); if (sequenceNumber){ sequenceNumber = sequenceNumber.toString(); } //determine element pair to test if(sequenceNumber) { //is this a group member if(targetId.includes(birthYearEnteredElementName)){ yearBornElementId = targetId; categoryElementId = `${categoryName}${sequenceNumber}`; } else { yearBornElementId = `${birthYearEnteredElementName}_${sequenceNumber}`; categoryElementId = targetId; } } else { //individual registration yearBornElementId = birthYearEnteredElementName; categoryElementId = categoryName; } return[yearBornElementId, categoryElementId] } //end IdElements function ValidateAge(elementIds) { //get input values from form const birthYearEntered = Number(document.getElementById(yearBornElementId).value); const categorySelected = document.getElementById(categoryElementId).value; //return if input empty if (!birthYearEntered || !categorySelected) { return; } //determine refernce values for category selected in form const categoryParms = CategoryCheck(categorySelected); //test form inputs against reference values const testResult = TestAge(birthYearEntered, categoryParms); if (testResult !== 4) { //validation failed, notify user ValidationResultDisplay(testResult, categorySelected, categoryElementId); } } //end ValidateAge function CategoryCheck(categorySelected) { //get parameters for selected category // clean up category name input from form if (categorySelected.slice(-1) === '+') { //replace + at end of Master categories categorySelected = categorySelected.slice(0, -1); } if (categorySelected.includes('/')) { //replace / used in some categories categorySelected = categorySelected.replace(/\//g, '_'); } if (categorySelected.includes(' ')) { //replace space used in some categories categorySelected = categorySelected.replace(/\s/g, '_'); } //category references const categories = [ {name: "Master80", floor: 80, ceiling: 89}, {name: "Master70", floor: 70, ceiling: 79}, {name: "Master60", floor: 60, ceiling: 69}, {name: "Master50", floor: 50, ceiling: 59}, {name: "Senior", floor: 21, ceiling: 49}, {name: "Junior", floor: 18, ceiling: 20}, {name: "Cadet", floor: 15, ceiling: 17}, {name: "Cub", floor: 13, ceiling: 14}, {name: "Bowman", floor: 10, ceiling: 12}, {name: "Yeoman", floor: 7, ceiling: 9}, {name: "Collegiate", floor: 17, ceiling: 49}, {name: "ExecFITA", floor: 21, ceiling: 89}, {name: "ParaW1", floor: 10, ceiling: 89}, {name: "ParaOpen", floor: 10, ceiling: 89}, {name: "ParaVI1", floor: 10, ceiling: 89}, {name: "ParaVI2_VI3", floor: 10, ceiling: 89}, {name: "ParaVI2_3", floor: 10, ceiling: 89} ]; //select reference category based on form input const categoryRef = categories.filter(category => category.name === categorySelected); return categoryRef; } //end CategoryCheck function TestAge(birthYearEntered, categoryParms) { //test inputs against category parameters // universal control parameters for category/age test const lowerlimit = 8; //lowest age that can register without official intervention const upperlimit = 90; //highest age that can register without official intervention const senior = 21; // sets lower limit that Master age group can register, i.e., senior const master = 50; //set age for category direction split, those below and above split have opposing hierarchies // parameters that inputs will test against let categoryRefName = categoryParms[0].name; let categoryRefFloor = categoryParms[0].floor; let categoryRefCeiling = categoryParms[0].ceiling; // parameters let age = eventYear - birthYearEntered; let testResultFlag = 4; //default test result flag // Test Flags - 0:test failed; 1:age ineligible for category; 2:age eligible for lower category; 3:require intervention; 4:OK if (age < lowerlimit || age >= upperlimit) { // screen out questionable ages testResultFlag = 3; } else if (age >= master) { // Master categories are in age descending order, i.e., higher age is lower category if (categoryRefFloor > age || categoryRefCeiling < senior) { testResultFlag = 1; } else if (categoryRefFloor >= senior && categoryRefCeiling < age) { testResultFlag = 2; } } else if (age < master) { // Categories are in age ascending order if (categoryRefFloor > age && categoryRefFloor < master && categoryRefName !== 'Collegiate') { testResultFlag = 2; } else if (categoryRefFloor >= master || categoryRefCeiling < age) { testResultFlag = 1; } } else { testResultFlag = 0; } //return test results return [testResultFlag, age]; } // end testAge() function ValidationResultDisplay(testResult, categorySelected, categoryElementId) { const resultFlag = testResult[0]; const archerAge = testResult[1]; const msg = new Array(4); //set up messages //setup alert messages msg[0]= "ERROR: \n An error has occurred; please contact the website administrator."; msg[1] = "VIOLATION: \n Archer is " + archerAge + " years old for " + eventYear + " competitions (based on their age as of December 31 " + eventYear + ") and not eligible for the " + categorySelected + " category. Please select another category"; msg[2] = "ADVISORY: \n Archer is " + archerAge + " years old for " + eventYear + " competitions and registering in a higher category than required by their age. If you register in the selected " + categorySelected + " category the archer will be 'shooting up'."; msg[3]= "INTERVENTION REQUIRED: \n Archer is " + archerAge + " years old. Please contact the tournament director for registration."; //select appropriate message if (resultFlag === 0) { //test failed alert(msg[0]); ClrCategory(categoryElementId); //reset category input on form } else if (resultFlag === 1) { //too old alert(msg[1]); ClrCategory(categoryElementId); //reset category input on form } else if (resultFlag === 2) { //shooting up alert(msg[2]); } else if (resultFlag === 3) { //unreasonable age alert(msg[3]); ClrCategory(categoryElementId); //reset category input on form } //end if //reset category form element if age not eligible for selected category function ClrCategory(categoryElementId) { document.getElementById(categoryElementId).value=""; //reset category input on form).val(''); } //end clrCategory return; } //end ValidationResultDisplay } //end CategoryAgeValidate