diff --git a/i18n/en.js b/i18n/en.js
index f458db9..eaabb84 100644
--- a/i18n/en.js
+++ b/i18n/en.js
@@ -42,6 +42,7 @@ const en = {
"validationDateBefore": "Date must be before {0}/{1}/{2}",
"validationEmailAddress": "Please enter an email address in this format: user@example.com",
"validationPhoneNumber": "Please enter a phone number in this format: 999-999-9999",
+ "validationZipCode": "Please enter a zip code in this format: 99999",
"validationSocialFull": "Please enter a valid Social Security Number in this format: 999-99-9999",
"validationSocialPartial": "Please enter the last four digits of a Social Security Number in this format: 9999",
"validationTextShortExact": "Entered text is too short (should have {0} characters)",
@@ -58,4 +59,4 @@ const en = {
"enterValue": "Enter a value"
}
-export default en;
\ No newline at end of file
+export default en;
diff --git a/i18n/es.js b/i18n/es.js
index 90811a6..b6f16e1 100644
--- a/i18n/es.js
+++ b/i18n/es.js
@@ -42,6 +42,7 @@ const es = {
"validationDateBefore": "La fecha debe ser anterior al {0}/{1}/{2}",
"validationEmailAddress": "Ingrese una dirección de correo electrónico con este formato: user@example.com",
"validationPhoneNumber": "Ingrese un número de teléfono con este formato: 999-999-9999",
+ "validationZipCode": "Por favor ponga un código postal en este formato: 99999",
"validationSocialFull": "Ingrese un número de Seguro Social válido con este formato: 999-99-9999",
"validationSocialPartial": "Ingrese los últimos cuatro dígitos de un número de Seguro Social con este formato: 9999",
"validationTextShortExact": "El texto ingresado es demasiado corto (debe tener {0} caracteres)",
diff --git a/questionnaire.js b/questionnaire.js
index e4416b8..217a9e8 100644
--- a/questionnaire.js
+++ b/questionnaire.js
@@ -5,7 +5,7 @@ import { validateInput, validationError } from "./validate.js"
import { translate } from "./common.js";
export const moduleParams = {};
-import * as mathjs from 'https://cdn.skypack.dev/mathjs@11.2.0';
+import * as mathjs from 'https://cdn.jsdelivr.net/npm/mathjs@15.2.0/+esm';
export const math=mathjs.create(mathjs.all)
window.math = math
@@ -979,9 +979,7 @@ export async function submitQuestionnaire(store, questName) {
formData[`${questName}.COMPLETED`] = true;
formData[`${questName}.COMPLETED_TS`] = new Date();
try {
- store(formData).then(() => {
- location.reload();
- });
+ store(formData);
} catch (e) {
console.log("Store failed", e);
}
diff --git a/replace2.js b/replace2.js
index 71243c2..b8c8afa 100644
--- a/replace2.js
+++ b/replace2.js
@@ -1,8 +1,8 @@
-import { questionQueue, nextClick, previousClicked, moduleParams, rbAndCbClick, textBoxInput, handleXOR, displayQuestion, parseSSN, parsePhoneNumber, submitQuestionnaire, textboxinput, math, radioAndCheckboxUpdate } from "./questionnaire.js";
+import { questionQueue, nextClick, previousClicked, moduleParams, rbAndCbClick, textBoxInput, handleXOR, displayQuestion, parseSSN, parsePhoneNumber, submitQuestionnaire, textboxinput, math, radioAndCheckboxUpdate, evaluateCondition } from "./questionnaire.js";
import { restoreResults } from "./localforageDAO.js";
import { parseGrid, grid_replace_regex } from "./buildGrid.js";
import { clearValidationError } from "./validate.js";
-import { responseRequestedModal, responseRequiredModal, responseErrorModal, submitModal } from "./common.js";
+import { responseRequestedModal, responseRequiredModal, responseErrorModal, submitModal } from "./common.js";
import en from "./i18n/en.js";
import es from "./i18n/es.js";
@@ -29,7 +29,7 @@ let reduceObj = (obj) => {
}
transform.render = async (obj, divId, previousResults = {}) => {
-
+
moduleParams.renderObj = obj;
moduleParams.previousResults = previousResults;
moduleParams.soccer = obj.soccer;
@@ -58,11 +58,11 @@ transform.render = async (obj, divId, previousResults = {}) => {
document.head.appendChild(link2);
}
}
-
+
// Define the Date prototype function toQuestFormat
Date.prototype.toQuestFormat = function () { return `${this.getFullYear()}-${this.getMonth() + 1}-${this.getDate()}` }
const current_date = new Date()
-
+
// first... build grids...
contents = contents.replace(grid_replace_regex, parseGrid);
// then we must unroll the loops...
@@ -146,7 +146,7 @@ transform.render = async (obj, divId, previousResults = {}) => {
//handle options for question
questOpts = questOpts ? questOpts : "";
- questOpts = questOpts.replaceAll(/(min|max)-count\s*=\s*(\d+)/g,'data-$1-count=$2')
+ questOpts = questOpts.replaceAll(/(min|max)-count\s*=\s*(\d+)/g, 'data-$1-count=$2')
// handle displayif on the question...
// if questArgs is undefined set it to blank.
@@ -211,8 +211,8 @@ transform.render = async (obj, divId, previousResults = {}) => {
return `${forId}`;
}
// replace {#id} with span tag
- questText=questText.replace(/\{\#([^}#]+)\}/g,fHash)
- function fHash(fullmatch,expr){
+ questText = questText.replace(/\{\#([^}#]+)\}/g, fHash)
+ function fHash(fullmatch, expr) {
return `${expr}`
}
@@ -271,9 +271,9 @@ transform.render = async (obj, divId, previousResults = {}) => {
let optionObj = paramSplit(options);
// can't have the value uri encoded...
if (optionObj.hasOwnProperty("value")) {
- optionObj.value = decodeURIComponent(optionObj.value);
+ optionObj.value = decodeURIComponent(optionObj.value);
}
-
+
options = reduceObj(optionObj);
if (optionObj.hasOwnProperty("min")) {
@@ -282,9 +282,9 @@ transform.render = async (obj, divId, previousResults = {}) => {
if (optionObj.hasOwnProperty("max")) {
options = options + ` data-max-date-uneval=${optionObj.max}`
}
-
+
const descText = type === 'month' ? "Type month and four-digit year" : type === 'date' ? "Select a date" : "Enter the month and year in format: four digit year - two digit month. YYYY-MM";
-
+
// Adding placeholders and aria-describedby attributes in one line
options += ` placeholder='Select ${type}' aria-describedby='${elementId}-desc' aria-label='Select ${type}'`;
return `${descText}`;
@@ -313,6 +313,12 @@ transform.render = async (obj, divId, previousResults = {}) => {
const { options, elementId } = guaranteeIdSet(opts, "SSNsm");
return ``;
}
+ // replace |zip| with text input
+ questText = questText.replace(/\|zip\|(?:([^\|\<]+[^\|]+)\|)?/g, fzip);
+ function fzip(fullmatch, opts) {
+ const { options, elementId } = guaranteeIdSet(opts, "zip");
+ return ``;
+ }
// replace |state| with state dropdown
questText = questText.replace(/\|state\|(?:([^\|\<]+[^\|]+)\|)?/g, fState);
@@ -509,7 +515,7 @@ transform.render = async (obj, divId, previousResults = {}) => {
const value = questText.startsWith('
') ? questText.split('
')[0] : '';
// make sure that the element id is set...
let { options, elementId } = guaranteeIdSet(opts, "num");
-
+
options = options.replaceAll('\"', "\'");
//instead of replacing max and min with data-min and data-max, they need to be added, as the up down buttons are needed for input type number
let optionObj = paramSplit(options)
@@ -523,22 +529,49 @@ transform.render = async (obj, divId, previousResults = {}) => {
options = options + ` data-max="${optionObj.max}"`
}
+ let elementName=questID;
+ if (optionObj.hasOwnProperty("name")) {
+ elementName=optionObj.name;
+ }
+
// Handle not converted and not yet calculated min and max values
const minMaxValueTest = (value) => { return value && !value.startsWith('valueOr') && !value.includes('isDefined') && value !== '0' ? value : ''; }
- const min = minMaxValueTest(optionObj.min);
- const max = minMaxValueTest(optionObj.max);
+ // Evaluate min and max, ensuring they are valid numbers or get evaluated if they aren't.
+ const evaluateMinMax = (value) => {
+ let result = minMaxValueTest(value);
+ if (result && isNaN(result)) {
+ result = evaluateCondition(result);
+ if (isNaN(result)) result = ''; // Reset if still not a number after evaluation
+ }
+ return result;
+ };
+
+ // Process min and max values
+ let min = evaluateMinMax(optionObj.min);
+ let max = evaluateMinMax(optionObj.max);
// Build the description text
- const descriptionText = `This field accepts numbers. Please enter a whole number ${min && max ? 'between ' + min + ' and ' + max : ''}.`;
+ const descriptionText = `This field accepts numbers. Please enter a whole number ${min && max ? `between ${min} and ${max}` : ''}.`;
+ const defaultPlaceholder = `placeholder="${moduleParams.i18n.enterValue}"`;
- // Add placeholder and aria-describedby
- const placeholder = min ? `placeholder="${moduleParams.i18n.example}: ${min}"` : (max ? `placeholder="${moduleParams.i18n.example}: ${max}"` : `placeholder=${moduleParams.i18n.enterValue}`);
+ // Use default placeholder when min to max range is a large distribution, e.g. max weight (999) and max age (125).
+ // Same for min == 0. Show default placeholder for those cases.
+ let placeholder;
+ if (max && max > 100) {
+ placeholder = defaultPlaceholder;
+ } else if (min && max) {
+ const avgValue = Math.floor((parseInt(min, 10) + parseInt(max, 10)) / 2);
+ placeholder = `placeholder="${moduleParams.i18n.example}: ${avgValue}"`;
+ } else {
+ placeholder = defaultPlaceholder;
+ }
+
options += ` ${placeholder} aria-describedby="${elementId}-desc"`;
//onkeypress forces whole numbers
- return `
+ return `