// Object which stores all the user selected/entered values let inputObj = { textChoice: 'manual', // choice of text entry initially set as manual. Can have values manual, calculated text: '', // User entered text in case of manual numberOfCharacters: '', // number of characters in text. Either from user entered text or user entered number schoolLevel: '', // Value of school level selected from dropdown category: '' // Value of category selected from dropdown }; // function handleTextRadioClick: responsible for showing or hiding text input / text length input based on selected option function handleTextRadioClick() { let textChoice = document.querySelector('input[name="text-input-option"]:checked').value; inputObj.textChoice = textChoice; if (textChoice === 'manual') { let value = removeSpecialCharacters(inputObj.text); let characters = value.length; setCharacterLength(characters); } else { let value = document.getElementById("inputTextCharacters").value; setCharacterLength(value); } // show or hide validation messages if (inputObj.textChoice === 'manual' && inputObj.text === '') { //document.getElementById('textarea-validation').style.display = 'block'; } else { document.getElementById('textarea-validation').style.display = 'none'; } if (inputObj.textChoice === 'calculated' && (inputObj.numberOfCharacters === '' || inputObj.numberOfCharacters === 0)) { //document.getElementById('textCharacters-validation').style.display = 'block'; } else { document.getElementById('textCharacters-validation').style.display = 'none'; } document.getElementById('min-count-100-validation').style.display = 'none'; document.getElementById('min-count-400-validation').style.display = 'none'; toggleElement('character-calculation-wrapper'); toggleElement('manual-character-input'); } // function toggleElement: hides/shows the html element based on current visibility. // accepts value of id attribute of element as parameter function toggleElement(id) { let element = document.getElementById(id); if (element.style.display === "none") { element.style.display = "block"; } else { element.style.display = "none"; } } // function handleTextAreaChange: captures the changes as user enters the text and gets the length // and sets number of characters to property numberOfCharacters on inputObj function handleTextAreaChange() { let value = document.getElementById("manual-text-entry").value; inputObj.text = value; value = removeSpecialCharacters(value); let characters = value.length; setCharacterLength(characters); document.getElementById("calculatedTextCharacters").setAttribute('value', characters); } // function removeSpecialCharacters: removes punctuation marks and other special characters // but allows numbers and alphabets along with language specific characters German: äöüÄÖÜß and French: ùûüÿàâæéèêëïîôœÙÛÜŸÀÂÆÉÈÊËÏÎÔŒ function removeSpecialCharacters(str) { return str.replace(/(?!\w|\ä|\ö|\ü|\Ä|\Ö|\Ü|\ß|\ù|\û|\ü|\ÿ|\à|\â|\æ|\é|\è|\ê|\ë|\ï|\î|\ô|\œ|\Ù|\Û|\Ÿ|\À|\Â|\Æ|\É|\È|\Ê|\Ë|\Ï|\Î|\Ô|\Œ)./g, '') // regex to remove special characters .replace(/^(\s*)([\W\w]*)(\b\s*$)/g, '$2'); // regex to trim the string to remove any whitespace at the beginning or the end } // function handleCharacterInputChange: captures changes in number of characters input field // and sets number of characters to property numberOfCharacters on inputObj function handleCharacterInputChange() { let value = document.getElementById("inputTextCharacters").value; setCharacterLength(value); } // function setCharacterLength: sets number of characters to property numberOfCharacters on inputObj function setCharacterLength(characters) { if (characters === '') { inputObj.numberOfCharacters = 0; } else { inputObj.numberOfCharacters = parseInt(characters); } } // function isFormValid: checks for mandatory input fields and validates te form // returns true if all values are filled else returns false // also shows error messages for respective inputs fields function isFormValid() { let invalidFields = 0; if (inputObj.textChoice === 'manual' && inputObj.text === '') { invalidFields++; document.getElementById('textarea-validation').style.display = 'block'; } else { document.getElementById('textarea-validation').style.display = 'none'; } if (inputObj.textChoice === 'calculated' && (inputObj.numberOfCharacters === '' || inputObj.numberOfCharacters === 0)) { invalidFields++; document.getElementById('textCharacters-validation').style.display = 'block'; } else { document.getElementById('textCharacters-validation').style.display = 'none'; } if (inputObj.schoolLevel === '' || inputObj.schoolLevel === 0) { invalidFields++; document.getElementById('schoolLevel-validation').style.display = 'block'; } else { document.getElementById('schoolLevel-validation').style.display = 'none'; } if (inputObj.category === '' || inputObj.category === 0) { invalidFields++; document.getElementById('category-validation').style.display = 'block'; } else { document.getElementById('category-validation').style.display = 'none'; } if ((inputObj.numberOfCharacters < 100 && (inputObj.schoolLevel === '1' || inputObj.schoolLevel === '2'))) { invalidFields++; document.getElementById('min-count-100-validation').style.display = 'block'; } else { document.getElementById('min-count-100-validation').style.display = 'none'; } if ((inputObj.numberOfCharacters < 400 && (inputObj.schoolLevel === '3' || inputObj.schoolLevel === '4'))) { invalidFields++; document.getElementById('min-count-400-validation').style.display = 'block'; } else { document.getElementById('min-count-400-validation').style.display = 'none'; } return invalidFields < 1 } // function showFeedbackForm: displays feedback form when calculation is done function showFeedbackForm() { let element = document.getElementById('feedback-form'); element.style.display = "block"; } // function schoolLevelChangeEvent: listens for change in school level dropdown // and sets selected value to property schoolLevel on inputObj function schoolLevelChangeEvent(event) { inputObj.schoolLevel = event.target.value; } // function categoryChangeEvent: listens for change in category dropdown // and sets selected value to property category on inputObj function categoryChangeEvent(event) { inputObj.category = event.target.value; } // function calculateReadingTime: This function is responsible for calculating reading time // reading time can be calculated if all inputs are valid function calculateReadingTime() { if (isFormValid()) { //variable x which holds final reading time in minutes let x = 0; // logic or algorithm for calculating reading time goes here // inputObj.numberOfCharacters has number of characters (number data type) // inputObj.schoolLevel has level of school (string data type) // inputObj.category has category of reader (string data type) // example calculation //x = (inputObj.numberOfCharacters * inputObj.schoolLevel * inputObj.category); let combination = inputObj.schoolLevel + '' + inputObj.category; let C = inputObj.numberOfCharacters; switch (combination) { case '11': x = (0.7165 * C) + (172.8332 * 0.690) - 125.9143; break; case '12': x = (0.3463 * C) + (185.4177 * 0.249) - 62.0577; break; case '13': x = (0.4967 * C) + (223.3422 * 0.386) - 101.3559; break; case '14': x = (0.6489 * C) + (195.7637 * 0.528) - 120.8358; break; case '15': x = (0.7165 * C) + (172.8332 * 0.690) - 125.9143; break; case '21': x = (0.5007 * C) + (703.686 * 0.505) - 358.5641; break; case '22': x = (0.3135 * C) + (902.8845 * 0.30) - 285.855; break; case '23': x = (0.3396 * C) + (956.5228 * 0.329) - 326.4739; break; case '24': x = (0.3797 * C) + (857.5144 * 0.378) - 328.6899; break; case '25': x = (0.5007 * C) + (703.686 * 0.505) - 358.5641; break; case '31': x = (0.3524 * C) + (563.8412 * 0.42) - 196.8003; break; case '32': x = (0.1941 * C) + (671.9616 * 0.204) - 131.0749; break; case '33': x = (0.2432 * C) + (712.2978 * 0.263) - 177.29; break; case '34': x = (0.2965 * C) + (628.5916 * 0.34) - 189.2485; break; case '35': x = (0.3524 * C) + (563.8412 * 0.42) - 196.8003; break; case '41': x = (0.3445 * C) + (1315.1448 * 0.357) - 459.0464; break; case '42': x = (0.2003 * C) + (1421.0975 * 0.206) - 290.0477; break; case '43': x = (0.2289 * C) + (1389.9964 * 0.24) - 325.0492; break; case '44': x = (0.2842 * C) + (1471.1005 * 0.298) - 431.9652; break; case '45': x = (0.3445 * C) + (1315.1448 * 0.357) - 459.0464; break; default: x = 'error'; break; } // get modulo division of x for rounding off till 30 seconds let xMod60 = x % 60; if (xMod60 <= 15) { roundOff = 0; } if (xMod60 > 15 && xMod60 <= 30) { roundOff = 30; } if (xMod60 > 30 && xMod60 <= 45) { roundOff = 30; } if (xMod60 > 45) { roundOff = 60; } // subtract mod seconds and add rounded off seconds let roundedOffSeconds = x - xMod60 + roundOff; // get formatted time in hh:mm:ss format let formattedTime = getFormattedTime(roundedOffSeconds) // set time value to html element var s = document.getElementById('reading-time-element'); s.innerHTML = formattedTime; // display html element which shows time let element = document.getElementById('calculate-time-element'); element.style.display = "block"; } } // function getFormattedTime // accepts seconds value and returns in hh:mm:ss format function getFormattedTime(totalSeconds) { let hours = Math.floor(totalSeconds / 3600); totalSeconds %= 3600; let minutes = Math.floor(totalSeconds / 60); let seconds = totalSeconds % 60; minutes = String(minutes).padStart(2, "0"); hours = String(hours).padStart(2, "0"); seconds = String(seconds).padStart(2, "0"); return hours + ":" + minutes + ":" + seconds; }